2008-11-18 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Compilation / PageCompiler.cs
1 //
2 // System.Web.Compilation.PageCompiler
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.CodeDom;
32 using System.Collections;
33 using System.IO;
34 using System.Reflection;
35 using System.Text;
36 using System.Web.Configuration;
37 using System.Web.UI;
38 using System.Web.SessionState;
39 using System.Web.Util;
40 #if NET_2_0
41 using System.Web.Profile;
42 #endif
43
44 namespace System.Web.Compilation
45 {
46         class PageCompiler : TemplateControlCompiler
47         {
48                 PageParser pageParser;
49                 static CodeTypeReference intRef = new CodeTypeReference (typeof (int));
50
51                 public PageCompiler (PageParser pageParser)
52                         : base (pageParser)
53                 {
54                         this.pageParser = pageParser;
55                 }
56
57                 protected override void CreateStaticFields ()
58                 {
59                         base.CreateStaticFields ();
60                         
61                         CodeMemberField fld = new CodeMemberField (
62 #if NET_2_0
63                                 typeof (object),
64 #else
65                                 typeof (ArrayList),
66 #endif
67                                 "__fileDependencies");
68                         fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
69                         fld.InitExpression = new CodePrimitiveExpression (null);
70                         mainClass.Members.Add (fld);
71                 }
72                 
73                 protected override void CreateConstructor (CodeStatementCollection localVars,
74                                                            CodeStatementCollection trueStmt)
75                 {
76                         if (pageParser.ClientTarget != null) {
77                                 CodeExpression prop;
78                                 prop = new CodePropertyReferenceExpression (thisRef, "ClientTarget");
79                                 CodeExpression ct = new CodePrimitiveExpression (pageParser.ClientTarget);
80                                 if (localVars == null)
81                                         localVars = new CodeStatementCollection ();
82                                 localVars.Add (new CodeAssignStatement (prop, ct));
83                         }
84
85                         ArrayList deps = pageParser.Dependencies;
86                         int depsCount = deps != null ? deps.Count : 0;
87                         
88                         if (depsCount > 0) {
89                                 if (localVars == null)
90                                         localVars = new CodeStatementCollection ();
91                                 if (trueStmt == null)
92                                         trueStmt = new CodeStatementCollection ();
93
94                                 CodeAssignStatement assign;
95 #if NET_2_0
96                                 localVars.Add (
97                                         new CodeVariableDeclarationStatement (
98                                                 typeof (string[]),
99                                                 "dependencies")
100                                 );
101
102                                 CodeVariableReferenceExpression dependencies = new CodeVariableReferenceExpression ("dependencies");
103                                 trueStmt.Add (
104                                         new CodeAssignStatement (dependencies, new CodeArrayCreateExpression (typeof (string), depsCount))
105                                 );
106                                 
107                                 CodeArrayIndexerExpression arrayIndex;
108                                 object o;
109                                 
110                                 for (int i = 0; i < depsCount; i++) {
111                                         o = deps [i];
112                                         arrayIndex = new CodeArrayIndexerExpression (dependencies, new CodeExpression[] {new CodePrimitiveExpression (i)});
113                                         assign = new CodeAssignStatement (arrayIndex, new CodePrimitiveExpression (o));
114                                         trueStmt.Add (assign);
115                                 }
116                                 
117                                 CodeMethodInvokeExpression getDepsCall = new CodeMethodInvokeExpression (
118                                         thisRef,
119                                         "GetWrappedFileDependencies",
120                                         new CodeExpression[] {dependencies}
121                                 );
122                                 assign = new CodeAssignStatement (GetMainClassFieldReferenceExpression ("__fileDependencies"), getDepsCall);
123 #else
124                                 localVars.Add (new CodeVariableDeclarationStatement (
125                                                 typeof (ArrayList),
126                                                 "dependencies")
127                                 );
128
129                                 CodeVariableReferenceExpression dependencies = new CodeVariableReferenceExpression ("dependencies");
130                                 trueStmt.Add (
131                                         new CodeAssignStatement (dependencies, new CodeObjectCreateExpression (typeof (ArrayList), new CodeExpression[] {new CodePrimitiveExpression (depsCount)}))
132                                 );
133
134                                 CodeMethodInvokeExpression invoke;
135                                 for (int i = 0; i < depsCount; i++) {
136                                         invoke = new CodeMethodInvokeExpression (dependencies, "Add", new CodeExpression[] {new CodePrimitiveExpression (deps [i])});
137                                         trueStmt.Add (invoke);
138                                 }
139                                 assign = new CodeAssignStatement (GetMainClassFieldReferenceExpression ("__fileDependencies"), dependencies);
140 #endif
141
142                                 trueStmt.Add (assign);
143                         }
144
145                         base.CreateConstructor (localVars, trueStmt);
146                 }
147                 
148                 protected override void AddInterfaces () 
149                 {
150                         base.AddInterfaces ();
151                         CodeTypeReference cref;
152                         
153                         if (pageParser.EnableSessionState) {
154                                 cref = new CodeTypeReference (typeof (IRequiresSessionState));
155 #if NET_2_0
156                                 if (partialClass != null)
157                                         partialClass.BaseTypes.Add (cref);
158                                 else
159 #endif
160                                         mainClass.BaseTypes.Add (cref);
161                         }
162                         
163                         if (pageParser.ReadOnlySessionState) {
164                                 cref = new CodeTypeReference (typeof (IReadOnlySessionState));
165 #if NET_2_0
166                                 if (partialClass != null)
167                                         partialClass.BaseTypes.Add (cref);                                      
168                                 else
169 #endif
170                                         mainClass.BaseTypes.Add (cref);
171                         }
172
173 #if NET_2_0
174                         if (pageParser.Async)
175                                 mainClass.BaseTypes.Add (new CodeTypeReference (typeof (System.Web.IHttpAsyncHandler)));
176                         
177                         mainClass.BaseTypes.Add (new CodeTypeReference (typeof (System.Web.IHttpHandler)));
178 #endif
179                 }
180
181                 void CreateGetTypeHashCode () 
182                 {
183                         CodeMemberMethod method = new CodeMemberMethod ();
184                         method.ReturnType = intRef;
185                         method.Name = "GetTypeHashCode";
186                         method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
187                         Random rnd = new Random (pageParser.InputFile.GetHashCode ());
188                         method.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (rnd.Next ())));
189                         mainClass.Members.Add (method);
190                 }
191
192                 static CodeAssignStatement CreatePropertyAssign (CodeExpression expr, string name, object value)
193                 {
194                         CodePropertyReferenceExpression prop;
195                         prop = new CodePropertyReferenceExpression (expr, name);
196                         CodePrimitiveExpression prim;
197                         prim = new CodePrimitiveExpression (value);
198                         return new CodeAssignStatement (prop, prim);
199                 }
200
201                 static CodeAssignStatement CreatePropertyAssign (string name, object value)
202                 {
203                         return CreatePropertyAssign (thisRef, name, value);
204                 }
205
206                 void AddStatementsFromDirective (CodeMemberMethod method)
207                 {
208                         string responseEncoding = pageParser.ResponseEncoding;
209                         if (responseEncoding != null)
210                                 method.Statements.Add (CreatePropertyAssign ("ResponseEncoding", responseEncoding));
211                         
212                         int codepage = pageParser.CodePage;
213                         if (codepage != -1)
214                                 method.Statements.Add (CreatePropertyAssign ("CodePage", codepage));
215
216                         string contentType = pageParser.ContentType;
217                         if (contentType != null)
218                                 method.Statements.Add (CreatePropertyAssign ("ContentType", contentType));
219
220                         if (pageParser.OutputCache) {
221                                 CodeMethodReferenceExpression init = new CodeMethodReferenceExpression (null,
222                                                 "InitOutputCache");
223                                 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (init,
224                                                 OutputCacheParams ());
225                                 method.Statements.Add (invoke);
226                         }
227                         
228                         int lcid = pageParser.LCID;
229                         if (lcid != -1)
230                                 method.Statements.Add (CreatePropertyAssign ("LCID", lcid));
231
232                         string culture = pageParser.Culture;
233                         if (culture != null)
234                                 method.Statements.Add (CreatePropertyAssign ("Culture", culture));
235
236                         culture = pageParser.UICulture;
237                         if (culture != null)
238                                 method.Statements.Add (CreatePropertyAssign ("UICulture", culture));
239
240                         string errorPage = pageParser.ErrorPage;
241                         if (errorPage != null)
242                                 method.Statements.Add (CreatePropertyAssign ("ErrorPage", errorPage));
243
244                         if (pageParser.HaveTrace) {
245                                 CodeAssignStatement stmt = new CodeAssignStatement ();
246                                 stmt.Left = new CodePropertyReferenceExpression (thisRef, "TraceEnabled");
247                                 stmt.Right = new CodePrimitiveExpression (pageParser.Trace);
248                                 method.Statements.Add (stmt);
249                         }
250
251                         if (pageParser.TraceMode != TraceMode.Default) {
252                                 CodeAssignStatement stmt = new CodeAssignStatement ();
253                                 CodeTypeReferenceExpression tm = new CodeTypeReferenceExpression ("System.Web.TraceMode");
254                                 stmt.Left = new CodePropertyReferenceExpression (thisRef, "TraceModeValue");
255                                 stmt.Right = new CodeFieldReferenceExpression (tm, pageParser.TraceMode.ToString ());
256                                 method.Statements.Add (stmt);
257                         }
258
259                         if (pageParser.NotBuffer) {
260                                 CodeAssignStatement stmt = new CodeAssignStatement ();
261                                 stmt.Left = new CodePropertyReferenceExpression (thisRef, "Buffer");
262                                 stmt.Right = new CodePrimitiveExpression (false);
263                                 method.Statements.Add (stmt);
264                         }
265
266 #if NET_2_0
267                         if (!pageParser.EnableEventValidation) {
268                                 CodeAssignStatement stmt = new CodeAssignStatement ();
269                                 CodePropertyReferenceExpression prop;
270                                 prop = new CodePropertyReferenceExpression (thisRef, "EnableEventValidation");
271                                 stmt.Left = prop;
272                                 stmt.Right = new CodePrimitiveExpression (pageParser.EnableEventValidation);
273                                 method.Statements.Add (stmt);
274                         }
275
276                         if (pageParser.MaintainScrollPositionOnPostBack) {
277                                 CodeAssignStatement stmt = new CodeAssignStatement ();
278                                 CodePropertyReferenceExpression prop;
279                                 prop = new CodePropertyReferenceExpression (thisRef, "MaintainScrollPositionOnPostBack");
280                                 stmt.Left = prop;
281                                 stmt.Right = new CodePrimitiveExpression (pageParser.MaintainScrollPositionOnPostBack);
282                                 method.Statements.Add (stmt);
283                         }
284 #endif
285                 }
286                 
287                 protected override void AddStatementsToInitMethod (CodeMemberMethod method)
288                 {
289 #if NET_2_0
290                         AddStatementsFromDirective (method);
291                         ILocation directiveLocation = pageParser.DirectiveLocation;
292
293                         CodeArgumentReferenceExpression ctrlVar = new CodeArgumentReferenceExpression("__ctrl");
294                         if (pageParser.Title != null)
295                                 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "Title", pageParser.Title), directiveLocation));
296
297                         if (pageParser.MasterPageFile != null)
298                                 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "MasterPageFile", pageParser.MasterPageFile), directiveLocation));
299
300                         if (pageParser.Theme != null)
301                                 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "Theme", pageParser.Theme), directiveLocation));
302
303                         if (pageParser.StyleSheetTheme != null)
304                                 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "StyleSheetTheme", pageParser.StyleSheetTheme), directiveLocation));
305
306                         if (pageParser.Async != false)
307                                 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "AsyncMode", pageParser.Async), directiveLocation));
308
309                         if (pageParser.AsyncTimeout != -1)
310                                 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "AsyncTimeout",
311                                                                                             TimeSpan.FromSeconds (pageParser.AsyncTimeout)), directiveLocation));
312
313                         CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (thisRef, "InitializeCulture");
314                         method.Statements.Add (AddLinePragma (new CodeExpressionStatement (expr), directiveLocation));
315 #endif
316                 }
317
318                 protected override void PrependStatementsToFrameworkInitialize (CodeMemberMethod method)
319                 {
320                         base.PrependStatementsToFrameworkInitialize (method);
321 #if NET_2_0
322                         if (pageParser.StyleSheetTheme != null)
323                                 method.Statements.Add (CreatePropertyAssign ("StyleSheetTheme", pageParser.StyleSheetTheme));
324 #endif
325                 }
326
327                 
328                 protected override void AppendStatementsToFrameworkInitialize (CodeMemberMethod method)
329                 {
330                         base.AppendStatementsToFrameworkInitialize (method);
331
332                         ArrayList deps = pageParser.Dependencies;
333                         int depsCount = deps != null ? deps.Count : 0;
334
335                         if (depsCount > 0) {
336                                 CodeFieldReferenceExpression fileDependencies = GetMainClassFieldReferenceExpression ("__fileDependencies");
337
338                                 method.Statements.Add (
339 #if NET_2_0
340                                         new CodeMethodInvokeExpression (
341                                                 thisRef,
342                                                 "AddWrappedFileDependencies",
343                                                 new CodeExpression[] {fileDependencies})
344 #else
345                                         new CodeAssignStatement (
346                                                 new CodeFieldReferenceExpression (thisRef, "FileDependencies"),
347                                                 fileDependencies
348                                         )
349 #endif
350                                 );
351
352                         }                       
353
354 #if ONLY_1_1
355                         AddStatementsFromDirective (method);
356 #endif
357                         
358 #if NET_1_1
359                         if (pageParser.ValidateRequest) {
360                                 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression ();
361                                 CodePropertyReferenceExpression prop;
362                                 prop = new CodePropertyReferenceExpression (thisRef, "Request");
363                                 expr.Method = new CodeMethodReferenceExpression (prop, "ValidateInput");
364                                 method.Statements.Add (expr);
365                         }
366 #endif
367                 }
368
369                 CodeExpression[] OutputCacheParams ()
370                 {
371                         return new CodeExpression [] {
372                                 new CodePrimitiveExpression (pageParser.OutputCacheDuration),
373 #if NET_2_0
374                                 new CodePrimitiveExpression (pageParser.OutputCacheVaryByContentEncodings),
375 #endif
376                                 new CodePrimitiveExpression (pageParser.OutputCacheVaryByHeader),
377                                 new CodePrimitiveExpression (pageParser.OutputCacheVaryByCustom),
378                                 new CodeSnippetExpression (typeof (OutputCacheLocation).ToString () +
379                                                 "." + pageParser.OutputCacheLocation.ToString ()),
380                                 new CodePrimitiveExpression (pageParser.OutputCacheVaryByParam)
381                                 };
382                 }
383
384 #if NET_2_0
385                 void CreateStronglyTypedProperty (Type type, string name)
386                 {
387                         if (type == null)
388                                 return;
389                         
390                         CodeMemberProperty mprop = new CodeMemberProperty ();
391                         mprop.Name = name;
392                         mprop.Type = new CodeTypeReference (type);
393                         mprop.Attributes = MemberAttributes.Public | MemberAttributes.New;
394                         CodeExpression prop = new CodePropertyReferenceExpression (new CodeBaseReferenceExpression (), name);
395                         prop = new CodeCastExpression (type, prop);
396                         mprop.GetStatements.Add (new CodeMethodReturnStatement (prop));
397                         if (partialClass != null)
398                                 partialClass.Members.Add (mprop);
399                         else
400                                 mainClass.Members.Add (mprop);
401                 }
402 #endif
403                 
404                 protected internal override void CreateMethods ()
405                 {
406                         base.CreateMethods ();
407
408 #if NET_2_0
409                         CreateProfileProperty ();
410                         CreateStronglyTypedProperty (pageParser.MasterType, "Master");
411                         CreateStronglyTypedProperty (pageParser.PreviousPageType, "PreviousPage");
412 #endif
413                         
414                         CreateGetTypeHashCode ();
415
416 #if NET_2_0
417                         if (pageParser.Async)
418                                 CreateAsyncMethods ();
419 #endif
420                 }
421
422 #if NET_2_0
423                 void CreateAsyncMethods ()
424                 {
425                         CodeMemberMethod method = new CodeMemberMethod ();
426                         CodeParameterDeclarationExpression arg;
427                         CodeMethodInvokeExpression invoke;
428
429                         // public virtual System.IAsyncResult BeginProcessRequest(System.Web.HttpContext context, System.AsyncCallback cb, object data);
430                         method.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
431                         method.Name = "BeginProcessRequest";
432                         method.Attributes = MemberAttributes.Public;
433                         
434                         arg = new CodeParameterDeclarationExpression ();
435                         arg.Type = new CodeTypeReference (typeof (HttpContext));
436                         arg.Name = "context";
437                         method.Parameters.Add (arg);
438
439                         arg = new CodeParameterDeclarationExpression ();
440                         arg.Type = new CodeTypeReference (typeof (AsyncCallback));
441                         arg.Name = "cb";
442                         method.Parameters.Add (arg);
443
444                         arg = new CodeParameterDeclarationExpression ();
445                         arg.Type = new CodeTypeReference (typeof (object));
446                         arg.Name = "data";
447                         method.Parameters.Add (arg);
448
449                         invoke = new CodeMethodInvokeExpression (thisRef, "AsyncPageBeginProcessRequest");
450                         invoke.Parameters.Add (new CodeArgumentReferenceExpression ("context"));
451                         invoke.Parameters.Add (new CodeArgumentReferenceExpression ("cb"));
452                         invoke.Parameters.Add (new CodeArgumentReferenceExpression ("data"));
453
454                         method.Statements.Add (new CodeMethodReturnStatement (invoke));
455                         mainClass.Members.Add (method);
456
457                         // public virtual void EndProcessRequest(System.IAsyncResult ar);
458                         method = new CodeMemberMethod ();
459                         method.ReturnType = new CodeTypeReference (typeof (void));
460                         method.Name = "EndProcessRequest";
461                         method.Attributes = MemberAttributes.Public;
462
463                         arg = new CodeParameterDeclarationExpression ();
464                         arg.Type = new CodeTypeReference (typeof (IAsyncResult));
465                         arg.Name = "ar";
466                         method.Parameters.Add (arg);
467
468                         invoke = new CodeMethodInvokeExpression (thisRef, "AsyncPageEndProcessRequest");
469                         invoke.Parameters.Add (new CodeArgumentReferenceExpression ("ar"));
470
471                         method.Statements.Add (invoke);
472                         mainClass.Members.Add (method);
473
474                         // public override void ProcessRequest(System.Web.HttpContext context);
475                         method = new CodeMemberMethod ();
476                         method.ReturnType = new CodeTypeReference (typeof (void));
477                         method.Name = "ProcessRequest";
478                         method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
479
480                         arg = new CodeParameterDeclarationExpression ();
481                         arg.Type = new CodeTypeReference (typeof (HttpContext));
482                         arg.Name = "context";
483                         method.Parameters.Add (arg);
484                         
485                         invoke = new CodeMethodInvokeExpression (new CodeBaseReferenceExpression (), "ProcessRequest");
486                         invoke.Parameters.Add (new CodeArgumentReferenceExpression ("context"));
487
488                         method.Statements.Add (invoke);
489                         mainClass.Members.Add (method);
490                 }
491 #endif
492                 
493                 public static Type CompilePageType (PageParser pageParser)
494                 {
495                         PageCompiler compiler = new PageCompiler (pageParser);
496                         return compiler.GetCompiledType ();
497                 }
498         }
499 }
500
501