for TARGET_J2EE only:
[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                         object o = foundries [foundryName];
69                         if (o == null)
70                                 return null;
71
72                         if (o is Foundry)
73                                 return ((Foundry)o).GetType (tag);
74
75                         ArrayList af = o as ArrayList;
76                         if (af == null)
77                                 return null;
78
79                         Type t;
80                         Exception e = null;
81                         foreach (Foundry f in af) {
82                                 try {
83                                         t = f.GetType (tag);
84                                         if (t != null)
85                                                 return t;
86                                 } catch (Exception ex) {
87                                         e = ex;
88                                 }
89                         }
90
91                         if (e != null)
92                                 throw e;
93                         
94                         return null;
95                 }
96
97                 public void RegisterFoundry (string foundryName,
98                                              Assembly assembly,
99                                              string nameSpace)
100                 {
101                         AssemblyFoundry foundry = new AssemblyFoundry (assembly, nameSpace);
102                         InternalRegister (foundryName, foundry);
103                 }
104
105                 public void RegisterFoundry (string foundryName,
106                                              string tagName,
107                                              Type type)
108                 {
109                         TagNameFoundry foundry = new TagNameFoundry (tagName, type);
110                         InternalRegister (foundryName, foundry);
111                 }
112
113 #if NET_2_0
114                 public void RegisterFoundry (string foundryName,
115                                              string tagName,
116                                              string source)
117                 {
118                         TagNameFoundry foundry = new TagNameFoundry (tagName, source);
119                         InternalRegister (foundryName, foundry);
120                 }
121
122                 public void RegisterAssemblyFoundry (string foundryName,
123                                                      string assemblyName,
124                                                      string nameSpace)
125                 {
126                         AssemblyFoundry foundry = new AssemblyFoundry (assemblyName, nameSpace);
127                         InternalRegister (foundryName, foundry);
128                 }               
129
130                 void RegisterConfigControls ()
131                 {
132                         PagesSection pages = WebConfigurationManager.GetSection ("system.web/pages") as PagesSection;
133                         if (pages == null)
134                                 return;
135
136                         TagPrefixCollection controls = pages.Controls;
137                         if (controls == null || controls.Count == 0)
138                                 return;
139                         
140                         IList appCode = BuildManager.CodeAssemblies;
141                         bool haveCodeAssemblies = appCode != null && appCode.Count > 0;
142                         Assembly asm;
143                         foreach (TagPrefixInfo tpi in controls) {
144                                 if (!String.IsNullOrEmpty (tpi.TagName))
145                                         RegisterFoundry (tpi.TagPrefix, tpi.TagName, tpi.Source);
146                                 else if (String.IsNullOrEmpty (tpi.Assembly)) {
147                                         if (haveCodeAssemblies) {
148                                                 foreach (object o in appCode) {
149                                                         asm = o as Assembly;
150                                                         if (asm == null)
151                                                                 continue;
152                                                         RegisterFoundry (tpi.TagPrefix, asm, tpi.Namespace);
153                                                 }
154                                         }
155                                 } else if (!String.IsNullOrEmpty (tpi.Namespace))
156                                         RegisterAssemblyFoundry (tpi.TagPrefix,
157                                                                  tpi.Assembly,
158                                                                  tpi.Namespace);
159                         }
160                 }
161 #endif
162                 
163                 void InternalRegister (string foundryName, Foundry foundry)
164                 {
165                         object f = foundries [foundryName];
166                         Foundry newFoundry = null;
167                         
168                         if (f is CompoundFoundry) {
169                                 ((CompoundFoundry) f).Add (foundry);
170                                 return;
171                         } else if (f == null || f is ArrayList || (f is AssemblyFoundry && foundry is AssemblyFoundry)) {
172                                 newFoundry = foundry;
173                         } else if (f != null) {
174                                 CompoundFoundry compound = new CompoundFoundry (foundryName);
175                                 compound.Add ((Foundry) f);
176                                 compound.Add (foundry);
177                                 newFoundry = foundry;
178                         }
179
180                         if (newFoundry == null)
181                                 return;
182
183                         if (f == null) {
184                                 foundries [foundryName] = newFoundry;
185                                 return;
186                         }
187
188                         ArrayList af = f as ArrayList;
189                         if (af == null) {
190                                 af = new ArrayList (2);
191                                 af.Add (f);
192                                 foundries [foundryName] = af;
193                         }
194                         
195                         af.Insert (0, newFoundry);
196                 }
197
198                 public bool LookupFoundry (string foundryName)
199                 {
200                         return foundries.Contains (foundryName);
201                 }
202
203                 abstract class Foundry
204                 {
205                         public abstract Type GetType (string componentName);
206                 }
207                 
208
209                 class TagNameFoundry : Foundry
210                 {
211                         string tagName;
212                         Type type;
213
214 #if NET_2_0
215                         string source;
216
217                         public bool FromWebConfig {
218                                 get { return source != null; }
219                         }
220                         
221                         public TagNameFoundry (string tagName, string source)
222                         {
223                                 this.tagName = tagName;
224                                 this.source = source;
225                         }
226 #endif
227                         
228                         public TagNameFoundry (string tagName, Type type)
229                         {
230                                 this.tagName = tagName;
231                                 this.type = type;
232                         }
233
234                         public override Type GetType (string componentName)
235                         {
236                                 if (0 != String.Compare (componentName, tagName, true))
237                                         return null;
238
239                                 return LoadType ();
240                         }
241
242                         Type LoadType ()
243                         {
244 #if NET_2_0
245                                 if (type != null)
246                                         return type;
247
248                                 HttpContext context = HttpContext.Current;
249                                 string vpath;
250                                 string realpath;
251                                 
252                                 if (VirtualPathUtility.IsAppRelative (source)) {
253                                         vpath = source;
254                                         realpath = context.Request.MapPath (source);
255                                 } else {
256                                         vpath = VirtualPathUtility.ToAppRelative (source);
257                                         realpath = source;
258                                 }
259                                 
260                                 if ((type = CachingCompiler.GetTypeFromCache (realpath)) != null)
261                                         return type;
262                                 
263                                 ArrayList other_deps = new ArrayList ();
264                                 type = UserControlParser.GetCompiledType (vpath, realpath, other_deps, context);
265                                 if (type != null) {
266                                         AspGenerator.AddTypeToCache (other_deps, realpath, type);
267                                         WebConfigurationManager.ExtraAssemblies.Add (type.Assembly.Location);
268                                 }
269                                 return type;
270 #else
271                                 return type;
272 #endif
273                         }
274                         
275                         public string TagName {
276                                 get { return tagName; }
277                         }
278                 }
279
280                 class AssemblyFoundry : Foundry
281                 {
282                         string nameSpace;
283                         Assembly assembly;
284 #if NET_2_0
285                         string assemblyName;
286                         Dictionary <string, Assembly> assemblyCache;
287 #endif
288                         
289                         public AssemblyFoundry (Assembly assembly, string nameSpace)
290                         {
291                                 this.assembly = assembly;
292                                 this.nameSpace = nameSpace;
293 #if NET_2_0
294                                 if (assembly != null)
295                                         this.assemblyName = assembly.FullName;
296                                 else
297                                         this.assemblyName = null;
298 #endif
299                         }
300
301 #if NET_2_0
302                         public AssemblyFoundry (string assemblyName, string nameSpace)
303                         {
304                                 this.assembly = null;
305                                 this.nameSpace = nameSpace;
306                                 this.assemblyName = assemblyName;
307                         }
308 #endif
309                         
310                         public override Type GetType (string componentName)
311                         {
312 #if NET_2_0
313                                 if (assembly == null && assemblyName != null)
314                                         assembly = GetAssemblyByName (assemblyName, true);
315 #endif
316                                 string typeName = String.Concat (nameSpace, ".", componentName);
317                                 if (assembly != null)
318                                         return assembly.GetType (typeName, true, true);
319
320 #if NET_2_0
321                                 IList tla = BuildManager.TopLevelAssemblies;
322                                 if (tla != null && tla.Count > 0) {
323                                         Type ret = null;
324                                         foreach (Assembly asm in tla) {
325                                                 if (asm == null)
326                                                         continue;
327                                                 ret = asm.GetType (typeName, false, true);
328                                                 if (ret != null)
329                                                         return ret;
330                                         }
331                                 }
332 #endif
333                                 return null;
334                         }
335
336 #if NET_2_0
337                         Assembly GetAssemblyByName (string name, bool throwOnMissing)
338                         {
339                                 if (assemblyCache == null)
340                                         assemblyCache = new Dictionary <string, Assembly> ();
341                                 
342                                 if (assemblyCache.ContainsKey (name))
343                                         return assemblyCache [name];
344                                 
345                                 Assembly assembly = null;
346                                 Exception error = null;
347                                 if (name.IndexOf (',') != -1) {
348                                         try {
349                                                 assembly = Assembly.Load (name);
350                                         } catch (Exception e) { error = e; }
351                                 }
352
353                                 if (assembly == null) {
354                                         try {
355                                                 assembly = Assembly.LoadWithPartialName (name);
356                                         } catch (Exception e) { error = e; }
357                                 }
358                         
359                                 if (assembly == null)
360                                         if (throwOnMissing)
361                                                 throw new HttpException ("Assembly " + name + " not found", error);
362                                         else
363                                                 return null;
364
365                                 assemblyCache.Add (name, assembly);
366                                 return assembly;
367                         }
368 #endif
369                 }
370
371                 class CompoundFoundry : Foundry
372                 {
373                         AssemblyFoundry assemblyFoundry;
374                         Hashtable tagnames;
375                         string tagPrefix;
376
377                         public CompoundFoundry (string tagPrefix)
378                         {
379                                 this.tagPrefix = tagPrefix;
380 #if NET_2_0
381                                 tagnames = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
382 #else
383                                 tagnames = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
384                                                           CaseInsensitiveComparer.DefaultInvariant);
385 #endif
386                         }
387
388                         public void Add (Foundry foundry)
389                         {
390                                 if (foundry is AssemblyFoundry) {
391                                         assemblyFoundry = (AssemblyFoundry) foundry;
392                                         return;
393                                 }
394                                 
395                                 TagNameFoundry tn = (TagNameFoundry) foundry;
396                                 string tagName = tn.TagName;
397                                 if (tagnames.Contains (tagName)) {
398 #if NET_2_0
399                                         if (tn.FromWebConfig)
400                                                 return;
401 #endif
402                                         string msg = String.Format ("{0}:{1} already registered.", tagPrefix, tagName);
403                                         throw new ApplicationException (msg);
404                                 }
405                                 tagnames.Add (tagName, foundry);
406                         }
407
408                         public override Type GetType (string componentName)
409                         {
410                                 Type type = null;
411                                 Foundry foundry = tagnames [componentName] as Foundry;
412                                 if (foundry != null)
413                                         return foundry.GetType (componentName);
414
415                                 if (assemblyFoundry != null) {
416                                         try {
417                                                 type = assemblyFoundry.GetType (componentName);
418                                                 return type;
419                                         } catch { }
420                                 }
421
422                                 string msg = String.Format ("Type {0} not registered for prefix {1}",
423                                                             componentName, tagPrefix);
424                                 throw new ApplicationException (msg);
425                         }
426                 }
427         }
428 }