File: System\IdentityModel\Tokens\DefaultTokenReplayCache.cs
Project: ndp\cdf\src\WCF\IdentityModel\System.IdentityModel.csproj (System.IdentityModel)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
 
namespace System.IdentityModel.Tokens
{
    /// <summary>
    /// A default implementation of the Token replay cache that is backed by
    /// a bounded cache.
    /// </summary>
    internal class DefaultTokenReplayCache : TokenReplayCache
    {
        static readonly int DefaultTokenReplayCacheCapacity = 500000;
        static readonly TimeSpan DefaultTokenReplayCachePurgeInterval = TimeSpan.FromMinutes(1);
 
        BoundedCache<SecurityToken> _internalCache;
 
        /// <summary>
        /// Constructs the default token replay cache.
        /// </summary>
        public DefaultTokenReplayCache()
            : this(DefaultTokenReplayCache.DefaultTokenReplayCacheCapacity, DefaultTokenReplayCache.DefaultTokenReplayCachePurgeInterval)
        { }
 
        /// <summary>
        /// Constructs the default token replay cache with the specified 
        /// capacity and purge interval.
        /// </summary>
        /// <param name="capacity">The capacity of the token cache</param>
        /// <param name="purgeInterval">The time interval after which the cache must be purged</param>
        public DefaultTokenReplayCache(int capacity, TimeSpan purgeInterval)
            : base()
        {
            _internalCache = new BoundedCache<SecurityToken>(capacity, purgeInterval, StringComparer.Ordinal);
        }
 
        /// <summary>
        /// Gets or Sets the current Capacity of the cache in number of SecurityTokens.
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">If 'value' is less than or equal to zero.</exception>
        public int Capacity
        {
            get { return _internalCache.Capacity; }
            set
            {
                if (value <= 0)
                {
                    throw DiagnosticUtility.ThrowHelperArgumentOutOfRange("value", value, SR.GetString(SR.ID0002));
                }
 
                _internalCache.Capacity = value;
            }
        }
 
        /// <summary>
        /// Removes all SecurityTokens from the Cache.
        /// </summary>
        public void Clear()
        {
            _internalCache.Clear();
        }
 
        /// <summary>
        /// Increases the maximum number of SecurityTokens that this cache will hold. 
        /// </summary>
        /// <param name="size">The capacity to increase.</param>
        /// <exception cref="ArgumentOutOfRangeException">The input parameter 'size' is less than or equal to zero.</exception>
        /// <returns>Updated capacity</returns>
        /// <remarks>If size + current capacity >= int.MaxValue then capacity will be set to int.MaxValue and the cache capacity will be unbounded.</remarks>
        public int IncreaseCapacity(int size)
        {
            if (size <= 0)
            {
                throw DiagnosticUtility.ThrowHelperArgumentOutOfRange("size", size, SR.GetString(SR.ID0002));
            }
 
            return _internalCache.IncreaseCapacity(size);
        }
 
        /// <summary>
        /// Gets or Sets the time interval that will be used when checking for expired SecurityTokens.
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">If 'value' is less than or equal to TimeSpan.Zero.</exception>
        public TimeSpan PurgeInterval
        {
            get { return _internalCache.PurgeInterval; }
            set
            {
                if (value <= TimeSpan.Zero)
                {
                    throw DiagnosticUtility.ThrowHelperArgumentOutOfRange("value", value, SR.GetString(SR.ID0016));
                }
 
                _internalCache.PurgeInterval = value;
            }
        }
 
        /// <summary>
        /// Attempt to add a new entry or update an existing entry.
        /// </summary>
        /// <param name="key">Key to use when adding item.</param>
        /// <param name="securityToken">SecurityToken to add to cache, can be null.</param>
        /// <param name="expirationTime">The expiration instant of the token being added.</param>
        /// <exception cref="System.IdentityModel.LimitExceededException">Thrown if an attempt is made to add a SecurityToken if cache is at capacity.</exception>
        /// <exception cref="InvalidOperationException">Thrown if the expiration time is infinite.</exception>
        public override void AddOrUpdate(string key, SecurityToken securityToken, DateTime expirationTime)
        {
            if (DateTime.Equals(expirationTime, DateTime.MaxValue))
            {
                throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID1072));
            }
 
            _internalCache.TryRemove(key);
            _internalCache.TryAdd(key, securityToken, expirationTime);
        }
 
        /// <summary>
        /// Attempt to find if a matching entry exists in the cache.
        /// </summary>
        /// <param name="key">The key to search for.</param>
        /// <returns>true if a matching entry is ifound in the cache, false otherwise</returns>
        public override bool Contains(string key)
        {
            return _internalCache.TryFind(key);
        }
 
        /// <summary>
        /// Attempt to get a SecurityToken
        /// </summary>
        /// <param name="key">The key to search for.</param>
        /// <returns>The <see cref="SecurityToken"/> found, if any, null otherwise.</returns>
        public override SecurityToken Get(string key)
        {
            SecurityToken token;
            _internalCache.TryGet(key, out token);
            return token;
        }
 
        /// <summary>
        /// Attempt to remove an entry from the cache
        /// </summary>
        /// <param name="key">The key to the entry to remove</param>
        public override void Remove(string key)
        {
            _internalCache.TryRemove(key);
        }
    }
}