Merge pull request #1032 from miguelzf/master
[mono.git] / mcs / class / System.Web / System.Web.Compilation / GenericBuildProvider.cs
1 //
2 // System.Web.Compilation.GenericBuildProvider
3 //
4 // Authors:
5 //   Marek Habersack (mhabersack@novell.com)
6 //
7 // (C) 2008 Novell, Inc
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
31 using System;
32 using System.CodeDom;
33 using System.CodeDom.Compiler;
34 using System.Collections;
35 using System.Collections.Generic;
36 using System.IO;
37 using System.Reflection;
38 using System.Web;
39 using System.Web.UI;
40
41 namespace System.Web.Compilation
42 {
43         internal abstract class GenericBuildProvider <TParser> : BuildProvider
44         {
45                 TParser _parser;
46                 CompilerType _compilerType;
47                 BaseCompiler _compiler;
48                 TextReader _reader;
49                 bool _parsed;
50                 bool _codeGenerated;
51
52                 protected bool Parsed {
53                         get { return _parsed; }
54                 }
55                 
56                 protected abstract TParser CreateParser (VirtualPath virtualPath, string physicalPath, TextReader reader, HttpContext context);
57                 protected abstract TParser CreateParser (VirtualPath virtualPath, string physicalPath, HttpContext context);
58                 protected abstract BaseCompiler CreateCompiler (TParser parser);
59                 protected abstract string GetParserLanguage (TParser parser);
60                 protected abstract ICollection GetParserDependencies (TParser parser);
61                 protected abstract string GetCodeBehindSource (TParser parser);
62                 protected abstract string GetClassType (BaseCompiler compiler, TParser parser);
63                 protected abstract AspGenerator CreateAspGenerator (TParser parser);
64                 protected abstract List <string> GetReferencedAssemblies (TParser parser);
65
66                 protected virtual string MapPath (VirtualPath virtualPath)
67                 {
68                         HttpContext ctx = HttpContext.Current;
69                         HttpRequest req = ctx != null ? ctx.Request : null;
70
71                         if (req != null)
72                                 return req.MapPath (VirtualPath);
73                         else
74                                 return null;
75                 }
76                 
77                 protected virtual TParser Parse ()
78                 {
79                         TParser parser = Parser;
80                         
81                         if (_parsed)
82                                 return parser;
83
84                         if (!IsDirectoryBuilder) {
85                                 AspGenerator generator = CreateAspGenerator (parser);
86                                 if (_reader != null)
87                                         generator.Parse (_reader, MapPath (VirtualPathInternal), true);
88                                 else
89                                         generator.Parse ();
90                         }
91                         
92                         _parsed = true;
93                         return parser;
94                 }
95
96                 protected virtual void OverrideAssemblyPrefix (TParser parser, AssemblyBuilder assemblyBuilder)
97                 {
98                 }
99
100                 internal override void GenerateCode ()
101                 {
102                         TParser parser = Parse ();
103                         _compiler = CreateCompiler (parser);
104                         if (NeedsConstructType)
105                                 _compiler.ConstructType ();
106                         _codeGenerated = true;
107                 }
108                 
109                 protected virtual void GenerateCode (AssemblyBuilder assemblyBuilder, TParser parser, BaseCompiler compiler)
110                 {                               
111                         CodeCompileUnit unit = _compiler.CompileUnit;
112                         if (unit == null)
113                                 throw new HttpException ("Unable to generate source code.");
114                                 
115                         assemblyBuilder.AddCodeCompileUnit (this, unit);
116                 }
117                 
118                 public override void GenerateCode (AssemblyBuilder assemblyBuilder)
119                 {
120                         if (!_codeGenerated)
121                                 GenerateCode ();
122                         
123                         TParser parser = Parse ();
124                         OverrideAssemblyPrefix (parser, assemblyBuilder);
125                         
126                         string codeBehindSource = GetCodeBehindSource (parser);
127                         if (codeBehindSource != null)
128                                 assemblyBuilder.AddCodeFile (codeBehindSource, this, true);
129
130                         List <string> refasms = GetReferencedAssemblies (parser);
131                         if (refasms != null && refasms.Count > 0) {
132                                 foreach (string loc in refasms)
133                                         assemblyBuilder.AddAssemblyReference (loc);
134                         }
135                         
136                         GenerateCode (assemblyBuilder, parser, _compiler);
137                 }
138
139                 protected virtual Type LoadTypeFromBin (BaseCompiler compiler, TParser parser)
140                 {
141                         return null;
142                 }
143                 
144                 public override Type GetGeneratedType (CompilerResults results)
145                 {
146                         if (NeedsLoadFromBin && _compiler != null)
147                                 return LoadTypeFromBin (_compiler, Parser);
148                         
149                         Type type = null;
150                         Assembly assembly = results != null ? results.CompiledAssembly : null;
151                         if (assembly != null) {
152                                 type = assembly.GetType (GetClassType (_compiler, Parser));
153                         }
154                         if (type == null) {
155                                 throw new HttpException (500, String.Format ("Type {0} could not be loaded", GetClassType (_compiler, Parser)));
156                         }
157                         return type;
158                 }
159
160                 // This is intended to be used by builders which may need to do special processing
161                 // on the virtualPath before actually opening the reader.
162                 protected virtual TextReader SpecialOpenReader (VirtualPath virtualPath, out string physicalPath)
163                 {
164                         physicalPath = null;
165                         return OpenReader (virtualPath.Original);
166                 }
167                 
168                 // FIXME: figure this out.
169                 public override ICollection VirtualPathDependencies {
170                         get {
171                                 TParser parser = Parser;
172                                 return GetParserDependencies (parser);
173                         }
174                 }
175
176                 internal override string LanguageName {
177                         get {
178                                 TParser parser = Parse ();
179                                 if (parser != null)
180                                         return GetParserLanguage (parser);
181                                 return base.LanguageName;
182                         }
183                 }
184                 
185                 public override CompilerType CodeCompilerType {
186                         get {
187                                 if (_compilerType == null)
188                                         _compilerType = GetDefaultCompilerTypeForLanguage (LanguageName);
189
190                                 return _compilerType;
191                         }
192                 }
193
194                 public TParser Parser {
195                         get {
196                                 if (_parser == null) {
197                                         VirtualPath vp = VirtualPathInternal;
198                                         if (vp == null)
199                                                 throw new HttpException ("VirtualPath not set, cannot instantiate parser.");
200                                         
201                                         if (!IsDirectoryBuilder) {
202                                                 string physicalPath;
203                                                 _reader = SpecialOpenReader (vp, out physicalPath);
204                                                 _parser = CreateParser (vp, physicalPath, _reader, HttpContext.Current);
205                                         } else
206                                                 _parser = CreateParser (vp, null,  HttpContext.Current);
207                                         
208                                         if (_parser == null)
209                                                 throw new HttpException ("Unable to create type parser.");
210                                 }
211                                 
212                                 return _parser;
213                         }
214                 }
215
216                 protected virtual bool IsDirectoryBuilder {
217                         get { return false; }
218                 }
219
220                 protected virtual bool NeedsConstructType {
221                         get { return true; }
222                 }
223
224                 protected virtual bool NeedsLoadFromBin {
225                         get { return false; }
226                 }
227                 
228                 internal override CodeCompileUnit CodeUnit {
229                         get {
230                                 if (!_codeGenerated)
231                                         GenerateCode ();
232                                 return _compiler.CompileUnit;
233                         }
234                 }
235         }
236 }