diff --git a/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs new file mode 100644 index 00000000..df4c751d --- /dev/null +++ b/src/Spring/Spring.Aop/Aop/Framework/AutoProxy/InheritanceBasedAopConfigurer.cs @@ -0,0 +1,368 @@ +#region License + +/* + * Copyright © 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +#region Imports + +using System; +using System.Collections; + +using AopAlliance.Aop; +using Spring.Util; +using Spring.Objects.Factory; +using Spring.Objects.Factory.Config; +using Spring.Objects.Factory.Support; +using Spring.Aop; +using Spring.Aop.Framework; +using Spring.Aop.Framework.Adapter; +using Spring.Aop.Framework.DynamicProxy; +using Spring.Core; + +#endregion + +namespace Spring.Aop.Framework.AutoProxy +{ + /// + /// implementation that replaces a group of objects + /// with a 'true' inheritance based AOP mechanism that delegates + /// to the given interceptors before invoking the object itself. + /// + /// Bruno Baia + public class InheritanceBasedAopConfigurer : IObjectFactoryPostProcessor, IObjectFactoryAware, IOrdered + { + #region Fields + + private IList objectNames; + private string[] interceptorNames = new string[0]; + private bool proxyTargetAttributes = true; + private bool proxyDeclaredMembersOnly = true; + private bool proxyInterfaces = false; + + private IObjectFactory objectFactory; + private int order = int.MaxValue; + private IAdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.Instance; + + #endregion + + #region Properties + + /// + /// Set the names of the objects in IList fashioned way + /// that should automatically get intercepted. + /// + /// + /// A name can specify a prefix to match by ending with "*", e.g. "myObject,tx*" + /// will match the object named "myObject" and all objects whose name start with "tx". + /// + public virtual IList ObjectNames + { + set { objectNames = value; } + } + + /// + /// Sets the common interceptors, a list of , + /// and introduction object names. + /// + /// + /// + /// If this property isn't set, there will be zero common interceptors. + /// This is perfectly valid, if "specific" interceptors such as + /// matching Advisors are all we want. + /// + /// + /// + /// The list of , + /// and introduction object names. + /// + /// + /// + public virtual string[] InterceptorNames + { + set { interceptorNames = value; } + } + + /// + /// Is target type attributes, method attributes, method's return type attributes + /// and method's parameter attributes to be proxied in addition + /// to any interfaces declared on the proxied ? + /// + public virtual bool ProxyTargetAttributes + { + get { return this.proxyTargetAttributes; } + set { this.proxyTargetAttributes = value; } + } + + /// + /// Gets or sets a value indicating whether inherited members should be proxied. + /// + /// + /// if inherited members should be proxied; + /// otherwise, . + /// + public bool ProxyDeclaredMembersOnly + { + get { return proxyDeclaredMembersOnly; } + set { proxyDeclaredMembersOnly = value; } + } + + /// + /// Gets or sets a value indicating whether interfaces members should be proxied. + /// + /// + /// if interfaces members should be proxied; + /// otherwise, . + /// + public bool ProxyInterfaces + { + get { return proxyInterfaces; } + set { proxyInterfaces = value; } + } + + #endregion + + #region IObjectFactoryAware Members + + /// + /// Callback that supplies the owning factory to an object instance. + /// + /// + /// Owning + /// (may not be ). The object can immediately + /// call methods on the factory. + /// + /// + ///

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

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

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

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

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

+ ///
+ /// the object name to check + /// if the names match + protected virtual bool IsObjectNameMatch(string objectName) + { + if (objectNames != null) + { + for (int i = 0; i < objectNames.Count; i++) + { + string mappedName = String.Copy((string)objectNames[i]); + if (PatternMatchUtils.SimpleMatch(mappedName, objectName)) + { + return true; + } + } + } + return false; + } + + #endregion + + #region Private Methods + + private IAdvisor[] ResolveInterceptorNames() + { + ArrayList advisors = new ArrayList(); + foreach (string name in interceptorNames) + { + object next = objectFactory.GetObject(name); + if (next is IAdvisors) + { + advisors.AddRange(((IAdvisors)next).Advisors); + } + else + { + advisors.Add(advisorAdapterRegistry.Wrap(next)); + } + } + return (IAdvisor[])advisors.ToArray(typeof(IAdvisor)); + } + + #endregion + + #region InheritanceBasedAopTargetSource inner class definition + + private class InheritanceBasedAopTargetSource : ITargetSource + { + private Type _targetType; + + public InheritanceBasedAopTargetSource(Type targetType) + { + _targetType = targetType; + } + + #region ITargetSource Members + + public object GetTarget() + { + return null; + } + + public bool IsStatic + { + get { return true; } + } + + public void ReleaseTarget(object target) + { + } + + public Type TargetType + { + get { return _targetType; } + } + + #endregion + } + + #endregion + } +} diff --git a/src/Spring/Spring.Aop/Spring.Aop.2005.csproj b/src/Spring/Spring.Aop/Spring.Aop.2005.csproj index dd9fc546..59be97d4 100644 --- a/src/Spring/Spring.Aop/Spring.Aop.2005.csproj +++ b/src/Spring/Spring.Aop/Spring.Aop.2005.csproj @@ -120,6 +120,7 @@ + diff --git a/src/Spring/Spring.Aop/Spring.Aop.2008.csproj b/src/Spring/Spring.Aop/Spring.Aop.2008.csproj index 684acb96..eee83f5b 100644 --- a/src/Spring/Spring.Aop/Spring.Aop.2008.csproj +++ b/src/Spring/Spring.Aop/Spring.Aop.2008.csproj @@ -136,6 +136,7 @@ +