From 0bc02e8db132ea1d0613b07f19dccbc304315024 Mon Sep 17 00:00:00 2001 From: eeichinger Date: Fri, 24 Jul 2009 16:34:14 +0000 Subject: [PATCH] synced AdvisedSupport with Spring/J --- .../Adapter/DefaultAdvisorAdapterRegistry.cs | 3 +- .../Adapter/GlobalAdvisorAdapterRegistry.cs | 3 +- .../Aop/Framework/AdvisedSupport.cs | 376 ++-- .../DynamicProxy/CachedAopProxyFactory.cs | 24 +- .../Spring.Aop/Aop/Framework/ProxyConfig.cs | 2 +- .../Spring.Aop/Aop/Framework/ProxyFactory.cs | 9 +- .../Aop/Framework/ProxyFactoryObject.cs | 1948 +++++++++-------- .../Target/AbstractPrototypeTargetSource.cs | 19 +- .../Support/AbstractApplicationContext.cs | 98 +- .../AbstractAutowireCapableObjectFactory.cs | 2 +- .../Factory/Support/AbstractObjectFactory.cs | 219 +- .../Factory/Support/ConstructorResolver.cs | 98 +- .../Factory/Support/WebObjectFactory.cs | 4 +- .../Aop/Framework/AopContextTests.cs | 4 +- .../ObjectNameAutoProxyCreatorTests.cs | 16 +- .../DynamicProxy/AbstractAopProxyTests.cs | 24 +- .../CachedAopProxyFactoryTests.cs | 49 +- .../DynamicProxy/DecoratorAopProxyTests.cs | 3 +- .../DefaultAopProxyFactoryTests.cs | 17 +- .../DynamicProxy/InheritanceAopProxyTests.cs | 15 +- .../Aop/Framework/ProxyFactoryObjectTests.cs | 88 +- .../Aop/Framework/ProxyFactoryTests.cs | 1 + .../Aop/SimpleBeforeAdviceAdapter.cs | 2 +- 23 files changed, 1716 insertions(+), 1308 deletions(-) diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs index 165cff20..f749f045 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/DefaultAdvisorAdapterRegistry.cs @@ -39,7 +39,8 @@ namespace Spring.Aop.Framework.Adapter /// interface. /// /// Rod Johnson - /// Aleksandar Seovic (.NET) + /// Aleksandar Seovic (.NET) + [Serializable] public class DefaultAdvisorAdapterRegistry : IAdvisorAdapterRegistry { private readonly IList adapters = new ArrayList(); diff --git a/src/Spring/Spring.Aop/Aop/Framework/Adapter/GlobalAdvisorAdapterRegistry.cs b/src/Spring/Spring.Aop/Aop/Framework/Adapter/GlobalAdvisorAdapterRegistry.cs index b321f2b7..e70bab88 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/Adapter/GlobalAdvisorAdapterRegistry.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/Adapter/GlobalAdvisorAdapterRegistry.cs @@ -27,7 +27,8 @@ namespace Spring.Aop.Framework.Adapter /// instance. /// /// Rod Johnson - /// Aleksandar Seovic (.NET) + /// Aleksandar Seovic (.NET) + [Serializable] public sealed class GlobalAdvisorAdapterRegistry : DefaultAdvisorAdapterRegistry { private static readonly GlobalAdvisorAdapterRegistry instance diff --git a/src/Spring/Spring.Aop/Aop/Framework/AdvisedSupport.cs b/src/Spring/Spring.Aop/Aop/Framework/AdvisedSupport.cs index 7ca9cc5c..38697132 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/AdvisedSupport.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/AdvisedSupport.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright © 2002-2005 the original author or authors. + * Copyright © 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,11 @@ #endregion -#region Imports - using System; using System.Collections; using System.Collections.Specialized; using System.Reflection; using System.Text; - using AopAlliance.Aop; using AopAlliance.Intercept; using Spring.Aop; @@ -34,8 +31,6 @@ using Spring.Aop.Target; using Spring.Util; using Spring.Proxy; -#endregion - namespace Spring.Aop.Framework { /// @@ -81,14 +76,7 @@ namespace Spring.Aop.Framework /// /// List of introductions. /// - private IList _introductions = new ArrayList(); - - /// - /// Array updated on changes to the advisors list, which is easier to - /// manipulate internally - /// - private IIntroductionAdvisor[] _introductionsArray - = new IIntroductionAdvisor[] { }; + private ArrayList _introductions = new ArrayList(); /// /// Interface map specifying which object should interface methods be @@ -114,8 +102,8 @@ namespace Spring.Aop.Framework /// private bool isActive; - private Type proxyType; - private ConstructorInfo proxyConstructor; + private Type cachedProxyType; + private ConstructorInfo cachedProxyConstructor; /// /// The list of event listeners. @@ -124,8 +112,14 @@ namespace Spring.Aop.Framework /// /// The advisor chain factory. - /// - private IAdvisorChainFactory advisorChainFactory; + /// + private IAdvisorChainFactory advisorChainFactory; + + /// + /// If no explicit interfaces are specified, interfaces will be automatically determined + /// from the target type + /// + private bool autoDetectInterfaces; #endregion @@ -137,8 +131,10 @@ namespace Spring.Aop.Framework /// default advisor chain factory. /// public AdvisedSupport() - { - AdvisorChainFactory = new HashtableCachingAdvisorChainFactory(); + { + this.advisorChainFactory = new HashtableCachingAdvisorChainFactory(); + this.AddListener(this.advisorChainFactory); + this.autoDetectInterfaces = true; } /// @@ -159,8 +155,38 @@ namespace Spring.Aop.Framework 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; + } + #endregion #region IAdvised implementation @@ -188,9 +214,10 @@ namespace Spring.Aop.Framework } } set - { + { + AssertUtils.ArgumentNotNull(value, "AdvisorChainFactory"); lock (this.SyncRoot) - { + { if (this.advisorChainFactory != null) { RemoveListener(this.advisorChainFactory); @@ -215,17 +242,19 @@ namespace Spring.Aop.Framework get { return this.m_targetSource; } set { - bool initialized = !(this.m_targetSource is EmptyTargetSource); - this.m_targetSource = value; - - if (this.m_targetSource != null && !initialized && interfaceMap.Count == 0) - { - Type[] interfaces = ReflectionUtils.GetInterfaces(this.m_targetSource.TargetType); - foreach (Type intf in interfaces) - { - AddInterfaceInternal(intf); - } - } + m_targetSource= (value != null) ? value : EmptyTargetSource.Empty; +// TODO (EE):remove +// bool initialized = !(this.m_targetSource is EmptyTargetSource); +// this.m_targetSource = value; +// +// if (this.m_targetSource != null && !initialized && interfaceMap.Count == 0) +// { +// Type[] interfaces = ReflectionUtils.GetInterfaces(this.m_targetSource.TargetType); +// foreach (Type intf in interfaces) +// { +// AddInterfaceInternal(intf); +// } +// } } } @@ -246,7 +275,6 @@ namespace Spring.Aop.Framework lock (this.SyncRoot) { IAdvisor[] advisorsArray = this._advisorsArray; - IIntroductionAdvisor[] introductionsArray = this._introductionsArray; for (int i = 0; i < advisorsArray.Length; i++) { @@ -256,9 +284,9 @@ namespace Spring.Aop.Framework if (!canBeSerialized) return false; } - for (int i = 0; i < introductionsArray.Length; i++) + for (int i = 0; i < this._introductions.Count; i++) { - IIntroductionAdvisor advisor = introductionsArray[i]; + IIntroductionAdvisor advisor = (IIntroductionAdvisor) this._introductions[i]; canBeSerialized = advisor.GetType().IsSerializable && advisor.Advice.GetType().IsSerializable; if (!canBeSerialized) return false; @@ -293,14 +321,26 @@ namespace Spring.Aop.Framework { lock (this.SyncRoot) { - this.interfaceMap.Clear(); - for (int i = 0; i < value.Length; i++) - { - AddInterfaceInternal(value[i]); - } - InterfacesChanged(); + DieIfFrozen("Cannot change interface list if frozen"); + SetInterfacesInternal(value); } } + } + + /// + /// Set interfaces to be proxied, bypassing locking and + /// + protected void SetInterfacesInternal(Type[] value) + { + this.interfaceMap.Clear(); + if (value != null) + { + for (int i = 0; i < value.Length; i++) + { + AddInterfaceInternal(value[i]); + } + } + InterfacesChanged(); } /// @@ -368,9 +408,7 @@ namespace Spring.Aop.Framework { get { - // lock(this.SyncRoot) { - // return (IAdvisor[]) _advisorsArray.Clone(); return _advisorsArray; } } @@ -399,7 +437,7 @@ namespace Spring.Aop.Framework { lock (this.SyncRoot) { - return (IIntroductionAdvisor[])this._introductionsArray.Clone(); + return (IIntroductionAdvisor[])this._introductions.ToArray(typeof(IIntroductionAdvisor)); } } } @@ -585,12 +623,9 @@ namespace Spring.Aop.Framework if (index == -1) { return false; - } - else - { - RemoveAdvisorInternal(index); - return true; - } + } + RemoveAdvisorInternal(index); + return true; } } @@ -664,38 +699,9 @@ namespace Spring.Aop.Framework RemoveInterface(intf); } this._introductions.RemoveAt(index); - UpdateIntroductionsArray(); } } - // - // /// - // /// Removes the supplied from the list of - // /// for this - // /// proxy. - // /// - // /// - // /// The to be removed. - // /// - // /// - // /// If this proxy configuration is frozen and the - // /// cannot be added. - // /// - // public bool RemoveInterceptor(IInterceptor interceptor) - // { - // AssertFrozen("Cannot remove interceptor: config is frozen"); - // int index = IndexOf(interceptor); - // if (index == -1) - // { - // return false; - // } - // else - // { - // RemoveAdvisor(index); - // return true; - // } - // } - /// /// Adds the supplied to the list /// of . @@ -729,7 +735,7 @@ namespace Spring.Aop.Framework this._advisors.Insert(index, advisor); } UpdateAdvisorsArray(); - InterceptorsChanged(); + AdviceChanged(); } } @@ -810,7 +816,6 @@ namespace Spring.Aop.Framework { this.interfaceMap[intf] = introductionAdvisor; } - UpdateIntroductionsArray(); if (this.interfaceMap.Count != intfCount) { InterfacesChanged(); @@ -924,16 +929,36 @@ namespace Spring.Aop.Framework /// 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 virtual string ToProxyConfigString() + public string ToProxyConfigString() { lock (this.SyncRoot) - { - return ToStringInternal(); + { + 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(); } #endregion @@ -952,7 +977,18 @@ namespace Spring.Aop.Framework #endregion - #region Properties + #region Properties + + /// + /// 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. /// @@ -1003,8 +1039,8 @@ namespace Spring.Aop.Framework /// internal Type ProxyType { - get { return this.proxyType; } - set { this.proxyType = value; } + get { return this.cachedProxyType; } + set { this.cachedProxyType = value; } } /// @@ -1012,8 +1048,8 @@ namespace Spring.Aop.Framework /// internal ConstructorInfo ProxyConstructor { - get { return this.proxyConstructor; } - set { this.proxyConstructor = value; } + get { return this.cachedProxyConstructor; } + set { this.cachedProxyConstructor = value; } } /// @@ -1249,7 +1285,7 @@ namespace Spring.Aop.Framework } this._advisors.RemoveAt(index); this.UpdateAdvisorsArray(); - this.InterceptorsChanged(); + this.AdviceChanged(); } /// @@ -1328,16 +1364,8 @@ namespace Spring.Aop.Framework this._advisorsArray = advisorsArray; } - /// - /// Bring the introductions array up to date with the list. - /// - private void UpdateIntroductionsArray() - { - IIntroductionAdvisor[] introductionsArray = new IIntroductionAdvisor[this._introductions.Count]; - this._introductions.CopyTo(introductionsArray, 0); - this._introductionsArray = introductionsArray; - } - + #region IAdvisedSupportListener support + /// /// Callback method that is invoked when the list of proxied interfaces /// has changed. @@ -1351,9 +1379,10 @@ namespace Spring.Aop.Framework /// to be generated on the next call to get a proxy. ///

/// - private void InterfacesChanged() + protected virtual void InterfacesChanged() { - ProxyType = null; + this.cachedProxyType = null; + this.cachedProxyConstructor = null; if (this.isActive) { foreach (IAdvisedSupportListener listener in this.listeners) @@ -1366,7 +1395,7 @@ namespace Spring.Aop.Framework /// /// Callback method that is invoked when the interceptor list has changed. /// - private void InterceptorsChanged() + protected virtual void AdviceChanged() { if (this.isActive) { @@ -1389,9 +1418,11 @@ namespace Spring.Aop.Framework { listener.Activated(this); } - } - } - + } + } + + #endregion + /// /// Creates an AOP proxy using this instance's configuration data. /// @@ -1407,7 +1438,33 @@ namespace Spring.Aop.Framework 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) + { + this.interfaceMap[introducedInterface] = introduction; + } + } + + if (targetInterfaces.Length > 0) + { + InterfacesChanged(); + } + } + if (!this.isActive) { Activate(); @@ -1416,6 +1473,22 @@ namespace Spring.Aop.Framework } } + /// + /// 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. @@ -1434,26 +1507,58 @@ namespace Spring.Aop.Framework /// instance. /// protected internal virtual void CopyConfigurationFrom(AdvisedSupport other) + { + CopyConfigurationFrom(other, other.TargetSource, new ArrayList(other.Advisors), new ArrayList(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.m_targetSource = other.m_targetSource; - this.proxyType = other.proxyType; - this.proxyConstructor = other.proxyConstructor; - - foreach (Type intf in other.interfaceMap.Keys) - { - this.interfaceMap[intf] = other.interfaceMap[intf]; - } + this.AdvisorChainFactory = other.advisorChainFactory; + this.m_targetSource = targetSource; +// this.cachedProxyType = other.cachedProxyType; +// this.cachedProxyConstructor = other.cachedProxyConstructor; + this.Interfaces = (Type[]) CollectionUtils.ToArray(other.Interfaces, typeof(Type)); + foreach (Type intf in other.interfaceMap.Keys) + { + this.interfaceMap[intf] = other.interfaceMap[intf]; + } this._advisors = new ArrayList(); - foreach (IAdvisor advisor in other._advisors) + foreach (IAdvisor advisor in advisors) { + AssertUtils.ArgumentNotNull(advisor, "Advisor must not be null"); AddAdvisor(advisor); } this._introductions = new ArrayList(); - foreach (IIntroductionAdvisor advisor in other._introductions) - { + foreach (IIntroductionAdvisor advisor in introductions) + { + // TODO (EE): implement +// ValidateIntroductionAdvisor((IIntroductionAdvisor) advisor); + AssertUtils.ArgumentNotNull(advisor, "IntroductionAdvisor must not be null"); AddIntroduction(advisor); } + UpdateAdvisorsArray(); + AdviceChanged(); } /// @@ -1468,33 +1573,10 @@ namespace Spring.Aop.Framework { lock (this.SyncRoot) { - return ToStringInternal(); + return ToProxyConfigString(); } } - /// - /// A that represents the current - /// configuration. - /// - /// - /// A that represents the current - /// configuration. - /// - private string ToStringInternal() - { - 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(); - } - /// /// Helper method that adds the names of all of the proxied interfaces /// to the buffer of the supplied . @@ -1568,7 +1650,7 @@ namespace Spring.Aop.Framework { throw new AopConfigException("Can't proxy null object"); } - return ReflectionUtils.GetInterfaces(target.GetType()); + return ReflectionUtils.GetInterfaces(target is Type ? (Type)target : target.GetType()); } } } \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CachedAopProxyFactory.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CachedAopProxyFactory.cs index 0fc210f4..a7dddc50 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CachedAopProxyFactory.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/CachedAopProxyFactory.cs @@ -55,8 +55,30 @@ namespace Spring.Aop.Framework.DynamicProxy /// private static readonly ILog logger = LogManager.GetLogger(typeof(CachedAopProxyFactory)); - private static Hashtable typeCache = new Hashtable(); + private static readonly Hashtable typeCache = new Hashtable(); + /// + /// Returns the number of proxy types in the cache + /// + public static int CountCachedTypes + { + get { return typeCache.Count; } + } + + /// + /// Clears the type cache + /// + public static void ClearCache() + { + typeCache.Clear(); + } + + /// + /// Creates a new instance + /// + public CachedAopProxyFactory() + {} + /// /// Generates the proxy type and caches the /// instance against the base type and the interfaces to proxy. diff --git a/src/Spring/Spring.Aop/Aop/Framework/ProxyConfig.cs b/src/Spring/Spring.Aop/Aop/Framework/ProxyConfig.cs index eda0c092..9c6ff7d3 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/ProxyConfig.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/ProxyConfig.cs @@ -169,7 +169,7 @@ namespace Spring.Aop.Framework /// public virtual bool IsFrozen { - get { return frozen; } + get { return this.frozen; } set { this.frozen = value; } } diff --git a/src/Spring/Spring.Aop/Aop/Framework/ProxyFactory.cs b/src/Spring/Spring.Aop/Aop/Framework/ProxyFactory.cs index 0dc56014..9a8c4f73 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/ProxyFactory.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/ProxyFactory.cs @@ -42,7 +42,7 @@ namespace Spring.Aop.Framework [Serializable] public class ProxyFactory : AdvisedSupport { - /// + /// /// Creates a new instance of the /// class. /// @@ -59,9 +59,8 @@ namespace Spring.Aop.Framework /// /// If the is . /// - public ProxyFactory(object target) : base(GetInterfaces(target)) + public ProxyFactory(object target) : base(target) { - Target = target; } /// @@ -74,7 +73,9 @@ namespace Spring.Aop.Framework ///

/// /// The interfaces to implement. - public ProxyFactory(Type[] interfaces) : base(interfaces) {} + public ProxyFactory(Type[] interfaces) : base(interfaces) + { + } /// /// Creates a new proxy according to the settings in this factory. diff --git a/src/Spring/Spring.Aop/Aop/Framework/ProxyFactoryObject.cs b/src/Spring/Spring.Aop/Aop/Framework/ProxyFactoryObject.cs index 7b3738c5..e4ccb889 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/ProxyFactoryObject.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/ProxyFactoryObject.cs @@ -1,5 +1,5 @@ -#region License - +#region License + /* * Copyright © 2002-2005 the original author or authors. * @@ -14,904 +14,1048 @@ * 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 AopAlliance.Aop; -using AopAlliance.Intercept; -using Common.Logging; -using Spring.Aop.Framework.Adapter; -using Spring.Aop.Support; -using Spring.Aop.Target; -using Spring.Core; -using Spring.Core.TypeResolution; -using Spring.Objects.Factory; -using Spring.Util; - -#endregion - -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, IAdvisedSupportListener - { - #region Fields - - /// - /// The shared instance for this class. - /// - private static readonly ILog logger = LogManager.GetLogger(typeof (ProxyFactoryObject)); - - /// - /// 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 const 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 mapping from an or interceptor - /// to an object name (or ), depending on where it was - /// sourced from. - /// - /// - ///

- /// If it's sourced from object name, it will need to be - /// refreshed each time a new prototype instance is created. - ///

- ///
- private IDictionary sourceDictionary = new Hashtable(); - - /// - /// Names of interceptors and pointcut objects in the factory. - /// - /// - ///

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

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

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

- ///
- private string[] introductionNames = null; - - /// - /// The name of the target object(in the enclosing - /// ). - /// - private string targetName = null; - - #endregion - - #region Properties - - /// - /// 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 - { - try - { - Interfaces = TypeResolutionUtils.ResolveInterfaceArray(value); - } - catch (Exception ex) - { - throw new AopConfigException("Bad value passed to the ProxyInterfaces property (see inner exception).", ex); - } - } - } - - /// - /// 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 { this.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 { this.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 { this.introductionNames = value; } - } - - #endregion - - #region IFactoryObjectAware implementation - - /// - /// 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 - { - this.objectFactory = value; - - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug("Setting IObjectFactory. Will configure target, interceptors and introductions..."); - } - - #endregion - - ConfigureAdvisorChain(); - ConfigureIntroductions(); - - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug("ProxyFactoryObject config: " + this); - } - - #endregion - - if (IsSingleton) - { - if (this.targetName != null) - { - TargetSource = NamedObjectToTargetSource(this.objectFactory.GetObject(this.targetName)); - } - - // eagerly initialize the shared singleton instance... - this.singletonInstance = CreateAopProxy().GetProxy(); - - // must listen to superclass advice and interface change - // events to recache singleton instance if necessary... - AddListener(this); - } - } - } - - #endregion - - #region IFactoryObject implementation - - /// - /// 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(this.SyncRoot) - { - return (this.IsSingleton ? GetSingletonInstance() : 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 - { - if (this.singletonInstance != null) - { - return this.singletonInstance.GetType(); - } - else if (Interfaces.Length == 1) - { - return Interfaces[0]; - } - else if (this.targetName != null && this.objectFactory != null) - { - return this.objectFactory.GetType(this.targetName); - } - else - { - return TargetSource.TargetType; - } - } - } - - /// - /// Is the object managed by this factory a singleton or a prototype? - /// - public virtual bool IsSingleton - { - get { return this.singleton; } - set { this.singleton = value; } - } - - #endregion - - #region Private Methods - - private object NewPrototypeInstance() - { - RefreshAdvisorChain(); - RefreshTarget(); - RefreshIntroductions(); - - // in the case of a prototype, we need to give the proxy - // an independent instance of the configuration... - - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug("Creating copy of prototype ProxyFactoryObject config: " + this); - } - - #endregion - - AdvisedSupport copy = new AdvisedSupport(); - copy.CopyConfigurationFrom(this); - - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug("Copy has config: " + copy); - } - - #endregion - - object generatedProxy = copy.CreateAopProxy().GetProxy(); - this.ProxyType = copy.ProxyType; - this.ProxyConstructor = copy.ProxyConstructor; - return generatedProxy; - } - - /// 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 ConfigureAdvisorChain() - { - if (this.interceptorNames == null || this.interceptorNames.Length == 0) - { - return; - } - - // materialize interceptor chain from object names... - for (int i = 0; i < this.interceptorNames.Length; ++i) - { - string name = this.interceptorNames[i]; - - if(name == null) - { - throw new AopConfigException("Found null interceptor name value in the InterceptorNames list; check your configuration."); - } - - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug("Configuring interceptor '" + name + "'"); - } - - #endregion - - if (name.EndsWith(GlobalInterceptorSuffix)) - { - IListableObjectFactory lof = this.objectFactory as IListableObjectFactory; - if (lof == null) - { - // TODO : test this... - throw new AopConfigException( - "Can only use global advisors or interceptors in conjunction with an IListableObjectFactory."); - } - else - { - AddGlobalAdvisor((IListableObjectFactory) this.objectFactory, - name.Substring(0, (name.Length - GlobalInterceptorSuffix.Length))); - continue; - } - } - - else if (i == this.interceptorNames.Length - 1 && - this.targetName == null && - this.m_targetSource == EmptyTargetSource.Empty) - { - // the last name in the chain may be an IAdvisor/IAdvice or a target/ITargetSource; - // unfortunately we don't know; we must look at type of the object... - if (!IsNamedObjectAnAdvisorOrAdvice(name)) - { - this.targetName = name; - continue; - } - } - - object advice = null; - if(this.IsSingleton || - this.objectFactory.IsSingleton(name)) - { - advice = this.objectFactory.GetObject(name); - } - else - { - advice = this.objectFactory.GetObject(name); - } - if (advice is IAdvisors) - { - IAdvisors advisors = (IAdvisors)advice; - foreach (object advisor in advisors.Advisors) - { - AddAdvisor(advisor, name); - } - } - else - { - AddAdvisor(advice, name); - } - } - } - - - private bool IsNamedObjectAnAdvisorOrAdvice(string name) - { - Type namedObjectType = this.objectFactory.GetType(name); - if (namedObjectType != null) - { - return typeof(IAdvisors).IsAssignableFrom(namedObjectType) - || typeof(IAdvisor).IsAssignableFrom(namedObjectType) - || typeof(IAdvice).IsAssignableFrom(namedObjectType); - } - // treat it as an IAdvisor if we can't tell... - return true; - } - - - /// - /// Configures introductions for this proxy. - /// - private void ConfigureIntroductions() - { - if (this.introductionNames == null || this.introductionNames.Length == 0) - { - return; - } - - // Materialize introductions from object names... - for (int i = 0; i < this.introductionNames.Length; ++i) - { - string name = this.introductionNames[i]; - - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug("Configuring introduction '" + name + "'"); - } - - #endregion - - if (name.EndsWith(GlobalInterceptorSuffix)) - { - if (!(this.objectFactory is IListableObjectFactory)) - { - throw new AopConfigException("Can only use global introductions with a ListableObjectFactory"); - } - else - { - AddGlobalIntroduction((IListableObjectFactory) this.objectFactory, - name.Substring(0, (name.Length - GlobalInterceptorSuffix.Length))); - } - } - else - { - // add a named introduction - object introduction = this.objectFactory.GetObject(this.introductionNames[i]); - AddIntroduction(introduction, this.introductionNames[i]); - } - } - } - - /// Add all global interceptors and pointcuts. - private void AddGlobalAdvisor(IListableObjectFactory objectFactory, string prefix) - { - string[] globalAspectNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisors)); - string[] globalAdvisorNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisor)); - string[] globalInterceptorNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IInterceptor)); - IList objects = new ArrayList(); - IDictionary names = new Hashtable(); - - for (int i = 0; i < globalAspectNames.Length; i++) - { - string name = globalAspectNames[i]; - if (name.StartsWith(prefix)) - { - 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.Length; i++) - { - string name = globalAdvisorNames[i]; - if (name.StartsWith(prefix)) - { - object obj = objectFactory.GetObject(name); - // exclude introduction advisors from interceptor list - if (!(obj is IIntroductionAdvisor)) - { - objects.Add(obj); - names[obj] = name; - } - } - } - for (int i = 0; i < globalInterceptorNames.Length; i++) - { - string name = globalInterceptorNames[i]; - if (name.StartsWith(prefix)) - { - object obj = objectFactory.GetObject(name); - objects.Add(obj); - names[obj] = name; - } - } - ((ArrayList) objects).Sort(new OrderComparator()); - foreach (object obj in objects) - { - string name = (string) names[obj]; - AddAdvisor(obj, name); - } - } - - /// Add all global introductions. - private void AddGlobalIntroduction(IListableObjectFactory objectFactory, string prefix) - { - string[] globalAspectNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisors)); - string[] globalAdvisorNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof (IAdvisor)); - string[] globalIntroductionNames = - ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof (IAdvice)); - IList objects = new ArrayList(); - IDictionary names = new Hashtable(); - - for (int i = 0; i < globalAspectNames.Length; 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.Length; 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.Length; 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; - } - } - } - ((ArrayList) objects).Sort(new OrderComparator()); - foreach (object obj in objects) - { - string name = (string) names[obj]; - AddIntroduction(obj, name); - } - } - - /// Add the given interceptor or pointcut to the interceptor list. - /// interceptor or pointcut to add - /// object name from which we obtained this object in our owning object factory - private void AddAdvisor(object next, string name) - { - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug("Adding advisor with name '" + name + "'."); - } - - #endregion - - IAdvisor advisor = NamedObjectToAdvisor(next); - AddAdvisor(advisor); - - // Record the pointcut as descended from the given object name. - // This allows us to refresh the interceptor list, which we'll need to - // do if we have to create a new prototype instance. Otherwise the new - // prototype instance wouldn't be truly independent, because it might - // reference the original instances of prototype interceptors. - this.sourceDictionary[advisor] = 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 AddIntroduction(object introduction, string name) - { - logger.Debug("Adding introduction with name [" + name + "]"); - IIntroductionAdvisor advisor = NamedObjectToIntroduction(introduction); - AddIntroduction(advisor); - - // Record the introduction as descended from the given object name. - // This allows us to refresh the introduction list, which we'll need to - // do if we have to create a new prototype instance. Otherwise the new - // prototype instance wouldn't be truly independent, because it might - // reference the original instances of prototype introductions. - this.sourceDictionary[advisor] = name; - } - - /// 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 void RefreshAdvisorChain() - { - IAdvisor[] advisors = Advisors; - for (int i = 0; i < advisors.Length; ++i) - { - string objectName = (string) this.sourceDictionary[advisors[i]]; - if (objectName != null) - { - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug("Refreshing object named '" + objectName + "'"); - } - - #endregion - - IAdvisor refreshedAdvisor - = NamedObjectToAdvisor(this.objectFactory.GetObject(objectName)); - ReplaceAdvisor(advisors[i], refreshedAdvisor); - this.sourceDictionary.Remove(advisors[i]); - // keep name mapping up to date... - this.sourceDictionary[refreshedAdvisor] = objectName; - } - else - { - // We can't throw an exception here, as the user may have added additional - // pointcuts programmatically we don't know about - logger.Info( - "Cannot find object name for Advisor [" + advisors[i] + "] when refreshing advisor chain"); - } - } - } - - /// - /// Refreshes target object for prototype instances. - /// - private void RefreshTarget() - { - #region Instrumentation - - if (logger.IsDebugEnabled) - { - logger.Debug("Refreshing target with name '" + this.targetName + "'"); - } - - #endregion - - if (StringUtils.IsNullOrEmpty(this.targetName)) - { - // TODO test... - throw new AopConfigException("Target name cannot be null (or composed wholly of whitespace) for prototype factory."); - } - object target = this.objectFactory.GetObject(this.targetName); - TargetSource = NamedObjectToTargetSource(target); - } - - /// 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 void RefreshIntroductions() - { - IIntroductionAdvisor[] introductions = Introductions; - for (int i = 0; i < introductions.Length; i++) - { - string objectName = (string) this.sourceDictionary[introductions[i]]; - if (objectName != null) - { - logger.Info("Refreshing introduction named '" + objectName + "'"); - object obj = this.objectFactory.GetObject(objectName); - IIntroductionAdvisor refreshedIntroduction = NamedObjectToIntroduction(obj); - - ReplaceIntroduction(i, refreshedIntroduction); - this.sourceDictionary.Remove(introductions[i]); - this.sourceDictionary[refreshedIntroduction] = objectName; - } - else - { - // We can't throw an exception here, as the user may have added additional - // introductions programmatically we don't know about - logger.Info( - "Cannot find object name for Introduction [" + introductions[i] + - "] when refreshing introduction list"); - } - } - } - - /// Wraps pointcut or interceptor with appropriate advisor - /// pointcut or interceptor that needs to be wrapped with advisor - /// Advisor - private IAdvisor NamedObjectToAdvisor(object next) - { - return GlobalAdvisorAdapterRegistry.Instance.Wrap(next); - } - - /// 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; - } - else - { - // It's an object that needs target source around it. - return new SingletonTargetSource(target); - } - } - - /// Wraps introduction with IIntroductionAdvisor if necessary - /// object to wrap - /// Introduction advisor - private IIntroductionAdvisor NamedObjectToIntroduction(object introduction) - { - if (introduction is IIntroductionAdvisor) - { - return (IIntroductionAdvisor) introduction; - } - else - { - return new DefaultIntroductionAdvisor((IAdvice) introduction); - } - } - - private object GetSingletonInstance() - { - if (this.singletonInstance == null) - { - this.singletonInstance = CreateAopProxy().GetProxy(); - } - return this.singletonInstance; - } - - #endregion - - #region IAdvisedSupportListener implementation - - /// - /// - public virtual void Activated(AdvisedSupport advisedSupport) - { - } - - /// No need to do anything when advice change, proxy can handle those changes by itself. - /// - /// - public virtual void AdviceChanged(AdvisedSupport advisedSupport) - { - } - - /// Implementation of listener for AdvisedSupport.InterfacesChanged event - /// event source - public virtual void InterfacesChanged(AdvisedSupport advisedSupport) - { - logger.Info("Implemented interfaces have changed; reseting singleton instance"); - this.singletonInstance = null; - this.ProxyType = null; - this.ProxyConstructor = null; - } - - #endregion - } + */ + +#endregion + +#region Imports + +using System; +using System.Collections; + +using AopAlliance.Aop; +using AopAlliance.Intercept; +using Common.Logging; +using Spring.Aop.Framework.Adapter; +using Spring.Aop.Support; +using Spring.Aop.Target; +using Spring.Core; +using Spring.Core.TypeResolution; +using Spring.Objects.Factory; +using Spring.Util; + +#endregion + +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 + { + #region Fields + + /// + /// The instance for this class. + /// + private readonly ILog logger; + + /// + /// 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. + /// + /// + ///

+ /// 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; + + #endregion + + #region Properties + + /// + /// Indicate whether this config shall be frozen upon creation + /// of the first proxy instance + /// + public bool FreezeProxy + { + 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 + { + // defer freezing this config until the first proxy gets created + this.freezeProxy = value; + } + } + + /// + /// Specify the AdvisorAdapterRegistry to use. Default is the + /// + public IAdvisorAdapterRegistry AdvisorAdapterRegistry + { + get { return advisorAdapterRegistry; } + set { advisorAdapterRegistry = 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 + { + set + { + try + { + Interfaces = TypeResolutionUtils.ResolveInterfaceArray(value); + } + catch (Exception ex) + { + throw new AopConfigException("Bad value passed to the ProxyInterfaces property (see inner exception).", ex); + } + } + } + + /// + /// 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 { this.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 { this.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 { this.introductionNames = value; } + } + + #endregion + + #region Construction and Initialization + + /// + /// Creates a new instance of ProxyFactoryObject + /// + public ProxyFactoryObject() + { + this.logger = LogManager.GetLogger(this.GetType()); + this.advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; + this.singleton = true; + } + + #endregion + + #region IObjectFactoryAware implementation + + /// + /// 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 + { + this.objectFactory = value; + } + } + + #endregion + + + #region IFactoryObject implementation + + /// + /// 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 (this.SyncRoot) + { + if (!this.initialized) + { + Initialize(); + this.initialized = true; + } + + if (this.IsSingleton) + { + return SingletonInstance; + } + + if (this.targetName == null) + { + logger.Warn("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 (this.SyncRoot) + { + if (this.singletonInstance != null) + { + return this.singletonInstance.GetType(); + } + else if (Interfaces.Length == 1) + { + return Interfaces[0]; + } + else if (this.targetName != null && this.objectFactory != null) + { + return this.objectFactory.GetType(this.targetName); + } + else + { + return TargetSource.TargetType; + } + } + } + } + + /// + /// Is the object managed by this factory a singleton or a prototype? + /// + public virtual bool IsSingleton + { + get { return this.singleton; } + set { this.singleton = value; } + } + + #endregion + + #region Private Methods + + private object SingletonInstance + { + get + { + if (this.singletonInstance == null) + { + this.TargetSource = FreshTargetSource(); + this.singletonInstance = CreateAopProxy().GetProxy(); + base.IsFrozen = this.freezeProxy; // freeze after creating proxy to allow for interface autodetection + } + return this.singletonInstance; + } + } + + private object NewPrototypeInstance() + { + // in the case of a prototype, we need to give the proxy + // an independent instance of the configuration... + + #region Instrumentation + + if (logger.IsDebugEnabled) + { + logger.Debug("Creating copy of prototype ProxyFactoryObject config: " + this); + } + + #endregion + + // 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); + + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug("Using ProxyConfig: " + copy); + } + #endregion + + object generatedProxy = copy.CreateAopProxy().GetProxy(); + base.IsFrozen = this.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() + { + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug(string.Format("Initialize: begin configure target, interceptors and introductions for {0}[{1}]", this.GetType().Name, this.GetHashCode())); + } + #endregion + + InitializeAdvisorChain(); + InitializeIntroductionChain(); + + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug(string.Format("Initialize: completed configuration for {0}[{1}]: {2}", this.GetType().Name, this.GetHashCode(), this.ToProxyConfigString())); + } + #endregion + } + + /// 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(this.interceptorNames)) + { + return; + } + + CheckInterceptorNames(); + + // Globals can't be last unless we specified a targetSource using the property... + if (this.interceptorNames[this.interceptorNames.Length - 1] != null + && this.interceptorNames[this.interceptorNames.Length - 1].EndsWith(GlobalInterceptorSuffix) + && this.targetName == null + && this.TargetSource == EmptyTargetSource.Empty) + { + throw new AopConfigException("Target required after globals"); + } + + // materialize interceptor chain from object names... + foreach (string name in this.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 = this.objectFactory as IListableObjectFactory; + if (lof == null) + { + throw new AopConfigException("Can only use global advisors or interceptors in conjunction with an IListableObjectFactory."); + } + + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug("Adding global advisor '" + name + "'"); + } + #endregion + + AddGlobalAdvisor(lof, name.Substring(0, (name.Length - GlobalInterceptorSuffix.Length))); + } + else + { + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug("resolving advisor name " + "'" + name + "'"); + } + #endregion + + // If we get here, we need to add a named interceptor. + // We must check if it's a singleton or prototype. + object advice; + if (this.IsSingleton || this.objectFactory.IsSingleton(name)) + { + advice = this.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) + { + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug(string.Format("Adding advisor list '{0}'", name)); + } + #endregion + + IAdvisors advisors = (IAdvisors)advice; + foreach (object element in advisors.Advisors) + { + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug(string.Format("Adding advisor '{0}' of type {1}", name, element.GetType().FullName)); + } + #endregion + IAdvisor advisor = NamedObjectToAdvisor(element); + AddAdvisor(advisor); + } + } + else + { + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug(string.Format("Adding advisor '{0}' of type {1}", name, advice.GetType().FullName)); + } + #endregion + + IAdvisor advisor = NamedObjectToAdvisor(advice); + AddAdvisor(advisor); + } + } + + private bool IsNamedObjectAnAdvisorOrAdvice(string name) + { + Type namedObjectType = this.objectFactory.GetType(name); + if (namedObjectType != null) + { + return typeof(IAdvisors).IsAssignableFrom(namedObjectType) + || typeof(IAdvisor).IsAssignableFrom(namedObjectType) + || typeof(IAdvice).IsAssignableFrom(namedObjectType); + } + // treat it as an IAdvisor if we can't tell... + return true; + } + + /// Add all global interceptors and pointcuts. + private void AddGlobalAdvisor(IListableObjectFactory objectFactory, string prefix) + { + string[] globalAspectNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisors)); + string[] globalAdvisorNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisor)); + string[] globalInterceptorNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IInterceptor)); + ArrayList objects = new ArrayList(); + Hashtable names = new Hashtable(); + + for (int i = 0; i < globalAspectNames.Length; i++) + { + string name = globalAspectNames[i]; + if (name.StartsWith(prefix)) + { + 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.Length; i++) + { + string name = globalAdvisorNames[i]; + if (name.StartsWith(prefix)) + { + object obj = objectFactory.GetObject(name); + // exclude introduction advisors from interceptor list + if (!(obj is IIntroductionAdvisor)) + { + objects.Add(obj); + names[obj] = name; + } + } + } + for (int i = 0; i < globalInterceptorNames.Length; i++) + { + string name = globalInterceptorNames[i]; + if (name.StartsWith(prefix)) + { + object obj = objectFactory.GetObject(name); + objects.Add(obj); + names[obj] = name; + } + } + ((ArrayList)objects).Sort(new OrderComparator()); + foreach (object obj in objects) + { + string name = (string)names[obj]; + AddAdvisorOnChainCreation(obj, name); + } + } + + /// + /// Configures introductions for this proxy. + /// + private void InitializeIntroductionChain() + { + if (ObjectUtils.IsEmpty(this.introductionNames)) + { + return; + } + + // Materialize introductions from object names... + foreach (string name in this.introductionNames) + { + if (name == null) + { + throw new AopConfigException("Found null interceptor name value in the InterceptorNames list; check your configuration."); + } + + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug("Adding introduction '" + name + "'"); + } + #endregion + + if (name.EndsWith(GlobalInterceptorSuffix)) + { + if (!(this.objectFactory is IListableObjectFactory)) + { + throw new AopConfigException("Can only use global introductions with a ListableObjectFactory"); + } + AddGlobalIntroduction((IListableObjectFactory)this.objectFactory, name.Substring(0, (name.Length - GlobalInterceptorSuffix.Length))); + } + else + { + // add a named introduction + object introduction; + if (this.IsSingleton || this.objectFactory.IsSingleton(name)) + { + introduction = this.objectFactory.GetObject(name); + AssertUtils.ArgumentNotNull(introduction, "introduction", "object factory returned a null object"); + } + else + { + introduction = new PrototypePlaceholder(name); + } + AddIntroductionOnChainCreation(introduction, name); + } + } + } + + /// Add all global introductions. + private void AddGlobalIntroduction(IListableObjectFactory objectFactory, string prefix) + { + string[] globalAspectNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisors)); + string[] globalAdvisorNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvisor)); + string[] globalIntroductionNames = + ObjectFactoryUtils.ObjectNamesForTypeIncludingAncestors(objectFactory, typeof(IAdvice)); + ArrayList objects = new ArrayList(); + Hashtable names = new Hashtable(); + + for (int i = 0; i < globalAspectNames.Length; 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.Length; 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.Length; 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(new OrderComparator()); + foreach (object obj in objects) + { + string name = (string)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.Debug(string.Format("Adding introduction with name '{0}'", name)); + IIntroductionAdvisor advisor = NamedObjectToIntroduction(introduction); + AddIntroduction(advisor); + } + + /// + /// Refreshes target object for prototype instances. + /// + private ITargetSource FreshTargetSource() + { + if (StringUtils.IsNullOrEmpty(this.targetName)) + { + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug("Not Refreshing TargetSource: No target name specified"); + } + #endregion + return this.TargetSource; + } + + AssertUtils.ArgumentNotNull(this.objectFactory, "ObjectFactory"); + #region Instrumentation + + if (logger.IsDebugEnabled) + { + logger.Debug("Refreshing TargetSource with name '" + this.targetName + "'"); + } + + #endregion + + object target = this.objectFactory.GetObject(this.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() + { + IAdvisor[] advisors = Advisors; + ArrayList freshAdvisors = new ArrayList(); + foreach (IAdvisor advisor in advisors) + { + if (advisor is PrototypePlaceholder) + { + PrototypePlaceholder pa = (PrototypePlaceholder)advisor; + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug(string.Format("Refreshing advisor '{0}'", pa.ObjectName)); + } + #endregion + AssertUtils.ArgumentNotNull(this.objectFactory, "ObjectFactory"); + + object advisorObject = this.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() + { + IIntroductionAdvisor[] introductions = Introductions; + ArrayList freshIntroductions = new ArrayList(); + foreach (IIntroductionAdvisor introduction in introductions) + { + if (introduction is PrototypePlaceholder) + { + PrototypePlaceholder pa = (PrototypePlaceholder)introduction; + #region Instrumentation + if (logger.IsDebugEnabled) + { + logger.Debug(string.Format("Refreshing introduction '{0}'", pa.ObjectName)); + } + #endregion + AssertUtils.ArgumentNotNull(this.objectFactory, "ObjectFactory"); + + object introductionObject = this.objectFactory.GetObject(pa.ObjectName); + IAdvisor 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); + } + + #endregion + + /// + /// 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.Info("Implemented interfaces have changed; reseting singleton instance"); + this.singletonInstance = null; + base.InterfacesChanged(); + } + + /// + /// Returns textual information about this configuration object + /// + protected override string ToProxyConfigStringInternal() + { + return string.Format("{0}\ntargetName={1}", base.ToProxyConfigStringInternal(), this.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(this.interceptorNames)) + { + String finalName = this.interceptorNames[this.interceptorNames.Length - 1]; + if (finalName != null && this.targetName == null && this.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. + this.targetName = finalName; + if (logger.IsDebugEnabled) + { + logger.Debug(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[this.interceptorNames.Length - 1]; + Array.Copy(this.interceptorNames, 0, newNames, 0, newNames.Length); + this.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; + this.message = "Placeholder for prototype Advisor/Advice/Introduction with bean name '" + objectName + "'"; + } + + #region Implementation of IAdvisor + + public bool IsPerInstance + { + get { throw new NotSupportedException("Cannot invoke methods: " + this.message); } + } + + public IAdvice Advice + { + get { throw new NotSupportedException("Cannot invoke methods: " + this.message); } + } + + #endregion + + #region Implementation of IIntroductionAdvisor + + public ITypeFilter TypeFilter + { + get { throw new NotSupportedException("Cannot invoke methods: " + this.message); } + } + + public Type[] Interfaces + { + get { throw new NotSupportedException("Cannot invoke methods: " + this.message); } + } + + public void ValidateInterfaces() + { + throw new NotSupportedException("Cannot invoke methods: " + this.message); + } + + #endregion + } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aop/Target/AbstractPrototypeTargetSource.cs b/src/Spring/Spring.Aop/Aop/Target/AbstractPrototypeTargetSource.cs index 85352fe3..3ea9496f 100644 --- a/src/Spring/Spring.Aop/Aop/Target/AbstractPrototypeTargetSource.cs +++ b/src/Spring/Spring.Aop/Aop/Target/AbstractPrototypeTargetSource.cs @@ -221,7 +221,24 @@ namespace Spring.Aop.Target #endregion - #region Fields + #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). diff --git a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs index 5c8ddfcc..16168c7a 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs @@ -415,6 +415,14 @@ namespace Spring.Context.Support { } + /// + /// 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. @@ -429,6 +437,15 @@ namespace Spring.Context.Support { } + /// + /// 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() + { + } + /// /// Instantiate and invoke all registered /// @@ -761,20 +778,58 @@ namespace Spring.Context.Support /// /// If the object factory could not be initialized. /// - public virtual void Refresh() + public void Refresh() { lock (SyncRoot) { - - _startupDate = DateTime.Now; + OnPreRefresh(); + + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("ApplicationContext Refresh: Refreshing object factory ")); + } + + #endregion + RefreshObjectFactory(); + IConfigurableListableObjectFactory objectFactory = ObjectFactory; + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("ApplicationContext Refresh: Registering well-known processors and objects")); + } + + #endregion + PrepareObjectFactory(objectFactory); + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("ApplicationContext Refresh: Custom post processing object factory")); + } + + #endregion + PostProcessObjectFactory(objectFactory); + + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("ApplicationContext Refresh: Post processing object factory using pre-registered processors")); + } + + #endregion + foreach (IObjectFactoryPostProcessor factoryProcessor in ObjectFactoryPostProcessors) { factoryProcessor.PostProcessObjectFactory(objectFactory); @@ -793,21 +848,57 @@ namespace Spring.Context.Support #endregion + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("ApplicationContext Refresh: Post processing object factory using defined processors")); + } + + #endregion + InvokeObjectFactoryPostProcessors(); + RegisterObjectPostProcessors(objectFactory); InitEventRegistry(); InitMessageSource(); OnRefresh(); + RefreshApplicationEventListeners(); + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("ApplicationContext Refresh: Preinstantiating singletons")); + } + + #endregion + objectFactory.PreInstantiateSingletons(); + OnPostRefresh(); + new DefensiveEventRaiser().Raise( ContextEvent, this, new ContextEventArgs(ContextEventArgs.ContextEvent.Refreshed)); + + #region Instrumentation + + if (log.IsInfoEnabled) + { + log.Info(string.Format("ApplicationContext Refresh: Completed")); + } + + #endregion } } + /// + /// Registers well-known s and + /// preregisters well-known dependencies using + /// + /// the raw object factory as returned from private void PrepareObjectFactory(IConfigurableListableObjectFactory objectFactory) { EnsureKnownObjectPostProcessors(objectFactory); @@ -819,7 +910,6 @@ namespace Spring.Context.Support objectFactory.RegisterResolvableDependency(typeof(IApplicationEventPublisher), this); objectFactory.RegisterResolvableDependency(typeof(IApplicationContext), this); objectFactory.RegisterResolvableDependency(typeof(IEventRegistry), this); - } /// diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs index a68000e3..a751b046 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs @@ -1810,7 +1810,7 @@ namespace Spring.Objects.Factory.Support if (log.IsDebugEnabled) { - log.Debug(string.Format("configuring object '{0}' using definition '{1}'", instance, name)); + log.Debug(string.Format("Configuring object using definition '{1}'", instance, name)); } #endregion diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs index 32e64310..e11ec5be 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs @@ -759,7 +759,7 @@ namespace Spring.Objects.Factory.Support { // 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))) + if (IsFactoryDereference(name) && !(ObjectUtils.IsAssignable(typeof(IFactoryObject), instance))) { throw new ObjectIsNotAFactoryException(canonicalName, instance); } @@ -770,7 +770,7 @@ namespace Spring.Objects.Factory.Support // it's a normal object ? - if (!ObjectUtils.IsAssignable(typeof (IFactoryObject), instance)) + if (!ObjectUtils.IsAssignable(typeof(IFactoryObject), instance)) { #region Instrumentation @@ -785,7 +785,7 @@ namespace Spring.Objects.Factory.Support } // the user wants the factory itself ? - if (!ObjectUtils.IsAssignable(typeof (IFactoryObject), instance) || IsFactoryDereference(name)) + if (!ObjectUtils.IsAssignable(typeof(IFactoryObject), instance) || IsFactoryDereference(name)) { #region Instrumentation @@ -819,8 +819,15 @@ namespace Spring.Objects.Factory.Support if (resultInstance == null) { + #region Instrumentation + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Dereferencing Object with name '{0}'", canonicalName)); + } + #endregion + // return object instance from factory... - IFactoryObject factory = (IFactoryObject) instance; + IFactoryObject factory = (IFactoryObject)instance; if (rod == null && ContainsObjectDefinition(canonicalName)) { @@ -854,6 +861,15 @@ namespace Spring.Objects.Factory.Support + "circular object reference."); } } + else + { + #region Instrumentation + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Returning factory product from cache for Object with name '{0}'", canonicalName)); + } + #endregion + } return resultInstance; } @@ -1873,89 +1889,122 @@ namespace Spring.Objects.Factory.Support /// protected object GetObjectInternal(string name, Type requiredType, object[] arguments, bool suppressConfigure) { - string objectName = TransformedObjectName(name); - object instance = null; - - // those are cases, where singleton cache can be used - if (arguments == null && !suppressConfigure) + const int INDENT = 3; + bool hasErrors = false; + try { - // eagerly check singleton cache for manually registered singletons... - object sharedInstance = GetSingleton(objectName); + string objectName = TransformedObjectName(name); - if (sharedInstance != null) + #region Instrumentation + if (log.IsDebugEnabled) { - #region Instrumentation + log.Debug(string.Format("{2}GetObjectInternal: obtaining instance for name {0} => canonical name {1}", name, objectName, new String(' ', nestingCount * INDENT))); + nestingCount++; + } + #endregion - if (IsSingletonCurrentlyInCreation(objectName)) + object instance = null; + + // 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) { + #region Instrumentation if (log.IsDebugEnabled) { - log.Debug("Returning eagerly cached instance of singleton object '" + objectName + - "' that is not fully initialized yet - a consequence of a circular reference"); + if (IsSingletonCurrentlyInCreation(objectName)) + { + log.Debug("Returning eagerly cached instance of singleton object '" + objectName + + "' that is not fully initialized yet - a consequence of a circular reference"); + } + else + { + log.Debug(string.Format("Returning cached instance of singleton object '{0}'.", objectName)); + } } + #endregion + + instance = GetObjectForInstance(sharedInstance, name, objectName, null); + return EnsureObjectIsOfRequiredType(name, instance, requiredType); } - else + } + + // check if object definition exists + RootObjectDefinition mergedObjectDefinition = null; + mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); + if (mergedObjectDefinition == null) + { + if (ParentObjectFactory != null) { - if (log.IsDebugEnabled) - { - log.Debug(string.Format("Returning cached instance of singleton object '{0}'.", objectName)); - } + return ParentObjectFactory.GetObject(name, requiredType, arguments); } - - #endregion - - instance = GetObjectForInstance(sharedInstance, name, objectName, null); - return EnsureObjectIsOfRequiredType(name, instance, requiredType); + throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]"); } - } - // check if object definition exists - RootObjectDefinition mergedObjectDefinition = null; - mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); - if (mergedObjectDefinition == null) - { - if (ParentObjectFactory != null) + if (arguments != null + || suppressConfigure) { - return ParentObjectFactory.GetObject(name, requiredType, arguments); + // 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; + } } - 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) + CheckMergedObjectDefinition(mergedObjectDefinition, objectName, requiredType, arguments); + + // return IObjectDefinition instance itself for an abstract object-definition + if (mergedObjectDefinition.IsAbstract) { - // Override constructor values and configure as a prototype if arguments are specified - mergedObjectDefinition.ConstructorArgumentValues = null; + 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... + instance = InstantiateObject(name, mergedObjectDefinition, arguments, true, suppressConfigure); } - } - CheckMergedObjectDefinition(mergedObjectDefinition, objectName, requiredType, arguments); - - // return IObjectDefinition instance itself for an abstract object-definition - if (mergedObjectDefinition.IsAbstract) - { - instance = mergedObjectDefinition; + return EnsureObjectIsOfRequiredType(name, instance, requiredType); } - else if (mergedObjectDefinition.IsSingleton) + catch { - // create object instance... - object sharedInstance = CreateAndCacheSingletonInstance(objectName, mergedObjectDefinition, arguments); - instance = GetObjectForInstance(sharedInstance, name, objectName, mergedObjectDefinition); + #region Instrumentation + if (log.IsErrorEnabled) + { + hasErrors = true; + nestingCount--; + log.Error(string.Format("{1}GetObjectInternal: error obtaining object {0}", name, new String(' ', nestingCount * INDENT))); + } + #endregion + throw; } - else + finally { - // it's a prototype, so create a new instance... - instance = InstantiateObject(name, mergedObjectDefinition, arguments, true, suppressConfigure); + #region Instrumentation + if (log.IsDebugEnabled && !hasErrors) + { + nestingCount--; + log.Debug(string.Format("{1}GetObjectInternal: returning instance for objectname {0}", name, new String(' ', nestingCount * INDENT))); + } + #endregion } - - return EnsureObjectIsOfRequiredType(name, instance, requiredType); } + [ThreadStatic] + private int nestingCount; + /// /// Checks, if the passed instance is of the required type. /// @@ -2001,12 +2050,10 @@ namespace Spring.Objects.Factory.Support if (sharedInstance == null) { #region Instrumentation - if (log.IsDebugEnabled) { - log.Debug("Creating shared instance of singleton object '" + objectName + "'"); + log.Debug(string.Format("Creating shared instance of singleton object '{0}'", objectName)); } - #endregion BeforeSingletonCreation(objectName); @@ -2019,6 +2066,13 @@ namespace Spring.Objects.Factory.Support AfterSingletonCreation(objectName); } AddSingleton(objectName, sharedInstance); + + #region Instrumentation + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Cached shared instance of singleton object '{0}'", objectName)); + } + #endregion } return sharedInstance; } @@ -2138,19 +2192,19 @@ namespace Spring.Objects.Factory.Support { if (objectPostProcessor is IObjectFactoryAware) { - ((IObjectFactoryAware) objectPostProcessor).ObjectFactory = this; + ((IObjectFactoryAware)objectPostProcessor).ObjectFactory = this; } // ensure the same instance doesn't get registered twice - if (!ObjectPostProcessors.Contains( objectPostProcessor )) + if (!ObjectPostProcessors.Contains(objectPostProcessor)) { - ObjectPostProcessors.Add( objectPostProcessor ); + ObjectPostProcessors.Add(objectPostProcessor); } - if (typeof( IInstantiationAwareObjectPostProcessor ).IsInstanceOfType( objectPostProcessor )) + if (typeof(IInstantiationAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) { hasInstantiationAwareBeanPostProcessors = true; } - if (typeof( IDestructionAwareObjectPostProcessor ).IsInstanceOfType( objectPostProcessor )) + if (typeof(IDestructionAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) { hasDestructionAwareBeanPostProcessors = true; } @@ -2206,6 +2260,19 @@ namespace Spring.Objects.Factory.Support } } + /// + /// 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); + } + + #region ISingletonObjectRegistry Members + /// /// Register the given existing object as singleton in the object factory, /// under the given object name. @@ -2228,17 +2295,6 @@ namespace Spring.Objects.Factory.Support } } - /// - /// 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); - } - /// /// Does this object factory contains a singleton instance with the /// supplied ? @@ -2253,9 +2309,6 @@ namespace Spring.Objects.Factory.Support } } - #region ISingletonObjectRegistry Members - - /// /// Gets the names of singleton objects registered in this registry. /// diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs index a2d570f5..0bd2934a 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ConstructorResolver.cs @@ -147,16 +147,16 @@ namespace Spring.Objects.Factory.Support if (resolvedValues != null) { - UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null; + UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = 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 unsatisfiedDependencyExceptionData); if (args == null) { - if (i == candidates.Length -1 && constructorToUse == null) + if (i == candidates.Length - 1 && constructorToUse == null) { throw new UnsatisfiedDependencyException(rod.ResourceDescription, objectName, @@ -167,7 +167,8 @@ namespace Spring.Objects.Factory.Support // try next constructor... continue; } - } else + } + else { // Explicit arguments given -> arguments length must match exactly if (paramTypes.Length != explicitArgs.Length) @@ -243,7 +244,7 @@ namespace Spring.Objects.Factory.Support public virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments) { ObjectWrapper wrapper = new ObjectWrapper(); - Type factoryClass = null; + Type factoryClass = null; bool isStatic = true; @@ -263,7 +264,7 @@ namespace Spring.Objects.Factory.Support // if we have constructor args, don't need to resolve them... expectedArgCount = arguments.Length; } - + if (StringUtils.HasText(definition.FactoryObjectName)) { @@ -277,73 +278,69 @@ namespace Spring.Objects.Factory.Support factoryClass = definition.ObjectType; } - bool autowiring = (definition.AutowireMode == AutoWiringMode.Constructor); #if NET_2_0 GenericArgumentsHolder genericArgsInfo = new GenericArgumentsHolder(definition.FactoryMethodName); + MethodInfo[] factoryMethodCandidates = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass); +#else + MethodInfo[] factoryMethodCandidates = FindMethods(definition.FactoryMethodName, expectedArgCount, isStatic, factoryClass); +#endif + + bool autowiring = (definition.AutowireMode == AutoWiringMode.Constructor); - MethodInfo[] factoryMethods = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass); - UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null; // try all matching methods to see if they match the constructor arguments... - for (int i = 0; i < factoryMethods.Length; i++) + for (int i = 0; i < factoryMethodCandidates.Length; i++) { - unsatisfiedDependencyExceptionData = null; - MethodInfo factoryMethod = factoryMethods[i]; - Type[] paramTypes = new Type[] { }; + MethodInfo factoryMethodCandidate = factoryMethodCandidates[i]; +#if NET_2_0 if (genericArgsInfo.ContainsGenericArguments) { string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments(); - if (factoryMethod.GetGenericArguments().Length != unresolvedGenericArgs.Length) + if (factoryMethodCandidate.GetGenericArguments().Length != unresolvedGenericArgs.Length) continue; - paramTypes = new Type[unresolvedGenericArgs.Length]; + Type[] paramTypes = new Type[unresolvedGenericArgs.Length]; for (int j = 0; j < unresolvedGenericArgs.Length; j++) { paramTypes[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]); } - factoryMethod = factoryMethod.MakeGenericMethod(paramTypes); + factoryMethodCandidate = factoryMethodCandidate.MakeGenericMethod(paramTypes); } -#else - MethodInfo[] factoryMethods = FindMethods(definition.FactoryMethodName, expectedArgCount, isStatic, factoryClass); - UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null; - // try all matching methods to see if they match the constructor arguments... - foreach(MethodInfo factoryMethod in factoryMethods) - { - Type[] paramTypes = new Type[] { }; #endif if (arguments == null || arguments.Length == 0) { - paramTypes = ReflectionUtils.GetParameterTypes(factoryMethod.GetParameters()); + Type[] paramTypes = ReflectionUtils.GetParameterTypes(factoryMethodCandidate.GetParameters()); // try to create the required arguments... - ArgumentsHolder args = CreateArgumentArray(name, definition, resolvedValues, wrapper, - paramTypes, factoryMethod, autowiring, out unsatisfiedDependencyExceptionData); + 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 factory method... + + // 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[] { factoryMethod }, arguments) == null) + if (ReflectionUtils.GetMethodByArgumentValues(new MethodInfo[] { factoryMethodCandidate }, arguments) == null) { continue; } - - object objectInstance = instantiationStrategy.Instantiate(definition, name, objectFactory, factoryMethod, arguments); + object objectInstance = instantiationStrategy.Instantiate(definition, name, objectFactory, factoryMethodCandidate, arguments); wrapper.WrappedInstance = objectInstance; #region Instrumentation if (log.IsDebugEnabled) { - log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via factory method [{1}].", name, factoryMethod)); + log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via factory method [{1}].", name, factoryMethodCandidate)); } #endregion @@ -412,10 +409,11 @@ namespace Spring.Objects.Factory.Support object originalValue = valueHolder.Value; object convertedValue = TypeConversionUtils.ConvertValueIfNecessary(paramType, originalValue, null); args.arguments[paramIndex] = convertedValue; - + //? args.preparedArguments[paramIndex] = convertedValue; - } catch (TypeMismatchException ex) + } + 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 = String.Format(CultureInfo.InvariantCulture, @@ -425,7 +423,8 @@ namespace Spring.Objects.Factory.Support unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage); return null; } - } else + } + else { // No explicit match found: we're either supposed to autowire or // have to fail creating an argument array for the given constructor. @@ -447,25 +446,26 @@ namespace Spring.Objects.Factory.Support args.arguments[paramIndex] = autowiredArgument; args.preparedArguments[paramIndex] = new AutowiredArgumentMarker(); resolveNecessary = true; - } catch (ObjectsException ex) + } + catch (ObjectsException ex) { unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, ex.Message); return null; } - + } } foreach (string autowiredObjectName in autowiredObjectNames) { - if (log.IsDebugEnabled) - { - log.Debug("Autowiring by type from object name '" + objectName + - "' via " + methodType + " to object named '" + autowiredObjectName + "'"); - } + if (log.IsDebugEnabled) + { + log.Debug("Autowiring by type from object name '" + objectName + + "' via " + methodType + " to object named '" + autowiredObjectName + "'"); + } } - + return args; } @@ -533,7 +533,7 @@ namespace Spring.Objects.Factory.Support minNrOfArgs = index + 1; } ConstructorArgumentValues.ValueHolder valueHolder = - (ConstructorArgumentValues.ValueHolder) entry.Value; + (ConstructorArgumentValues.ValueHolder)entry.Value; string argName = "constructor argument with index " + index; object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, argName, valueHolder.Value); @@ -557,10 +557,10 @@ namespace Spring.Objects.Factory.Support } foreach (DictionaryEntry namedArgumentEntry in definition.ConstructorArgumentValues.NamedArgumentValues) { - string argumentName = (string) namedArgumentEntry.Key; + string argumentName = (string)namedArgumentEntry.Key; string syntheticArgumentName = "constructor argument with name " + argumentName; ConstructorArgumentValues.ValueHolder valueHolder = - (ConstructorArgumentValues.ValueHolder) namedArgumentEntry.Value; + (ConstructorArgumentValues.ValueHolder)namedArgumentEntry.Value; object resolvedValue = valueResolver.ResolveValueIfNecessary(objectName, definition, syntheticArgumentName, valueHolder.Value); resolvedValues.AddNamedArgumentValue(argumentName, resolvedValue); @@ -625,9 +625,9 @@ namespace Spring.Objects.Factory.Support 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. + // 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, this.arguments); int rawTypeDiffWeight = AutowireUtils.GetTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024; return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight); diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs index 1e294ffa..67dd49f5 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs @@ -266,8 +266,8 @@ namespace Spring.Objects.Factory.Support protected override object CreateAndCacheSingletonInstance( string objectName, RootObjectDefinition objectDefinition, object[] arguments) { - if (objectDefinition is IWebObjectDefinition - && ((IWebObjectDefinition)objectDefinition).Scope != ObjectScope.Application) + if (IsWebScopedSingleton(objectDefinition) + ) { ObjectScope scope = ((IWebObjectDefinition)objectDefinition).Scope; diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/AopContextTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/AopContextTests.cs index 71e59468..096ee2c9 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AopContextTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AopContextTests.cs @@ -222,9 +222,9 @@ namespace Spring.Aop.Framework private ITestObject CreateProxy(object target, IAdvice interceptor, bool exposeProxy) { - ProxyFactory pf = new ProxyFactory(); + ProxyFactory pf = new ProxyFactory(target); pf.ExposeProxy = exposeProxy; - pf.Target = target; +// pf.Target = target; pf.AddAdvice(interceptor); return pf.GetProxy() as ITestObject; 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 4433e4ac..415ce656 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreatorTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/AutoProxy/ObjectNameAutoProxyCreatorTests.cs @@ -96,14 +96,6 @@ namespace Spring.Aop.Framework.AutoProxy ProxyAssertions(testObject, 1); } - [Test] - public void DecoratorProxyWithWildcardMatch() - { - ITestObject testObject = (ITestObject)ctx.GetObject("decoratorProxy"); - DecoratorProxyAssertions(testObject); - Assert.AreEqual("decoratorProxy", testObject.Name); - } - [Test] public void FrozenProxy() { @@ -141,6 +133,14 @@ namespace Spring.Aop.Framework.AutoProxy 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"); 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 f6eac444..15f680f7 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs @@ -459,15 +459,13 @@ namespace Spring.Aop.Framework.DynamicProxy ITestObject target = new TestObject(); target.Age = 26; - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = target; + 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(); - advised.Target = proxy1; + advised = new AdvisedSupport(proxy1); advised.AddAdvice(new NopInterceptor()); aop = CreateAopProxy(advised); ITestObject proxy2 = (ITestObject)aop.GetProxy(); @@ -483,14 +481,12 @@ namespace Spring.Aop.Framework.DynamicProxy TheCommand target = new TheCommand(); // proxy - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = target; + AdvisedSupport advised = new AdvisedSupport(target); advised.AddAdvice(new NopInterceptor()); object proxy = CreateProxy(advised); // proxy again - advised = new AdvisedSupport(); - advised.Target = proxy; + advised = new AdvisedSupport(proxy); advised.AddAdvice(new NopInterceptor()); proxy = CreateAopProxy(advised); @@ -844,8 +840,7 @@ namespace Spring.Aop.Framework.DynamicProxy NopInterceptor ni = new NopInterceptor(); - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = mockTargetSource; + AdvisedSupport advised = new AdvisedSupport(mockTargetSource); advised.AddAdvice(ni); AbstractProxyTypeBuilderTests.InterfaceWithGenericMethod proxy = @@ -884,8 +879,7 @@ namespace Spring.Aop.Framework.DynamicProxy NopInterceptor ni = new NopInterceptor(); - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = mockTargetSource; + AdvisedSupport advised = new AdvisedSupport(mockTargetSource); advised.AddAdvice(ni); AbstractProxyTypeBuilderTests.GenericInterface proxy = @@ -927,8 +921,7 @@ namespace Spring.Aop.Framework.DynamicProxy TestObject target = new TestObject(); target.Age = 26; - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = target; + AdvisedSupport advised = new AdvisedSupport(target); advised.AddAdvice(new NopInterceptor()); ITestObject proxy = CreateProxy(advised) as ITestObject; @@ -1716,8 +1709,7 @@ namespace Spring.Aop.Framework.DynamicProxy public void CanCastProxyToIAdvised() { TestObject to = new TestObject(); - AdvisedSupport advisedSupport = new AdvisedSupport(); - advisedSupport.Target = to; + AdvisedSupport advisedSupport = new AdvisedSupport(to); NopInterceptor ni = new NopInterceptor(); advisedSupport.AddAdvice(0, ni); 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 32ea96d7..10e5eae3 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CachedAopProxyFactoryTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/CachedAopProxyFactoryTests.cs @@ -39,8 +39,9 @@ namespace Spring.Aop.Framework.DynamicProxy [TestFixture] public sealed class CachedAopProxyFactoryTests : DefaultAopProxyFactoryTests { - protected override IAopProxy CreateAopProxy(AdvisedSupport advisedSupport) + protected override IAopProxy CreateAopProxy(ProxyFactory advisedSupport) { + // return (IAopProxy) advisedSupport.GetProxy(); IAopProxyFactory apf = new CachedAopProxyFactory(); return apf.CreateAopProxy(advisedSupport); } @@ -48,24 +49,20 @@ namespace Spring.Aop.Framework.DynamicProxy [SetUp] public void SetUp() { - // Clear Aop proxy type cache - Assert.IsNotNull(TypeCacheField); - TypeCacheField.SetValue(null, new Hashtable()); + CachedAopProxyFactory.ClearCache(); } [Test] public void DoesNotCacheWithDifferentBaseType() { // Decorated-based proxy (BaseType == TargetType) - AdvisedSupport advisedSupport = new AdvisedSupport(); + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); advisedSupport.ProxyTargetType = true; - advisedSupport.Target = new TestObject(); CreateAopProxy(advisedSupport); // Composition-based proxy (BaseType = BaseCompositionAopProxy) - advisedSupport = new AdvisedSupport(); + advisedSupport = new ProxyFactory(new TestObject()); advisedSupport.ProxyTargetType = false; - advisedSupport.Target = new TestObject(); CreateAopProxy(advisedSupport); AssertAopProxyTypeCacheCount(2); @@ -74,12 +71,10 @@ namespace Spring.Aop.Framework.DynamicProxy [Test] public void DoesNotCacheWithDifferentTargetType() { - AdvisedSupport advisedSupport = new AdvisedSupport(); - advisedSupport.Target = new BadCommand(); + ProxyFactory advisedSupport = new ProxyFactory(new BadCommand()); CreateAopProxy(advisedSupport); - advisedSupport = new AdvisedSupport(); - advisedSupport.Target = new GoodCommand(); + advisedSupport = new ProxyFactory(new GoodCommand()); CreateAopProxy(advisedSupport); AssertAopProxyTypeCacheCount(2); @@ -88,20 +83,17 @@ namespace Spring.Aop.Framework.DynamicProxy [Test] public void DoesNotCacheWithDifferentInterfaces() { - AdvisedSupport advisedSupport = new AdvisedSupport(); - advisedSupport.Target = new TestObject(); + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); CreateAopProxy(advisedSupport); - advisedSupport = new AdvisedSupport(); - advisedSupport.Target = new TestObject(); + advisedSupport = new ProxyFactory(new TestObject()); advisedSupport.AddInterface(typeof(IPerson)); CreateAopProxy(advisedSupport); AssertAopProxyTypeCacheCount(2); // Same with Introductions - advisedSupport = new AdvisedSupport(); - advisedSupport.Target = new TestObject(); + advisedSupport = new ProxyFactory(new TestObject()); TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(); ti.TimeStamp = new DateTime(666L); IIntroductionAdvisor introduction = new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped)); @@ -114,14 +106,12 @@ namespace Spring.Aop.Framework.DynamicProxy [Test] public void DoesCacheWithTwoDecoratorBasedProxy() { - AdvisedSupport advisedSupport = new AdvisedSupport(); + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); advisedSupport.ProxyTargetType = true; - advisedSupport.Target = new TestObject(); CreateAopProxy(advisedSupport); - advisedSupport = new AdvisedSupport(); + advisedSupport = new ProxyFactory(new TestObject()); advisedSupport.ProxyTargetType = true; - advisedSupport.Target = new TestObject(); CreateAopProxy(advisedSupport); AssertAopProxyTypeCacheCount(1); @@ -130,27 +120,18 @@ namespace Spring.Aop.Framework.DynamicProxy [Test] public void DoesCacheWithTwoCompositionBasedProxy() { - AdvisedSupport advisedSupport = new AdvisedSupport(); - advisedSupport.Target = new TestObject(); + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); CreateAopProxy(advisedSupport); - advisedSupport = new AdvisedSupport(); - advisedSupport.Target = new TestObject(); + advisedSupport = new ProxyFactory(new TestObject()); CreateAopProxy(advisedSupport); AssertAopProxyTypeCacheCount(1); } - - private static readonly FieldInfo TypeCacheField = - typeof(CachedAopProxyFactory).GetField("typeCache", BindingFlags.Static | BindingFlags.NonPublic); - private void AssertAopProxyTypeCacheCount(int count) { - Assert.IsNotNull(TypeCacheField); - Hashtable cache = TypeCacheField.GetValue(null) as Hashtable; - Assert.IsNotNull(cache); - Assert.AreEqual(count, cache.Count); + Assert.AreEqual(count, CachedAopProxyFactory.CountCachedTypes); } #region Helper classes definitions 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 786e1145..b2aa097b 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DecoratorAopProxyTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DecoratorAopProxyTests.cs @@ -209,8 +209,7 @@ namespace Spring.Aop.Framework.DynamicProxy NopInterceptor ni = new NopInterceptor(); - AdvisedSupport advised = new AdvisedSupport(); - advised.TargetSource = mockTargetSource; + AdvisedSupport advised = new AdvisedSupport(mockTargetSource); advised.AddAdvice(ni); // Cast to the interface that method belongs to 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 88f26769..bd0d5025 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DefaultAopProxyFactoryTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/DefaultAopProxyFactoryTests.cs @@ -36,8 +36,9 @@ namespace Spring.Aop.Framework.DynamicProxy [TestFixture] public class DefaultAopProxyFactoryTests { - protected virtual IAopProxy CreateAopProxy(AdvisedSupport advisedSupport) + protected virtual IAopProxy CreateAopProxy(ProxyFactory advisedSupport) { +// return (IAopProxy) advisedSupport.GetProxy(); IAopProxyFactory apf = new DefaultAopProxyFactory(); return apf.CreateAopProxy(advisedSupport); } @@ -46,21 +47,23 @@ namespace Spring.Aop.Framework.DynamicProxy [ExpectedException(typeof(AopConfigException), ExpectedMessage="Cannot create IAopProxy with null ProxyConfig")] public void NullConfig() { - CreateAopProxy(null); + IAopProxyFactory apf = new DefaultAopProxyFactory(); + apf.CreateAopProxy(null); } [Test] [ExpectedException(typeof(AopConfigException), ExpectedMessage="Cannot create IAopProxy with no advisors and no target source")] public void NoInterceptorsAndNoTarget() { - AdvisedSupport advisedSupport = new AdvisedSupport(new Type[] { typeof(ITestObject) }); + ProxyFactory advisedSupport = new ProxyFactory(new Type[] { typeof(ITestObject) }); CreateAopProxy(advisedSupport); } [Test] public void TargetDoesNotImplementAnyInterfaces() { - AdvisedSupport advisedSupport = new AdvisedSupport(); + ProxyFactory advisedSupport = new ProxyFactory(); + advisedSupport.AopProxyFactory = new DefaultAopProxyFactory(); advisedSupport.ProxyTargetType = false; advisedSupport.Target = new DoesNotImplementAnyInterfacesTestObject(); @@ -72,9 +75,7 @@ namespace Spring.Aop.Framework.DynamicProxy [Test] public void TargetImplementsAnInterface() { - AdvisedSupport advisedSupport = new AdvisedSupport(); - advisedSupport.Target = new TestObject(); - + ProxyFactory advisedSupport = new ProxyFactory(new TestObject()); IAopProxy aopProxy = CreateAopProxy(advisedSupport); Assert.IsNotNull(aopProxy); @@ -84,7 +85,7 @@ namespace Spring.Aop.Framework.DynamicProxy [Test] public void TargetImplementsAnInterfaceWithProxyTargetTypeSetToTrue() { - AdvisedSupport advisedSupport = new AdvisedSupport(); + ProxyFactory advisedSupport = new ProxyFactory(); advisedSupport.ProxyTargetType = true; advisedSupport.Target = new TestObject(); 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 e9d79f08..9906c1f3 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/InheritanceAopProxyTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/InheritanceAopProxyTests.cs @@ -230,8 +230,7 @@ namespace Spring.Aop.Framework.DynamicProxy { NopInterceptor ni = new NopInterceptor(); - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); advised.AddAdvice(ni); object proxy = CreateProxy(advised); @@ -253,8 +252,7 @@ namespace Spring.Aop.Framework.DynamicProxy { NopInterceptor ni = new NopInterceptor(); - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); advised.AddAdvice(ni); object proxy = CreateProxy(advised); @@ -277,8 +275,7 @@ namespace Spring.Aop.Framework.DynamicProxy { NopInterceptor ni = new NopInterceptor(); - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); advised.AddAdvice(ni); object proxy = CreateProxy(advised); @@ -296,8 +293,7 @@ namespace Spring.Aop.Framework.DynamicProxy { NopInterceptor ni = new NopInterceptor(); - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); advised.AddAdvice(ni); object proxy = CreateProxy(advised); @@ -314,8 +310,7 @@ namespace Spring.Aop.Framework.DynamicProxy { NopInterceptor ni = new NopInterceptor(); - AdvisedSupport advised = new AdvisedSupport(); - advised.Target = new InheritanceTestObject(); + AdvisedSupport advised = new AdvisedSupport(new InheritanceTestObject()); advised.AddAdvice(ni); object proxy = CreateProxy(advised); diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs index f5b6058a..68a16098 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryObjectTests.cs @@ -32,9 +32,7 @@ using System.Web; using AopAlliance.Aop; using AopAlliance.Intercept; using NUnit.Framework; - using Rhino.Mocks; - using Spring.Aop.Advice; using Spring.Aop.Framework.Adapter; using Spring.Aop.Interceptor; @@ -164,7 +162,7 @@ namespace Spring.Aop.Framework Assert.AreEqual(di.Count, 0); test1.Age = (5); Assert.AreEqual(test1_1.Age, test1.Age); - Assert.AreEqual(di.Count, 3); + Assert.AreEqual(3, di.Count); } [Test] @@ -180,7 +178,7 @@ namespace Spring.Aop.Framework public void PrototypeInstancesAreIndependent() { IObjectFactory objectFactory = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTests.xml", GetType())); - // Initial count value set in object factory XML + // Initial count value set in object factory XML int INITIAL_COUNT = 10; @@ -222,7 +220,7 @@ namespace Spring.Aop.Framework public void CanGetFactoryReferenceAndManipulate() { ITestObject to = (ITestObject)factory.GetObject("test1"); - // no exception + // no exception string dummy = to.Name; IAdvised config = (IAdvised)to; @@ -246,7 +244,7 @@ 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, Ignore("change according to ProxyFactoryBeanTests.canAddAndRemoveAdvicesOnSingleton")] @@ -376,7 +374,7 @@ namespace Spring.Aop.Framework /// /// Note that we can't add or remove interfaces without reconfiguring the - /// singleton. + /// singleton. /// [Test] public void CanAddAndRemoveAspectInterfacesOnSingletonByCasting() @@ -463,6 +461,7 @@ namespace Spring.Aop.Framework Assert.IsTrue(agi.GlobalsAdded == -1); ProxyFactoryObject pfb = (ProxyFactoryObject)factory.GetObject("&validGlobals"); + pfb.GetObject(); // for creation Assert.AreEqual(2, pfb.Advisors.Length, "Proxy should have 1 global and 1 explicit advisor"); Assert.AreEqual(1, pfb.Introductions.Length, "Proxy should have 1 global introduction"); @@ -519,20 +518,34 @@ namespace Spring.Aop.Framework mocks.VerifyAll(); } - [Test] - [ExpectedException(typeof(AopConfigException))] - public void AddAdvisorWhenConfigIsFrozen() + private ProxyFactoryObject CreateFrozenProxyFactory() { ProxyFactoryObject fac = new ProxyFactoryObject(); + fac.AddInterface(typeof(ITestObject)); fac.IsFrozen = true; - fac.AddAdvisor(new PointcutForVoid()); + fac.AddAdvisor(new PointcutForVoid()); // this is ok, no proxy created yet + 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] [ExpectedException(typeof(AopConfigException))] public void RemoveAdvisorWhenConfigIsFrozen() { - ProxyFactoryObject fac = new ProxyFactoryObject(); + ProxyFactoryObject fac = CreateFrozenProxyFactory(); fac.IsFrozen = true; fac.RemoveAdvisor(new PointcutForVoid()); } @@ -541,7 +554,7 @@ namespace Spring.Aop.Framework [ExpectedException(typeof(AopConfigException))] public void ReplaceAdvisorWhenConfigIsFrozen() { - ProxyFactoryObject fac = new ProxyFactoryObject(); + ProxyFactoryObject fac = CreateFrozenProxyFactory(); fac.IsFrozen = true; fac.ReplaceAdvisor(new PointcutForVoid(), new PointcutForVoid()); } @@ -581,22 +594,31 @@ namespace Spring.Aop.Framework GoodCommand target = new GoodCommand(); NopInterceptor advice = new NopInterceptor(); - IObjectFactory mock = (IObjectFactory)mocks.CreateMock(typeof(IObjectFactory)); - Expect.Call(mock.IsSingleton("advice")).Return(true); // advice is a singleton... - Expect.Call(mock.GetObject("advice")).Return(advice); - Expect.Call(mock.GetType("prototype")).Return(typeof(GoodCommand)); - - Expect.Call(mock.GetObject("advice")).Return(advice); - Expect.Call(mock.GetObject("prototype")).Return(target); - mocks.ReplayAll(); + MockRepository mocks = new MockRepository(); + IObjectFactory factory = (IObjectFactory) mocks.CreateMock(typeof(IObjectFactory)); ProxyFactoryObject fac = new ProxyFactoryObject(); fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName }; fac.IsSingleton = false; fac.InterceptorNames = new string[] { "advice", "prototype" }; - fac.ObjectFactory = mock; + fac.ObjectFactory = factory; - fac.GetObject(); +// using (mocks.Record()) + { + using (mocks.Unordered()) + { + Expect.Call(factory.IsSingleton("advice")).Return(true); + Expect.Call(factory.GetObject("advice")).Return(advice); + Expect.Call(factory.GetType("prototype")).Return(target.GetType()); + Expect.Call(factory.GetObject("prototype")).Return(target); + } + } + mocks.ReplayAll(); + +// using(mocks.Playback()) + { + fac.GetObject(); + } mocks.VerifyAll(); } @@ -633,7 +655,7 @@ namespace Spring.Aop.Framework } [Test] - public void SingletonProxyWithPrototypeTarget() + public void SingletonProxyWithPrototypeTargetCreatesTargetOnlyOnce() { try { @@ -651,7 +673,7 @@ namespace Spring.Aop.Framework fac.InterceptorNames = new string[] { "advice", "prototype" }; fac.ObjectFactory = ctx; - Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "First Call"); + Assert.AreEqual(0, InstantiationCountingCommand.NumberOfInstantiations, "First Call"); fac.GetObject(); Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Second Call"); fac.GetObject(); @@ -685,8 +707,7 @@ namespace Spring.Aop.Framework } [Test] - [ExpectedException(typeof(AopConfigException))] - public void NullNameInInterceptorNamesArray() + public void NullNameInInterceptorNamesArrayThrowAopConfigException() { IObjectFactory factory = (IObjectFactory) mocks.CreateMock(typeof(IObjectFactory)); @@ -695,6 +716,13 @@ namespace Spring.Aop.Framework fac.IsSingleton = false; fac.InterceptorNames = new string[] { null, null }; fac.ObjectFactory = factory; + try + { + fac.GetObject(); + Assert.Fail(); + } + catch (AopConfigException) + {} } [Test] @@ -843,7 +871,7 @@ namespace Spring.Aop.Framework XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null); HelperInterface2 hc = (HelperInterface2)objectFactory.GetObject("MyProxy"); - Console.WriteLine(hc.SecondDoSomething()); + Console.WriteLine(hc.SecondDoSomething()); } [Test] @@ -899,7 +927,7 @@ namespace Spring.Aop.Framework { ProxyFactoryObject factoryObject = (ProxyFactoryObject) this.factory.GetObject( "&concurrentPrototype" ); Type testObjectType1 = factoryObject.GetObject().GetType(); - + factoryObject.Interfaces = new Type[] {}; Type testObjectType2 = factoryObject.GetObject().GetType(); @@ -1032,7 +1060,7 @@ namespace Spring.Aop.Framework int GlobalsAdded { get; set; } } - /// Use as a global interceptor. Checks that + /// Use as a global interceptor. Checks that /// global interceptors can add aspect interfaces. /// NB: Add only via global interceptors in XML file. /// diff --git a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryTests.cs index 74cf433f..e318d4b9 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/ProxyFactoryTests.cs @@ -26,6 +26,7 @@ using AopAlliance.Aop; using AopAlliance.Intercept; using DotNetMock.Dynamic; using NUnit.Framework; +using Rhino.Mocks; using Spring.Aop.Interceptor; using Spring.Aop.Support; using Spring.Objects; diff --git a/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceAdapter.cs b/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceAdapter.cs index 96e09301..811e9b26 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceAdapter.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/SimpleBeforeAdviceAdapter.cs @@ -25,7 +25,6 @@ using AopAlliance.Intercept; using Spring.Aop.Framework.Adapter; #endregion - namespace Spring.Aop { /// @@ -33,6 +32,7 @@ namespace Spring.Aop /// /// Dmitriy Kopylenko /// Simon White (.NET) + [Serializable] public class SimpleBeforeAdviceAdapter : IAdvisorAdapter { #region IAdvisorAdapter Members