Merge pull request #704 from jgagnon/master
[mono.git] / mcs / class / System.Web / System.Web / StaticSiteMapProvider.cs
index e44aeab285b32e53eb5b5744416bb7f720eb6f25..e6765c148f86ea3480cd75b4912e0a8c3ba8f728 100644 (file)
@@ -4,9 +4,11 @@
 // Authors:
 //     Lluis Sanchez Gual (lluis@novell.com)
 //     Ben Maurer (bmaurer@users.sourceforge.net)
+//     Juraj Skripsky (js@hotfeet.ch)
 //
 // (C) 2003 Ben Maurer
 // (C) 2005 Novell, Inc (http://www.novell.com)
+// (C) 2007 HotFeet GmbH (http://www.hotfeet.ch)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-
-#if NET_2_0
-using System.Collections;
-using System.Collections.Specialized;
-using System.Text;
-using System.Configuration.Provider;
+using System.Collections.Generic;
 using System.Web.Util;
-using System.Globalization;
 
 namespace System.Web
 {
        public abstract class StaticSiteMapProvider : SiteMapProvider
        {
-               Hashtable nodeToParent;
-               Hashtable nodeToChildren;
-               Hashtable urlToNode;
-               Hashtable keyToNode;
+               Dictionary<string, SiteMapNode> keyToNode;
+               Dictionary<SiteMapNode, SiteMapNode> nodeToParent;
+               Dictionary<SiteMapNode, SiteMapNodeCollection> nodeToChildren;
+               Dictionary<string, SiteMapNode> urlToNode;
                
+               protected StaticSiteMapProvider ()
+               {
+                       keyToNode = new Dictionary<string, SiteMapNode> ();
+                       nodeToParent = new Dictionary<SiteMapNode, SiteMapNode> ();
+                       nodeToChildren = new Dictionary<SiteMapNode, SiteMapNodeCollection> ();
+                       urlToNode = new Dictionary<string, SiteMapNode> (StringComparer.InvariantCultureIgnoreCase);
+               }
+
                internal protected override void AddNode (SiteMapNode node, SiteMapNode parentNode)
                {
                        if (node == null)
                                throw new ArgumentNullException ("node");
-                       
-                       lock (this) {
-                               string url = node.Url;
-                               if (url != null && url.Length > 0) {
-                                       url = MapUrl (url);
 
-                                       if (FindSiteMapNode (url) != null)
-                                               throw new InvalidOperationException ();
-                               
-                                       UrlToNode [url] = node;
+                       lock (this_lock) {
+                               string nodeKey = node.Key;
+                               if (FindSiteMapNodeFromKey (nodeKey) != null && node.Provider == this)
+                                       throw new InvalidOperationException (string.Format ("A node with key '{0}' already exists.",nodeKey));
+
+                               string nodeUrl = node.Url;
+                               if (!String.IsNullOrEmpty (nodeUrl)) {
+                                       string url = MapUrl (nodeUrl);
+                                       SiteMapNode foundNode = FindSiteMapNode (url);
+                                       if (foundNode != null && String.Compare (foundNode.Url, url, RuntimeHelpers.StringComparison) == 0)
+                                               throw new InvalidOperationException (String.Format (
+                                                       "Multiple nodes with the same URL '{0}' were found. " + 
+                                                       "StaticSiteMapProvider requires that sitemap nodes have unique URLs.",
+                                                       node.Url
+                                               ));
+
+                                       urlToNode.Add (url, node);
                                }
-                               
-                               if (FindSiteMapNodeFromKey (node.Key) != null)
-                                       throw new InvalidOperationException (string.Format ("A node with key {0} already exists.",node.Key));
-                               KeyToNode [node.Key] = node;
+                               keyToNode.Add (nodeKey, node);
 
                                if (node == RootNode)
                                        return;
@@ -72,66 +81,23 @@ namespace System.Web
                                if (parentNode == null)
                                        parentNode = RootNode;
 
-                               NodeToParent [node] = parentNode;
-                               if (NodeToChildren [parentNode] == null)
-                                       NodeToChildren [parentNode] = new SiteMapNodeCollection ();
-                                       
-                               ((SiteMapNodeCollection) NodeToChildren [parentNode]).Add (node);
-                       }
-               }
-               
-               Hashtable NodeToParent {
-                       get {
-                               lock (this) {
-                                       if (nodeToParent == null)
-                                               nodeToParent = new Hashtable ();
-                               }
-                               return nodeToParent;
-                       }
-               }
-               
-               Hashtable NodeToChildren {
-                       get {
-                               lock (this) {
-                                       if (nodeToChildren == null)
-                                               nodeToChildren = new Hashtable ();
-                               }
-                               return nodeToChildren;
-                       }
-               }
-               
-               Hashtable UrlToNode {
-                       get {
-                               lock (this) {
-                                       if (urlToNode == null) {
-                                               urlToNode = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
-                                       }
-                               }
-                               return urlToNode;
-                       }
-               }
-               
-               Hashtable KeyToNode {
-                       get {
-                               lock (this) {
-                                       if (keyToNode == null)
-                                               keyToNode = new Hashtable ();
-                               }
-                               return keyToNode;
+                               nodeToParent.Add (node, parentNode);
+
+                               SiteMapNodeCollection children;
+                               if (!nodeToChildren.TryGetValue (parentNode, out children)) 
+                                       nodeToChildren.Add (parentNode, children = new SiteMapNodeCollection ());
+
+                               children.Add (node);
                        }
                }
                
                protected virtual void Clear ()
                {
-                       lock (this) {
-                               if (urlToNode != null)
-                                       urlToNode.Clear ();
-                               if (nodeToChildren != null)
-                                       nodeToChildren.Clear ();
-                               if (nodeToParent != null)
-                                       nodeToParent.Clear ();
-                               if (keyToNode != null)
-                                       keyToNode.Clear ();
+                       lock (this_lock) {
+                               urlToNode.Clear ();
+                               nodeToChildren.Clear ();
+                               nodeToParent.Clear ();
+                               keyToNode.Clear ();
                        }
                }
 
@@ -140,14 +106,18 @@ namespace System.Web
                        if (rawUrl == null)
                                throw new ArgumentNullException ("rawUrl");
                        
-                       if (rawUrl.Length > 0) {
-                               this.BuildSiteMap();
-                               rawUrl = MapUrl (rawUrl);
-                               SiteMapNode node = (SiteMapNode) UrlToNode [rawUrl];
-                               if (node != null && IsAccessibleToUser (HttpContext.Current, node))
-                                       return node;
-                       }
-                       return null;
+                       if (rawUrl == String.Empty)
+                               return null;                    
+                       
+                       BuildSiteMap();
+                       SiteMapNode node;
+                       if (VirtualPathUtility.IsAppRelative (rawUrl))
+                               rawUrl = VirtualPathUtility.ToAbsolute (rawUrl, HttpRuntime.AppDomainAppVirtualPath, false);
+
+                       if (!urlToNode.TryGetValue (rawUrl, out node))
+                               return null;
+
+                       return CheckAccessibility (node);
                }
 
                public override SiteMapNodeCollection GetChildNodes (SiteMapNode node)
@@ -155,9 +125,10 @@ namespace System.Web
                        if (node == null)
                                throw new ArgumentNullException ("node");
                        
-                       this.BuildSiteMap();
-                       SiteMapNodeCollection col = (SiteMapNodeCollection) NodeToChildren [node];
-                       if (col == null) return SiteMapNodeCollection.EmptyCollection;
+                       BuildSiteMap();
+                       SiteMapNodeCollection col;
+                       if (!nodeToChildren.TryGetValue (node, out col))
+                               return SiteMapNodeCollection.EmptyCollection;
                        
                        SiteMapNodeCollection ret = null;
                        for (int n=0; n<col.Count; n++) {
@@ -170,42 +141,53 @@ namespace System.Web
                                } else if (ret != null)
                                        ret.Add (col[n]);
                        }
-                       
-                       if (ret != null) {
-                               if (ret.Count > 0)
-                                       return SiteMapNodeCollection.ReadOnly (ret);
-                       } else
+
+                       if (ret == null)
                                return SiteMapNodeCollection.ReadOnly (col);
-                       
-                       return null;
+                       else if (ret.Count > 0)
+                               return SiteMapNodeCollection.ReadOnly (ret);
+                       else
+                               return SiteMapNodeCollection.EmptyCollection;
                }
                
                public override SiteMapNode GetParentNode (SiteMapNode node)
                {
                        if (node == null)
                                throw new ArgumentNullException ("node");
-                       this.BuildSiteMap();
-                       SiteMapNode parent = (SiteMapNode) NodeToParent [node];
-                       return parent != null && IsAccessibleToUser (HttpContext.Current, parent) ? parent : null;
+
+                       BuildSiteMap();
+                       SiteMapNode parent;
+                       nodeToParent.TryGetValue (node, out parent);
+                       return CheckAccessibility (parent);
                }
                
                protected override void RemoveNode (SiteMapNode node)
                {
                        if (node == null)
                                throw new ArgumentNullException("node");
+
+                       string key = node.Key;
+                       string url;
                        
-                       lock (this) {
-                               SiteMapNode parent = (SiteMapNode) NodeToParent [node];
-                               if (NodeToParent.Contains (node))
-                                       NodeToParent.Remove (node);
-                               
-                               if (node.Url != null && node.Url.Length > 0 && UrlToNode.Contains (node.Url))
-                                       UrlToNode.Remove (node.Url);
+                       lock (this_lock) {
+                               if (keyToNode.ContainsKey (key))
+                                       keyToNode.Remove (key);
+                               url = node.Url;
+                               if (!String.IsNullOrEmpty (url)) {
+                                       url = MapUrl (url);
+                                       if (urlToNode.ContainsKey (url))
+                                               urlToNode.Remove (url);
+                               }
                                
-                               if (parent != null) {
-                                       SiteMapNodeCollection siblings = (SiteMapNodeCollection) NodeToChildren [node];
-                                       if (siblings != null && siblings.Contains (node))
-                                               siblings.Remove (node);
+                               if (node == RootNode)
+                                       return;
+
+                               SiteMapNode parent;
+                               if (nodeToParent.TryGetValue (node, out parent)) {
+                                       nodeToParent.Remove (node);
+
+                                       if (nodeToChildren.ContainsKey (parent))
+                                               nodeToChildren [parent].Remove (node);
                                }
                        }
                }
@@ -215,24 +197,32 @@ namespace System.Web
                        if (key == null)
                                throw new ArgumentNullException ("key");
                        
-                       SiteMapNode ret = (SiteMapNode) KeyToNode [key];
-                       return ret != null && IsAccessibleToUser (HttpContext.Current, ret) ? ret : null;
+                       SiteMapNode ret;
+                       keyToNode.TryGetValue (key, out ret);
+                       return CheckAccessibility (ret);
                }
 
                public abstract SiteMapNode BuildSiteMap ();
+               
+               SiteMapNode CheckAccessibility (SiteMapNode node) {
+                       return (node != null && IsAccessibleToUser (HttpContext.Current, node)) ? node : null;
+               }
 
-               string MapUrl (string url)
+               internal string MapUrl (string url)
                {
-                       if (HttpContext.Current == null)
+                       if (String.IsNullOrEmpty (url))
                                return url;
 
-                       if (UrlUtils.IsRelativeUrl (url))
-                               return UrlUtils.Combine (HttpRuntime.AppDomainAppVirtualPath, url);
+                       string appVPath = HttpRuntime.AppDomainAppVirtualPath;
+                       if (String.IsNullOrEmpty (appVPath))
+                               appVPath = "/";
+                       
+                       if (VirtualPathUtility.IsAppRelative (url))
+                               return VirtualPathUtility.ToAbsolute (url, appVPath, true);
                        else
-                               return UrlUtils.ResolveVirtualPathFromAppAbsolute (url);
+                               return VirtualPathUtility.ToAbsolute (UrlUtils.Combine (appVPath, url), appVPath, true);
                }
-
        }
 }
-#endif
+