A target retrieved from a dynamic target source, is not entirely thread safe, e.g.ThreadLocalTargetSource [SPRNET-1289]

This commit is contained in:
bbaia
2010-04-12 14:40:40 +00:00
parent e3d54e2695
commit f9b55fb84e
17 changed files with 1077 additions and 1254 deletions

View File

@@ -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);
}

View File

@@ -1,19 +1,19 @@
#region License
/*
* Copyright <20> 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 <20> 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;
/// <summary>
/// Target source wrapper
/// Target source
/// </summary>
public ITargetSourceWrapper m_targetSourceWrapper;
public ITargetSource m_targetSource;
/// <summary>
/// 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++)

View File

@@ -1,88 +1,88 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Base class that each dynamic composition proxy has to extend.
/// </summary>
/// <author>Aleksandar Seovic</author>
/// <author>Bruno Baia</author>
[Serializable]
public abstract class BaseCompositionAopProxy : AdvisedProxy, IAopProxy, ISerializable
{
#region Constructor (s) / Destructor
/// <summary>
/// Default constructor.
/// </summary>
public BaseCompositionAopProxy()
{}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Aop.Framework.DynamicProxy.BaseCompositionAopProxy"/> class.
/// </summary>
/// <param name="advised">The proxy configuration.</param>
public BaseCompositionAopProxy(IAdvised advised) : base(advised)
{
base.Initialize(advised, this);
}
/// <summary>
/// Deserialization constructor.
/// </summary>
/// <param name="info">Serialization data.</param>
/// <param name="context">Serialization context.</param>
protected BaseCompositionAopProxy(SerializationInfo info, StreamingContext context) : base(info, context)
{}
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Base class that each dynamic composition proxy has to extend.
/// </summary>
/// <author>Aleksandar Seovic</author>
/// <author>Bruno Baia</author>
[Serializable]
public abstract class BaseCompositionAopProxy : AdvisedProxy, IAopProxy, ISerializable
{
#region Constructor (s) / Destructor
/// <summary>
/// Default constructor.
/// </summary>
public BaseCompositionAopProxy()
{}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Aop.Framework.DynamicProxy.BaseCompositionAopProxy"/> class.
/// </summary>
/// <param name="advised">The proxy configuration.</param>
public BaseCompositionAopProxy(IAdvised advised) : base(advised)
{
base.Initialize(advised, this);
}
/// <summary>
/// Deserialization constructor.
/// </summary>
/// <param name="info">Serialization data.</param>
/// <param name="context">Serialization context.</param>
protected BaseCompositionAopProxy(SerializationInfo info, StreamingContext context) : base(info, context)
{}
///<summary>
///Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"></see> with the data needed to serialize the target object.
///</summary>
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
}
#endregion
#region IAopProxy Members
/// <summary>
/// Returns this proxy instance
/// </summary>
/// <returns></returns>
object IAopProxy.GetProxy()
{
return this;
}
}
#endregion
#region IAopProxy Members
/// <summary>
/// Returns this proxy instance
/// </summary>
/// <returns></returns>
object IAopProxy.GetProxy()
{
return this;
}
#endregion
#region Equal, HashCode and ToString overrides
@@ -94,31 +94,36 @@ namespace Spring.Aop.Framework.DynamicProxy
/// <returns>true if the specified Object is equal to the current target object; otherwise, false</returns>
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;
}
/// <summary>
@@ -127,15 +132,14 @@ namespace Spring.Aop.Framework.DynamicProxy
/// <returns>A hash code for the target object.</returns>
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;
}
/// <summary>
@@ -144,17 +148,20 @@ namespace Spring.Aop.Framework.DynamicProxy
/// <returns>A String that represents the target object</returns>
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
}
}

View File

@@ -42,10 +42,9 @@ namespace Spring.Aop.Framework.DynamicProxy
#region Fields
/// <summary>
/// The local variable to store
/// the <see cref="Spring.Aop.Framework.ITargetSourceWrapper"/> instance.
/// The local variable to store the target instance.
/// </summary>
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
}
/// <summary>
/// Generates the IL instructions that pushes
/// the target instance on which calls should be delegated to.
/// </summary>
/// <param name="il">The IL generator to use.</param>
protected override void PushTarget(ILGenerator il)
{
il.Emit(OpCodes.Ldloc, target);
}
/// <summary>
@@ -101,32 +110,18 @@ namespace Spring.Aop.Framework.DynamicProxy
/// </param>
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);
}
/// <summary>

View File

@@ -1,97 +0,0 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Decorates a target source with the <see cref="System.IDisposable"/>
/// interface.
/// </summary>
/// <remarks>
/// <p>
/// This implementation will release the target object when said object
/// is disposed.
/// </p>
/// </remarks>
/// <author>Aleksandar Seovic</author>
[Serializable]
public sealed class DynamicTargetSourceWrapper : ITargetSourceWrapper
{
private ITargetSource targetSource;
private object target;
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Aop.Framework.DynamicTargetSourceWrapper"/>
/// class.
/// </summary>
/// <param name="targetSource">
/// The target object that proxy methods will be delegated to.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="targetSource"/> is
/// <see langword="null"/>.
/// </exception>
internal DynamicTargetSourceWrapper(ITargetSource targetSource)
{
AssertUtils.ArgumentNotNull(targetSource, "targetSource");
this.targetSource = targetSource;
}
/// <summary>
/// Returns the target object that proxy methods will be delegated to.
/// </summary>
/// <returns>The target object.</returns>
public object GetTarget()
{
if (this.target == null)
{
this.target = targetSource.GetTarget();
}
return this.target;
}
/// <summary>
/// Releases the dynamic target when this object is disposed.
/// </summary>
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;
}
}
}
}

View File

@@ -1,38 +0,0 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Decorates a target source with the <see cref="System.IDisposable"/>
/// interface.
/// </summary>
/// <author>Aleksandar Seovic</author>
public interface ITargetSourceWrapper : IDisposable
{
/// <summary>
/// Returns the target object that proxy methods will be delegated to.
/// </summary>
/// <returns>The target object.</returns>
object GetTarget();
}
}

View File

@@ -1,87 +0,0 @@
#region License
/*
* Copyright <20> 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
{
/// <summary>
/// Decorates a target source with the <see cref="System.IDisposable"/>
/// interface.
/// </summary>
/// <remarks>
/// <p>
/// Because the target source is static, the target object can be cached
/// and simply returned as is.
/// </p>
/// </remarks>
/// <author>Aleksandar Seovic</author>
[Serializable]
public sealed class StaticTargetSourceWrapper : ITargetSourceWrapper
{
private object target;
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Aop.Framework.StaticTargetSourceWrapper"/>
/// class.
/// </summary>
/// <param name="targetSource">
/// The target object that proxy methods will be delegated to.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="targetSource"/> is
/// <see langword="null"/>.
/// </exception>
internal StaticTargetSourceWrapper(ITargetSource targetSource)
{
AssertUtils.ArgumentNotNull(targetSource, "targetSource");
this.target = targetSource.GetTarget();
}
/// <summary>
/// Returns the target object that proxy methods will be delegated to.
/// </summary>
/// <returns>The target object.</returns>
public object GetTarget()
{
return this.target;
}
/// <summary>
/// Performs application-defined tasks associated with freeing,
/// releasing, or resetting unmanaged resources.
/// </summary>
/// <remarks>
/// <note type="implementnotes">
/// This is a no-op operation in this implementation.
/// </note>
/// </remarks>
public void Dispose()
{
// do nothing, this is static target source wrapper...
}
}
}

View File

@@ -239,11 +239,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\DynamicTargetSourceWrapper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\HashtableCachingAdvisorChainFactory.cs"
SubType = "Code"
@@ -284,11 +279,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\ITargetSourceWrapper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\ProxyConfig.cs"
SubType = "Code"
@@ -309,11 +299,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\StaticTargetSourceWrapper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\Adapter\AdvisorAdapterRegistrationManager.cs"
SubType = "Code"

View File

@@ -241,11 +241,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\DynamicTargetSourceWrapper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\HashtableCachingAdvisorChainFactory.cs"
SubType = "Code"
@@ -286,11 +281,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\ITargetSourceWrapper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\ProxyConfig.cs"
SubType = "Code"
@@ -311,11 +301,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\StaticTargetSourceWrapper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Aop\Framework\Adapter\AdvisorAdapterRegistrationManager.cs"
SubType = "Code"

View File

@@ -205,9 +205,6 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\Framework\DynamicProxy\TargetAopProxyMethodBuilder.cs" />
<Compile Include="Aop\Framework\DynamicTargetSourceWrapper.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\Framework\HashtableCachingAdvisorChainFactory.cs">
<SubType>Code</SubType>
</Compile>
@@ -232,7 +229,6 @@
<Compile Include="Aop\Framework\ITargetAware.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\Framework\ITargetSourceWrapper.cs" />
<Compile Include="Aop\Framework\ProxyConfig.cs">
<SubType>Code</SubType>
</Compile>
@@ -245,9 +241,6 @@
<Compile Include="Aop\Framework\ReflectiveMethodInvocation.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\Framework\StaticTargetSourceWrapper.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\IAdvisor.cs">
<SubType>Code</SubType>
</Compile>

View File

@@ -216,9 +216,6 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\Framework\DynamicProxy\TargetAopProxyMethodBuilder.cs" />
<Compile Include="Aop\Framework\DynamicTargetSourceWrapper.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\Framework\HashtableCachingAdvisorChainFactory.cs">
<SubType>Code</SubType>
</Compile>
@@ -243,7 +240,6 @@
<Compile Include="Aop\Framework\ITargetAware.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\Framework\ITargetSourceWrapper.cs" />
<Compile Include="Aop\Framework\ProxyConfig.cs">
<SubType>Code</SubType>
</Compile>
@@ -256,9 +252,6 @@
<Compile Include="Aop\Framework\ReflectiveMethodInvocation.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\Framework\StaticTargetSourceWrapper.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Aop\IAdvisor.cs">
<SubType>Code</SubType>
</Compile>

View File

@@ -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
}
/// <summary>
/// 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.
/// </summary>
protected virtual void CallAssertUnderstands(ILGenerator il, MethodInfo method, LocalBuilder targetRef, string targetName)
/// <param name="il">The IL generator to use.</param>
/// <param name="method">The method to test for</param>
/// <param name="targetName">the name of the target to be used in error messages</param>
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);
}
/// <summary>
@@ -315,17 +312,13 @@ namespace Spring.Proxy
/// <param name="method">The method to proxy.</param>
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
}

View File

@@ -233,7 +233,7 @@ namespace Spring.EnterpriseServices
/// <summary>
/// Suppress output to avoid Spring.Core dependency
/// </summary>
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);
}

View File

@@ -847,8 +847,6 @@ namespace Spring.Aop.Framework.DynamicProxy
CreateProxy(advised) as AbstractProxyTypeBuilderTests.InterfaceWithGenericMethod;
Assert.IsNotNull(proxy);
DynamicProxyManager.SaveAssembly();
proxy.PolymorphicMethod<int>();
proxy.PolymorphicMethod<string>();
@@ -870,6 +868,11 @@ namespace Spring.Aop.Framework.DynamicProxy
proxy.WithMixedConstraint<bool, DerivedTestObject>();
Assert.AreEqual(10, ni.Count);
//if (this is DecoratorAopProxyTests)
//{
// DynamicProxyManager.SaveAssembly();
//}
}
[Test]

View File

@@ -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
}
}

View File

@@ -69,4 +69,13 @@
<ref local="threadLocalTs2" />
</property>
</object>
<object id="mtPrototype" type="Spring.Aop.Target.ThreadLocalTargetSourceTests+MultiThreadClass" singleton="false" />
<object id="mtTest" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="targetSource">
<object type="Spring.Aop.Target.ThreadLocalTargetSource">
<property name="targetObjectName" value="mtPrototype" />
</object>
</property>
</object>
</objects>