2005-06-25 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web.Compilation / CachingCompiler.cs
1 //
2 // System.Web.Compilation.CachingCompiler
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2002 Ximian, Inc (http://www.ximian.com)
8 // (c) Copyright Novell, Inc. (http://www.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.CodeDom.Compiler;
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.IO;
36 using System.Reflection;
37 using System.Web.UI;
38 using System.Web.Caching;
39 using System.Web.Configuration;
40
41 namespace System.Web.Compilation
42 {
43         class CachingCompiler
44         {
45                 static string dynamicBase = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
46                 static object compilationLock = new object ();
47                 const string cachePrefix = "@@Assembly";
48                 const string cacheTypePrefix = "@@@Type";
49
50                 public static void InsertType (Type type, string filename)
51                 {
52                         string [] cacheKeys = new string [] { cachePrefix + filename };
53                         CacheDependency dep = new CacheDependency (null, cacheKeys);
54                         HttpRuntime.Cache.InsertPrivate (cacheTypePrefix + filename, type, dep);
55                 }
56
57                 public static Type GetTypeFromCache (string filename)
58                 {
59                         return (Type) HttpRuntime.Cache [cacheTypePrefix + filename];
60                 }
61
62                 public static CompilerResults Compile (BaseCompiler compiler)
63                 {
64                         Cache cache = HttpRuntime.Cache;
65                         string key = cachePrefix + compiler.Parser.InputFile;
66                         CompilerResults results = (CompilerResults) cache [key];
67                         if (results != null)
68                                 return results;
69
70                         lock (compilationLock) {
71                                 results = (CompilerResults) cache [key];
72                                 if (results != null)
73                                         return results;
74
75                                 ICodeCompiler comp = compiler.Compiler;
76                                 results = comp.CompileAssemblyFromDom (compiler.CompilerParameters, compiler.Unit);
77                                 string [] deps = (string []) compiler.Parser.Dependencies.ToArray (typeof (string));
78                                 cache.InsertPrivate (key, results, new CacheDependency (deps));
79                         }
80
81                         return results;
82                 }
83
84                 public static CompilerResults Compile (WebServiceCompiler compiler)
85                 {
86                         string key = cachePrefix + compiler.Parser.PhysicalPath;
87                         Cache cache = HttpRuntime.Cache;
88                         CompilerResults results = (CompilerResults) cache [key];
89                         if (results != null)
90                                 return results;
91
92                         lock (compilationLock) {
93                                 results = (CompilerResults) cache [key];
94                                 if (results != null)
95                                         return results;
96
97                                 SimpleWebHandlerParser parser = compiler.Parser;
98                                 CompilerParameters options = compiler.CompilerOptions;
99                                 options.IncludeDebugInformation = parser.Debug;
100                                 results = compiler.Compiler.CompileAssemblyFromFile (options, compiler.InputFile);
101                                 string [] deps = (string []) parser.Dependencies.ToArray (typeof (string));
102                                 cache.InsertPrivate (key, results, new CacheDependency (deps));
103                         }
104
105                         return results;
106                 }
107
108                 internal static CompilerParameters GetOptions (ICollection assemblies)
109                 {
110                         CompilerParameters options = new CompilerParameters ();
111                         if (assemblies != null) {
112                                 StringCollection coll = options.ReferencedAssemblies;
113                                 foreach (string str in assemblies)
114                                         coll.Add (str);
115                         }
116
117                         return options;
118                 }
119
120                 public static CompilerResults Compile (string language, string key, string file,
121                                                         ArrayList assemblies)
122                 {
123                         Cache cache = HttpRuntime.Cache;
124                         CompilerResults results = (CompilerResults) cache [cachePrefix + key];
125                         if (results != null)
126                                 return results;
127
128                         if (!Directory.Exists (dynamicBase))
129                                 Directory.CreateDirectory (dynamicBase);
130
131                         lock (compilationLock) {
132                                 results = (CompilerResults) cache [cachePrefix + key];
133                                 if (results != null)
134                                         return results;
135  
136                                 CompilationConfiguration config;
137                                 config = CompilationConfiguration.GetInstance (HttpContext.Current);
138                                 CodeDomProvider provider = config.GetProvider (language);
139                                 if (provider == null)
140                                         throw new HttpException ("Configuration error. Language not supported: " +
141                                                                   language, 500);
142
143                                 ICodeCompiler compiler = provider.CreateCompiler ();
144                                 CompilerParameters options = GetOptions (assemblies);
145                                 TempFileCollection tempcoll = new TempFileCollection (config.TempDirectory, true);
146                                 string dllfilename = Path.GetFileName (tempcoll.AddExtension ("dll", true));
147                                 options.OutputAssembly = Path.Combine (dynamicBase, dllfilename);
148                                 results = compiler.CompileAssemblyFromFile (options, file);
149                                 ArrayList realdeps = new ArrayList (assemblies.Count + 1);
150                                 realdeps.Add (file);
151                                 for (int i = assemblies.Count - 1; i >= 0; i--) {
152                                         string current = (string) assemblies [i];
153                                         if (Path.IsPathRooted (current))
154                                                 realdeps.Add (current);
155                                 }
156
157                                 string [] deps = (string []) realdeps.ToArray (typeof (string));
158                                 cache.InsertPrivate (cachePrefix + key, results, new CacheDependency (deps));
159                         }
160
161                         return results;
162                 }
163
164                 public static Type CompileAndGetType (string typename, string language, string key,
165                                                 string file, ArrayList assemblies)
166                 {
167                         CompilerResults result = CachingCompiler.Compile (language, key, file, assemblies);
168                         if (result.NativeCompilerReturnValue != 0) {
169                                 StreamReader reader = new StreamReader (file);
170                                 throw new CompilationException (file, result.Errors, reader.ReadToEnd ());
171                         }
172
173                         Assembly assembly = result.CompiledAssembly;
174                         if (assembly == null) {
175                                 StreamReader reader = new StreamReader (file);
176                                 throw new CompilationException (file, result.Errors, reader.ReadToEnd ());
177                         }
178                 
179                         Type type = assembly.GetType (typename, true);
180                         InsertType (type, file);
181                         return type;
182                 }
183         }
184 }
185