From 4fce21df8ddd2fc670587e297bf3a7d01a33cc39 Mon Sep 17 00:00:00 2001 From: bbaia Date: Tue, 5 Aug 2008 17:14:26 +0000 Subject: [PATCH] Added DynamicCodeManager.Clear() method. Used by ContextRegistry.Clear(). --- .../Context/Support/ContextRegistry.cs | 571 +++++++++--------- .../Spring.Core/Util/DynamicCodeManager.cs | 11 + .../Context/Support/ContextRegistryTests.cs | 36 +- 3 files changed, 332 insertions(+), 286 deletions(-) diff --git a/src/Spring/Spring.Core/Context/Support/ContextRegistry.cs b/src/Spring/Spring.Core/Context/Support/ContextRegistry.cs index 0f4047b9..96e74c39 100644 --- a/src/Spring/Spring.Core/Context/Support/ContextRegistry.cs +++ b/src/Spring/Spring.Core/Context/Support/ContextRegistry.cs @@ -1,285 +1,286 @@ -#region License - -/* - * Copyright © 2002-2005 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in 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; -using System.Collections; -using System.Collections.Specialized; -using System.Configuration; -using Common.Logging; - -using Spring.Util; - -#endregion - -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 - { - /// - /// The shared instance for this class (and derived classes). - /// - private static readonly ILog log = LogManager.GetLogger(typeof(ContextRegistry)); - - private static readonly object syncRoot = new Object(); - private static readonly ContextRegistry instance = new ContextRegistry(); - private static string rootContextName = null; - - private IDictionary contextMap = CollectionsUtil.CreateCaseInsensitiveHashtable(); - - #region Constructor (s) / Destructor - - // CLOVER:OFF - - /// - /// Creates a new instance of the ContextRegistry class. - /// - /// - ///

- /// Explicit static constructor to tell C# compiler - /// not to mark type as beforefieldinit. - ///

- ///
- static ContextRegistry() - {} - - // CLOVER:ON - - #endregion - - /// - /// 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; - - /// - /// Gets an object that should be used to synchronize access to ContextRegistry - /// from the calling code. - /// - public static object SyncRoot - { - get { return syncRoot; } - } - - /// - /// 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) - { - lock (syncRoot) - { - if (instance.contextMap.Contains(context.Name)) - { - IApplicationContext ctx = (IApplicationContext)instance.contextMap[context.Name]; - throw new ApplicationContextException( - string.Format("Existing context '{0}' already registered under name '{1}'.", - ctx, context.Name)); - } - instance.contextMap[context.Name] = context; - - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug(String.Format( - "Registering context '{0}' under name '{1}'.", context, context.Name)); - } - - #endregion - - if (rootContextName == null) - { - rootContextName = context.Name; - } - } - } - - /// - /// 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(); - 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 = (IApplicationContext)instance.contextMap[name]; - - #region Instrumentation - - if (log.IsDebugEnabled) - { - if (ctx == null) - { - log.Debug(String.Format( - "No context registered under name '{0}'.", name)); - } - else - { - log.Debug(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) - { - foreach (IApplicationContext ctx in instance.contextMap.Values) - { - ctx.Dispose(); - } - instance.contextMap.Clear(); - rootContextName = null; - ConfigurationUtils.RefreshSection(AbstractApplicationContext.ContextSectionName); - if (Cleared != null) - { - Cleared(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) - { - return (instance.contextMap[name] != null); - } - } - - private static bool rootContextCurrentlyInCreation; - - private static void InitializeContextIfNeeded() - { - if (rootContextName == null) - { - 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; - } - } - } - } -} - +#region License + +/* + * Copyright © 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in 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; +using System.Collections; +using System.Collections.Specialized; +using System.Configuration; +using Common.Logging; + +using Spring.Util; + +#endregion + +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 + { + /// + /// The shared instance for this class (and derived classes). + /// + private static readonly ILog log = LogManager.GetLogger(typeof(ContextRegistry)); + + private static readonly object syncRoot = new Object(); + private static readonly ContextRegistry instance = new ContextRegistry(); + private static string rootContextName = null; + + private IDictionary contextMap = CollectionsUtil.CreateCaseInsensitiveHashtable(); + + #region Constructor (s) / Destructor + + // CLOVER:OFF + + /// + /// Creates a new instance of the ContextRegistry class. + /// + /// + ///

+ /// Explicit static constructor to tell C# compiler + /// not to mark type as beforefieldinit. + ///

+ ///
+ static ContextRegistry() + {} + + // CLOVER:ON + + #endregion + + /// + /// 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; + + /// + /// Gets an object that should be used to synchronize access to ContextRegistry + /// from the calling code. + /// + public static object SyncRoot + { + get { return syncRoot; } + } + + /// + /// 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) + { + lock (syncRoot) + { + if (instance.contextMap.Contains(context.Name)) + { + IApplicationContext ctx = (IApplicationContext)instance.contextMap[context.Name]; + throw new ApplicationContextException( + string.Format("Existing context '{0}' already registered under name '{1}'.", + ctx, context.Name)); + } + instance.contextMap[context.Name] = context; + + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(String.Format( + "Registering context '{0}' under name '{1}'.", context, context.Name)); + } + + #endregion + + if (rootContextName == null) + { + rootContextName = context.Name; + } + } + } + + /// + /// 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(); + 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 = (IApplicationContext)instance.contextMap[name]; + + #region Instrumentation + + if (log.IsDebugEnabled) + { + if (ctx == null) + { + log.Debug(String.Format( + "No context registered under name '{0}'.", name)); + } + else + { + log.Debug(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) + { + foreach (IApplicationContext ctx in instance.contextMap.Values) + { + ctx.Dispose(); + } + instance.contextMap.Clear(); + rootContextName = null; + ConfigurationUtils.RefreshSection(AbstractApplicationContext.ContextSectionName); + DynamicCodeManager.Clear(); + if (Cleared != null) + { + Cleared(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) + { + return (instance.contextMap[name] != null); + } + } + + private static bool rootContextCurrentlyInCreation; + + private static void InitializeContextIfNeeded() + { + if (rootContextName == null) + { + 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; + } + } + } + } +} + diff --git a/src/Spring/Spring.Core/Util/DynamicCodeManager.cs b/src/Spring/Spring.Core/Util/DynamicCodeManager.cs index 6ed6aac9..c19e9092 100644 --- a/src/Spring/Spring.Core/Util/DynamicCodeManager.cs +++ b/src/Spring/Spring.Core/Util/DynamicCodeManager.cs @@ -140,5 +140,16 @@ namespace Spring.Util AssemblyBuilder assembly = (AssemblyBuilder) module.Assembly; assembly.Save(assembly.GetName().Name + ".dll"); } + + /// + /// Removes all registered s. + /// + public static void Clear() + { + lock (s_moduleCache.SyncRoot) + { + s_moduleCache.Clear(); + } + } } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Context/Support/ContextRegistryTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/ContextRegistryTests.cs index 369d635c..89e8df81 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/ContextRegistryTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/ContextRegistryTests.cs @@ -22,8 +22,13 @@ using System; using System.Xml; + using NUnit.Framework; +using Spring.Objects; +using Spring.Proxy; +using Spring.Objects.Factory.Support; + #endregion namespace Spring.Context.Support @@ -41,7 +46,6 @@ namespace Spring.Context.Support ContextRegistry.Clear(); } - /// /// This handler simulates calls to ContextRegistry during context creation /// @@ -130,6 +134,36 @@ namespace Spring.Context.Support Assert.IsNull(context, "Named context is not null even though a context has not been registered under the lookup name."); } + + [Test] + public void ClearWithDynamicProxies() + { + CompositionProxyTypeBuilder typeBuilder = new CompositionProxyTypeBuilder(); + typeBuilder.TargetType = typeof(TestObject); + Type proxyType = typeBuilder.BuildProxyType(); + + XmlApplicationContext ctx1 = new XmlApplicationContext(); + RootObjectDefinition od1 = new RootObjectDefinition(proxyType, false); + od1.PropertyValues.Add("Name", "Bruno"); + ((DefaultListableObjectFactory)ctx1.ObjectFactory).RegisterObjectDefinition("testObject", od1); + ContextRegistry.RegisterContext(ctx1); + + ITestObject to1 = ContextRegistry.GetContext().GetObject("testObject") as ITestObject; + Assert.IsNotNull(to1); + Assert.AreEqual("Bruno", to1.Name); + + XmlApplicationContext ctx2 = new XmlApplicationContext(); + RootObjectDefinition od2 = new RootObjectDefinition(proxyType, false); + od2.PropertyValues.Add("Name", "Baia"); + ((DefaultListableObjectFactory)ctx2.ObjectFactory).RegisterObjectDefinition("testObject", od2); + + ContextRegistry.Clear(); + + ITestObject to2 = ctx2.GetObject("testObject") as ITestObject; + Assert.IsNotNull(to2); + Assert.AreEqual("Baia", to2.Name); + } + #if NET_2_0 // TODO : Add support for .NET 1.x [Test]