From 70d2b5413f6a11752ae0809a02be3a3857ab405d Mon Sep 17 00:00:00 2001 From: sbohlen Date: Wed, 22 Sep 2010 17:48:41 +0000 Subject: [PATCH] SPRNET-1226 Update docs to reflect the requirement for a non-null, non-empty string cache key. Added guard clauses in the BaseCacheAttribute constructor to prevent passing null or empty string as the cache key argument. Tests added to ensure guard clauses behave as expected. --- doc/reference/src/aop-aspect-library.xml | 16 +- .../Spring.Core/Caching/BaseCacheAttribute.cs | 358 +++++++++--------- .../Caching/BaseCacheAttributeTests.cs | 26 +- 3 files changed, 218 insertions(+), 182 deletions(-) diff --git a/doc/reference/src/aop-aspect-library.xml b/doc/reference/src/aop-aspect-library.xml index 313e6755..2b198ac1 100644 --- a/doc/reference/src/aop-aspect-library.xml +++ b/doc/reference/src/aop-aspect-library.xml @@ -196,14 +196,14 @@ public Airport GetAirport(long id) The first parameter is the cache name. The second string parameter is the cache key and is a string expression that incorporates the argument - passed into the method, the id. The method parameter names are exposed as - variables to the key expression. If you do not specify a key, then all the - parameter values will be used to cache the returned value. The expression - may also call out to other objects in the Spring container allowing for a - more complex key algorithm to be encapsulated. The end result is that the - Airport object is cached by id for 60 seconds in a cache named - AspNetCache. The TimetoLive property could also have been specified on the - configuration of the AspNetCache object. + passed into the method, the id. The cache key value cannot be null or an + empty string (""). The method parameter names are exposed as variables to + the key expression. The expression may also call out to other objects in + the Spring container allowing for a more complex key algorithm to be + encapsulated. The end result is that the Airport object is cached by id + for 60 seconds in a cache named AspNetCache. The TimetoLive property could + also have been specified on the configuration of the AspNetCache + object. The configuration to enable the caching aspect is shown below diff --git a/src/Spring/Spring.Core/Caching/BaseCacheAttribute.cs b/src/Spring/Spring.Core/Caching/BaseCacheAttribute.cs index 62a25e00..130a7bc0 100644 --- a/src/Spring/Spring.Core/Caching/BaseCacheAttribute.cs +++ b/src/Spring/Spring.Core/Caching/BaseCacheAttribute.cs @@ -1,174 +1,186 @@ -using System; -using Spring.Core.TypeConversion; -using Spring.Expressions; - -namespace Spring.Caching -{ - /// - /// Abstract base class containing shared properties for all cache attributes. - /// - /// Aleksandar Seovic - [Serializable] - public abstract class BaseCacheAttribute : Attribute - { - #region Fields - - /// - /// The instance used to parse values. - /// - /// - /// - protected static readonly TimeSpanConverter TimeSpanConverter = new TimeSpanConverter(); - - private string cacheName; - private string key; - private IExpression keyExpression; - private string condition; - private IExpression conditionExpression; - private string timeToLive = null; - private TimeSpan timeToLiveTimeSpan = TimeSpan.MinValue; - - #endregion - - #region Constructors - - /// - /// Creates an attribute instance. - /// - public BaseCacheAttribute() - { - } - - /// - /// Creates an attribute instance. - /// - /// - /// The name of the cache to use. - /// - /// - /// An expression string that should be evaluated in order to determine - /// the cache key for the item. - /// - public BaseCacheAttribute(string cacheName, string key) - { - this.CacheName = cacheName; - this.Key = key; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the name of the cache to use. - /// - /// - /// The name of the cache to use. - /// - public string CacheName - { - get { return cacheName; } - set { cacheName = value; } - } - - /// - /// Gets or sets a SpEL expression that should be evaluated in order - /// to determine the cache key for the item. - /// - /// - /// An expression string that should be evaluated in order to determine - /// the cache key for the item. - /// - public string Key - { - get { return key; } - set - { - key = value; - keyExpression = Expression.Parse(value); - } - } - - /// - /// Gets an expression instance that should be evaluated in order - /// to determine the cache key for the item. - /// - /// - /// An expression instance that should be evaluated in order to determine - /// the cache key for the item. - /// - public IExpression KeyExpression - { - get { return keyExpression; } - } - - /// - /// Gets or sets a SpEL expression that should be evaluated in order - /// to determine whether the item should be cached. - /// - /// - /// An expression string that should be evaluated in order to determine - /// whether the item should be cached. - /// - public string Condition - { - get { return condition; } - set - { - condition = value; - conditionExpression = Expression.Parse(value); - } - } - - /// - /// Gets an expression instance that should be evaluated in order - /// to determine whether the item should be cached. - /// - /// - /// An expression instance that should be evaluated in order to determine - /// whether the item should be cached. - /// - public IExpression ConditionExpression - { - get { return conditionExpression; } - } - - /// - /// The amount of time an object should remain in the cache. - /// - /// - /// If no TTL is specified, the default TTL defined by the - /// cache's policy will be applied. - /// - /// - /// The amount of time object should remain in the cache - /// formatted to be recognizable by . - /// - public string TimeToLive - { - get { return timeToLive; } - set - { - timeToLive = value; - timeToLiveTimeSpan = (timeToLive == null) ? TimeSpan.MinValue : (TimeSpan)TimeSpanConverter.ConvertFrom(timeToLive); - } - } - - - /// - /// The amount of time an object should remain in the cache (in seconds). - /// - /// - /// If no TTL is specified, the default TTL defined by the - /// cache's policy will be applied. - /// - /// - /// The amount of time object should remain in the cache (in seconds). - /// - public TimeSpan TimeToLiveTimeSpan - { - get { return timeToLiveTimeSpan; } - } - - #endregion } +using System; +using Spring.Core.TypeConversion; +using Spring.Expressions; + +namespace Spring.Caching +{ + /// + /// Abstract base class containing shared properties for all cache attributes. + /// + /// Aleksandar Seovic + [Serializable] + public abstract class BaseCacheAttribute : Attribute + { + #region Fields + + /// + /// The instance used to parse values. + /// + /// + /// + protected static readonly TimeSpanConverter TimeSpanConverter = new TimeSpanConverter(); + + private string cacheName; + private string key; + private IExpression keyExpression; + private string condition; + private IExpression conditionExpression; + private string timeToLive = null; + private TimeSpan timeToLiveTimeSpan = TimeSpan.MinValue; + + #endregion + + #region Constructors + + /// + /// Creates an attribute instance. + /// + public BaseCacheAttribute() + { + } + + /// + /// Creates an attribute instance. + /// + /// + /// The name of the cache to use. + /// + /// + /// An expression string that should be evaluated in order to determine + /// the cache key for the item. + /// + /// The cache key cannot evaluate be null or an empty string. + public BaseCacheAttribute(string cacheName, string key) + { + if (null == key) + { + throw new ArgumentNullException("key", "The expression for the Cache Key cannot be null."); + } + + if (key.Trim() == string.Empty) + { + throw new ArgumentOutOfRangeException("key", "The expression for the Cache Key cannot be an empty string."); + } + + this.CacheName = cacheName; + this.Key = key; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the name of the cache to use. + /// + /// + /// The name of the cache to use. + /// + public string CacheName + { + get { return cacheName; } + set { cacheName = value; } + } + + /// + /// Gets or sets a SpEL expression that should be evaluated in order + /// to determine the cache key for the item. + /// + /// + /// An expression string that should be evaluated in order to determine + /// the cache key for the item. + /// + public string Key + { + get { return key; } + set + { + key = value; + keyExpression = Expression.Parse(value); + } + } + + /// + /// Gets an expression instance that should be evaluated in order + /// to determine the cache key for the item. + /// + /// + /// An expression instance that should be evaluated in order to determine + /// the cache key for the item. + /// + public IExpression KeyExpression + { + get { return keyExpression; } + } + + /// + /// Gets or sets a SpEL expression that should be evaluated in order + /// to determine whether the item should be cached. + /// + /// + /// An expression string that should be evaluated in order to determine + /// whether the item should be cached. + /// + public string Condition + { + get { return condition; } + set + { + condition = value; + conditionExpression = Expression.Parse(value); + } + } + + /// + /// Gets an expression instance that should be evaluated in order + /// to determine whether the item should be cached. + /// + /// + /// An expression instance that should be evaluated in order to determine + /// whether the item should be cached. + /// + public IExpression ConditionExpression + { + get { return conditionExpression; } + } + + /// + /// The amount of time an object should remain in the cache. + /// + /// + /// If no TTL is specified, the default TTL defined by the + /// cache's policy will be applied. + /// + /// + /// The amount of time object should remain in the cache + /// formatted to be recognizable by . + /// + public string TimeToLive + { + get { return timeToLive; } + set + { + timeToLive = value; + timeToLiveTimeSpan = (timeToLive == null) ? TimeSpan.MinValue : (TimeSpan)TimeSpanConverter.ConvertFrom(timeToLive); + } + } + + + /// + /// The amount of time an object should remain in the cache (in seconds). + /// + /// + /// If no TTL is specified, the default TTL defined by the + /// cache's policy will be applied. + /// + /// + /// The amount of time object should remain in the cache (in seconds). + /// + public TimeSpan TimeToLiveTimeSpan + { + get { return timeToLiveTimeSpan; } + } + + #endregion + } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Caching/BaseCacheAttributeTests.cs b/test/Spring/Spring.Core.Tests/Caching/BaseCacheAttributeTests.cs index 98302232..20611634 100644 --- a/test/Spring/Spring.Core.Tests/Caching/BaseCacheAttributeTests.cs +++ b/test/Spring/Spring.Core.Tests/Caching/BaseCacheAttributeTests.cs @@ -38,6 +38,16 @@ namespace Spring.Caching private class DerivedCacheAttribute : BaseCacheAttribute { + public DerivedCacheAttribute() + { + + } + + public DerivedCacheAttribute(string cacheName, string key) + : base(cacheName, key) + { + + } } public string TestProperty @@ -78,7 +88,21 @@ namespace Spring.Caching public void AllowsForExtendedTimeSpanConverterSyntax() { att.TimeToLive = "5ms"; - Assert.AreEqual( new TimeSpan(0,0,0,0,5), att.TimeToLiveTimeSpan ); + Assert.AreEqual(new TimeSpan(0, 0, 0, 0, 5), att.TimeToLiveTimeSpan); + } + + [Test] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void KeyCannotBeEmptyString() + { + att = new DerivedCacheAttribute("someName", string.Empty); + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void KeyCannotBeNull() + { + att = new DerivedCacheAttribute("someName", null); } } } \ No newline at end of file