using System; using System.Collections.Generic; using System.Diagnostics; namespace DotNetOpenId { /// /// A dictionary of handle/Association pairs. /// /// /// Each method is locked, even if it is only one line, so that they are thread safe /// against each other, particularly the ones that enumerate over the list, since they /// can break if the collection is changed by another thread during enumeration. /// [DebuggerDisplay("Count = {assocs.Count}")] internal class Associations { [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] Dictionary assocs; /// /// Instantiates a mapping between association handles and objects. /// public Associations() { this.assocs = new Dictionary(); } /// /// Stores an in the collection. /// public void Set(Association association) { if (association == null) throw new ArgumentNullException("association"); lock (this) { this.assocs[association.Handle] = association; } } /// /// Returns the with the given handle. Null if not found. /// public Association Get(string handle) { lock (this) { Association assoc; assocs.TryGetValue(handle, out assoc); return assoc; } } /// /// Removes the with the given handle. /// /// Whether an with the given handle was in the collection for removal. public bool Remove(string handle) { lock (this) { return assocs.Remove(handle); } } /// /// Gets the issued most recently. Null if no valid associations exist. /// public Association Best { get { lock (this) { Association best = null; foreach (Association assoc in assocs.Values) { if (best == null || best.Issued < assoc.Issued) best = assoc; } return best; } } } /// /// Removes all expired associations from the collection. /// public void ClearExpired() { lock (this) { var expireds = new List(assocs.Count); foreach (Association assoc in assocs.Values) if (assoc.IsExpired) expireds.Add(assoc); foreach (Association assoc in expireds) assocs.Remove(assoc.Handle); } } } }