summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenId/Associations.cs
blob: 529713bd247cca4d996baccdeec10a9984e44146 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace DotNetOpenId {
	/// <summary>
	/// A dictionary of handle/Association pairs.
	/// </summary>
	/// <remarks>
	/// 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.
	/// </remarks>
	[DebuggerDisplay("Count = {assocs.Count}")]
	internal class Associations {
		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		Dictionary<string, Association> assocs;

		/// <summary>
		/// Instantiates a mapping between association handles and <see cref="Association"/> objects.
		/// </summary>
		public Associations() {
			this.assocs = new Dictionary<string, Association>();
		}

		/// <summary>
		/// Stores an <see cref="Association"/> in the collection.
		/// </summary>
		public void Set(Association association) {
			if (association == null) throw new ArgumentNullException("association");
			lock (this) {
				this.assocs[association.Handle] = association;
			}
		}

		/// <summary>
		/// Returns the <see cref="Association"/> with the given handle.  Null if not found.
		/// </summary>
		public Association Get(string handle) {
			lock (this) {
				Association assoc;
				assocs.TryGetValue(handle, out assoc);
				return assoc;
			}
		}

		/// <summary>
		/// Removes the <see cref="Association"/> with the given handle.
		/// </summary>
		/// <returns>Whether an <see cref="Association"/> with the given handle was in the collection for removal.</returns>
		public bool Remove(string handle) {
			lock (this) {
				return assocs.Remove(handle);
			}
		}

		/// <summary>
		/// Gets the <see cref="Association"/> issued most recently.  Null if no valid associations exist.
		/// </summary>
		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;
				}
			}
		}

		/// <summary>
		/// Removes all expired associations from the collection.
		/// </summary>
		public void ClearExpired() {
			lock (this) {
				var expireds = new List<Association>(assocs.Count);
				foreach (Association assoc in assocs.Values)
					if (assoc.IsExpired)
						expireds.Add(assoc);
				foreach (Association assoc in expireds)
					assocs.Remove(assoc.Handle);
			}
		}
	}

}