2007-05-22 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Compilation / AspComponentFoundry.cs
1 //
2 // System.Web.Compilation.AspComponentFoundry
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 using System;
31 using System.Collections;
32 using System.IO;
33 using System.Reflection;
34
35 #if NET_2_0
36 using System.Collections.Generic;
37 using System.Web;
38 using System.Web.Configuration;
39 using System.Web.UI;
40 #endif
41
42 namespace System.Web.Compilation
43 {
44         internal class AspComponentFoundry
45         {
46                 private Hashtable foundries;
47
48                 public AspComponentFoundry ()
49                 {
50 #if NET_2_0
51                         foundries = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
52 #else
53                         foundries = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
54                                                    CaseInsensitiveComparer.DefaultInvariant);
55 #endif
56
57                         Assembly sw = typeof (AspComponentFoundry).Assembly;
58                         RegisterFoundry ("asp", sw, "System.Web.UI.WebControls");
59                         RegisterFoundry ("", "object", typeof (System.Web.UI.ObjectTag));
60
61 #if NET_2_0
62                         RegisterConfigControls ();
63 #endif
64                 }
65
66                 public Type GetComponentType (string foundryName, string tag)
67                 {
68                         Foundry foundry = foundries [foundryName] as Foundry;
69                         if (foundry == null)
70                                 return null;
71
72                         return foundry.GetType (tag);
73                 }
74
75                 public void RegisterFoundry (string foundryName,
76                                              Assembly assembly,
77                                              string nameSpace)
78                 {
79                         AssemblyFoundry foundry = new AssemblyFoundry (assembly, nameSpace);
80                         InternalRegister (foundryName, foundry);
81                 }
82
83                 public void RegisterFoundry (string foundryName,
84                                              string tagName,
85                                              Type type)
86                 {
87                         TagNameFoundry foundry = new TagNameFoundry (tagName, type);
88                         InternalRegister (foundryName, foundry);
89                 }
90
91 #if NET_2_0
92                 public void RegisterFoundry (string foundryName,
93                                              string tagName,
94                                              string source)
95                 {
96                         TagNameFoundry foundry = new TagNameFoundry (tagName, source);
97                         InternalRegister (foundryName, foundry);
98                 }
99
100                 public void RegisterAssemblyFoundry (string foundryName,
101                                                      string assemblyName,
102                                                      string nameSpace)
103                 {
104                         AssemblyFoundry foundry = new AssemblyFoundry (assemblyName, nameSpace);
105                         InternalRegister (foundryName, foundry);
106                 }               
107
108                 void RegisterConfigControls ()
109                 {
110                         PagesSection pages = WebConfigurationManager.GetSection ("system.web/pages") as PagesSection;
111                         if (pages == null)
112                                 return;
113
114                         TagPrefixCollection controls = pages.Controls;
115                         if (controls == null || controls.Count == 0)
116                                 return;
117                         
118                         IList appCode = BuildManager.CodeAssemblies;
119                         bool haveCodeAssemblies = appCode != null && appCode.Count > 0;
120                         Assembly asm;
121                         foreach (TagPrefixInfo tpi in controls) {
122                                 if (!String.IsNullOrEmpty (tpi.TagName))
123                                         RegisterFoundry (tpi.TagPrefix, tpi.TagName, tpi.Source);
124                                 else if (String.IsNullOrEmpty (tpi.Assembly)) {
125                                         if (haveCodeAssemblies) {
126                                                 foreach (object o in appCode) {
127                                                         asm = o as Assembly;
128                                                         if (asm == null)
129                                                                 continue;
130                                                         RegisterFoundry (tpi.TagPrefix, asm, tpi.Namespace);
131                                                 }
132                                         }
133                                 } else if (!String.IsNullOrEmpty (tpi.Namespace))
134                                         RegisterAssemblyFoundry (tpi.TagPrefix,
135                                                                  tpi.Assembly,
136                                                                  tpi.Namespace);
137                         }
138                 }
139 #endif
140                 
141                 void InternalRegister (string foundryName, Foundry foundry)
142                 {
143                         object f = foundries [foundryName];
144                         if (f is CompoundFoundry) {
145                                 ((CompoundFoundry) f).Add (foundry);
146                         } else if (f == null || (f is AssemblyFoundry && foundry is AssemblyFoundry)) {
147                                 // If more than 1 namespace/assembly specified, the last one is used.
148                                 foundries [foundryName] = foundry;
149                         } else if (f != null) {
150                                 CompoundFoundry compound = new CompoundFoundry (foundryName);
151                                 compound.Add ((Foundry) f);
152                                 compound.Add (foundry);
153                                 foundries [foundryName] = compound;
154                         }
155                 }
156
157                 public bool LookupFoundry (string foundryName)
158                 {
159                         return foundries.Contains (foundryName);
160                 }
161
162                 abstract class Foundry
163                 {
164                         public abstract Type GetType (string componentName);
165                 }
166                 
167
168                 class TagNameFoundry : Foundry
169                 {
170                         string tagName;
171                         Type type;
172
173 #if NET_2_0
174                         string source;
175
176                         public bool FromWebConfig {
177                                 get { return source != null; }
178                         }
179                         
180                         public TagNameFoundry (string tagName, string source)
181                         {
182                                 this.tagName = tagName;
183                                 this.source = source;
184                         }
185 #endif
186                         
187                         public TagNameFoundry (string tagName, Type type)
188                         {
189                                 this.tagName = tagName;
190                                 this.type = type;
191                         }
192
193                         public override Type GetType (string componentName)
194                         {
195                                 if (0 != String.Compare (componentName, tagName, true))
196                                         return null;
197
198                                 return LoadType ();
199                         }
200
201                         Type LoadType ()
202                         {
203 #if NET_2_0
204                                 if (type != null)
205                                         return type;
206
207                                 HttpContext context = HttpContext.Current;
208                                 string vpath;
209                                 string realpath;
210                                 
211                                 if (VirtualPathUtility.IsAppRelative (source)) {
212                                         vpath = source;
213                                         realpath = context.Request.MapPath (source);
214                                 } else {
215                                         vpath = VirtualPathUtility.ToAppRelative (source);
216                                         realpath = source;
217                                 }
218                                 
219                                 if ((type = CachingCompiler.GetTypeFromCache (realpath)) != null)
220                                         return type;
221                                 
222                                 ArrayList other_deps = new ArrayList ();
223                                 type = UserControlParser.GetCompiledType (vpath, realpath, other_deps, context);
224                                 if (type != null) {
225                                         AspGenerator.AddTypeToCache (other_deps, realpath, type);
226                                         WebConfigurationManager.ExtraAssemblies.Add (type.Assembly.Location);
227                                 }
228                                 return type;
229 #else
230                                 return type;
231 #endif
232                         }
233                         
234                         public string TagName {
235                                 get { return tagName; }
236                         }
237                 }
238
239                 class AssemblyFoundry : Foundry
240                 {
241                         string nameSpace;
242                         Assembly assembly;
243 #if NET_2_0
244                         string assemblyName;
245                         Dictionary <string, Assembly> assemblyCache;
246 #endif
247                         
248                         public AssemblyFoundry (Assembly assembly, string nameSpace)
249                         {
250                                 this.assembly = assembly;
251                                 this.nameSpace = nameSpace;
252 #if NET_2_0
253                                 if (assembly != null)
254                                         this.assemblyName = assembly.FullName;
255                                 else
256                                         this.assemblyName = null;
257 #endif
258                         }
259
260 #if NET_2_0
261                         public AssemblyFoundry (string assemblyName, string nameSpace)
262                         {
263                                 this.assembly = null;
264                                 this.nameSpace = nameSpace;
265                                 this.assemblyName = assemblyName;
266                         }
267 #endif
268                         
269                         public override Type GetType (string componentName)
270                         {
271 #if NET_2_0
272                                 if (assembly == null && assemblyName != null)
273                                         assembly = GetAssemblyByName (assemblyName, true);
274 #endif
275                                 string typeName = String.Format ("{0}.{1}", nameSpace, componentName);
276                                 if (assembly != null)
277                                         return assembly.GetType (typeName, true, true);
278
279 #if NET_2_0
280                                 IList tla = BuildManager.TopLevelAssemblies;
281                                 if (tla != null && tla.Count > 0) {
282                                         Type ret = null;
283                                         foreach (Assembly asm in tla) {
284                                                 if (asm == null)
285                                                         continue;
286                                                 ret = asm.GetType (typeName, false, true);
287                                                 if (ret != null)
288                                                         return ret;
289                                         }
290                                 }
291 #endif
292                                 return null;
293                         }
294
295 #if NET_2_0
296                         Assembly GetAssemblyByName (string name, bool throwOnMissing)
297                         {
298                                 if (assemblyCache == null)
299                                         assemblyCache = new Dictionary <string, Assembly> ();
300                                 
301                                 if (assemblyCache.ContainsKey (name))
302                                         return assemblyCache [name];
303                                 
304                                 Assembly assembly = null;
305                                 Exception error = null;
306                                 if (name.IndexOf (',') != -1) {
307                                         try {
308                                                 assembly = Assembly.Load (name);
309                                         } catch (Exception e) { error = e; }
310                                 }
311
312                                 if (assembly == null) {
313                                         try {
314                                                 assembly = Assembly.LoadWithPartialName (name);
315                                         } catch (Exception e) { error = e; }
316                                 }
317                         
318                                 if (assembly == null)
319                                         if (throwOnMissing)
320                                                 throw new HttpException ("Assembly " + name + " not found", error);
321                                         else
322                                                 return null;
323
324                                 assemblyCache.Add (name, assembly);
325                                 return assembly;
326                         }
327 #endif
328                 }
329
330                 class CompoundFoundry : Foundry
331                 {
332                         AssemblyFoundry assemblyFoundry;
333                         Hashtable tagnames;
334                         string tagPrefix;
335
336                         public CompoundFoundry (string tagPrefix)
337                         {
338                                 this.tagPrefix = tagPrefix;
339 #if NET_2_0
340                                 tagnames = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
341 #else
342                                 tagnames = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
343                                                           CaseInsensitiveComparer.DefaultInvariant);
344 #endif
345                         }
346
347                         public void Add (Foundry foundry)
348                         {
349                                 if (foundry is AssemblyFoundry) {
350                                         assemblyFoundry = (AssemblyFoundry) foundry;
351                                         return;
352                                 }
353                                 
354                                 TagNameFoundry tn = (TagNameFoundry) foundry;
355                                 string tagName = tn.TagName;
356                                 if (tagnames.Contains (tagName)) {
357 #if NET_2_0
358                                         if (tn.FromWebConfig)
359                                                 return;
360 #endif
361                                         string msg = String.Format ("{0}:{1} already registered.", tagPrefix, tagName);
362                                         throw new ApplicationException (msg);
363                                 }
364                                 tagnames.Add (tagName, foundry);
365                         }
366
367                         public override Type GetType (string componentName)
368                         {
369                                 Type type = null;
370                                 Foundry foundry = tagnames [componentName] as Foundry;
371                                 if (foundry != null)
372                                         return foundry.GetType (componentName);
373
374                                 if (assemblyFoundry != null) {
375                                         try {
376                                                 type = assemblyFoundry.GetType (componentName);
377                                                 return type;
378                                         } catch { }
379                                 }
380
381                                 string msg = String.Format ("Type {0} not registered for prefix {1}",
382                                                             componentName, tagPrefix);
383                                 throw new ApplicationException (msg);
384                         }
385                 }
386         }
387 }