2009-06-25 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web.DynamicData / System.Web.DynamicData / DynamicDataRouteHandler.cs
1 //
2 // DynamicDataRouteHandler.cs
3 //
4 // Authors:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //      Marek Habersack <mhabersack@novell.com>
7 //
8 // Copyright (C) 2008-2009 Novell Inc. http://novell.com
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 using System;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Collections.Specialized;
35 using System.Data.Linq.Mapping;
36 using System.Globalization;
37 using System.Security.Permissions;
38 using System.Security.Principal;
39 using System.Threading;
40 using System.Web.Caching;
41 using System.Web.Compilation;
42 using System.Web.Routing;
43 using System.Web.UI;
44
45 namespace System.Web.DynamicData
46 {
47         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
49         public class DynamicDataRouteHandler : IRouteHandler
50         {
51                 static ReaderWriterLockSlim contextsLock = new ReaderWriterLockSlim ();
52                 
53                 static Dictionary <HttpContext, RouteContext> contexts = new Dictionary <HttpContext, RouteContext> ();
54                 Dictionary <RouteContext, IHttpHandler> handlers;
55
56                 Dictionary <RouteContext, IHttpHandler> Handlers {
57                         get {
58                                 if (handlers == null)
59                                         handlers = new Dictionary <RouteContext, IHttpHandler> ();
60
61                                 return handlers;
62                         }
63                 }
64
65                 public static RequestContext GetRequestContext (HttpContext httpContext)
66                 {
67                         if (httpContext == null)
68                                 throw new ArgumentNullException ("httpContext");
69                         
70                         RouteContext rc;
71                         bool locked = false;
72                         try {
73                                 contextsLock.EnterReadLock ();
74                                 locked = true;
75                                 if (contexts.TryGetValue (httpContext, out rc) && rc != null)
76                                         return rc.Context;
77                         } finally {
78                                 if (locked)
79                                         contextsLock.ExitReadLock ();
80                         }
81
82                         var ctxWrapper = new HttpContextWrapper (httpContext);
83                         RouteData rd = RouteTable.Routes.GetRouteData (ctxWrapper);
84                         if (rd == null)
85                                 rd = new RouteData ();
86                         
87                         var ret = new RequestContext (ctxWrapper, rd);
88
89                         locked = false;
90                         try {
91                                 contextsLock.EnterWriteLock ();
92                                 locked = true;
93                                 contexts.Add (httpContext, MakeRouteContext (ret, null, null, null));
94                         } finally {
95                                 if (locked)
96                                         contextsLock.ExitWriteLock ();
97                         }
98
99                         return ret;
100                 }
101
102                 public static MetaTable GetRequestMetaTable (HttpContext httpContext)
103                 {
104                         if (httpContext == null)
105                                 throw new ArgumentNullException ("httpContext");
106
107                         RouteContext rc;
108                         bool locked = false;
109                         try {
110                                 contextsLock.EnterReadLock ();
111                                 locked = true;
112                                 if (contexts.TryGetValue (httpContext, out rc) && rc != null)
113                                         return rc.Table;
114                         } finally {
115                                 if (locked)
116                                         contextsLock.ExitReadLock ();
117                         }
118
119                         return null;
120                 }
121
122                 [MonoTODO]
123                 public static void SetRequestMetaTable (HttpContext httpContext, MetaTable table)
124                 {
125                         throw new NotImplementedException ();
126                 }
127
128                 public DynamicDataRouteHandler ()
129                 {
130                 }
131
132                 public MetaModel Model { get; internal set; }
133
134                 [MonoTODO]
135                 public virtual IHttpHandler CreateHandler (DynamicDataRoute route, MetaTable table, string action)
136                 {
137                         var vp = String.Concat (String.Concat (HttpContext.Current.Request.ApplicationPath, "DynamicData/PageTemplates/", action, ".aspx"));
138                         return (IHttpHandler) BuildManager.CreateInstanceFromVirtualPath (vp, typeof (Page));
139                 }
140
141                 [MonoTODO]
142                 protected virtual string GetCustomPageVirtualPath (MetaTable table, string viewName)
143                 {
144                         throw new NotImplementedException ();
145                 }
146
147                 [MonoTODO]
148                 protected virtual string GetScaffoldPageVirtualPath (MetaTable table, string viewName)
149                 {
150                         throw new NotImplementedException ();
151                 }
152
153                 IHttpHandler IRouteHandler.GetHttpHandler (RequestContext requestContext)
154                 {
155                         if (requestContext == null)
156                                 throw new ArgumentNullException ("requestContext");
157                         RouteData rd = requestContext.RouteData;
158                         var dr = rd.Route as DynamicDataRoute;
159                         if (dr == null)
160                                 throw new ArgumentException ("The argument RequestContext does not have DynamicDataRoute in its RouteData");
161                         string action = dr.GetActionFromRouteData (rd);
162                         MetaTable mt = dr.GetTableFromRouteData (rd);
163                         RouteContext rc = MakeRouteContext (requestContext, dr, action, mt);
164                         IHttpHandler h;
165                         
166                         Dictionary <RouteContext, IHttpHandler> handlers = Handlers;
167                         if (handlers.TryGetValue (rc, out h))
168                                 return h;
169                         h = CreateHandler (dr, mt, action);
170                         handlers.Add (rc, h);
171                         return h;
172                 }
173
174                 static RouteContext MakeRouteContext (RequestContext context, DynamicDataRoute route, string action, MetaTable table)
175                 {
176                         RouteData rd = null;
177                         
178                         if (route == null) {
179                                 rd = context.RouteData;
180                                 route = rd.Route as DynamicDataRoute;
181                         }
182
183                         if (route != null) {
184                                 if (action == null) {
185                                         if (rd == null)
186                                                 rd = context.RouteData;
187                                         action = route.GetActionFromRouteData (rd);
188                                 }
189                         
190                                 if (table == null) {
191                                         if (rd == null)
192                                                 rd = context.RouteData;
193                                 
194                                         table = route.GetTableFromRouteData (rd);
195                                 }
196                         }
197                         
198                         return new RouteContext () {
199                                 Route = route,
200                                 Action = action,
201                                 Table = table,
202                                 Context = context};
203                 }
204                 
205                 sealed class RouteContext
206                 {
207                         public DynamicDataRoute Route;
208                         public string Action;
209                         public MetaTable Table;
210                         public RequestContext Context;
211
212                         public RouteContext ()
213                         {
214                         }
215                         
216                         public override bool Equals (object obj)
217                         {
218                                 RouteContext other = obj as RouteContext;
219                                 return other.Route == Route & other.Action == Action && other.Table == Table && other.Context == Context;
220                         }
221
222                         public override int GetHashCode ()
223                         {
224                                 return (Route != null ? Route.GetHashCode () << 27 : 0) +
225                                         (Action != null ? Action.GetHashCode () << 19 : 0) +
226                                         (Table != null ? Table.GetHashCode () << 9 : 0) +
227                                         (Context != null ? Context.GetHashCode () : 0);
228                         }
229                 }
230         }
231 }