//----------------------------------------------------------------------- // // Copyright (c) Outercurve Foundation. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.OpenId.Extensions { using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Text; using DotNetOpenAuth.Messaging; using Validation; /// /// Manages a fast, two-way mapping between type URIs and their aliases. /// internal class AliasManager { /// /// The format of auto-generated aliases. /// private const string AliasFormat = "alias{0}"; /// /// Tracks extension Type URIs and aliases assigned to them. /// private Dictionary typeUriToAliasMap = new Dictionary(); /// /// Tracks extension aliases and Type URIs assigned to them. /// private Dictionary aliasToTypeUriMap = new Dictionary(); /// /// Gets the aliases that have been set. /// public IEnumerable Aliases { get { return this.aliasToTypeUriMap.Keys; } } /// /// Gets an alias assigned for a given Type URI. A new alias is assigned if necessary. /// /// The type URI. /// The alias assigned to this type URI. Never null. public string GetAlias(string typeUri) { Requires.NotNullOrEmpty(typeUri, "typeUri"); string alias; return this.typeUriToAliasMap.TryGetValue(typeUri, out alias) ? alias : this.AssignNewAlias(typeUri); } /// /// Sets an alias and the value that will be returned by . /// /// The alias. /// The type URI. public void SetAlias(string alias, string typeUri) { Requires.NotNullOrEmpty(alias, "alias"); Requires.NotNullOrEmpty(typeUri, "typeUri"); this.aliasToTypeUriMap.Add(alias, typeUri); this.typeUriToAliasMap.Add(typeUri, alias); } /// /// Takes a sequence of type URIs and assigns aliases for all of them. /// /// The type URIs to create aliases for. /// An optional dictionary of URI/alias pairs that suggest preferred aliases to use if available for certain type URIs. public void AssignAliases(IEnumerable typeUris, IDictionary preferredTypeUriToAliases) { Requires.NotNull(typeUris, "typeUris"); // First go through the actually used type URIs and see which ones have matching preferred aliases. if (preferredTypeUriToAliases != null) { foreach (string typeUri in typeUris) { if (this.typeUriToAliasMap.ContainsKey(typeUri)) { // this Type URI is already mapped to an alias. continue; } string preferredAlias; if (preferredTypeUriToAliases.TryGetValue(typeUri, out preferredAlias) && !this.IsAliasUsed(preferredAlias)) { this.SetAlias(preferredAlias, typeUri); } } } // Now go through the whole list again and assign whatever is left now that the preferred ones // have gotten their picks where available. foreach (string typeUri in typeUris) { if (this.typeUriToAliasMap.ContainsKey(typeUri)) { // this Type URI is already mapped to an alias. continue; } this.AssignNewAlias(typeUri); } } /// /// Sets up aliases for any Type URIs in a dictionary that do not yet have aliases defined, /// and where the given preferred alias is still available. /// /// A dictionary of type URI keys and alias values. public void SetPreferredAliasesWhereNotSet(IDictionary preferredTypeUriToAliases) { Requires.NotNull(preferredTypeUriToAliases, "preferredTypeUriToAliases"); foreach (var pair in preferredTypeUriToAliases) { if (this.typeUriToAliasMap.ContainsKey(pair.Key)) { // type URI is already mapped continue; } if (this.aliasToTypeUriMap.ContainsKey(pair.Value)) { // alias is already mapped continue; } // The type URI and alias are as yet unset, so go ahead and assign them. this.SetAlias(pair.Value, pair.Key); } } /// /// Gets the Type Uri encoded by a given alias. /// /// The alias. /// The Type URI. /// Thrown if the given alias does not have a matching TypeURI. public string ResolveAlias(string alias) { Requires.NotNullOrEmpty(alias, "alias"); string typeUri = this.TryResolveAlias(alias); if (typeUri == null) { throw new ArgumentOutOfRangeException("alias"); } return typeUri; } /// /// Gets the Type Uri encoded by a given alias. /// /// The alias. /// The Type URI for the given alias, or null if none for that alias exist. public string TryResolveAlias(string alias) { Requires.NotNullOrEmpty(alias, "alias"); string typeUri = null; this.aliasToTypeUriMap.TryGetValue(alias, out typeUri); return typeUri; } /// /// Returns a value indicating whether an alias has already been assigned to a type URI. /// /// The alias in question. /// True if the alias has already been assigned. False otherwise. public bool IsAliasUsed(string alias) { Requires.NotNullOrEmpty(alias, "alias"); return this.aliasToTypeUriMap.ContainsKey(alias); } /// /// Determines whether a given TypeURI has an associated alias assigned to it. /// /// The type URI. /// /// true if the given type URI already has an alias assigned; false otherwise. /// public bool IsAliasAssignedTo(string typeUri) { Requires.NotNull(typeUri, "typeUri"); return this.typeUriToAliasMap.ContainsKey(typeUri); } /// /// Assigns a new alias to a given Type URI. /// /// The type URI to assign a new alias to. /// The newly generated alias. private string AssignNewAlias(string typeUri) { Requires.NotNullOrEmpty(typeUri, "typeUri"); ErrorUtilities.VerifyInternal(!this.typeUriToAliasMap.ContainsKey(typeUri), "Oops! This type URI already has an alias!"); string alias = string.Format(CultureInfo.InvariantCulture, AliasFormat, this.typeUriToAliasMap.Count + 1); this.typeUriToAliasMap.Add(typeUri, alias); this.aliasToTypeUriMap.Add(alias, typeUri); return alias; } } }