fixed SPRNET-1259
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
using Common.Logging;
|
||||
using Spring.Caching;
|
||||
using Spring.Context;
|
||||
using Spring.Expressions;
|
||||
@@ -37,10 +37,23 @@ namespace Spring.Aspects.Cache
|
||||
/// access to common functionality, such as obtaining a cache instance.
|
||||
/// </summary>
|
||||
/// <author>Aleksandar Seovic</author>
|
||||
public class BaseCacheAdvice : IApplicationContextAware
|
||||
public abstract class BaseCacheAdvice : IApplicationContextAware
|
||||
{
|
||||
/// <summary>
|
||||
/// Shared logger instance
|
||||
/// </summary>
|
||||
protected readonly ILog logger;
|
||||
|
||||
private IApplicationContext applicationContext;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new default instance.
|
||||
/// </summary>
|
||||
protected BaseCacheAdvice()
|
||||
{
|
||||
logger = LogManager.GetLogger(this.GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="Spring.Context.IApplicationContext"/> that this
|
||||
/// object runs in.
|
||||
@@ -138,8 +151,8 @@ namespace Spring.Aspects.Cache
|
||||
/// <summary>
|
||||
/// Retrieves custom attribute for the specified attribute type.
|
||||
/// </summary>
|
||||
/// <param name="method">
|
||||
/// Method to get attribute from.
|
||||
/// <param name="attributeProvider">
|
||||
/// Method/Parameter to get attribute from.
|
||||
/// </param>
|
||||
/// <param name="attributeType">
|
||||
/// Attribute type.
|
||||
@@ -147,14 +160,32 @@ namespace Spring.Aspects.Cache
|
||||
/// <returns>
|
||||
/// Attribute instance if one is found, <c>null</c> otherwise.
|
||||
/// </returns>
|
||||
protected static object GetCustomAttribute(MethodInfo method, Type attributeType)
|
||||
protected object GetCustomAttribute(ICustomAttributeProvider attributeProvider, Type attributeType)
|
||||
{
|
||||
object[] attributes = method.GetCustomAttributes(attributeType, false);
|
||||
object[] attributes = attributeProvider.GetCustomAttributes(attributeType, false);
|
||||
if (attributes.Length > 0)
|
||||
{
|
||||
return attributes[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves custom attribute for the specified attribute type.
|
||||
/// </summary>
|
||||
/// <param name="attributeProvider">
|
||||
/// Method/Parameter to get attribute from.
|
||||
/// </param>
|
||||
/// <param name="attributeType">
|
||||
/// Attribute type.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Attribute instance if one is found, <c>null</c> otherwise.
|
||||
/// </returns>
|
||||
protected object[] GetCustomAttributes(ICustomAttributeProvider attributeProvider, Type attributeType)
|
||||
{
|
||||
object[] attributes = attributeProvider.GetCustomAttributes(attributeType, false);
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#region Imports
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using Common.Logging;
|
||||
using Spring.Aop;
|
||||
@@ -52,8 +54,19 @@ namespace Spring.Aspects.Cache
|
||||
/// <author>Aleksandar Seovic</author>
|
||||
public class CacheParameterAdvice : BaseCacheAdvice, IAfterReturningAdvice
|
||||
{
|
||||
// shared logger instance
|
||||
private static readonly ILog logger = LogManager.GetLogger(typeof(CacheParameterAdvice));
|
||||
private class CacheParameterInfo
|
||||
{
|
||||
public readonly ParameterInfo[] Parameters;
|
||||
public readonly CacheParameterAttribute[][] CacheParameterAttributes;
|
||||
|
||||
public CacheParameterInfo(ParameterInfo[] parameters, CacheParameterAttribute[][] cacheParameterAttributes)
|
||||
{
|
||||
Parameters = parameters;
|
||||
CacheParameterAttributes = cacheParameterAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Hashtable _cacheParameterInfoCache = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// Executes after target <paramref name="method"/>
|
||||
@@ -78,35 +91,54 @@ namespace Spring.Aspects.Cache
|
||||
/// <seealso cref="AopAlliance.Intercept.IMethodInterceptor.Invoke"/>
|
||||
public void AfterReturning(object returnValue, MethodInfo method, object[] arguments, object target)
|
||||
{
|
||||
ParameterInfo[] parameters = method.GetParameters();
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
bool isLogDebugEnabled = logger.IsDebugEnabled;
|
||||
|
||||
CacheParameterInfo cpi = GetCacheParameterInfo(method);
|
||||
CacheParameterAttribute[][] cacheParameterAttributes = cpi.CacheParameterAttributes;
|
||||
|
||||
for (int i = 0; i < cacheParameterAttributes.Length; i++)
|
||||
{
|
||||
ParameterInfo p = parameters[i];
|
||||
CacheParameterAttribute[] paramInfoArray =
|
||||
(CacheParameterAttribute[])p.GetCustomAttributes(typeof(CacheParameterAttribute), false);
|
||||
|
||||
bool isLogDebugEnabled = logger.IsDebugEnabled;
|
||||
foreach (CacheParameterAttribute paramInfo in paramInfoArray)
|
||||
foreach (CacheParameterAttribute paramInfo in cacheParameterAttributes[i])
|
||||
{
|
||||
if (EvalCondition(paramInfo.Condition, paramInfo.ConditionExpression, arguments[i], null))
|
||||
{
|
||||
ICache cache = GetCache(paramInfo.CacheName);
|
||||
AssertUtils.ArgumentNotNull(cache, "CacheName",
|
||||
"Parameter cache with the specified name [" + paramInfo.CacheName +
|
||||
"] does not exist.");
|
||||
if (cache == null)
|
||||
{
|
||||
throw new ArgumentNullException("CacheName", string.Format("Parameter cache with the specified name [{0}] does not exist.", paramInfo.CacheName));
|
||||
}
|
||||
object key = paramInfo.KeyExpression.GetValue(arguments[i]);
|
||||
#region Instrumentation
|
||||
|
||||
#region Instrumentation
|
||||
if (isLogDebugEnabled)
|
||||
{
|
||||
logger.Debug("Caching parameter for key [" + key + "].");
|
||||
logger.Debug(string.Format("Caching parameter for key [{0}].", key));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
cache.Insert(key, arguments[i], paramInfo.TimeToLiveTimeSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CacheParameterInfo GetCacheParameterInfo(MethodInfo method)
|
||||
{
|
||||
CacheParameterInfo cpi = (CacheParameterInfo) _cacheParameterInfoCache[method];
|
||||
if (cpi == null)
|
||||
{
|
||||
ParameterInfo[] parameters = method.GetParameters();
|
||||
CacheParameterAttribute[][] parameterInfos = new CacheParameterAttribute[parameters.Length][];
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
ParameterInfo p = parameters[i];
|
||||
CacheParameterAttribute[] paramInfoArray = (CacheParameterAttribute[])GetCustomAttributes(p, typeof(CacheParameterAttribute));
|
||||
parameterInfos[i] = paramInfoArray;
|
||||
}
|
||||
cpi = new CacheParameterInfo(parameters, parameterInfos);
|
||||
_cacheParameterInfoCache[method] = cpi;
|
||||
}
|
||||
return cpi;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#region License
|
||||
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2006 the original author or authors.
|
||||
*
|
||||
@@ -14,213 +14,236 @@
|
||||
* 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.Collections;
|
||||
using System.Reflection;
|
||||
using AopAlliance.Intercept;
|
||||
using Common.Logging;
|
||||
using Spring.Caching;
|
||||
using Spring.Expressions;
|
||||
using Spring.Util;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Aspects.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of a result caching advice.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// This advice can be used to cache the return value of the method.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// Parameters that determine where, how and for how long the return value
|
||||
/// will be cached are retrieved from the <see cref="CacheResultAttribute"/> and/or
|
||||
/// <see cref="CacheResultItemsAttribute"/> that are defined on the pointcut.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <seealso cref="CacheResultAttribute"/>
|
||||
/// <seealso cref="CacheResultItemsAttribute"/>
|
||||
/// <author>Aleksandar Seovic</author>
|
||||
public class CacheResultAdvice : BaseCacheAdvice, IMethodInterceptor
|
||||
{
|
||||
// shared logger instance
|
||||
private static readonly ILog logger = LogManager.GetLogger(typeof (CacheResultAdvice));
|
||||
|
||||
// NullValue
|
||||
private static readonly object NullValue = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Applies caching around a method invocation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// This method tries to retrieve an object from the cache, using the supplied
|
||||
/// <paramref name="invocation"/> to generate a cache key. If an object is found
|
||||
/// in the cache, the cached value is returned and the method call does not
|
||||
/// proceed any further down the invocation chain.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// If object does not exist in the cache, the advised method is called (using
|
||||
/// <see cref="AopAlliance.Intercept.IJoinpoint.Proceed()"/>)
|
||||
/// and any return value is cached for the next method invocation.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <param name="invocation">
|
||||
/// The method invocation that is being intercepted.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A cached object or the result of the
|
||||
/// <see cref="AopAlliance.Intercept.IJoinpoint.Proceed()"/> call.
|
||||
/// </returns>
|
||||
/// <exception cref="System.Exception">
|
||||
/// If any of the interceptors in the chain or the target object itself
|
||||
/// throws an exception.
|
||||
/// </exception>
|
||||
public object Invoke(IMethodInvocation invocation)
|
||||
{
|
||||
CacheResultAttribute resultInfo =
|
||||
(CacheResultAttribute) GetCustomAttribute(invocation.Method, typeof (CacheResultAttribute));
|
||||
CacheResultItemsAttribute[] itemInfoArray =
|
||||
(CacheResultItemsAttribute[])invocation.Method.GetCustomAttributes(typeof(CacheResultItemsAttribute), false);
|
||||
|
||||
bool cacheHit = false;
|
||||
object returnValue = GetReturnValue(invocation, resultInfo, out cacheHit);
|
||||
|
||||
if (!cacheHit && itemInfoArray.Length > 0 && returnValue is IEnumerable)
|
||||
{
|
||||
CacheResultItems((IEnumerable)returnValue, itemInfoArray);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains return value either from cache or by invoking target method
|
||||
/// and caches it if necessary.
|
||||
/// </summary>
|
||||
/// <param name="invocation">
|
||||
/// The method invocation that is being intercepted.
|
||||
/// </param>
|
||||
/// <param name="resultInfo">
|
||||
/// Attribute specifying where and how to cache return value. Can be <c>null</c>,
|
||||
/// in which case no caching of the result as a whole will be performed
|
||||
/// (if the result is collection, individual items could still be cached separately).
|
||||
/// </param>
|
||||
/// <param name="cacheHit">
|
||||
/// Returns <c>true</c> if the return value was found in cache, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Return value for the specified <paramref name="invocation"/>.
|
||||
/// </returns>
|
||||
private object GetReturnValue(IMethodInvocation invocation, CacheResultAttribute resultInfo, out bool cacheHit)
|
||||
{
|
||||
if (resultInfo != null)
|
||||
{
|
||||
object returnValue = null;
|
||||
bool isLogDebugEnabled = logger.IsDebugEnabled;
|
||||
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region Imports
|
||||
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using AopAlliance.Intercept;
|
||||
using Common.Logging;
|
||||
using Spring.Caching;
|
||||
using Spring.Expressions;
|
||||
using Spring.Util;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Spring.Aspects.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of a result caching advice.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// This advice can be used to cache the return value of the method.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// Parameters that determine where, how and for how long the return value
|
||||
/// will be cached are retrieved from the <see cref="CacheResultAttribute"/> and/or
|
||||
/// <see cref="CacheResultItemsAttribute"/> that are defined on the pointcut.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <seealso cref="CacheResultAttribute"/>
|
||||
/// <seealso cref="CacheResultItemsAttribute"/>
|
||||
/// <author>Aleksandar Seovic</author>
|
||||
public class CacheResultAdvice : BaseCacheAdvice, IMethodInterceptor
|
||||
{
|
||||
// NullValue
|
||||
private static readonly object NullValue = new object();
|
||||
|
||||
private class CacheResultInfo
|
||||
{
|
||||
public readonly CacheResultAttribute ResultInfo;
|
||||
public readonly CacheResultItemsAttribute[] ItemInfoArray;
|
||||
|
||||
public CacheResultInfo(CacheResultAttribute resultInfo, CacheResultItemsAttribute[] itemInfoArray)
|
||||
{
|
||||
ResultInfo = resultInfo;
|
||||
ItemInfoArray = itemInfoArray;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Hashtable _cacheResultAttributeCache = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// Applies caching around a method invocation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// This method tries to retrieve an object from the cache, using the supplied
|
||||
/// <paramref name="invocation"/> to generate a cache key. If an object is found
|
||||
/// in the cache, the cached value is returned and the method call does not
|
||||
/// proceed any further down the invocation chain.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// If object does not exist in the cache, the advised method is called (using
|
||||
/// <see cref="AopAlliance.Intercept.IJoinpoint.Proceed()"/>)
|
||||
/// and any return value is cached for the next method invocation.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
/// <param name="invocation">
|
||||
/// The method invocation that is being intercepted.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A cached object or the result of the
|
||||
/// <see cref="AopAlliance.Intercept.IJoinpoint.Proceed()"/> call.
|
||||
/// </returns>
|
||||
/// <exception cref="System.Exception">
|
||||
/// If any of the interceptors in the chain or the target object itself
|
||||
/// throws an exception.
|
||||
/// </exception>
|
||||
public object Invoke(IMethodInvocation invocation)
|
||||
{
|
||||
CacheResultInfo cacheResultInfo = GetCacheResultInfo(invocation.Method);
|
||||
|
||||
bool cacheHit = false;
|
||||
object returnValue = GetReturnValue(invocation, cacheResultInfo.ResultInfo, out cacheHit);
|
||||
|
||||
if (!cacheHit && cacheResultInfo.ItemInfoArray.Length > 0 && returnValue is IEnumerable)
|
||||
{
|
||||
CacheResultItems((IEnumerable)returnValue, cacheResultInfo.ItemInfoArray);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains return value either from cache or by invoking target method
|
||||
/// and caches it if necessary.
|
||||
/// </summary>
|
||||
/// <param name="invocation">
|
||||
/// The method invocation that is being intercepted.
|
||||
/// </param>
|
||||
/// <param name="resultInfo">
|
||||
/// Attribute specifying where and how to cache return value. Can be <c>null</c>,
|
||||
/// in which case no caching of the result as a whole will be performed
|
||||
/// (if the result is collection, individual items could still be cached separately).
|
||||
/// </param>
|
||||
/// <param name="cacheHit">
|
||||
/// Returns <c>true</c> if the return value was found in cache, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Return value for the specified <paramref name="invocation"/>.
|
||||
/// </returns>
|
||||
private object GetReturnValue(IMethodInvocation invocation, CacheResultAttribute resultInfo, out bool cacheHit)
|
||||
{
|
||||
if (resultInfo != null)
|
||||
{
|
||||
object returnValue = null;
|
||||
bool isLogDebugEnabled = logger.IsDebugEnabled;
|
||||
|
||||
IDictionary vars = PrepareVariables(invocation.Method, invocation.Arguments);
|
||||
|
||||
AssertUtils.ArgumentNotNull(resultInfo.KeyExpression, "KeyExpression",
|
||||
"The cache attribute is missing the key definition.");
|
||||
object resultKey = resultInfo.KeyExpression.GetValue(null, vars);
|
||||
ICache cache = GetCache(resultInfo.CacheName);
|
||||
AssertUtils.ArgumentNotNull(cache, "CacheName",
|
||||
"Result cache with the specified name [" + resultInfo.CacheName +
|
||||
"] does not exist.");
|
||||
|
||||
returnValue = cache.Get(resultKey);
|
||||
cacheHit = (returnValue != null);
|
||||
if (!cacheHit)
|
||||
{
|
||||
#region Instrumentation
|
||||
|
||||
if (isLogDebugEnabled)
|
||||
{
|
||||
logger.Debug("Object for key [" + resultKey + "] was not found in cache. Proceeding...");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
returnValue = invocation.Proceed();
|
||||
if (EvalCondition(resultInfo.Condition, resultInfo.ConditionExpression, returnValue, vars))
|
||||
{
|
||||
#region Instrumentation
|
||||
|
||||
if (isLogDebugEnabled)
|
||||
{
|
||||
logger.Debug("Caching object for key [" + resultKey + "].");
|
||||
}
|
||||
|
||||
#endregion
|
||||
cache.Insert(resultKey, (returnValue==null)?NullValue:returnValue, resultInfo.TimeToLiveTimeSpan);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Instrumentation
|
||||
|
||||
if (isLogDebugEnabled)
|
||||
{
|
||||
logger.Debug("Cache hit for [" + resultKey + "]. Aborting invocation...");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
return (returnValue==NullValue)?null:returnValue;
|
||||
}
|
||||
|
||||
cacheHit = false;
|
||||
return invocation.Proceed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches each item from the collection returned by target method.
|
||||
/// </summary>
|
||||
/// <param name="items">
|
||||
/// A collection of items to cache.
|
||||
/// </param>
|
||||
/// <param name="itemInfoArray">
|
||||
/// Attributes specifying where and how to cache each item from the collection.
|
||||
/// </param>
|
||||
private void CacheResultItems(IEnumerable items, CacheResultItemsAttribute[] itemInfoArray)
|
||||
{
|
||||
foreach (CacheResultItemsAttribute itemInfo in itemInfoArray)
|
||||
{
|
||||
ICache cache = GetCache(itemInfo.CacheName);
|
||||
AssertUtils.ArgumentNotNull(cache, "CacheName",
|
||||
"Result item cache with the specified name [" + itemInfo.CacheName +
|
||||
"The cache attribute is missing the key definition.");
|
||||
object resultKey = resultInfo.KeyExpression.GetValue(null, vars);
|
||||
ICache cache = GetCache(resultInfo.CacheName);
|
||||
AssertUtils.ArgumentNotNull(cache, "CacheName",
|
||||
"Result cache with the specified name [" + resultInfo.CacheName +
|
||||
"] does not exist.");
|
||||
|
||||
returnValue = cache.Get(resultKey);
|
||||
cacheHit = (returnValue != null);
|
||||
if (!cacheHit)
|
||||
{
|
||||
#region Instrumentation
|
||||
|
||||
if (isLogDebugEnabled)
|
||||
{
|
||||
logger.Debug("Object for key [" + resultKey + "] was not found in cache. Proceeding...");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
returnValue = invocation.Proceed();
|
||||
if (EvalCondition(resultInfo.Condition, resultInfo.ConditionExpression, returnValue, vars))
|
||||
{
|
||||
#region Instrumentation
|
||||
|
||||
if (isLogDebugEnabled)
|
||||
{
|
||||
logger.Debug("Caching object for key [" + resultKey + "].");
|
||||
}
|
||||
|
||||
#endregion
|
||||
cache.Insert(resultKey, (returnValue == null) ? NullValue : returnValue, resultInfo.TimeToLiveTimeSpan);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#region Instrumentation
|
||||
|
||||
if (isLogDebugEnabled)
|
||||
{
|
||||
logger.Debug("Cache hit for [" + resultKey + "]. Aborting invocation...");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
return (returnValue == NullValue) ? null : returnValue;
|
||||
}
|
||||
|
||||
cacheHit = false;
|
||||
return invocation.Proceed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches each item from the collection returned by target method.
|
||||
/// </summary>
|
||||
/// <param name="items">
|
||||
/// A collection of items to cache.
|
||||
/// </param>
|
||||
/// <param name="itemInfoArray">
|
||||
/// Attributes specifying where and how to cache each item from the collection.
|
||||
/// </param>
|
||||
private void CacheResultItems(IEnumerable items, CacheResultItemsAttribute[] itemInfoArray)
|
||||
{
|
||||
foreach (CacheResultItemsAttribute itemInfo in itemInfoArray)
|
||||
{
|
||||
ICache cache = GetCache(itemInfo.CacheName);
|
||||
AssertUtils.ArgumentNotNull(cache, "CacheName",
|
||||
"Result item cache with the specified name [" + itemInfo.CacheName +
|
||||
"] does not exist.");
|
||||
|
||||
AssertUtils.ArgumentNotNull(itemInfo.KeyExpression, "KeyExpression",
|
||||
"The cache attribute is missing the key definition.");
|
||||
|
||||
bool isDebugEnabled = logger.IsDebugEnabled;
|
||||
foreach (object item in items)
|
||||
{
|
||||
if (EvalCondition(itemInfo.Condition, itemInfo.ConditionExpression, item, null))
|
||||
{
|
||||
object itemKey = itemInfo.KeyExpression.GetValue(item);
|
||||
#region Instrumentation
|
||||
|
||||
if (isDebugEnabled)
|
||||
{
|
||||
logger.Debug("Caching collection item for key [" + itemKey + "].");
|
||||
}
|
||||
|
||||
#endregion
|
||||
cache.Insert(itemKey, (item==null?NullValue:item), itemInfo.TimeToLiveTimeSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"The cache attribute is missing the key definition.");
|
||||
|
||||
bool isDebugEnabled = logger.IsDebugEnabled;
|
||||
foreach (object item in items)
|
||||
{
|
||||
if (EvalCondition(itemInfo.Condition, itemInfo.ConditionExpression, item, null))
|
||||
{
|
||||
object itemKey = itemInfo.KeyExpression.GetValue(item);
|
||||
#region Instrumentation
|
||||
|
||||
if (isDebugEnabled)
|
||||
{
|
||||
logger.Debug("Caching collection item for key [" + itemKey + "].");
|
||||
}
|
||||
|
||||
#endregion
|
||||
cache.Insert(itemKey, (item == null ? NullValue : item), itemInfo.TimeToLiveTimeSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CacheResultInfo GetCacheResultInfo(MethodInfo method)
|
||||
{
|
||||
CacheResultInfo cacheResultInfo = (CacheResultInfo)_cacheResultAttributeCache[method];
|
||||
// no need for locking here - last one wins
|
||||
if (cacheResultInfo == null)
|
||||
{
|
||||
CacheResultAttribute resultInfo = (CacheResultAttribute)GetCustomAttribute(method, typeof(CacheResultAttribute));
|
||||
CacheResultItemsAttribute[] itemInfoArray = (CacheResultItemsAttribute[])GetCustomAttributes(method, typeof(CacheResultItemsAttribute));
|
||||
|
||||
cacheResultInfo = new CacheResultInfo(resultInfo, itemInfoArray);
|
||||
_cacheResultAttributeCache[method] = cacheResultInfo;
|
||||
}
|
||||
return cacheResultInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,8 +55,7 @@ namespace Spring.Aspects.Cache
|
||||
/// <author>Aleksandar Seovic</author>
|
||||
public class InvalidateCacheAdvice : BaseCacheAdvice, IAfterReturningAdvice
|
||||
{
|
||||
// shared logger instance
|
||||
//private static readonly ILog logger = LogManager.GetLogger(typeof(InvalidateCacheAdvice));
|
||||
private readonly Hashtable _invalidateCacheAttributeCache = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// Executes after <paramref name="target"/> <paramref name="method"/>
|
||||
@@ -81,8 +80,7 @@ namespace Spring.Aspects.Cache
|
||||
/// <seealso cref="AopAlliance.Intercept.IMethodInterceptor.Invoke"/>
|
||||
public void AfterReturning(object returnValue, MethodInfo method, object[] arguments, object target)
|
||||
{
|
||||
InvalidateCacheAttribute[] cacheInfoArray =
|
||||
(InvalidateCacheAttribute[]) method.GetCustomAttributes(typeof(InvalidateCacheAttribute), false);
|
||||
InvalidateCacheAttribute[] cacheInfoArray = GetInvalidateCacheInfo(method);
|
||||
|
||||
if (cacheInfoArray.Length > 0)
|
||||
{
|
||||
@@ -115,6 +113,17 @@ namespace Spring.Aspects.Cache
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InvalidateCacheAttribute[] GetInvalidateCacheInfo(MethodInfo method)
|
||||
{
|
||||
InvalidateCacheAttribute[] cacheInfoArray = (InvalidateCacheAttribute[]) _invalidateCacheAttributeCache[method];
|
||||
if (cacheInfoArray == null)
|
||||
{
|
||||
cacheInfoArray = (InvalidateCacheAttribute[])GetCustomAttributes(method, typeof(InvalidateCacheAttribute));
|
||||
_invalidateCacheAttributeCache[method] = cacheInfoArray;
|
||||
}
|
||||
return cacheInfoArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,6 +170,5 @@ namespace Spring.Caching
|
||||
get { return timeToLiveTimeSpan; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -77,7 +77,7 @@ namespace Spring.Transaction.Interceptor
|
||||
/// <summary>
|
||||
/// Cache of <see cref="ITransactionAttribute"/>s, keyed by method and target class.
|
||||
/// </summary>
|
||||
private IDictionary _transactionAttibuteCache = new Hashtable();
|
||||
private readonly IDictionary _transactionAttibuteCache = new Hashtable();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the
|
||||
@@ -135,11 +135,10 @@ namespace Spring.Transaction.Interceptor
|
||||
public ITransactionAttribute ReturnTransactionAttribute(MethodInfo method, Type targetType)
|
||||
{
|
||||
object cacheKey = getCacheKey(method, targetType);
|
||||
object cached = null;
|
||||
|
||||
lock (_transactionAttibuteCache)
|
||||
lock (_transactionAttibuteCache)
|
||||
{
|
||||
cached = _transactionAttibuteCache[cacheKey];
|
||||
object cached = _transactionAttibuteCache[cacheKey];
|
||||
|
||||
if (cached != null)
|
||||
{
|
||||
@@ -228,7 +227,7 @@ namespace Spring.Transaction.Interceptor
|
||||
|
||||
private object getCacheKey(MethodBase method, Type targetType)
|
||||
{
|
||||
return targetType + String.Empty + method.GetHashCode();
|
||||
return string.Intern(targetType.AssemblyQualifiedName + "." + method);
|
||||
}
|
||||
|
||||
private ITransactionAttribute computeTransactionAttribute(MethodInfo method, Type targetType)
|
||||
|
||||
@@ -375,14 +375,13 @@ namespace Spring.Aspects.Cache
|
||||
|
||||
private void ExpectAttributeRetrieval( MethodInfo method )
|
||||
{
|
||||
mockInvocation.ExpectAndReturn( "Method", method );
|
||||
mockInvocation.ExpectAndReturn( "Method", method );
|
||||
mockInvocation.SetValue( "Method", method );
|
||||
}
|
||||
|
||||
private void ExpectCacheKeyGeneration( MethodInfo method, params object[] arguments )
|
||||
{
|
||||
mockInvocation.ExpectAndReturn( "Method", method );
|
||||
mockInvocation.ExpectAndReturn( "Arguments", arguments );
|
||||
// mockInvocation.ExpectAndReturn( "Method", method );
|
||||
mockInvocation.SetValue( "Arguments", arguments );
|
||||
}
|
||||
|
||||
private void ExpectCacheInstanceRetrieval( string cacheName, ICache cache )
|
||||
|
||||
Reference in New Issue
Block a user