2009-04-28 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / StaticSiteMapProvider.cs
1 //
2 // System.Web.StaticSiteMapProvider.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //      Ben Maurer (bmaurer@users.sourceforge.net)
7 //      Juraj Skripsky (js@hotfeet.ch)
8 //
9 // (C) 2003 Ben Maurer
10 // (C) 2005 Novell, Inc (http://www.novell.com)
11 // (C) 2007 HotFeet GmbH (http://www.hotfeet.ch)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33
34 #if NET_2_0
35 using System.Collections.Generic;
36
37 namespace System.Web
38 {
39         public abstract class StaticSiteMapProvider : SiteMapProvider
40         {
41                 Dictionary<string, SiteMapNode> keyToNode;
42                 Dictionary<SiteMapNode, SiteMapNode> nodeToParent;
43                 Dictionary<SiteMapNode, SiteMapNodeCollection> nodeToChildren;
44                 Dictionary<string, SiteMapNode> urlToNode;
45                         
46                 protected StaticSiteMapProvider ()
47                 {
48                         keyToNode = new Dictionary<string, SiteMapNode> ();
49                         nodeToParent = new Dictionary<SiteMapNode, SiteMapNode> ();
50                         nodeToChildren = new Dictionary<SiteMapNode, SiteMapNodeCollection> ();
51                         urlToNode = new Dictionary<string, SiteMapNode> (StringComparer.InvariantCultureIgnoreCase);
52                 }
53
54                 internal protected override void AddNode (SiteMapNode node, SiteMapNode parentNode)
55                 {
56                         if (node == null)
57                                 throw new ArgumentNullException ("node");
58
59                         lock (this_lock) {
60                                 if (FindSiteMapNodeFromKey (node.Key) != null && node.Provider == this)
61                                         throw new InvalidOperationException (string.Format ("A node with key '{0}' already exists.",node.Key));
62
63                                 if (!String.IsNullOrEmpty (node.Url)) {
64                                         string url = MapUrl (node.Url);
65                                         
66                                         if (FindSiteMapNode (url) != null)
67                                                 throw new InvalidOperationException (String.Format (
68                                                         "Multiple nodes with the same URL '{0}' were found. " + 
69                                                         "StaticSiteMapProvider requires that sitemap nodes have unique URLs.",
70                                                         node.Url
71                                                 ));
72                                 
73                                         urlToNode.Add (url, node);
74                                 }
75                                 keyToNode.Add (node.Key, node);
76
77                                 if (node == RootNode)
78                                         return;
79
80                                 if (parentNode == null)
81                                         parentNode = RootNode;
82
83                                 nodeToParent.Add (node, parentNode);
84
85                                 SiteMapNodeCollection children;
86                                 if (!nodeToChildren.TryGetValue (parentNode, out children)) 
87                                         nodeToChildren.Add (parentNode, children = new SiteMapNodeCollection ());
88
89                                 children.Add (node);
90                         }
91                 }
92                 
93                 protected virtual void Clear ()
94                 {
95                         lock (this_lock) {
96                                 urlToNode.Clear ();
97                                 nodeToChildren.Clear ();
98                                 nodeToParent.Clear ();
99                                 keyToNode.Clear ();
100                         }
101                 }
102
103                 public override SiteMapNode FindSiteMapNode (string rawUrl)
104                 {
105                         if (rawUrl == null)
106                                 throw new ArgumentNullException ("rawUrl");
107                         
108                         if (rawUrl == String.Empty)
109                                 return null;                    
110                         
111                         BuildSiteMap();
112                         SiteMapNode node;
113                         urlToNode.TryGetValue (MapUrl (rawUrl), out node);
114                         return CheckAccessibility (node);
115                 }
116
117                 public override SiteMapNodeCollection GetChildNodes (SiteMapNode node)
118                 {
119                         if (node == null)
120                                 throw new ArgumentNullException ("node");
121                         
122                         BuildSiteMap();
123                         SiteMapNodeCollection col;
124                         if (!nodeToChildren.TryGetValue (node, out col))
125                                 return SiteMapNodeCollection.EmptyCollection;
126                         
127                         SiteMapNodeCollection ret = null;
128                         for (int n=0; n<col.Count; n++) {
129                                 if (!IsAccessibleToUser (HttpContext.Current, col[n])) {
130                                         if (ret == null) {
131                                                 ret = new SiteMapNodeCollection ();
132                                                 for (int m=0; m<n; m++)
133                                                         ret.Add (col[m]);
134                                         }
135                                 } else if (ret != null)
136                                         ret.Add (col[n]);
137                         }
138
139                         if (ret == null)
140                                 return SiteMapNodeCollection.ReadOnly (col);
141                         else if (ret.Count > 0)
142                                 return SiteMapNodeCollection.ReadOnly (ret);
143                         else
144                                 return SiteMapNodeCollection.EmptyCollection;
145                 }
146                 
147                 public override SiteMapNode GetParentNode (SiteMapNode node)
148                 {
149                         if (node == null)
150                                 throw new ArgumentNullException ("node");
151
152                         BuildSiteMap();
153                         SiteMapNode parent;
154                         nodeToParent.TryGetValue (node, out parent);
155                         return CheckAccessibility (parent);
156                 }
157                 
158                 protected override void RemoveNode (SiteMapNode node)
159                 {
160                         if (node == null)
161                                 throw new ArgumentNullException("node");
162
163                         string key = node.Key;
164                         string url;
165                         
166                         lock (this_lock) {
167                                 if (keyToNode.ContainsKey (key))
168                                         keyToNode.Remove (key);
169                                 url = node.Url;
170                                 if (!String.IsNullOrEmpty (url)) {
171                                         url = MapUrl (url);
172                                         if (urlToNode.ContainsKey (url))
173                                                 urlToNode.Remove (url);
174                                 }
175                                 
176                                 if (node == RootNode)
177                                         return;
178
179                                 SiteMapNode parent;
180                                 if (nodeToParent.TryGetValue (node, out parent)) {
181                                         nodeToParent.Remove (node);
182
183                                         if (nodeToChildren.ContainsKey (parent))
184                                                 nodeToChildren [parent].Remove (node);
185                                 }
186                         }
187                 }
188                 
189                 public override SiteMapNode FindSiteMapNodeFromKey (string key)
190                 {
191                         if (key == null)
192                                 throw new ArgumentNullException ("key");
193                         
194                         SiteMapNode ret;
195                         keyToNode.TryGetValue (key, out ret);
196                         return CheckAccessibility (ret);
197                 }
198
199                 public abstract SiteMapNode BuildSiteMap ();
200                 
201                 SiteMapNode CheckAccessibility (SiteMapNode node) {
202                         return (node != null && IsAccessibleToUser (HttpContext.Current, node)) ? node : null;
203                 }
204
205                 string MapUrl (string url)
206                 {
207                         if (VirtualPathUtility.IsAppRelative (url))
208                                 return VirtualPathUtility.ToAbsolute (url);
209                         else
210                                 return url;
211                 }
212         }
213 }
214 #endif
215