diff --git a/BreakingChanges-1.2.txt b/BreakingChanges-1.2.txt index 498d2970..728c8b4d 100644 --- a/BreakingChanges-1.2.txt +++ b/BreakingChanges-1.2.txt @@ -30,12 +30,19 @@ Spring.Core A new property MsgDelivery has been added. The class, CachedMessageProducer, which is unlikely to be use by end users, was directly upgraded to the latest API without any backwards compatibility support. +4. AbstractApplicationContext.CaseSensitive renamed to AbstractApplicationContext.IsCaseSensitive + + Spring.Aop ---------- 1. AbstractAutoProxyCreator.FindEligibleAdvisors(Type) changed to AbstractAutoProxyCreator.FindEligibleAdvisors(Type, Name) +2. It is not possible to change a ProxyFactoryObject's product configuration at runtime + if IsSingleton==true since factory object singleton products get cached now. + + Changes (1.2 RC1 to 1.2.0 or greater) ===================================== diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs index 81f99df4..165cff20 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs @@ -42,7 +42,7 @@ namespace Spring.Aop.Framework.Adapter /// Aleksandar Seovic (.NET) public class DefaultAdvisorAdapterRegistry : IAdvisorAdapterRegistry { - private IList adapters = new ArrayList(); + private readonly IList adapters = new ArrayList(); /// /// Creates a new instance of the diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreator.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreator.cs index df790b0f..2ebf8fb8 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreator.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/DefaultAdvisorAutoProxyCreator.cs @@ -21,6 +21,8 @@ #region Imports using System; +using System.Collections; +using Spring.Context; using Spring.Objects.Factory; #endregion @@ -35,7 +37,7 @@ namespace Spring.Aop.Framework.AutoProxy /// Rod Johnson /// Adhari C Mahendra (.NET) /// Erich Eichinger (.NET) - public class DefaultAdvisorAutoProxyCreator : AbstractAdvisorAutoProxyCreator, IObjectNameAware + public class DefaultAdvisorAutoProxyCreator : AbstractAdvisorAutoProxyCreator, IObjectNameAware, IInitializingObject { /// /// Separator between prefix and remainder of object name @@ -43,6 +45,7 @@ namespace Spring.Aop.Framework.AutoProxy public static readonly string SEPARATOR = "."; private bool usePrefix; private string advisorObjectNamePrefix; + private IList cachedAdvisors; #region Properties @@ -97,7 +100,21 @@ namespace Spring.Aop.Framework.AutoProxy } } - #endregion + #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 IList 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. @@ -109,5 +126,14 @@ namespace Spring.Aop.Framework.AutoProxy { return (!usePrefix || advisorName.StartsWith(advisorObjectNamePrefix)); } - } + + /// + /// 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); + } } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs index 5cffebf8..5c8ddfcc 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs @@ -33,6 +33,7 @@ using Spring.Objects.Events; using Spring.Objects.Events.Support; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; +using Spring.Objects.Factory.Support; using Spring.Objects.Support; using Spring.Util; @@ -75,7 +76,7 @@ namespace Spring.Context.Support /// /// public abstract class AbstractApplicationContext - : ConfigurableResourceLoader, IConfigurableApplicationContext + : ConfigurableResourceLoader, IConfigurableApplicationContext, IObjectDefinitionRegistry { #region Constants @@ -124,7 +125,7 @@ namespace Spring.Context.Support /// /// The instance for this class. /// - private static readonly ILog log = LogManager.GetLogger(typeof(AbstractApplicationContext)); + protected readonly ILog log; /// /// The instance we delegate @@ -140,10 +141,10 @@ namespace Spring.Context.Support private IApplicationContext _parentApplicationContext; private readonly IList _objectFactoryPostProcessors; - private IList _defaultObjectPostProcessors; + private readonly IList _defaultObjectPostProcessors; private string _name; private DateTime _startupDate; - private readonly bool _caseSensitive; + private readonly bool _isCaseSensitive; #endregion @@ -196,8 +197,10 @@ namespace Spring.Context.Support protected AbstractApplicationContext(string name, bool caseSensitive, IApplicationContext parentApplicationContext) { + log = LogManager.GetLogger(this.GetType()); + _name = (StringUtils.IsNullOrEmpty(name)) ? DefaultRootContextName : name; - _caseSensitive = caseSensitive; + _isCaseSensitive = caseSensitive; _parentApplicationContext = parentApplicationContext; _objectFactoryPostProcessors = new ArrayList(); _defaultObjectPostProcessors = new ArrayList(); @@ -294,9 +297,9 @@ namespace Spring.Context.Support /// Gets a flag indicating whether context should be case sensitive. /// /// true if object lookups are case sensitive; otherwise, false. - protected bool CaseSensitive + public bool IsCaseSensitive { - get { return _caseSensitive; } + get { return _isCaseSensitive; } } /// @@ -1517,6 +1520,9 @@ namespace Spring.Context.Support /// 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. @@ -1528,6 +1534,60 @@ namespace Spring.Context.Support #endregion + #region IObjectDefinitionRegistry Members + + /// + /// 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) + { + ObjectFactory.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) + { + ObjectFactory.RegisterAlias(name, theAlias); + } + + #endregion + #region IMessageSource Members /// @@ -1896,12 +1956,14 @@ namespace Spring.Context.Support private sealed class ObjectPostProcessorChecker : IObjectPostProcessor, IOrdered { + private readonly ILog log; private int _objectPostProcessorTargetCount; private IConfigurableListableObjectFactory _objectFactory; public ObjectPostProcessorChecker() { + log = LogManager.GetLogger(this.GetType()); } public void Reset(IConfigurableListableObjectFactory objectFactory, int objectPostProcessorTargetCount) diff --git a/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContext.cs index 6be4cf89..2c0ae2ec 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractXmlApplicationContext.cs @@ -1,5 +1,5 @@ -#region License - +#region License + /* * Copyright © 2002-2005 the original author or authors. * @@ -14,228 +14,226 @@ * 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.IO; -using Common.Logging; -using Spring.Objects; -using Spring.Objects.Factory.Config; -using Spring.Objects.Factory.Support; -using Spring.Objects.Factory.Xml; -using Spring.Util; - -#endregion - -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 - { - /// - /// The instance for this class. - /// - private static readonly ILog log = LogManager.GetLogger(typeof(AbstractXmlApplicationContext)); - - 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) - {} - - /// - /// 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; } - - /// - /// 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. - IConfigurableListableObjectFactory oldObjectFactory = null; - oldObjectFactory = _objectFactory; - - if (oldObjectFactory != null) - { - _objectFactory = null; - oldObjectFactory.Dispose(); - } - - try - { - DefaultListableObjectFactory objectFactory = CreateObjectFactory(); - LoadObjectDefinitions(objectFactory); - - _objectFactory = objectFactory; - - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug( - 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); - } - } - - - /// - /// 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 the method. - /// - protected virtual void LoadObjectDefinitions( - XmlObjectDefinitionReader objectDefinitionReader) - { - string[] locations = ConfigurationLocations; - if (locations != null) - { - objectDefinitionReader.LoadObjectDefinitions(ConfigurationLocations); - } - } - - - /// - /// 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); + */ + +#endregion + +#region Imports + +using System; +using System.IO; +using System.Threading; +using Common.Logging; +using Spring.Objects; +using Spring.Objects.Factory.Config; +using Spring.Objects.Factory.Support; +using Spring.Objects.Factory.Xml; +using Spring.Util; + +#endregion + +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; + + /// + /// 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) + { } + + /// + /// 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; } + + /// + /// 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. + IConfigurableListableObjectFactory oldObjectFactory = null; + oldObjectFactory = Interlocked.Exchange(ref _objectFactory, null); + + if (oldObjectFactory != null) + { + // _objectFactory = null; + oldObjectFactory.Dispose(); + } + + try + { + DefaultListableObjectFactory objectFactory = CreateObjectFactory(); + LoadObjectDefinitions(objectFactory); + + _objectFactory = objectFactory; + + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug( + 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); + } + } + + + /// + /// 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 the method. + /// + protected virtual void LoadObjectDefinitions( + XmlObjectDefinitionReader objectDefinitionReader) + { + string[] locations = ConfigurationLocations; + if (locations != null) + { + objectDefinitionReader.LoadObjectDefinitions(ConfigurationLocations); + } + } + + + /// + /// 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); } /// @@ -246,57 +244,60 @@ namespace Spring.Context.Support 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) - { - - } - - /// - /// 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(CaseSensitive, GetInternalParentObjectFactory()); - } - - /// - /// Subclasses must return their internal object factory here. - /// - /// - /// The internal object factory for the application context. - /// - /// - public override IConfigurableListableObjectFactory ObjectFactory - { - get - { - lock(SyncRoot) - { - return _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); + } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs index cfeee781..b7d6cef0 100644 --- a/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/GenericApplicationContext.cs @@ -1,5 +1,5 @@ -#region License - +#region License + /* * Copyright 2002-2007 the original author or authors. * @@ -14,243 +14,166 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ - -#endregion - -using System; -using Spring.Core.IO; -using Spring.Objects.Factory.Config; -using Spring.Objects.Factory.Support; -using Spring.Util; - -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(); - /// - /// - /// - /// Mark Pollack - public class GenericApplicationContext : AbstractApplicationContext, IObjectDefinitionRegistry - { - private DefaultListableObjectFactory objectFactory; - - private bool refreshed = false; - - - /// - /// Initializes a new instance of the class. - /// - public GenericApplicationContext() - { - objectFactory = new DefaultListableObjectFactory(); - } - - /// - /// Initializes a new instance of the class. - /// - /// if set to true names in the context are case sensitive. - public GenericApplicationContext(bool caseSensitive) - { - objectFactory = new DefaultListableObjectFactory(caseSensitive); - } - - - /// - /// Initializes a new instance of the class. - /// - /// The object factory instance to use for this context. - public GenericApplicationContext(DefaultListableObjectFactory objectFactory) - { - AssertUtils.ArgumentNotNull(objectFactory, "objectFactory", "ObjectFactory must not be null"); - this.objectFactory = objectFactory; - } - - - /// - /// Initializes a new instance of the class. - /// - /// The parent application context. - public GenericApplicationContext(IApplicationContext parent) - { - objectFactory = new DefaultListableObjectFactory(); - ParentContext = 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 GenericApplicationContext(string name, bool caseSensitive, IApplicationContext parent) : this(caseSensitive) - { - Name = name; - ParentContext = parent; - } - - - /// - /// 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(objectFactory) - { - ParentContext = parent; - } - - - - /// - /// Gets the parent context, or if there is no - /// parent context. Set the parent of this application context also setting - /// the parent of the interanl ObjectFactory accordingly. - /// - /// The parent context - /// - /// The parent context, or if there is no - /// parent. - /// - /// - public override IApplicationContext ParentContext - { - get - { - return base.ParentContext; - } - set { - base.ParentContext = value; - objectFactory.ParentObjectFactory = 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; } - } - - - - #region IObjectDefinitionRegistry Members - - /// - /// 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. - /// - public override IObjectDefinition GetObjectDefinition(string name) - { - return objectFactory.GetObjectDefinition(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. - /// - public void RegisterObjectDefinition(string name, IObjectDefinition definition) - { - objectFactory.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 void RegisterAlias(string name, string theAlias) - { - objectFactory.RegisterAlias(name, theAlias); + */ + +#endregion + +using System; +using Spring.Objects.Factory.Config; +using Spring.Objects.Factory.Support; +using Spring.Util; + +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; + + + /// + /// Initializes a new instance of the class. + /// + public GenericApplicationContext() + : this(null, true, null, new DefaultListableObjectFactory()) + { + // 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. + /// + /// 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) + { + 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; } } /// @@ -258,11 +181,9 @@ namespace Spring.Context.Support /// i.e. whether there is a local object or alias registered under this name or /// an inner object created with this name. /// - public bool IsObjectNameInUse(string objectName) + public override bool IsObjectNameInUse(string objectName) { return objectFactory.IsObjectNameInUse(objectName); - } - - #endregion - } + } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableObjectFactory.cs index f9e01ea1..7c0bbe7e 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableObjectFactory.cs @@ -50,8 +50,8 @@ namespace Spring.Objects.Factory.Config /// Juergen Hoeller /// Rick Evans (.NET) public interface IConfigurableObjectFactory : IHierarchicalObjectFactory, ISingletonObjectRegistry - { - /// + { + /// /// Set the parent of this object factory. /// /// diff --git a/src/Spring/Spring.Core/Objects/Factory/IHierarchicalObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IHierarchicalObjectFactory.cs index a7affbd2..13a1ed21 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IHierarchicalObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IHierarchicalObjectFactory.cs @@ -47,7 +47,7 @@ namespace Spring.Objects.Factory /// /// Determines whether the local object factory contains a bean of the given name, - /// ignoring object defined in ancestor contexts. + /// 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. /// diff --git a/src/Spring/Spring.Core/Objects/Factory/IListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IListableObjectFactory.cs index 6a4e51be..4e07ef16 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IListableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IListableObjectFactory.cs @@ -57,8 +57,8 @@ namespace Spring.Objects.Factory /// Rod Johnson /// Rick Evans (.NET) public interface IListableObjectFactory : IObjectFactory - { - /// + { + /// /// Check if this object factory contains an object definition with the given name. /// /// diff --git a/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs index 41ccd8bb..fe3231aa 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs @@ -150,7 +150,12 @@ namespace Spring.Objects.Factory /// Rick Evans (.NET) public interface IObjectFactory : IDisposable { - /// + /// + /// Determine whether this object factory treats object names case-sensitive or not. + /// + bool IsCaseSensitive { get; } + + /// /// Is this object a singleton? /// /// @@ -196,8 +201,8 @@ namespace Spring.Objects.Factory /// /// /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. + /// 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. diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs index db9e6331..92875548 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs @@ -79,7 +79,7 @@ namespace Spring.Objects.Factory.Support /// /// The instance for this class. /// - private readonly ILog log = LogManager.GetLogger(typeof(AbstractAutowireCapableObjectFactory)); + private readonly ILog log; #region Constructor (s) / Destructor @@ -113,6 +113,8 @@ namespace Spring.Objects.Factory.Support protected AbstractAutowireCapableObjectFactory(bool caseSensitive, IObjectFactory parentFactory) : base(caseSensitive, parentFactory) { + log = LogManager.GetLogger(this.GetType()); + this.IgnoreDependencyInterface(typeof(IObjectFactoryAware)); this.IgnoreDependencyInterface(typeof(IObjectNameAware)); } diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinitionReader.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinitionReader.cs index 5e6ac00c..800bea15 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectDefinitionReader.cs @@ -44,10 +44,9 @@ namespace Spring.Objects.Factory.Support #region Constants /// - /// The shared instance for this class (and derived classes). + /// The instance for this class (and derived classes). /// - protected static readonly ILog log = - LogManager.GetLogger(typeof (AbstractObjectDefinitionReader)); + protected readonly ILog log; #endregion @@ -94,6 +93,8 @@ namespace Spring.Objects.Factory.Support IObjectDefinitionRegistry registry, AppDomain domain) { + log = LogManager.GetLogger(this.GetType()); + AssertUtils.ArgumentNotNull(registry, "registry", "IObjectDefinitionRegistry must not be null"); _registry = registry; _domain = domain; diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs index ad53396b..32e64310 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs @@ -89,19 +89,22 @@ namespace Spring.Objects.Factory.Support /// private static readonly object CURRENTLY_IN_CREATION = new Object(); - /// - /// The instance for this class. - /// - private readonly ILog log = LogManager.GetLogger(typeof(AbstractObjectFactory)); - /// /// 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 object emptyObject = new object(); + private static readonly object emptyObject = new object(); + /// + /// The instance for this class. + /// + private readonly ILog log; + /// + /// Cache of singleton objects created by s: FactoryObject name -> product + /// + private readonly Hashtable factoryObjectProductCache = new Hashtable(); #region Constructor (s) / Destructor @@ -730,63 +733,128 @@ namespace Spring.Objects.Factory.Support /// /// The singleton instance of the object. /// + [Obsolete("")] protected internal virtual object GetObjectForInstance(string name, object instance) { - //string objectName = TransformedObjectName(name); + return GetObjectForInstance(instance, name, TransformedObjectName(name), null); + } + /// + /// 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) && !(instance is IFactoryObject)) + if (IsFactoryDereference(name) && !(ObjectUtils.IsAssignable(typeof (IFactoryObject), instance))) { - throw new ObjectIsNotAFactoryException(TransformedObjectName(name), 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, we use it to - // create an object instance, unless the caller actually wants - // a reference to the factory. - if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IFactoryObject), instance)) + // 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 (!IsFactoryDereference(name)) + #region Instrumentation + + if (log.IsDebugEnabled) { + log.Debug(string.Format("Calling code asked for normal instance for name '{0}'.", canonicalName)); + } - // return object instance from factory... - IFactoryObject factory = (IFactoryObject)instance; - string objectName = TransformedObjectName(name); + #endregion - #region Instrumentation + return instance; + } - if (log.IsDebugEnabled) + // the user wants the factory itself ? + if (!ObjectUtils.IsAssignable(typeof (IFactoryObject), instance) || IsFactoryDereference(name)) + { + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug( + string.Format("Calling code asked for IFactoryObject instance for name '{0}'.", + TransformedObjectName(name))); + } + + #endregion + + return instance; + } + + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Object with name '{0}' is a factory object.", canonicalName)); + } + + #endregion + + object resultInstance = null; + + if (rod == null) + { + resultInstance = factoryObjectProductCache[canonicalName]; + } + + if (resultInstance == null) + { + // 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) { - log.Debug(string.Format("Object with name '{0}' is a factory object.", objectName)); - } - - #endregion - - RootObjectDefinition rod = - (ContainsObjectDefinition(objectName) ? GetMergedObjectDefinition(objectName, true) : null); - instance = GetObjectFromFactoryObject(factory, objectName, rod); - - if (instance == null) - { - throw new FactoryObjectNotInitializedException(TransformedObjectName(name), - "Factory object returned null object - " - + "possible cause: not fully initialized due to " - + "circular object reference."); + resultInstance = factoryObjectProductCache[canonicalName]; + if (resultInstance == null) + { + resultInstance = GetObjectFromFactoryObject(factory, canonicalName, rod); + if (resultInstance != null) + { + factoryObjectProductCache.Add(canonicalName, resultInstance); + } + return resultInstance; + } } } - else + + resultInstance = GetObjectFromFactoryObject(factory, canonicalName, rod); + + if (resultInstance == null) { - // the user wants the factory itself... - if (log.IsDebugEnabled) - { - log.Debug( - string.Format("Calling code asked for IFactoryObject instance for name '{0}'.", - TransformedObjectName(name))); - } + throw new FactoryObjectNotInitializedException(canonicalName, + "Factory object returned null object - " + + "possible cause: not fully initialized due to " + + "circular object reference."); } } - return instance; + return resultInstance; } /// @@ -1836,7 +1904,7 @@ namespace Spring.Objects.Factory.Support #endregion - instance = GetObjectForInstance(name, sharedInstance); + instance = GetObjectForInstance(sharedInstance, name, objectName, null); return EnsureObjectIsOfRequiredType(name, instance, requiredType); } } @@ -1877,7 +1945,7 @@ namespace Spring.Objects.Factory.Support { // create object instance... object sharedInstance = CreateAndCacheSingletonInstance(objectName, mergedObjectDefinition, arguments); - instance = GetObjectForInstance(name, sharedInstance); + instance = GetObjectForInstance(sharedInstance, name, objectName, mergedObjectDefinition); } else { diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs index 1081610c..b2bbbb1c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs @@ -269,7 +269,7 @@ namespace Spring.Objects.Factory.Support { //SPRNET-986 ObjectUtils.EmptyObjects -> null instance = objectFactory.InstantiateObject(actualInnerObjectName, mod, null, false, false); - result = objectFactory.GetObjectForInstance(actualInnerObjectName, instance); + result = objectFactory.GetObjectForInstance(instance, actualInnerObjectName, actualInnerObjectName, mod); } catch (ObjectsException ex) { diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs index dad16c3a..cf74e438 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs @@ -58,6 +58,14 @@ namespace Spring.Objects.Factory.Support /// private Hashtable objects = new Hashtable(); + /// + /// Determine whether this object factory treats object names case-sensitive or not. + /// + public bool IsCaseSensitive + { + get { return true; } + } + /// /// Return the number of objects defined in the factory. /// diff --git a/src/Spring/Spring.Core/Util/ObjectUtils.cs b/src/Spring/Spring.Core/Util/ObjectUtils.cs index 57168af7..154de6d9 100644 --- a/src/Spring/Spring.Core/Util/ObjectUtils.cs +++ b/src/Spring/Spring.Core/Util/ObjectUtils.cs @@ -25,6 +25,7 @@ using System.Collections; using System.Globalization; using System.Reflection; using System.Runtime.Remoting; +using System.Runtime.Remoting.Proxies; using Common.Logging; using Spring.Objects; using Spring.Reflection.Dynamic; @@ -311,8 +312,32 @@ namespace Spring.Util /// 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 (RemotingServices.IsTransparentProxy(obj)) + { + RealProxy rp = RemotingServices.GetRealProxy(obj); + if (rp is IRemotingTypeInfo) + { + return ((IRemotingTypeInfo) rp).CanCastTo(type, obj); + } + else if (rp != null) + { + type = rp.GetProxiedType(); + } + + if (type == null) + { + // cannot decide + return false; + } + } + return (type.IsInstanceOfType(obj) || - (!type.IsPrimitive && obj == null) || (type.Equals(typeof(bool)) && obj is Boolean) || (type.Equals(typeof(byte)) && obj is Byte) || (type.Equals(typeof(char)) && obj is Char) || diff --git a/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs b/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs index 2d93b0f2..7e7491e9 100644 --- a/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs +++ b/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs @@ -57,11 +57,6 @@ namespace Spring.Context.Support /// Aleksandar Seovic public class WebApplicationContext : AbstractXmlApplicationContext { - /// - /// The instance for this class. - /// - private static readonly ILog log = LogManager.GetLogger(typeof(WebApplicationContext)); - // holds construction info for debugging output private DateTime _constructionTimeStamp; private string _constructionUrl; @@ -133,6 +128,8 @@ namespace Spring.Context.Support static WebApplicationContext() { + ILog s_weblog = LogManager.GetLogger(typeof(WebApplicationContext)); + // register for ContextRegistry.Cleared event - we need to discard our cache in this case ContextRegistry.Cleared += new EventHandler(OnContextRegistryCleared); @@ -153,23 +150,23 @@ namespace Spring.Context.Support typeof(HttpRuntime).GetField("_beforeFirstRequest", BindingFlags.Instance | BindingFlags.NonPublic). GetValue(runtime); } - log.Debug("BeforeFirstRequest:" + beforeFirstRequest); + s_weblog.Debug("BeforeFirstRequest:" + beforeFirstRequest); if (beforeFirstRequest) { try { string firstRequestPath = HttpRuntime.AppDomainAppVirtualPath.TrimEnd('/') + "/dummy.context"; - log.Info("Forcing first request " + firstRequestPath); + s_weblog.Info("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); - log.Info("Successfully processed first request!"); + s_weblog.Info("Successfully processed first request!"); } catch (Exception ex) { - log.Error("Failed processing first request", ex); + s_weblog.Error("Failed processing first request", ex); throw; } } @@ -184,9 +181,10 @@ namespace Spring.Context.Support { lock (s_webContextCache) { - if (log.IsDebugEnabled) + ILog s_weblog = LogManager.GetLogger(typeof(WebApplicationContext)); + if (s_weblog.IsDebugEnabled) { - log.Debug("received ContextRegistry.Cleared event - clearing webContextCache"); + s_weblog.Debug("received ContextRegistry.Cleared event - clearing webContextCache"); } s_webContextCache.Clear(); } @@ -229,20 +227,23 @@ namespace Spring.Context.Support contextName = DefaultRootContextName; } + ILog s_weblog = LogManager.GetLogger(typeof(WebApplicationContext)); + bool isLogDebugEnabled = s_weblog.IsDebugEnabled; + lock (s_webContextCache) { - if (log.IsDebugEnabled) + if (isLogDebugEnabled) { - log.Debug(string.Format("looking up web context '{0}' in WebContextCache", contextName)); + s_weblog.Debug(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 (log.IsDebugEnabled) + if (isLogDebugEnabled) { - log.Debug( + s_weblog.Debug( string.Format("returning WebContextCache hit '{0}' for vpath '{1}' ", context, contextName)); } return context; @@ -251,9 +252,9 @@ namespace Spring.Context.Support // lookup ContextRegistry lock (ContextRegistry.SyncRoot) { - if (log.IsDebugEnabled) + if (isLogDebugEnabled) { - log.Debug(string.Format("looking up web context '{0}' in ContextRegistry", contextName)); + s_weblog.Debug(string.Format("looking up web context '{0}' in ContextRegistry", contextName)); } if (ContextRegistry.IsContextRegistered(contextName)) @@ -266,9 +267,9 @@ namespace Spring.Context.Support // finally ask HttpConfigurationSystem for the requested context try { - if (log.IsDebugEnabled) + if (isLogDebugEnabled) { - log.Debug( + s_weblog.Debug( string.Format( "web context for vpath '{0}' not found. Force creation using filepath '{1}'", contextName, virtualPath)); @@ -282,20 +283,20 @@ namespace Spring.Context.Support if (context != null) { - if (log.IsDebugEnabled) - log.Debug(string.Format("got context '{0}' for vpath '{1}'", context, contextName)); + if (isLogDebugEnabled) + s_weblog.Debug(string.Format("got context '{0}' for vpath '{1}'", context, contextName)); } else { - if (log.IsDebugEnabled) - log.Debug(string.Format("no context defined for vpath '{0}'", contextName)); + if (isLogDebugEnabled) + s_weblog.Debug(string.Format("no context defined for vpath '{0}'", contextName)); } } catch (Exception ex) { - if (log.IsErrorEnabled) + if (s_weblog.IsErrorEnabled) { - log.Error(string.Format("failed creating context '{0}'", contextName), ex); + s_weblog.Error(string.Format("failed creating context '{0}'", contextName), ex); } #if NET_1_1 if (ConfigurationUtils.IsConfigurationException(ex)) @@ -314,9 +315,9 @@ namespace Spring.Context.Support // 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 (log.IsDebugEnabled) + if (isLogDebugEnabled) { - log.Debug( + s_weblog.Debug( string.Format("added context '{0}' to WebContextCache for vpath '{1}'", context, contextName)); } @@ -329,9 +330,9 @@ namespace Spring.Context.Support if (!s_webContextCache.ContainsKey(parentContext.Name)) { s_webContextCache.Add(parentContext.Name, parentContext); - if (log.IsDebugEnabled) + if (isLogDebugEnabled) { - log.Debug( + s_weblog.Debug( string.Format("added parent context '{0}' to WebContextCache for vpath '{1}'", parentContext, parentContext.Name)); } @@ -369,7 +370,7 @@ namespace Spring.Context.Support protected override DefaultListableObjectFactory CreateObjectFactory() { string contextPath = GetContextPathWithTrailingSlash(); - return new WebObjectFactory(contextPath, this.CaseSensitive, GetInternalParentObjectFactory()); + return new WebObjectFactory(contextPath, this.IsCaseSensitive, GetInternalParentObjectFactory()); } /// 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 b473843d..7fec7558 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorCircularReferencesTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/AdvisorAutoProxyCreatorCircularReferencesTests.cs @@ -22,6 +22,7 @@ using System; using System.Reflection; +using Common.Logging; using NUnit.Framework; using Spring.Aop.Framework.DynamicProxy; using Spring.Aop.Support; @@ -45,23 +46,67 @@ namespace Spring.Aop.Framework.AutoProxy public void TestAutoProxyCreation() { 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(context.GetObject("testAdvisor"))); - Assert.IsFalse(AopUtils.IsAopProxy(context.GetObject("&testObjectFactory"))); + Assert.IsFalse(AopUtils.IsAopProxy(countingAdvisor)); + + TestObjectFactoryObject testObjectFactory = (TestObjectFactoryObject) context.GetObject("&testObjectFactory"); + Assert.IsFalse(AopUtils.IsAopProxy(testObjectFactory)); + Assert.IsFalse(AopUtils.IsAopProxy(context.GetObject("someOtherObject"))); // this one is completely independent Assert.IsTrue(AopUtils.IsAopProxy(context.GetObject("independentObject"))); - // products of the factory created at runtime should be proxied - Assert.IsFalse(AopUtils.IsAopProxy(context.GetObject("testObjectFactory"))); + + // 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); + + 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 TestAdvisor : StaticMethodMatcherPointcutAdvisor + public class TestDefaultAdvisorAutoProxyCreator : DefaultAdvisorAutoProxyCreator, IInitializingObject + { + private readonly ILog _logger; + + public TestDefaultAdvisorAutoProxyCreator() + { + _logger = LogManager.GetLogger(this.GetType().Name + "#" + GetHashCode()); + _logger.Trace("Created instance"); + } + + protected override object[] GetAdvicesAndAdvisorsForObject(Type targetType, string targetName, ITargetSource customTargetSource) + { + _logger.Trace("GetAdvicesAndAdvisorsForObject begin"); + object[] advices = base.GetAdvicesAndAdvisorsForObject(targetType, targetName, customTargetSource); + _logger.Trace("GetAdvicesAndAdvisorsForObject end"); + return advices; + } + + public override void AfterPropertiesSet() + { + _logger.Trace("AfterPropertiesSet"); + base.AfterPropertiesSet(); + } + } + + public class CountingAfterReturningAdvisor : StaticMethodMatcherPointcutAdvisor { private ITestObject testObject; @@ -71,26 +116,62 @@ namespace Spring.Aop.Framework.AutoProxy set { this.testObject = value; } } + public int GetCalls() + { + return ((CountingAfterReturningAdvice) base.Advice).GetCalls(); + } + + public CountingAfterReturningAdvisor() + { + LogManager.GetLogger(this.GetType()).Trace("Created instance #" + this.GetHashCode()); + base.Advice = new CountingAfterReturningAdvice(); + } + public override bool Matches(MethodInfo method, Type targetType) { return true; } } - public class SomeOtherObject - {} + public class SomeOtherObject : ICloneable + { + public SomeOtherObject() + { + LogManager.GetLogger(this.GetType()).Trace("Created instance #" + this.GetHashCode()); + } - public class IndependentObject - { } + public object Clone() + { + return this; + } + } + + public class IndependentObject : ICloneable + { + public IndependentObject() + { + LogManager.GetLogger(this.GetType()).Trace("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.Trace("Created instance"); } public SomeOtherObject SomeOtherObject @@ -101,15 +182,15 @@ namespace Spring.Aop.Framework.AutoProxy public object GetObject() { + GetObjectCounter++; // return product only, if factory has been fully initialized! if (!initialized) { + _logger.Trace("GetObject(): not initialized, returning null"); return null; } - else - { - return testObject; - } + _logger.Trace("GetObject(): initialized, returning testObject"); + return testObject; } public Type ObjectType @@ -119,12 +200,11 @@ namespace Spring.Aop.Framework.AutoProxy // return type only if we are ready to deliver our product! if (!initialized) { + _logger.Trace("get_ObjectType(): not initialized, returning null"); return null; } - else - { - return typeof(ITestObject); - } + _logger.Trace("get_ObjectType(): initialized, returning typeof(ITestObject)"); + return typeof(ITestObject); } } @@ -135,6 +215,7 @@ namespace Spring.Aop.Framework.AutoProxy public void AfterPropertiesSet() { + _logger.Trace("AfterPropertiesSet"); Assert.IsNotNull(someOtherObject); testObject = new TestObject(); initialized = true; 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 a3ec4d4e..2c12e6dc 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/advisorAutoProxyCreatorCircularReferencesTests.xml +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/advisorAutoProxyCreatorCircularReferencesTests.xml @@ -2,22 +2,23 @@ Reproduces a problem with AutoProxyCreators, IFactoryObjects, circular dependencies and a certain order of object definitions - + - - - - + + + + + - + \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs index ec6dcc7d..953b5490 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs @@ -243,9 +243,10 @@ namespace Spring.Aop.Framework } /// - /// Must see effect immediately on behaviour. + /// Must see effect immediately on behaviour. + /// TODO (EE): Note that we can't add or remove interfaces without reconfiguring the singleton. /// - [Test] + [Test, Ignore("change according to ProxyFactoryBeanTests.canAddAndRemoveAdvicesOnSingleton")] public void CanAddAndRemoveIntroductionsOnSingleton() { try diff --git a/test/Spring/Spring.Core.Tests/CommonTypes.cs b/test/Spring/Spring.Core.Tests/CommonTypes.cs index b13b9e26..5ad0ce54 100644 --- a/test/Spring/Spring.Core.Tests/CommonTypes.cs +++ b/test/Spring/Spring.Core.Tests/CommonTypes.cs @@ -128,7 +128,12 @@ namespace Spring #region IObjectFactory Members - public object this[string name] + public bool IsCaseSensitive + { + get { return true; } + } + + public object this[string name] { get { return null; } } @@ -216,7 +221,13 @@ namespace Spring #region IObjectFactory Members - public object this[string name] + public bool IsCaseSensitive + { + get { innerExecute(); + return true; } + } + + public object this[string name] { get { diff --git a/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs b/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs index 1bec58e6..bb7eb564 100644 --- a/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs +++ b/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs @@ -263,6 +263,11 @@ namespace Spring.Context // factory.AddObjectPostProcessor(new ApplicationContextAwareProcessor(this)); } + public override bool IsObjectNameInUse(string objectName) + { + return factory.IsObjectNameInUse(objectName); + } + public override IConfigurableListableObjectFactory ObjectFactory { get { return factory; } @@ -416,7 +421,12 @@ namespace Spring.Context #region IObjectFactory Members - public object this[string name] + public bool IsCaseSensitive + { + get { return true; } + } + + public object this[string name] { get { return null; } } diff --git a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs index adf2e81f..96d227b9 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs @@ -158,7 +158,12 @@ namespace Spring.Context.Support #region IObjectFactory Members - public object this[string name] + public bool IsCaseSensitive + { + get { return true; } + } + + public object this[string name] { get { return null; } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs index 40c98aeb..ae046ac2 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs @@ -26,8 +26,10 @@ using System.Reflection; using NUnit.Framework; using Spring.Aop.Config; +using Spring.Aop.Framework.AutoProxy; using Spring.Context; using Spring.Context.Support; +using Spring.Core.IO; using Spring.Objects; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; @@ -40,6 +42,31 @@ namespace Spring.Transaction.Config [TestFixture] public class TxNamespaceParserTests { + private class ResourceXmlApplicationContext : AbstractXmlApplicationContext + { + 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; } + } + } + + private const string APPCTXCFG_PROLOG = @""; + private const string APPCTXCFG_START = APPCTXCFG_PROLOG + @""; + private const string APPCTXCFG_END = @""; + private IApplicationContext ctx; [SetUp] @@ -50,6 +77,19 @@ namespace Spring.Transaction.Config ctx = new XmlApplicationContext("assembly://Spring.Data.Tests/Spring.Transaction.Config/TxNamespaceParserTests.xml"); } + [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() { diff --git a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests_TxAttributeDriven.xml b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests_TxAttributeDriven.xml new file mode 100644 index 00000000..90123b20 --- /dev/null +++ b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests_TxAttributeDriven.xml @@ -0,0 +1,4 @@ + + + + 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 357af79f..54c8bc6f 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 @@ -25,9 +25,14 @@ namespace Spring.Messaging.Nms.Connections { public class TestMessageConsumer : IMessageConsumer { - public event MessageListener Listener; + private void InvokeListener(IMessage message) + { + MessageListener listener = Listener; + if (listener != null) listener(message); + } + public IMessage Receive() { throw new NotImplementedException(); diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.2008.csproj b/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.2008.csproj index 6d4d918d..fd64add6 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.2008.csproj +++ b/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.2008.csproj @@ -46,10 +46,6 @@ False ..\..\..\lib\Net\2.0\Common.Logging.dll - - False - ..\..\..\lib\Net\2.0\Common.Logging.Log4Net.dll - False ..\..\..\lib\Net\2.0\log4net.dll diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.dll.config b/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.dll.config index bbaa7231..8d7d63c5 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.dll.config +++ b/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.dll.config @@ -32,12 +32,17 @@ limitations under the License. + + + + diff --git a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2008.csproj b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2008.csproj index fd28387e..3312e1c1 100644 --- a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2008.csproj +++ b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2008.csproj @@ -2,7 +2,7 @@ Debug AnyCPU - 9.0.21022 + 9.0.30729 2.0 {41BC3AEA-7EB3-48BF-B1EC-84119376AC98} Library @@ -33,10 +33,6 @@ False ..\..\..\lib\Net\2.0\Common.Logging.dll - - False - ..\..\..\lib\Net\2.0\Common.Logging.Log4Net.dll - False ..\..\..\lib\Net\2.0\log4net.dll