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