New test.
[mono.git] / mcs / class / System.Web / System.Web / SiteMapProvider.cs
1 //
2 // System.Web.SiteMapProvider
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Lluis Sanchez Gual (lluis@novell.com)
7 //
8 // (C) 2003 Ben Maurer
9 // (C) 2005 Novell, Inc (http://www.novell.com)
10 //
11
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 #if NET_2_0
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.Text;
37 using System.Configuration.Provider;
38 using System.Web.Util;
39 using System.Globalization;
40 using System.Web.Configuration;
41
42 namespace System.Web {
43         public abstract class SiteMapProvider : ProviderBase {
44                 
45                 bool enableLocalization;
46                 SiteMapProvider parentProvider;
47                 SiteMapProvider rootProviderCache;
48                 bool securityTrimming;
49                 object resolveLock = new Object();
50                 bool resolving;
51                 
52                 protected virtual void AddNode (SiteMapNode node)
53                 {
54                         AddNode (node, null);
55                 }
56                 
57                 internal protected virtual void AddNode (SiteMapNode node, SiteMapNode parentNode)
58                 {
59                         throw new NotImplementedException ();
60                 }
61
62                 public virtual SiteMapNode FindSiteMapNode (HttpContext context)
63                 {
64                         if (context == null)
65                                 return null;
66                         
67                         SiteMapNode ret = this.FindSiteMapNode (context.Request.RawUrl);
68                         if (ret == null)
69                                 ret = this.FindSiteMapNode (context.Request.Path);
70                         return ret;
71                 }
72
73                 public abstract SiteMapNode FindSiteMapNode (string rawUrl);
74                 
75                 public virtual SiteMapNode FindSiteMapNodeFromKey (string key)
76                 {
77                         /* msdn2 says this function always returns
78                          * null, but it seems to just call
79                          * FindSiteMapNode(string rawUrl) */
80                         return FindSiteMapNode (key);
81                 }
82
83                 public abstract SiteMapNodeCollection GetChildNodes (SiteMapNode node);
84                 
85                 public virtual SiteMapNode GetCurrentNodeAndHintAncestorNodes (int upLevel)
86                 {
87                         if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
88
89                         return CurrentNode;
90                 }
91                 
92                 public virtual SiteMapNode GetCurrentNodeAndHintNeighborhoodNodes (int upLevel, int downLevel)
93                 {
94                         if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
95                         if (downLevel < -1) throw new ArgumentOutOfRangeException ("downLevel");
96                         
97                         return CurrentNode;
98                 }
99
100                 public abstract SiteMapNode GetParentNode (SiteMapNode node);
101                 
102                 public virtual SiteMapNode GetParentNodeRelativeToCurrentNodeAndHintDownFromParent (int walkupLevels, int relativeDepthFromWalkup)
103                 {
104                         if (walkupLevels < 0) throw new ArgumentOutOfRangeException ("walkupLevels");
105                         if (relativeDepthFromWalkup < 0) throw new ArgumentOutOfRangeException ("relativeDepthFromWalkup");
106                         
107                         SiteMapNode node = GetCurrentNodeAndHintAncestorNodes (walkupLevels);
108                         for (int n=0; n<walkupLevels && node != null; n++)
109                                 node = GetParentNode (node);
110                                 
111                         if (node == null) return null;
112
113                         HintNeighborhoodNodes (node, 0, relativeDepthFromWalkup);
114                         return node;
115                 }
116                 
117                 public virtual SiteMapNode GetParentNodeRelativeToNodeAndHintDownFromParent (SiteMapNode node, int walkupLevels, int relativeDepthFromWalkup)
118                 {
119                         if (walkupLevels < 0) throw new ArgumentOutOfRangeException ("walkupLevels");
120                         if (relativeDepthFromWalkup < 0) throw new ArgumentOutOfRangeException ("relativeDepthFromWalkup");
121                         if (node == null) throw new ArgumentNullException ("node");
122                         
123                         HintAncestorNodes (node, walkupLevels);
124                         for (int n=0; n<walkupLevels && node != null; n++)
125                                 node = GetParentNode (node);
126                                 
127                         if (node == null) return null;
128                         
129                         HintNeighborhoodNodes (node, 0, relativeDepthFromWalkup);
130                         return node;
131                 }
132                 
133                 protected internal abstract SiteMapNode GetRootNodeCore ();
134                 
135                 protected static SiteMapNode GetRootNodeCoreFromProvider (SiteMapProvider provider)
136                 {
137                         return provider.GetRootNodeCore ();
138                 }
139                 
140                 public virtual void HintAncestorNodes (SiteMapNode node, int upLevel)
141                 {
142                         if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
143                         if (node == null) throw new ArgumentNullException ("node");
144                 }
145                 
146                 public virtual void HintNeighborhoodNodes (SiteMapNode node, int upLevel, int downLevel)
147                 {
148                         if (upLevel < -1) throw new ArgumentOutOfRangeException ("upLevel");
149                         if (downLevel < -1) throw new ArgumentOutOfRangeException ("downLevel");
150                         if (node == null) throw new ArgumentNullException ("node");
151                 }
152                 
153                 protected virtual void RemoveNode (SiteMapNode node)
154                 {
155                         throw new NotImplementedException ();
156                 }
157
158                 public override void Initialize (string name, NameValueCollection attributes)
159                 {
160                         base.Initialize (name, attributes);
161                         if (attributes["securityTrimmingEnabled"] != null)
162                                 securityTrimming = (bool) Convert.ChangeType (attributes ["securityTrimmingEnabled"], typeof(bool));
163                 }
164                 
165                 [MonoTODO ("need to implement cases 2 and 3")]
166                 public virtual bool IsAccessibleToUser (HttpContext context, SiteMapNode node)
167                 {
168                         if (context == null) throw new ArgumentNullException ("context");
169                         if (node == null) throw new ArgumentNullException ("node");
170
171                         /* the node is accessible (according to msdn2)
172                          * if:
173                          *
174                          * 1. the current user is in the node's Roles.
175                          *
176                          * 2. the current thread's WindowsIdentity has
177                          * file access to the url. (and the url is
178                          * located within the current application).
179                          *
180                          * 3. the <authorization> configuration element
181                          * lists the current user as being authorized
182                          * for the node's url. (and the url is located
183                          * within the current application)
184                         */
185
186                         /* 1. */
187                         if (node.Roles != null)
188                                 foreach (string rolename in node.Roles)
189                                         if (context.User.IsInRole (rolename))
190                                                 return true;
191
192                         /* 2. */
193                         /* XXX */
194
195                         AuthorizationSection config = (AuthorizationSection) WebConfigurationManager.GetSection (
196                                 "system.web/authorization",
197                                 node.Url);
198                         if (config != null)
199                                 return config.IsValidUser (context.User, context.Request.HttpMethod);
200
201                         return false;
202                 }
203                 
204                 public virtual SiteMapNode CurrentNode {
205                         get {
206                                 if (HttpContext.Current != null) {
207                                         SiteMapNode ret = ResolveSiteMapNode (HttpContext.Current);
208                                         if (ret != null) return ret;
209                                         return FindSiteMapNode (HttpContext.Current);
210                                 } else
211                                         return null;
212                         }
213                 }
214                 
215                 public virtual SiteMapProvider ParentProvider {
216                         get { return parentProvider; }
217                         set { parentProvider = value; }
218                 }
219                 
220                 public virtual SiteMapProvider RootProvider {
221                         get {
222                                 lock (this) {
223                                         if (rootProviderCache == null) {
224                                                 SiteMapProvider current = this;
225                                                 while (current.ParentProvider != null)
226                                                         current = current.ParentProvider;
227                                                 
228                                                 rootProviderCache = current;
229                                         }
230                                 }
231                                 return rootProviderCache;
232                         }
233                 }
234                 
235                 protected SiteMapNode ResolveSiteMapNode (HttpContext context)
236                 {
237                         SiteMapResolveEventArgs args = new SiteMapResolveEventArgs (context, this);
238                         if (SiteMapResolve != null) {
239                                 lock (resolveLock) {
240                                         if (resolving) return null;
241                                         resolving = true;
242                                         SiteMapNode r = SiteMapResolve (this, args);
243                                         resolving = false;
244                                         return r;
245                                 }
246                         }
247                         else
248                                 return null;
249                 }
250                 
251                 public bool EnableLocalization {
252                         get { return enableLocalization; }
253                         set { enableLocalization = value; }
254                 }
255                 
256                 public bool SecurityTrimmingEnabled {
257                         get { return securityTrimming; }
258                 }
259
260                 string resourceKey;
261                 public string ResourceKey {
262                         get { return resourceKey; }
263                         set { resourceKey = value; }
264                 }
265
266                 public virtual SiteMapNode RootNode {
267                         get {
268                                 SiteMapNode node = GetRootNodeCore ();
269                                 return ReturnNodeIfAccessible (node);
270                         }
271                 }
272
273                 public event SiteMapResolveEventHandler SiteMapResolve;
274
275                 internal static SiteMapNode ReturnNodeIfAccessible (SiteMapNode node)
276                 {
277                         if (node.IsAccessibleToUser (HttpContext.Current))
278                                 return node;
279                         else
280                                 throw new InvalidOperationException (); /* need
281                                                                          * a
282                                                                          * message
283                                                                          * here */
284                 }
285         }
286 }
287 #endif
288