diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyMethodBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyMethodBuilder.cs index e2d05ce2..6b58cdaa 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyMethodBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyMethodBuilder.cs @@ -1,787 +1,790 @@ -#region License - -/* - * Copyright © 2002-2006 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#endregion - -#region Imports - -using System; -using System.Collections; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.Serialization; - -using Spring.Proxy; -using Spring.Util; - -#endregion - -namespace Spring.Aop.Framework.DynamicProxy -{ - /// - /// Base class for AOP method builders that contains common functionalities. - /// - /// Aleksandar Seovic - /// Bruno Baia - public abstract class AbstractAopProxyMethodBuilder : AbstractProxyMethodBuilder - { - #region Fields - - /// - /// The implementation to use. - /// - protected IAopProxyTypeGenerator aopProxyGenerator; - - /// - /// The dictionary to cache the list of target - /// s. - /// - protected IDictionary targetMethods; - - /// - /// The dictionary to cache the list of target - /// s defined on the proxy. - /// - protected IDictionary onProxyTargetMethods; - - // variables - - /// - /// The local variable to store the list of method interceptors. - /// - protected LocalBuilder interceptors; - - /// - /// The local variable to store the target type being proxied. - /// - protected LocalBuilder targetType; - - /// - /// The local variable to store method arguments. - /// - protected LocalBuilder arguments; - - /// - /// The local variable to store the return value. - /// - protected LocalBuilder returnValue; - -#if NET_2_0 - /// - /// The local variable to store the closed generic method - /// when the target method is generic. - /// - protected LocalBuilder genericTargetMethod; - - /// - /// The local variable to store the closed generic method - /// when the target method defined on the proxy is generic. - /// - protected LocalBuilder genericOnProxyTargetMethod; -#endif - /// - /// The field to cache the target . - /// - protected FieldBuilder targetMethodCacheField; - - /// - /// The field to cache the target - /// defined on the proxy. - /// - protected FieldBuilder onProxyTargetMethodCacheField; - - // convinience fields - - /// - /// Indicates if the method returns a value. - /// - protected bool methodReturnsValue; - - // private fields - - private static IDictionary ldindOpCodes; - - #endregion - - #region Constructor(s) / Destructor - - static AbstractAopProxyMethodBuilder() - { - ldindOpCodes = new Hashtable(); - ldindOpCodes[typeof(sbyte)] = OpCodes.Ldind_I1; - ldindOpCodes[typeof(short)] = OpCodes.Ldind_I2; - ldindOpCodes[typeof(int)] = OpCodes.Ldind_I4; - ldindOpCodes[typeof(long)] = OpCodes.Ldind_I8; - ldindOpCodes[typeof(byte)] = OpCodes.Ldind_U1; - ldindOpCodes[typeof(ushort)] = OpCodes.Ldind_U2; - ldindOpCodes[typeof(uint)] = OpCodes.Ldind_U4; - ldindOpCodes[typeof(ulong)] = OpCodes.Ldind_I8; - ldindOpCodes[typeof(float)] = OpCodes.Ldind_R4; - ldindOpCodes[typeof(double)] = OpCodes.Ldind_R8; - ldindOpCodes[typeof(char)] = OpCodes.Ldind_U2; - ldindOpCodes[typeof(bool)] = OpCodes.Ldind_I1; - } - - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// if the interface is to be - /// implemented explicitly; otherwise . - /// - /// - /// The dictionary to cache the list of target - /// s. - /// - protected AbstractAopProxyMethodBuilder( - TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, - bool explicitImplementation, IDictionary targetMethods) - : this(typeBuilder, aopProxyGenerator, explicitImplementation, targetMethods, new Hashtable()) - { - } - - /// - /// Creates a new instance of the method builder. - /// - /// The type builder to use. - /// - /// The implementation to use. - /// - /// - /// if the interface is to be - /// implemented explicitly; otherwise . - /// - /// - /// The dictionary to cache the list of target - /// s. - /// - /// - /// The dictionary to cache the list of target - /// s defined on the proxy. - /// - protected AbstractAopProxyMethodBuilder( - TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, - bool explicitImplementation, IDictionary targetMethods, IDictionary onProxyTargetMethods) - : base(typeBuilder, aopProxyGenerator, explicitImplementation) - { - this.aopProxyGenerator = aopProxyGenerator; - this.targetMethods = targetMethods; - this.onProxyTargetMethods = onProxyTargetMethods; - } - - #endregion - - #region Protected Members - - /// - /// Generates the proxy method. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected override void GenerateMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - methodReturnsValue = (method.ReturnType != typeof(void)); - - DeclareLocals(il, method); - - GenerateTargetMethodCacheField(il, method); - GenerateOnProxyTargetMethodCacheField(il, method); - - BeginMethod(il, method); - GenerateMethodLogic(il, method, interfaceMethod); - EndMethod(il, method); - } - - /// - /// Generates unique method id for the cache field. - /// - /// The target method. - /// An unique method name. - protected virtual string GenerateMethodCacheFieldId(MethodInfo method) - { - return "_m" + Guid.NewGuid().ToString("N"); - } - - /// - /// Create static field that will cache target method. - /// - /// The IL generator to use. - /// The target method. - protected virtual void GenerateTargetMethodCacheField( - ILGenerator il, MethodInfo method) - { - string methodId = GenerateMethodCacheFieldId(method); - targetMethods.Add(methodId, method); - - targetMethodCacheField = typeBuilder.DefineField(methodId, typeof(MethodInfo), - FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly); - -#if NET_2_0 - MakeGenericMethod(il, method, targetMethodCacheField, genericTargetMethod); -#endif - } - - /// - /// Create static field that will cache target method when defined on the proxy. - /// - /// The IL generator to use. - /// The target method. - protected virtual void GenerateOnProxyTargetMethodCacheField( - ILGenerator il, MethodInfo method) - { - } - -#if NET_2_0 - /// - /// Create a closed generic method for the current call - /// if target method is a generic definition. - /// - /// The IL generator to use. - /// The target method. - /// - /// The field that contains the method generic definition - /// - /// - /// The local variable to store the closed generic method. - /// - protected void MakeGenericMethod(ILGenerator il, MethodInfo method, - FieldBuilder methodCacheField, LocalBuilder localMethod) - { - // if target method is a generic definition, - // create a closed generic method for the current call. - if (method.IsGenericMethodDefinition) - { - Type[] genericArgs = method.GetGenericArguments(); - - LocalBuilder typeArgs = il.DeclareLocal(typeof(Type[])); - - il.Emit(OpCodes.Ldsfld, methodCacheField); - - // specify array size and create an array - il.Emit(OpCodes.Ldc_I4, genericArgs.Length); - il.Emit(OpCodes.Newarr, typeof(Type)); - il.Emit(OpCodes.Stloc, typeArgs); - - // populate array with type arguments - for (int i = 0; i < genericArgs.Length; i++) - { - il.Emit(OpCodes.Ldloc, typeArgs); - il.Emit(OpCodes.Ldc_I4, i); - il.Emit(OpCodes.Ldtoken, genericArgs[i]); - il.EmitCall(OpCodes.Call, References.GetTypeFromHandle, null); - il.Emit(OpCodes.Stelem_Ref); - } - - il.Emit(OpCodes.Ldloc, typeArgs); - il.Emit(OpCodes.Callvirt, References.MakeGenericMethod); - il.Emit(OpCodes.Stloc, localMethod); - } - } -#endif - - /// - /// Generates the IL instructions that pushes - /// the target type on stack. - /// - /// The IL generator to use. - protected virtual void PushTargetType(ILGenerator il) - { - aopProxyGenerator.PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.TargetTypeField); - } - - /// - /// Generates the IL instructions that pushes - /// the current - /// instance on stack. - /// - /// The IL generator to use. - protected virtual void PushAdvisedProxy(ILGenerator il) - { - aopProxyGenerator.PushAdvisedProxy(il); - } - - /// - /// Pushes the target to stack. - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void PushTargetMethodInfo(ILGenerator il, MethodInfo method) - { -#if NET_2_0 - if (method.IsGenericMethodDefinition) - { - il.Emit(OpCodes.Ldloc, genericTargetMethod); - return; - } -#endif - il.Emit(OpCodes.Ldsfld, targetMethodCacheField); - } - - /// - /// Pushes the target defined on the proxy to stack. - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void PushOnProxyTargetMethodInfo(ILGenerator il, MethodInfo method) - { - if (onProxyTargetMethodCacheField != null) - { -#if NET_2_0 - if (method.IsGenericMethodDefinition) - { - il.Emit(OpCodes.Ldloc, genericOnProxyTargetMethod); - return; - } -#endif - il.Emit(OpCodes.Ldsfld, onProxyTargetMethodCacheField); - } - else - { - il.Emit(OpCodes.Ldnull); - } - } - - /// - /// Creates local variable declarations. - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void DeclareLocals(ILGenerator il, MethodInfo method) - { - interceptors = il.DeclareLocal(typeof(IList)); - targetType = il.DeclareLocal(typeof(Type)); - arguments = il.DeclareLocal(typeof(Object[])); - -#if NET_2_0 - if (method.IsGenericMethodDefinition) - { - genericTargetMethod = il.DeclareLocal(typeof(MethodInfo)); - genericOnProxyTargetMethod = il.DeclareLocal(typeof(MethodInfo)); - } -#endif - if (methodReturnsValue) - { - returnValue = il.DeclareLocal(method.ReturnType); - } - -#if DEBUG - interceptors.SetLocalSymInfo("interceptors"); - targetType.SetLocalSymInfo("targetType"); - arguments.SetLocalSymInfo("arguments"); -#if NET_2_0 - if (method.IsGenericMethodDefinition) - { - genericTargetMethod.SetLocalSymInfo("genericTargetMethod"); - genericOnProxyTargetMethod.SetLocalSymInfo("genericOnProxyTargetMethod"); - } -#endif - if (methodReturnsValue) - { - returnValue.SetLocalSymInfo("returnValue"); - } -#endif - } - - /// - /// Initializes local variables - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void BeginMethod(ILGenerator il, MethodInfo method) - { - Label jmpProxyNotExposed = il.DefineLabel(); - - // set current proxy to this object - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.AdvisedField); - il.EmitCall(OpCodes.Callvirt, References.ExposeProxyProperty, null); - il.Emit(OpCodes.Brfalse_S, jmpProxyNotExposed); - il.Emit(OpCodes.Ldarg_0); - il.EmitCall(OpCodes.Call, References.PushProxyMethod, null); - - il.MarkLabel(jmpProxyNotExposed); - - // initialize targetType - PushTargetType(il); - il.Emit(OpCodes.Stloc, targetType); - - // initialize interceptors - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldloc, targetType); - PushTargetMethodInfo(il, method); - il.EmitCall(OpCodes.Call, References.GetInterceptorsMethod, null); - il.Emit(OpCodes.Stloc, interceptors); - } - - /// - /// Generates method logic. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected virtual void GenerateMethodLogic( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - Label jmpDirectCall = il.DefineLabel(); - Label jmpEndIf = il.DefineLabel(); - - // check if there are any interceptors - il.Emit(OpCodes.Ldloc, interceptors); - il.EmitCall(OpCodes.Callvirt, References.CountProperty, null); - il.Emit(OpCodes.Ldc_I4_0); - - // if not jump to direct call - il.Emit(OpCodes.Ble, jmpDirectCall); - - // otherwise call Invoke and jump to method end - CallInvoke(il, method); - il.Emit(OpCodes.Br, jmpEndIf); - - // call method directly - il.MarkLabel(jmpDirectCall); - CallDirectProxiedMethod(il, method, interfaceMethod); - if (methodReturnsValue) - { - // store return value, unboxing is not necessary because we called method directly - il.Emit(OpCodes.Stloc, returnValue); - } - - il.MarkLabel(jmpEndIf); - - if (methodReturnsValue) - { - if (!method.ReturnType.IsValueType) - { - ProcessReturnValue(il, returnValue); - } - } - } - - /// - /// Calls method using Invoke - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void CallInvoke(ILGenerator il, MethodInfo method) - { - ParameterInfo[] parameters = method.GetParameters(); - - SetupMethodArguments(il, method, parameters); - - PushAdvisedProxy(il); - - // setup parameters for call - il.Emit(OpCodes.Ldarg_0); // proxy - PushTarget(il); // target - il.Emit(OpCodes.Ldloc, targetType); // target type - PushTargetMethodInfo(il, method); // method - PushOnProxyTargetMethodInfo(il, method); // method defined on proxy - il.Emit(OpCodes.Ldloc, arguments); // args - il.Emit(OpCodes.Ldloc, interceptors); // interceptors - - // call Invoke - il.EmitCall(OpCodes.Call, References.InvokeMethod, null); - - // process return value - if (methodReturnsValue) - { - EmitUnboxIfNeeded(il, method.ReturnType); - il.Emit(OpCodes.Stloc, returnValue); - } - else - { - il.Emit(OpCodes.Pop); - } - - // process byRef arguments - for (int i = 0; i < parameters.Length; i++) - { - if (parameters[i].ParameterType.IsByRef) - { - il.Emit(OpCodes.Ldarg_S, i + 1); - il.Emit(OpCodes.Ldloc, arguments); - il.Emit(OpCodes.Ldc_I4_S, i); - il.Emit(OpCodes.Ldelem_Ref); - Type type = parameters[i].ParameterType.GetElementType(); - EmitUnboxIfNeeded(il, type); - EmitStoreValueIndirect(il, type); - } - } - } - - /// - /// Setup proxied method arguments. - /// - /// The IL generator to use. - /// The method to proxy. - /// The method's parameters. - protected void SetupMethodArguments( - ILGenerator il, MethodInfo method, ParameterInfo[] parameters) - { - if (parameters.Length > 0) - { - // specify array size and create an array - il.Emit(OpCodes.Ldc_I4, parameters.Length); - il.Emit(OpCodes.Newarr, typeof(Object)); - il.Emit(OpCodes.Stloc, arguments); - - // populate array with params - for (int i = 0; i < parameters.Length; i++) - { - Type type = parameters[i].ParameterType; - - il.Emit(OpCodes.Ldloc, arguments); - il.Emit(OpCodes.Ldc_I4, i); - il.Emit(OpCodes.Ldarg_S, i + 1); - - // setup byRef arguments - if (type.IsByRef) - { - type = type.GetElementType(); - EmitLoadValueIndirect(il, type); - } - -#if NET_2_0 - if (type.IsValueType || type.IsGenericParameter) -#else - if (type.IsValueType) -#endif - { - il.Emit(OpCodes.Box, type); - } - - il.Emit(OpCodes.Stelem_Ref); - } - } - else - { - il.Emit(OpCodes.Ldnull); - il.Emit(OpCodes.Stloc, arguments); - } - } - - /// - /// Calls proxied method directly. - /// - /// The IL generator to use. - /// The method to proxy. - /// - /// The interface definition of the method, if applicable. - /// - protected abstract void CallDirectProxiedMethod( - ILGenerator il, MethodInfo method, MethodInfo interfaceMethod); - - /// - /// Ends method by returning return value if appropriate. - /// - /// The IL generator to use. - /// The method to proxy. - protected virtual void EndMethod(ILGenerator il, MethodInfo method) - { - Label jmpProxyNotExposed = il.DefineLabel(); - - // reset current proxy to old value - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.AdvisedField); - il.EmitCall(OpCodes.Callvirt, References.ExposeProxyProperty, null); - il.Emit(OpCodes.Brfalse_S, jmpProxyNotExposed); - il.EmitCall(OpCodes.Call, References.PopProxyMethod, null); - - il.MarkLabel(jmpProxyNotExposed); - - if (methodReturnsValue) - { - il.Emit(OpCodes.Ldloc, returnValue); - } - } - - #endregion - - #region Reflection.Emit utility methods - - /// - /// Emits MSIL instructions to load a value of the specified - /// onto the evaluation stack indirectly. - /// - /// The IL generator to use. - /// The type of the value. - protected static void EmitLoadValueIndirect(ILGenerator il, Type type) - { - if (type.IsValueType) - { - if (type == typeof(int)) il.Emit(OpCodes.Ldind_I4); - else if (type == typeof(uint)) il.Emit(OpCodes.Ldind_U4); - else if (type == typeof(char)) il.Emit(OpCodes.Ldind_I2); - else if (type == typeof(bool)) il.Emit(OpCodes.Ldind_I1); - else if (type == typeof(float)) il.Emit(OpCodes.Ldind_R4); - else if (type == typeof(double)) il.Emit(OpCodes.Ldind_R8); - else if (type == typeof(short)) il.Emit(OpCodes.Ldind_I2); - else if (type == typeof(ushort)) il.Emit(OpCodes.Ldind_U2); - else if (type == typeof(long) || type == typeof(ulong)) il.Emit(OpCodes.Ldind_I8); - else il.Emit(OpCodes.Ldobj, type); - } - else - { - il.Emit(OpCodes.Ldind_Ref); - } - } - - /// - /// Emit MSIL instructions to store a value of the specified - /// at a supplied address. - /// - /// The IL generator to use. - /// The type of the value. - protected static void EmitStoreValueIndirect(ILGenerator il, Type type) - { - if (type.IsValueType) - { - if (type.IsEnum) EmitStoreValueIndirect(il, Enum.GetUnderlyingType(type)); - else if (type == typeof(int)) il.Emit(OpCodes.Stind_I4); - else if (type == typeof(short)) il.Emit(OpCodes.Stind_I2); - else if (type == typeof(long) || type == typeof(ulong)) il.Emit(OpCodes.Stind_I8); - else if (type == typeof(char)) il.Emit(OpCodes.Stind_I2); - else if (type == typeof(bool)) il.Emit(OpCodes.Stind_I1); - else if (type == typeof(float)) il.Emit(OpCodes.Stind_R4); - else if (type == typeof(double)) il.Emit(OpCodes.Stind_R8); - else il.Emit(OpCodes.Stobj, type); - } - else - { - il.Emit(OpCodes.Stind_Ref); - } - } - - /// - /// Emits MSIL instructions to convert the boxed representation - /// of the supplied to its unboxed form. - /// - /// The IL generator to use. - /// The type specified in the instruction. - protected static void EmitUnboxIfNeeded(ILGenerator il, Type type) - { -#if NET_2_0 - if (type.IsValueType || type.IsGenericParameter) - { - il.Emit(OpCodes.Unbox_Any, type); - } -#else - if (type.IsValueType) - { - il.Emit(OpCodes.Unbox, type); - il.Emit(OpCodes.Ldobj, type); - } -#endif - } - - #endregion - } - - #region References helper class definition - - internal struct References - { - // fields - public static readonly FieldInfo AdvisedField = - typeof(AdvisedProxy).GetField("m_advised", BindingFlags.Instance | BindingFlags.Public); - - public static readonly FieldInfo TargetTypeField = - typeof(AdvisedProxy).GetField("m_targetType", BindingFlags.Instance | BindingFlags.Public); - - public static readonly FieldInfo IntroductionsField = - typeof(AdvisedProxy).GetField("m_introductions", BindingFlags.Instance | BindingFlags.Public); - - public static readonly FieldInfo TargetSourceWrapperField = - typeof(AdvisedProxy).GetField("m_targetSourceWrapper", BindingFlags.Instance | BindingFlags.Public); - - // constructors - public static readonly ConstructorInfo BaseCompositionAopProxyConstructor = - typeof(BaseCompositionAopProxy).GetConstructor(new Type[] { typeof(IAdvised) }); - - public static readonly ConstructorInfo BaseCompositionAopProxySerializationConstructor = - typeof(BaseCompositionAopProxy).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, - new Type[] {typeof(SerializationInfo), typeof(StreamingContext)}, - null); - - public static readonly ConstructorInfo AdvisedProxyConstructor = - typeof(AdvisedProxy).GetConstructor(new Type[] { typeof(IAdvised), typeof(IAopProxy) }); - - public static readonly ConstructorInfo AdvisedProxySerializationConstructor = - typeof(AdvisedProxy).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, - new Type[] {typeof (SerializationInfo), typeof (StreamingContext)}, - null); - public static readonly ConstructorInfo ObjectConstructor = - typeof(Object).GetConstructor(Type.EmptyTypes); - - // methods - public static readonly MethodInfo PushProxyMethod = - typeof(AopContext).GetMethod("PushProxy", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(Object) }, null); - - public static readonly MethodInfo PopProxyMethod = - typeof(AopContext).GetMethod("PopProxy", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null); - - public static readonly MethodInfo InvokeMethod = - typeof(AdvisedProxy).GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Object), typeof(Object), typeof(Type), typeof(MethodInfo), typeof(MethodInfo), typeof(Object[]), typeof(IList) }, null); - - public static readonly MethodInfo GetInterceptorsMethod = - typeof(AdvisedProxy).GetMethod("GetInterceptors", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Type), typeof(MethodInfo) }, null); - - public static readonly MethodInfo GetTargetMethod = - typeof(ITargetSourceWrapper).GetMethod("GetTarget", Type.EmptyTypes); - - public static readonly MethodInfo GetTypeMethod = - typeof(Object).GetMethod("GetType", Type.EmptyTypes); - - public static readonly MethodInfo GetTypeFromHandle = - typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }); - -#if NET_2_0 - public static readonly MethodInfo MakeGenericMethod = - typeof(MethodInfo).GetMethod("MakeGenericMethod", new Type[] { typeof(Type[]) }); -#endif - - public static readonly MethodInfo DisposeMethod = - typeof(IDisposable).GetMethod("Dispose", Type.EmptyTypes); - - public static readonly MethodInfo AddSerializationValue = - typeof(SerializationInfo).GetMethod("AddValue", new Type[] { typeof(string), typeof(object) }); - - public static readonly MethodInfo GetSerializationValue = - typeof(SerializationInfo).GetMethod("GetValue", new Type[] { typeof(string), typeof(Type) }); - - // properties - public static readonly MethodInfo ExposeProxyProperty = - typeof(IAdvised).GetProperty("ExposeProxy", typeof(Boolean)).GetGetMethod(); - - public static readonly MethodInfo CountProperty = - typeof(ICollection).GetProperty("Count", typeof(Int32)).GetGetMethod(); - } - - #endregion -} +#region License + +/* + * Copyright © 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +#region Imports + +using System; +using System.Collections; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.Serialization; + +using Spring.Proxy; +using Spring.Util; + +#endregion + +namespace Spring.Aop.Framework.DynamicProxy +{ + /// + /// Base class for AOP method builders that contains common functionalities. + /// + /// Aleksandar Seovic + /// Bruno Baia + public abstract class AbstractAopProxyMethodBuilder : AbstractProxyMethodBuilder + { + #region Fields + + /// + /// The implementation to use. + /// + protected IAopProxyTypeGenerator aopProxyGenerator; + + /// + /// The dictionary to cache the list of target + /// s. + /// + protected IDictionary targetMethods; + + /// + /// The dictionary to cache the list of target + /// s defined on the proxy. + /// + protected IDictionary onProxyTargetMethods; + + // variables + + /// + /// The local variable to store the list of method interceptors. + /// + protected LocalBuilder interceptors; + + /// + /// The local variable to store the target type being proxied. + /// + protected LocalBuilder targetType; + + /// + /// The local variable to store method arguments. + /// + protected LocalBuilder arguments; + + /// + /// The local variable to store the return value. + /// + protected LocalBuilder returnValue; + +#if NET_2_0 + /// + /// The local variable to store the closed generic method + /// when the target method is generic. + /// + protected LocalBuilder genericTargetMethod; + + /// + /// The local variable to store the closed generic method + /// when the target method defined on the proxy is generic. + /// + protected LocalBuilder genericOnProxyTargetMethod; +#endif + /// + /// The field to cache the target . + /// + protected FieldBuilder targetMethodCacheField; + + /// + /// The field to cache the target + /// defined on the proxy. + /// + protected FieldBuilder onProxyTargetMethodCacheField; + + // convinience fields + + /// + /// Indicates if the method returns a value. + /// + protected bool methodReturnsValue; + + // private fields + + private static IDictionary ldindOpCodes; + + #endregion + + #region Constructor(s) / Destructor + + static AbstractAopProxyMethodBuilder() + { + ldindOpCodes = new Hashtable(); + ldindOpCodes[typeof(sbyte)] = OpCodes.Ldind_I1; + ldindOpCodes[typeof(short)] = OpCodes.Ldind_I2; + ldindOpCodes[typeof(int)] = OpCodes.Ldind_I4; + ldindOpCodes[typeof(long)] = OpCodes.Ldind_I8; + ldindOpCodes[typeof(byte)] = OpCodes.Ldind_U1; + ldindOpCodes[typeof(ushort)] = OpCodes.Ldind_U2; + ldindOpCodes[typeof(uint)] = OpCodes.Ldind_U4; + ldindOpCodes[typeof(ulong)] = OpCodes.Ldind_I8; + ldindOpCodes[typeof(float)] = OpCodes.Ldind_R4; + ldindOpCodes[typeof(double)] = OpCodes.Ldind_R8; + ldindOpCodes[typeof(char)] = OpCodes.Ldind_U2; + ldindOpCodes[typeof(bool)] = OpCodes.Ldind_I1; + } + + /// + /// Creates a new instance of the method builder. + /// + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// if the interface is to be + /// implemented explicitly; otherwise . + /// + /// + /// The dictionary to cache the list of target + /// s. + /// + protected AbstractAopProxyMethodBuilder( + TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, + bool explicitImplementation, IDictionary targetMethods) + : this(typeBuilder, aopProxyGenerator, explicitImplementation, targetMethods, new Hashtable()) + { + } + + /// + /// Creates a new instance of the method builder. + /// + /// The type builder to use. + /// + /// The implementation to use. + /// + /// + /// if the interface is to be + /// implemented explicitly; otherwise . + /// + /// + /// The dictionary to cache the list of target + /// s. + /// + /// + /// The dictionary to cache the list of target + /// s defined on the proxy. + /// + protected AbstractAopProxyMethodBuilder( + TypeBuilder typeBuilder, IAopProxyTypeGenerator aopProxyGenerator, + bool explicitImplementation, IDictionary targetMethods, IDictionary onProxyTargetMethods) + : base(typeBuilder, aopProxyGenerator, explicitImplementation) + { + this.aopProxyGenerator = aopProxyGenerator; + this.targetMethods = targetMethods; + this.onProxyTargetMethods = onProxyTargetMethods; + } + + #endregion + + #region Protected Members + + /// + /// Generates the proxy method. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected override void GenerateMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + methodReturnsValue = (method.ReturnType != typeof(void)); + + DeclareLocals(il, method); + + GenerateTargetMethodCacheField(il, method); + GenerateOnProxyTargetMethodCacheField(il, method); + + BeginMethod(il, method); + GenerateMethodLogic(il, method, interfaceMethod); + EndMethod(il, method); + } + + /// + /// Generates unique method id for the cache field. + /// + /// The target method. + /// An unique method name. + protected virtual string GenerateMethodCacheFieldId(MethodInfo method) + { + return "_m" + Guid.NewGuid().ToString("N"); + } + + /// + /// Create static field that will cache target method. + /// + /// The IL generator to use. + /// The target method. + protected virtual void GenerateTargetMethodCacheField( + ILGenerator il, MethodInfo method) + { + string methodId = GenerateMethodCacheFieldId(method); + targetMethods.Add(methodId, method); + + targetMethodCacheField = typeBuilder.DefineField(methodId, typeof(MethodInfo), + FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly); + +#if NET_2_0 + MakeGenericMethod(il, method, targetMethodCacheField, genericTargetMethod); +#endif + } + + /// + /// Create static field that will cache target method when defined on the proxy. + /// + /// The IL generator to use. + /// The target method. + protected virtual void GenerateOnProxyTargetMethodCacheField( + ILGenerator il, MethodInfo method) + { + } + +#if NET_2_0 + /// + /// Create a closed generic method for the current call + /// if target method is a generic definition. + /// + /// The IL generator to use. + /// The target method. + /// + /// The field that contains the method generic definition + /// + /// + /// The local variable to store the closed generic method. + /// + protected void MakeGenericMethod(ILGenerator il, MethodInfo method, + FieldBuilder methodCacheField, LocalBuilder localMethod) + { + // if target method is a generic definition, + // create a closed generic method for the current call. + if (method.IsGenericMethodDefinition) + { + Type[] genericArgs = method.GetGenericArguments(); + + LocalBuilder typeArgs = il.DeclareLocal(typeof(Type[])); + + il.Emit(OpCodes.Ldsfld, methodCacheField); + + // specify array size and create an array + il.Emit(OpCodes.Ldc_I4, genericArgs.Length); + il.Emit(OpCodes.Newarr, typeof(Type)); + il.Emit(OpCodes.Stloc, typeArgs); + + // populate array with type arguments + for (int i = 0; i < genericArgs.Length; i++) + { + il.Emit(OpCodes.Ldloc, typeArgs); + il.Emit(OpCodes.Ldc_I4, i); + il.Emit(OpCodes.Ldtoken, genericArgs[i]); + il.EmitCall(OpCodes.Call, References.GetTypeFromHandle, null); + il.Emit(OpCodes.Stelem_Ref); + } + + il.Emit(OpCodes.Ldloc, typeArgs); + il.Emit(OpCodes.Callvirt, References.MakeGenericMethod); + il.Emit(OpCodes.Stloc, localMethod); + } + } +#endif + + /// + /// Generates the IL instructions that pushes + /// the target type on stack. + /// + /// The IL generator to use. + protected virtual void PushTargetType(ILGenerator il) + { + aopProxyGenerator.PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.TargetTypeField); + } + + /// + /// Generates the IL instructions that pushes + /// the current + /// instance on stack. + /// + /// The IL generator to use. + protected virtual void PushAdvisedProxy(ILGenerator il) + { + aopProxyGenerator.PushAdvisedProxy(il); + } + + /// + /// Pushes the target to stack. + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void PushTargetMethodInfo(ILGenerator il, MethodInfo method) + { +#if NET_2_0 + if (method.IsGenericMethodDefinition) + { + il.Emit(OpCodes.Ldloc, genericTargetMethod); + return; + } +#endif + il.Emit(OpCodes.Ldsfld, targetMethodCacheField); + } + + /// + /// Pushes the target defined on the proxy to stack. + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void PushOnProxyTargetMethodInfo(ILGenerator il, MethodInfo method) + { + if (onProxyTargetMethodCacheField != null) + { +#if NET_2_0 + if (method.IsGenericMethodDefinition) + { + il.Emit(OpCodes.Ldloc, genericOnProxyTargetMethod); + return; + } +#endif + il.Emit(OpCodes.Ldsfld, onProxyTargetMethodCacheField); + } + else + { + il.Emit(OpCodes.Ldnull); + } + } + + /// + /// Creates local variable declarations. + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void DeclareLocals(ILGenerator il, MethodInfo method) + { + interceptors = il.DeclareLocal(typeof(IList)); + targetType = il.DeclareLocal(typeof(Type)); + arguments = il.DeclareLocal(typeof(Object[])); + +#if NET_2_0 + if (method.IsGenericMethodDefinition) + { + genericTargetMethod = il.DeclareLocal(typeof(MethodInfo)); + genericOnProxyTargetMethod = il.DeclareLocal(typeof(MethodInfo)); + } +#endif + if (methodReturnsValue) + { + returnValue = il.DeclareLocal(method.ReturnType); + } + +#if DEBUG + interceptors.SetLocalSymInfo("interceptors"); + targetType.SetLocalSymInfo("targetType"); + arguments.SetLocalSymInfo("arguments"); +#if NET_2_0 + if (method.IsGenericMethodDefinition) + { + genericTargetMethod.SetLocalSymInfo("genericTargetMethod"); + genericOnProxyTargetMethod.SetLocalSymInfo("genericOnProxyTargetMethod"); + } +#endif + if (methodReturnsValue) + { + returnValue.SetLocalSymInfo("returnValue"); + } +#endif + } + + /// + /// Initializes local variables + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void BeginMethod(ILGenerator il, MethodInfo method) + { + Label jmpProxyNotExposed = il.DefineLabel(); + + // set current proxy to this object + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.AdvisedField); + il.EmitCall(OpCodes.Callvirt, References.ExposeProxyProperty, null); + il.Emit(OpCodes.Brfalse_S, jmpProxyNotExposed); + il.Emit(OpCodes.Ldarg_0); + il.EmitCall(OpCodes.Call, References.PushProxyMethod, null); + + il.MarkLabel(jmpProxyNotExposed); + + // initialize targetType + PushTargetType(il); + il.Emit(OpCodes.Stloc, targetType); + + // initialize interceptors + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldloc, targetType); + PushTargetMethodInfo(il, method); + il.EmitCall(OpCodes.Call, References.GetInterceptorsMethod, null); + il.Emit(OpCodes.Stloc, interceptors); + } + + /// + /// Generates method logic. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected virtual void GenerateMethodLogic( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) + { + Label jmpDirectCall = il.DefineLabel(); + Label jmpEndIf = il.DefineLabel(); + + // check if there are any interceptors + il.Emit(OpCodes.Ldloc, interceptors); + il.EmitCall(OpCodes.Callvirt, References.CountProperty, null); + il.Emit(OpCodes.Ldc_I4_0); + + // if not jump to direct call + il.Emit(OpCodes.Ble, jmpDirectCall); + + // otherwise call Invoke and jump to method end + CallInvoke(il, method); + il.Emit(OpCodes.Br, jmpEndIf); + + // call method directly + il.MarkLabel(jmpDirectCall); + CallDirectProxiedMethod(il, method, interfaceMethod); + if (methodReturnsValue) + { + // store return value, unboxing is not necessary because we called method directly + il.Emit(OpCodes.Stloc, returnValue); + } + + il.MarkLabel(jmpEndIf); + + if (methodReturnsValue) + { + if (!method.ReturnType.IsValueType) + { + ProcessReturnValue(il, returnValue); + } + } + } + + /// + /// Calls method using Invoke + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void CallInvoke(ILGenerator il, MethodInfo method) + { + ParameterInfo[] parameters = method.GetParameters(); + + SetupMethodArguments(il, method, parameters); + + PushAdvisedProxy(il); + + // setup parameters for call + il.Emit(OpCodes.Ldarg_0); // proxy + PushTarget(il); // target + il.Emit(OpCodes.Ldloc, targetType); // target type + PushTargetMethodInfo(il, method); // method + PushOnProxyTargetMethodInfo(il, method); // method defined on proxy + il.Emit(OpCodes.Ldloc, arguments); // args + il.Emit(OpCodes.Ldloc, interceptors); // interceptors + + // call Invoke + il.EmitCall(OpCodes.Call, References.InvokeMethod, null); + + // process return value + if (methodReturnsValue) + { + EmitUnboxIfNeeded(il, method.ReturnType); + il.Emit(OpCodes.Stloc, returnValue); + } + else + { + il.Emit(OpCodes.Pop); + } + + // process byRef arguments + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].ParameterType.IsByRef) + { + il.Emit(OpCodes.Ldarg_S, i + 1); + il.Emit(OpCodes.Ldloc, arguments); + il.Emit(OpCodes.Ldc_I4_S, i); + il.Emit(OpCodes.Ldelem_Ref); + Type type = parameters[i].ParameterType.GetElementType(); + EmitUnboxIfNeeded(il, type); + EmitStoreValueIndirect(il, type); + } + } + } + + /// + /// Setup proxied method arguments. + /// + /// The IL generator to use. + /// The method to proxy. + /// The method's parameters. + protected void SetupMethodArguments( + ILGenerator il, MethodInfo method, ParameterInfo[] parameters) + { + if (parameters.Length > 0) + { + // specify array size and create an array + il.Emit(OpCodes.Ldc_I4, parameters.Length); + il.Emit(OpCodes.Newarr, typeof(Object)); + il.Emit(OpCodes.Stloc, arguments); + + // populate array with params + for (int i = 0; i < parameters.Length; i++) + { + Type type = parameters[i].ParameterType; + + il.Emit(OpCodes.Ldloc, arguments); + il.Emit(OpCodes.Ldc_I4, i); + il.Emit(OpCodes.Ldarg_S, i + 1); + + // setup byRef arguments + if (type.IsByRef) + { + type = type.GetElementType(); + EmitLoadValueIndirect(il, type); + } + +#if NET_2_0 + if (type.IsValueType || type.IsGenericParameter) +#else + if (type.IsValueType) +#endif + { + il.Emit(OpCodes.Box, type); + } + + il.Emit(OpCodes.Stelem_Ref); + } + } + else + { + il.Emit(OpCodes.Ldnull); + il.Emit(OpCodes.Stloc, arguments); + } + } + + /// + /// Calls proxied method directly. + /// + /// The IL generator to use. + /// The method to proxy. + /// + /// The interface definition of the method, if applicable. + /// + protected abstract void CallDirectProxiedMethod( + ILGenerator il, MethodInfo method, MethodInfo interfaceMethod); + + /// + /// Ends method by returning return value if appropriate. + /// + /// The IL generator to use. + /// The method to proxy. + protected virtual void EndMethod(ILGenerator il, MethodInfo method) + { + Label jmpProxyNotExposed = il.DefineLabel(); + + // reset current proxy to old value + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.AdvisedField); + il.EmitCall(OpCodes.Callvirt, References.ExposeProxyProperty, null); + il.Emit(OpCodes.Brfalse_S, jmpProxyNotExposed); + il.EmitCall(OpCodes.Call, References.PopProxyMethod, null); + + il.MarkLabel(jmpProxyNotExposed); + + if (methodReturnsValue) + { + il.Emit(OpCodes.Ldloc, returnValue); + } + } + + #endregion + + #region Reflection.Emit utility methods + + /// + /// Emits MSIL instructions to load a value of the specified + /// onto the evaluation stack indirectly. + /// + /// The IL generator to use. + /// The type of the value. + protected static void EmitLoadValueIndirect(ILGenerator il, Type type) + { + if (type.IsValueType) + { + if (type == typeof(int)) il.Emit(OpCodes.Ldind_I4); + else if (type == typeof(uint)) il.Emit(OpCodes.Ldind_U4); + else if (type == typeof(char)) il.Emit(OpCodes.Ldind_I2); + else if (type == typeof(bool)) il.Emit(OpCodes.Ldind_I1); + else if (type == typeof(float)) il.Emit(OpCodes.Ldind_R4); + else if (type == typeof(double)) il.Emit(OpCodes.Ldind_R8); + else if (type == typeof(short)) il.Emit(OpCodes.Ldind_I2); + else if (type == typeof(ushort)) il.Emit(OpCodes.Ldind_U2); + else if (type == typeof(long) || type == typeof(ulong)) il.Emit(OpCodes.Ldind_I8); + else il.Emit(OpCodes.Ldobj, type); + } + else + { + il.Emit(OpCodes.Ldind_Ref); + } + } + + /// + /// Emit MSIL instructions to store a value of the specified + /// at a supplied address. + /// + /// The IL generator to use. + /// The type of the value. + protected static void EmitStoreValueIndirect(ILGenerator il, Type type) + { + if (type.IsValueType) + { + if (type.IsEnum) EmitStoreValueIndirect(il, Enum.GetUnderlyingType(type)); + else if (type == typeof(int)) il.Emit(OpCodes.Stind_I4); + else if (type == typeof(short)) il.Emit(OpCodes.Stind_I2); + else if (type == typeof(long) || type == typeof(ulong)) il.Emit(OpCodes.Stind_I8); + else if (type == typeof(char)) il.Emit(OpCodes.Stind_I2); + else if (type == typeof(bool)) il.Emit(OpCodes.Stind_I1); + else if (type == typeof(float)) il.Emit(OpCodes.Stind_R4); + else if (type == typeof(double)) il.Emit(OpCodes.Stind_R8); + else il.Emit(OpCodes.Stobj, type); + } + else + { + il.Emit(OpCodes.Stind_Ref); + } + } + + /// + /// Emits MSIL instructions to convert the boxed representation + /// of the supplied to its unboxed form. + /// + /// The IL generator to use. + /// The type specified in the instruction. + protected static void EmitUnboxIfNeeded(ILGenerator il, Type type) + { +#if NET_2_0 + if (type.IsValueType || type.IsGenericParameter) + { + il.Emit(OpCodes.Unbox_Any, type); + } +#else + if (type.IsValueType) + { + il.Emit(OpCodes.Unbox, type); + il.Emit(OpCodes.Ldobj, type); + } +#endif + } + + #endregion + } + + #region References helper class definition + + internal struct References + { + // fields + public static readonly FieldInfo AdvisedField = + typeof(AdvisedProxy).GetField("m_advised", BindingFlags.Instance | BindingFlags.Public); + + public static readonly FieldInfo TargetTypeField = + typeof(AdvisedProxy).GetField("m_targetType", BindingFlags.Instance | BindingFlags.Public); + + public static readonly FieldInfo IntroductionsField = + typeof(AdvisedProxy).GetField("m_introductions", BindingFlags.Instance | BindingFlags.Public); + + public static readonly FieldInfo TargetSourceField = + typeof(AdvisedProxy).GetField("m_targetSource", BindingFlags.Instance | BindingFlags.Public); + + // constructors + public static readonly ConstructorInfo BaseCompositionAopProxyConstructor = + typeof(BaseCompositionAopProxy).GetConstructor(new Type[] { typeof(IAdvised) }); + + public static readonly ConstructorInfo BaseCompositionAopProxySerializationConstructor = + typeof(BaseCompositionAopProxy).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, + new Type[] {typeof(SerializationInfo), typeof(StreamingContext)}, + null); + + public static readonly ConstructorInfo AdvisedProxyConstructor = + typeof(AdvisedProxy).GetConstructor(new Type[] { typeof(IAdvised), typeof(IAopProxy) }); + + public static readonly ConstructorInfo AdvisedProxySerializationConstructor = + typeof(AdvisedProxy).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, + new Type[] {typeof (SerializationInfo), typeof (StreamingContext)}, + null); + public static readonly ConstructorInfo ObjectConstructor = + typeof(Object).GetConstructor(Type.EmptyTypes); + + // methods + public static readonly MethodInfo PushProxyMethod = + typeof(AopContext).GetMethod("PushProxy", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(Object) }, null); + + public static readonly MethodInfo PopProxyMethod = + typeof(AopContext).GetMethod("PopProxy", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null); + + public static readonly MethodInfo InvokeMethod = + typeof(AdvisedProxy).GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Object), typeof(Object), typeof(Type), typeof(MethodInfo), typeof(MethodInfo), typeof(Object[]), typeof(IList) }, null); + + public static readonly MethodInfo GetInterceptorsMethod = + typeof(AdvisedProxy).GetMethod("GetInterceptors", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Type), typeof(MethodInfo) }, null); + + public static readonly MethodInfo GetTargetMethod = + typeof(ITargetSource).GetMethod("GetTarget", Type.EmptyTypes); + + public static readonly MethodInfo GetReleaseTargetMethod = + typeof(ITargetSource).GetMethod("ReleaseTarget", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Object) }, null); + + public static readonly MethodInfo GetTypeMethod = + typeof(Object).GetMethod("GetType", Type.EmptyTypes); + + public static readonly MethodInfo GetTypeFromHandle = + typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }); + +#if NET_2_0 + public static readonly MethodInfo MakeGenericMethod = + typeof(MethodInfo).GetMethod("MakeGenericMethod", new Type[] { typeof(Type[]) }); +#endif + + public static readonly MethodInfo DisposeMethod = + typeof(IDisposable).GetMethod("Dispose", Type.EmptyTypes); + + public static readonly MethodInfo AddSerializationValue = + typeof(SerializationInfo).GetMethod("AddValue", new Type[] { typeof(string), typeof(object) }); + + public static readonly MethodInfo GetSerializationValue = + typeof(SerializationInfo).GetMethod("GetValue", new Type[] { typeof(string), typeof(Type) }); + + // properties + public static readonly MethodInfo ExposeProxyProperty = + typeof(IAdvised).GetProperty("ExposeProxy", typeof(Boolean)).GetGetMethod(); + + public static readonly MethodInfo CountProperty = + typeof(ICollection).GetProperty("Count", typeof(Int32)).GetGetMethod(); + } + + #endregion +} diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyTypeBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyTypeBuilder.cs index a8125901..0e1499d0 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyTypeBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AbstractAopProxyTypeBuilder.cs @@ -49,7 +49,7 @@ namespace Spring.Aop.Framework.DynamicProxy public override void PushTarget(ILGenerator il) { PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.TargetSourceWrapperField); + il.Emit(OpCodes.Ldfld, References.TargetSourceField); il.EmitCall(OpCodes.Callvirt, References.GetTargetMethod, null); } diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AdvisedProxy.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AdvisedProxy.cs index 0867baec..da76b349 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AdvisedProxy.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/AdvisedProxy.cs @@ -1,19 +1,19 @@ #region License -/* - * 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. - * 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. +/* + * 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. + * 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 @@ -60,9 +60,9 @@ namespace Spring.Aop.Framework.DynamicProxy public IAdvice[] m_introductions; /// - /// Target source wrapper + /// Target source /// - public ITargetSourceWrapper m_targetSourceWrapper; + public ITargetSource m_targetSource; /// /// Type of target object. @@ -127,7 +127,7 @@ namespace Spring.Aop.Framework.DynamicProxy { m_advised = (IAdvised)info.GetValue("advised", typeof(IAdvised)); m_introductions = (IAdvice[])info.GetValue("introductions", typeof(IAdvice[])); - m_targetSourceWrapper = (ITargetSourceWrapper)info.GetValue("tsWrapper", typeof(ITargetSourceWrapper)); + m_targetSource = (ITargetSource)info.GetValue("targetSource", typeof(ITargetSource)); m_targetType = (Type)info.GetValue("targetType", typeof(Type)); } @@ -141,7 +141,7 @@ namespace Spring.Aop.Framework.DynamicProxy { info.AddValue("advised", m_advised); info.AddValue("introductions", m_introductions); - info.AddValue("tsWrapper", m_targetSourceWrapper); + info.AddValue("targetSource", m_targetSource); info.AddValue("targetType", m_targetType); } @@ -159,18 +159,9 @@ namespace Spring.Aop.Framework.DynamicProxy protected void Initialize(IAdvised advised, IAopProxy proxy) { this.m_advised = advised; + this.m_targetSource = advised.TargetSource; this.m_targetType = advised.TargetSource.TargetType; - // initialize target - if (advised.TargetSource.IsStatic) - { - this.m_targetSourceWrapper = new StaticTargetSourceWrapper(advised.TargetSource); - } - else - { - this.m_targetSourceWrapper = new DynamicTargetSourceWrapper(advised.TargetSource); - } - // initialize introduction advice this.m_introductions = new IAdvice[advised.Introductions.Length]; for (int i = 0; i < advised.Introductions.Length; i++) diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseCompositionAopProxy.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseCompositionAopProxy.cs index f10a59d3..18fa553e 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseCompositionAopProxy.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/BaseCompositionAopProxy.cs @@ -1,88 +1,88 @@ -#region License - -/* - * Copyright © 2002-2005 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#endregion - -#region Imports - -using System; -using System.Runtime.Serialization; -using System.Security.Permissions; - -#endregion - -namespace Spring.Aop.Framework.DynamicProxy -{ - /// - /// Base class that each dynamic composition proxy has to extend. - /// - /// Aleksandar Seovic - /// Bruno Baia - [Serializable] - public abstract class BaseCompositionAopProxy : AdvisedProxy, IAopProxy, ISerializable - { - #region Constructor (s) / Destructor - - /// - /// Default constructor. - /// - public BaseCompositionAopProxy() - {} - - /// - /// Creates a new instance of the - /// class. - /// - /// The proxy configuration. - public BaseCompositionAopProxy(IAdvised advised) : base(advised) - { - base.Initialize(advised, this); - } - - /// - /// Deserialization constructor. - /// - /// Serialization data. - /// Serialization context. - protected BaseCompositionAopProxy(SerializationInfo info, StreamingContext context) : base(info, context) - {} - +#region License + +/* + * Copyright © 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +#region Imports + +using System; +using System.Runtime.Serialization; +using System.Security.Permissions; + +#endregion + +namespace Spring.Aop.Framework.DynamicProxy +{ + /// + /// Base class that each dynamic composition proxy has to extend. + /// + /// Aleksandar Seovic + /// Bruno Baia + [Serializable] + public abstract class BaseCompositionAopProxy : AdvisedProxy, IAopProxy, ISerializable + { + #region Constructor (s) / Destructor + + /// + /// Default constructor. + /// + public BaseCompositionAopProxy() + {} + + /// + /// Creates a new instance of the + /// class. + /// + /// The proxy configuration. + public BaseCompositionAopProxy(IAdvised advised) : base(advised) + { + base.Initialize(advised, this); + } + + /// + /// Deserialization constructor. + /// + /// Serialization data. + /// Serialization context. + protected BaseCompositionAopProxy(SerializationInfo info, StreamingContext context) : base(info, context) + {} + /// ///Populates a with the data needed to serialize the target object. /// - void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); - } - - #endregion - - #region IAopProxy Members - - /// - /// Returns this proxy instance - /// - /// - object IAopProxy.GetProxy() - { - return this; - } - + } + + #endregion + + #region IAopProxy Members + + /// + /// Returns this proxy instance + /// + /// + object IAopProxy.GetProxy() + { + return this; + } + #endregion #region Equal, HashCode and ToString overrides @@ -94,31 +94,36 @@ namespace Spring.Aop.Framework.DynamicProxy /// true if the specified Object is equal to the current target object; otherwise, false public override bool Equals(object obj) { + bool equals = false; + object target = m_targetSource.GetTarget(); AdvisedProxy otherProxy = obj as AdvisedProxy; + object otherTarget = null; if (otherProxy != null) { - using (m_targetSourceWrapper) - using (otherProxy.m_targetSourceWrapper) - { - object target = m_targetSourceWrapper.GetTarget(); - object otherTarget = otherProxy.m_targetSourceWrapper.GetTarget(); - if (target == null) - { - return (otherTarget == null); - } - return target.Equals(otherTarget); - } - } - - using (m_targetSourceWrapper) - { - object target = m_targetSourceWrapper.GetTarget(); + otherTarget = otherProxy.m_targetSource.GetTarget(); if (target == null) { - return (obj == null); + equals = (otherTarget == null); + } + else + { + equals = target.Equals(otherTarget); } - return target.Equals(obj); } + else if (target == null) + { + equals = (obj == null); + } + else + { + equals = target.Equals(obj); + } + m_targetSource.ReleaseTarget(target); + if (otherProxy != null) + { + otherProxy.m_targetSource.ReleaseTarget(otherTarget); + } + return equals; } /// @@ -127,15 +132,14 @@ namespace Spring.Aop.Framework.DynamicProxy /// A hash code for the target object. public override int GetHashCode() { - using (m_targetSourceWrapper) + int hashCode = 0; + object target = m_targetSource.GetTarget(); + if (target != null) { - object target = m_targetSourceWrapper.GetTarget(); - if (target != null) - { - return target.GetHashCode(); - } - return 0; + hashCode = target.GetHashCode(); } + m_targetSource.ReleaseTarget(target); + return hashCode; } /// @@ -144,17 +148,20 @@ namespace Spring.Aop.Framework.DynamicProxy /// A String that represents the target object public override string ToString() { - using (m_targetSourceWrapper) + string str; + object target = m_targetSource.GetTarget(); + if (target != null) { - object target = m_targetSourceWrapper.GetTarget(); - if (target != null) - { - return target.ToString(); - } - return base.ToString(); + str = target.ToString(); } + else + { + str = base.ToString(); + } + m_targetSource.ReleaseTarget(target); + return str; } - #endregion - } + #endregion + } } \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/TargetAopProxyMethodBuilder.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/TargetAopProxyMethodBuilder.cs index 4f32f260..67118a98 100644 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/TargetAopProxyMethodBuilder.cs +++ b/src/Spring/Spring.Aop/Aop/Framework/DynamicProxy/TargetAopProxyMethodBuilder.cs @@ -42,10 +42,9 @@ namespace Spring.Aop.Framework.DynamicProxy #region Fields /// - /// The local variable to store - /// the instance. + /// The local variable to store the target instance. /// - protected LocalBuilder targetSource; + protected LocalBuilder target; #endregion @@ -84,11 +83,21 @@ namespace Spring.Aop.Framework.DynamicProxy protected override void DeclareLocals(ILGenerator il, MethodInfo method) { base.DeclareLocals(il, method); - targetSource = il.DeclareLocal(typeof(ITargetSourceWrapper)); + target = il.DeclareLocal(typeof(object)); #if DEBUG - targetSource.SetLocalSymInfo("targetSource"); + target.SetLocalSymInfo("target"); #endif + } + + /// + /// Generates the IL instructions that pushes + /// the target instance on which calls should be delegated to. + /// + /// The IL generator to use. + protected override void PushTarget(ILGenerator il) + { + il.Emit(OpCodes.Ldloc, target); } /// @@ -101,32 +110,18 @@ namespace Spring.Aop.Framework.DynamicProxy /// protected override void GenerateMethodLogic( ILGenerator il, MethodInfo method, MethodInfo interfaceMethod) - { - Label jmpEndFinally = il.DefineLabel(); + { + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.TargetSourceField); + il.EmitCall(OpCodes.Callvirt, References.GetTargetMethod, null); + il.Emit(OpCodes.Stloc, target); - // save target source so we can call Dispose later - PushAdvisedProxy(il); - il.Emit(OpCodes.Ldfld, References.TargetSourceWrapperField); - il.Emit(OpCodes.Stloc, targetSource); - - // open try/finally block - il.BeginExceptionBlock(); - - base.GenerateMethodLogic(il, method, interfaceMethod); - - // open finally block - il.BeginFinallyBlock(); - - // call Dispose on target source - il.Emit(OpCodes.Ldloc, targetSource); - il.Emit(OpCodes.Brfalse, jmpEndFinally); - il.Emit(OpCodes.Ldloc, targetSource); - il.EmitCall(OpCodes.Callvirt, References.DisposeMethod, null); - - il.MarkLabel(jmpEndFinally); - - // close try/finally block - il.EndExceptionBlock(); + base.GenerateMethodLogic(il, method, interfaceMethod); + + PushAdvisedProxy(il); + il.Emit(OpCodes.Ldfld, References.TargetSourceField); + PushTarget(il); + il.EmitCall(OpCodes.Callvirt, References.GetReleaseTargetMethod, null); } /// diff --git a/src/Spring/Spring.Aop/Aop/Framework/DynamicTargetSourceWrapper.cs b/src/Spring/Spring.Aop/Aop/Framework/DynamicTargetSourceWrapper.cs deleted file mode 100644 index d7e191ae..00000000 --- a/src/Spring/Spring.Aop/Aop/Framework/DynamicTargetSourceWrapper.cs +++ /dev/null @@ -1,97 +0,0 @@ -#region License - -/* - * Copyright © 2002-2005 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#endregion - -#region Imports - -using System; -using Spring.Util; - -#endregion - -namespace Spring.Aop.Framework -{ - /// - /// Decorates a target source with the - /// interface. - /// - /// - ///

- /// This implementation will release the target object when said object - /// is disposed. - ///

- ///
- /// Aleksandar Seovic - [Serializable] - public sealed class DynamicTargetSourceWrapper : ITargetSourceWrapper - { - private ITargetSource targetSource; - private object target; - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The target object that proxy methods will be delegated to. - /// - /// - /// If the supplied is - /// . - /// - internal DynamicTargetSourceWrapper(ITargetSource targetSource) - { - AssertUtils.ArgumentNotNull(targetSource, "targetSource"); - this.targetSource = targetSource; - } - - /// - /// Returns the target object that proxy methods will be delegated to. - /// - /// The target object. - public object GetTarget() - { - if (this.target == null) - { - this.target = targetSource.GetTarget(); - } - - return this.target; - } - - /// - /// Releases the dynamic target when this object is disposed. - /// - public void Dispose() - { - GC.SuppressFinalize(this); - Dispose(true); - } - - private void Dispose(bool disposing) - { - if (disposing && this.target != null) - { - this.targetSource.ReleaseTarget(this.target); - this.target = null; - } - } - } -} diff --git a/src/Spring/Spring.Aop/Aop/Framework/ITargetSourceWrapper.cs b/src/Spring/Spring.Aop/Aop/Framework/ITargetSourceWrapper.cs deleted file mode 100644 index 58dceaaf..00000000 --- a/src/Spring/Spring.Aop/Aop/Framework/ITargetSourceWrapper.cs +++ /dev/null @@ -1,38 +0,0 @@ -#region License - -/* - * Copyright © 2002-2005 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#endregion - -using System; - -namespace Spring.Aop.Framework -{ - /// - /// Decorates a target source with the - /// interface. - /// - /// Aleksandar Seovic - public interface ITargetSourceWrapper : IDisposable - { - /// - /// Returns the target object that proxy methods will be delegated to. - /// - /// The target object. - object GetTarget(); - } -} \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aop/Framework/StaticTargetSourceWrapper.cs b/src/Spring/Spring.Aop/Aop/Framework/StaticTargetSourceWrapper.cs deleted file mode 100644 index 65df4d14..00000000 --- a/src/Spring/Spring.Aop/Aop/Framework/StaticTargetSourceWrapper.cs +++ /dev/null @@ -1,87 +0,0 @@ -#region License - -/* - * Copyright © 2002-2005 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#endregion - -#region Imports - -using System; -using Spring.Util; - -#endregion - -namespace Spring.Aop.Framework -{ - /// - /// Decorates a target source with the - /// interface. - /// - /// - ///

- /// Because the target source is static, the target object can be cached - /// and simply returned as is. - ///

- ///
- /// Aleksandar Seovic - [Serializable] - public sealed class StaticTargetSourceWrapper : ITargetSourceWrapper - { - private object target; - - /// - /// Creates a new instance of the - /// - /// class. - /// - /// - /// The target object that proxy methods will be delegated to. - /// - /// - /// If the supplied is - /// . - /// - internal StaticTargetSourceWrapper(ITargetSource targetSource) - { - AssertUtils.ArgumentNotNull(targetSource, "targetSource"); - this.target = targetSource.GetTarget(); - } - - /// - /// Returns the target object that proxy methods will be delegated to. - /// - /// The target object. - public object GetTarget() - { - return this.target; - } - - /// - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// - /// - /// - /// This is a no-op operation in this implementation. - /// - /// - public void Dispose() - { - // do nothing, this is static target source wrapper... - } - } -} \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Spring.Aop.2002.csproj b/src/Spring/Spring.Aop/Spring.Aop.2002.csproj index 341e1152..5b8f1249 100644 --- a/src/Spring/Spring.Aop/Spring.Aop.2002.csproj +++ b/src/Spring/Spring.Aop/Spring.Aop.2002.csproj @@ -239,11 +239,6 @@ SubType = "Code" BuildAction = "Compile" /> - - - - - - Code - - Code - Code @@ -232,7 +229,6 @@ Code - Code @@ -245,9 +241,6 @@ Code - - Code - Code diff --git a/src/Spring/Spring.Aop/Spring.Aop.2008.csproj b/src/Spring/Spring.Aop/Spring.Aop.2008.csproj index 7a8760d0..d5f642a4 100644 --- a/src/Spring/Spring.Aop/Spring.Aop.2008.csproj +++ b/src/Spring/Spring.Aop/Spring.Aop.2008.csproj @@ -216,9 +216,6 @@ Code - - Code - Code @@ -243,7 +240,6 @@ Code - Code @@ -256,9 +252,6 @@ Code - - Code - Code diff --git a/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs b/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs index ea1c3788..88caa9b6 100644 --- a/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs +++ b/src/Spring/Spring.Core/Proxy/AbstractProxyMethodBuilder.cs @@ -270,17 +270,13 @@ namespace Spring.Proxy protected virtual void CallDirectTargetMethod( ILGenerator il, MethodInfo targetMethod) { - // setup target object for call - PushTarget(il); - // TODO (EE): check for null and interface type and throw NotSupportedException - LocalBuilder targetRef = il.DeclareLocal(typeof(object)); - il.Emit(OpCodes.Stloc, targetRef); - - CallAssertUnderstands(il, targetMethod, targetRef, "target"); + // setup target instance for CallAssertUnderstands + PushTarget(il); + CallAssertUnderstands(il, targetMethod, "target"); // setup target and cast to type method is on - il.Emit(OpCodes.Ldloc, targetRef); + PushTarget(il); il.Emit(OpCodes.Castclass, targetMethod.DeclaringType); // setup parameters for call @@ -295,17 +291,18 @@ namespace Spring.Proxy } /// - /// Emits code to ensure that target understands the method and throw a sensible exception otherwise. + /// Emits code to ensure that target on stack understands the method and throw a sensible exception otherwise. /// - protected virtual void CallAssertUnderstands(ILGenerator il, MethodInfo method, LocalBuilder targetRef, string targetName) + /// The IL generator to use. + /// The method to test for + /// the name of the target to be used in error messages + protected virtual void CallAssertUnderstands(ILGenerator il, MethodInfo method, string targetName) { - // AssertArgumentType - il.Emit(OpCodes.Ldloc, targetRef); il.Emit(OpCodes.Ldstr, targetName); il.Emit(OpCodes.Ldtoken, method.DeclaringType); - il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) })); -// il.Emit(OpCodes.Ldstr, string.Format("Interface method '{0}.{1}()' was not handled by any interceptor and the target does not implement this method.", method.DeclaringType.FullName, method.Name)); - il.Emit(OpCodes.Call, typeof(AssertUtils).GetMethod("Understands", new Type[] { typeof(object), typeof(string), typeof(Type) })); + il.Emit(OpCodes.Call, References.GetTypeFromHandleMethod); + //il.Emit(OpCodes.Ldstr, string.Format("Interface method '{0}.{1}()' was not handled by any interceptor and the target does not implement this method.", method.DeclaringType.FullName, method.Name)); + il.Emit(OpCodes.Call, References.UnderstandsMethod); } /// @@ -315,17 +312,13 @@ namespace Spring.Proxy /// The method to proxy. protected virtual void CallDirectBaseMethod(ILGenerator il, MethodInfo method) { - // setup proxy instance for call - PushProxy(il); - // TODO (EE): check for null and interface type and throw NotSupportedException - LocalBuilder targetRef = il.DeclareLocal(typeof(object)); - il.Emit(OpCodes.Stloc, targetRef); + // setup proxy instance for CallAssertUnderstands + PushProxy(il); + CallAssertUnderstands(il, method, "base"); - CallAssertUnderstands(il, method, targetRef, "base"); - - // setup target and cast to type method is on - il.Emit(OpCodes.Ldloc, targetRef); + // setup proxy and cast to type method is on + PushProxy(il); il.Emit(OpCodes.Castclass, method.DeclaringType); // setup parameters for call @@ -389,4 +382,18 @@ namespace Spring.Proxy #endregion } + + #region References helper class definition + + internal struct References + { + // methods + public static readonly MethodInfo GetTypeFromHandleMethod = + typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }); + + public static readonly MethodInfo UnderstandsMethod = + typeof(AssertUtils).GetMethod("Understands", new Type[] { typeof(object), typeof(string), typeof(Type) }); + } + + #endregion } diff --git a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs index edc4f7b6..4fdc503d 100644 --- a/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs +++ b/src/Spring/Spring.Services/EnterpriseServices/ServicedComponentExporter.cs @@ -233,7 +233,7 @@ namespace Spring.EnterpriseServices /// /// Suppress output to avoid Spring.Core dependency /// - protected override void CallAssertUnderstands(ILGenerator il, MethodInfo method, LocalBuilder targetRef, string targetName) + protected override void CallAssertUnderstands(ILGenerator il, MethodInfo method, string targetName) { // base.CallAssertUnderstands(il, method, targetRef, targetName); } 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 8786ca3c..1dd9e4b7 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Framework/DynamicProxy/AbstractAopProxyTests.cs @@ -847,8 +847,6 @@ namespace Spring.Aop.Framework.DynamicProxy CreateProxy(advised) as AbstractProxyTypeBuilderTests.InterfaceWithGenericMethod; Assert.IsNotNull(proxy); - DynamicProxyManager.SaveAssembly(); - proxy.PolymorphicMethod(); proxy.PolymorphicMethod(); @@ -870,6 +868,11 @@ namespace Spring.Aop.Framework.DynamicProxy proxy.WithMixedConstraint(); Assert.AreEqual(10, ni.Count); + + //if (this is DecoratorAopProxyTests) + //{ + // DynamicProxyManager.SaveAssembly(); + //} } [Test] diff --git a/test/Spring/Spring.Aop.Tests/Aop/Target/ThreadLocalTargetSourceTests.cs b/test/Spring/Spring.Aop.Tests/Aop/Target/ThreadLocalTargetSourceTests.cs index ea5fe734..83a0851c 100644 --- a/test/Spring/Spring.Aop.Tests/Aop/Target/ThreadLocalTargetSourceTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aop/Target/ThreadLocalTargetSourceTests.cs @@ -17,6 +17,7 @@ using System; using System.IO; using System.Reflection; using System.Threading; +using System.Collections; using Common.Logging; using NUnit.Framework; using Spring.Objects; @@ -42,7 +43,6 @@ namespace Spring.Aop.Target { this.ObjectFactory = new XmlObjectFactory ( new ReadOnlyXmlTestResource ("threadLocalTests.xml", GetType ())); - //TODO-LOGGING XmlConfigurator.Configure (new FileInfo ("Spring.Aop.Tests.dll.config")); log = LogManager.GetLogger (MethodBase.GetCurrentMethod ().DeclaringType); } @@ -152,5 +152,79 @@ namespace Spring.Aop.Target // Bound to two threads Assert.AreEqual (2, ((IThreadLocalTargetSourceStats) apartment).Objects); } + + private static bool multiThreadedTestFailed = false; + + [Test] + public virtual void MultiThreadedTest() + { + multiThreadedTestFailed = false; + + this.ObjectFactory = new XmlObjectFactory( + new ReadOnlyXmlTestResource("threadLocalTests.xml", GetType())); + log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // Initialize property. + IMultiThreadInterface mtObject = (IMultiThreadInterface)ObjectFactory.GetObject("mtTest"); + + // Start threads. + ArrayList threads = new ArrayList(); + for (int i = 0; i < 100; i++) + { + Thread thread = new Thread(new ParameterizedThreadStart(CheckName)); + threads.Add(thread); + thread.Start(mtObject); + } + + // Wait for threads to end. + foreach (Thread thread in threads) + { + thread.Join(); + } + + Assert.IsFalse(multiThreadedTestFailed); + } + + private void CheckName(object mtObject) + { + string name = ((IMultiThreadInterface)mtObject).GenerateAndSetName(100); + + // Returned name should be equal to property. + if (!name.Equals(((IMultiThreadInterface)mtObject).Name)) + { + multiThreadedTestFailed = true; + } + //Console.WriteLine(String.Format("Expected: {0}; Actual: {1}", + // name, ((IMultiThreadInterface)mtObject).Name)); + } + + #region Helper classes + + public interface IMultiThreadInterface + { + string Name { get; } + string GenerateAndSetName(int sleep); + } + + public class MultiThreadClass : IMultiThreadInterface + { + private string _name; + + public string Name + { + get { return _name; } + } + + public string GenerateAndSetName(int sleep) + { + string generated = "Thread_" + Thread.CurrentThread.ManagedThreadId; + _name = generated; + + Thread.Sleep(sleep); + return generated; + } + } + + #endregion } } \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/threadLocalTests.xml b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/threadLocalTests.xml index 3629123b..ff1e1147 100644 --- a/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/threadLocalTests.xml +++ b/test/Spring/Spring.Aop.Tests/Data/Spring/Aop/Target/threadLocalTests.xml @@ -69,4 +69,13 @@ + + + + + + + + +