(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / System.Web / System.Web / HttpApplicationFactory.cs
blob5882982564c4c3ec6779b36be1c87ed41ee50e37
1 //
2 // System.Web.HttpApplicationFactory
3 //
4 // Author:
5 // Patrik Torstensson (ptorsten@hotmail.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
9 //
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.
31 using System;
32 using System.Collections;
33 using System.IO;
34 using System.Reflection;
35 using System.Web.UI;
36 using System.Web.Compilation;
37 using System.Web.SessionState;
39 namespace System.Web {
40 class HttpApplicationFactory {
41 private string _appFilename;
42 private Type _appType;
44 private bool _appInitialized;
45 private bool _appFiredEnd;
47 private Stack _appFreePublicList;
48 private int _appFreePublicInstances;
49 static private int _appMaxFreePublicInstances = 32;
51 private HttpApplicationState _state;
53 static IHttpHandler custApplication;
55 static private HttpApplicationFactory s_Factory = new HttpApplicationFactory();
57 public HttpApplicationFactory() {
58 _appInitialized = false;
59 _appFiredEnd = false;
61 _appFreePublicList = new Stack();
62 _appFreePublicInstances = 0;
65 static private string GetAppFilename (HttpContext context)
67 string physicalAppPath = context.Request.PhysicalApplicationPath;
68 string appFilePath = Path.Combine (physicalAppPath, "Global.asax");
69 if (File.Exists (appFilePath))
70 return appFilePath;
72 return Path.Combine (physicalAppPath, "global.asax");
75 private void CompileApp(HttpContext context) {
76 if (File.Exists(_appFilename)) {
77 // Setup filemonitor for all filedepend also. CacheDependency?
79 _appType = ApplicationFileParser.GetCompiledApplicationType (_appFilename, context);
80 if (_appType == null) {
81 string msg = String.Format ("Error compiling application file ({0}).", _appFilename);
82 throw new ApplicationException (msg);
84 } else {
85 _appType = typeof (System.Web.HttpApplication);
86 _state = new HttpApplicationState ();
90 static bool IsEventHandler (MethodInfo m)
92 if (m.ReturnType != typeof (void))
93 return false;
95 ParameterInfo [] pi = m.GetParameters ();
96 int length = pi.Length;
97 if (length == 0)
98 return true;
100 if (length != 2)
101 return false;
103 if (pi [0].ParameterType != typeof (object) ||
104 pi [1].ParameterType != typeof (EventArgs))
105 return false;
107 return true;
110 static void AddEvent (MethodInfo method, Hashtable appTypeEventHandlers)
112 string name = method.Name.Replace ("_On", "_");
113 if (appTypeEventHandlers [name] == null) {
114 appTypeEventHandlers [name] = method;
115 return;
118 ArrayList list;
119 if (appTypeEventHandlers [name] is MethodInfo)
120 list = new ArrayList ();
121 else
122 list = appTypeEventHandlers [name] as ArrayList;
124 list.Add (method);
127 static Hashtable GetApplicationTypeEvents (HttpApplication app)
129 Type appType = app.GetType ();
130 Hashtable appTypeEventHandlers = new Hashtable ();
131 ArrayList evtMethods = new ArrayList ();
132 BindingFlags flags = BindingFlags.Public |
133 BindingFlags.NonPublic |
134 BindingFlags.Instance |
135 BindingFlags.Static;
137 MethodInfo [] methods = appType.GetMethods (flags);
138 foreach (MethodInfo m in methods) {
139 if (IsEventHandler (m))
140 AddEvent (m, appTypeEventHandlers);
143 return appTypeEventHandlers;
146 static bool FireEvent (string method_name, object target, object [] args)
148 Hashtable possibleEvents = GetApplicationTypeEvents ((HttpApplication) target);
149 MethodInfo method = possibleEvents [method_name] as MethodInfo;
150 if (method == null)
151 return false;
153 if (method.GetParameters ().Length == 0)
154 method.Invoke (target, null);
155 else
156 method.Invoke (target, args);
158 return true;
161 internal static void FireOnAppStart (HttpApplication app)
163 object [] args = new object [] {app, EventArgs.Empty};
164 FireEvent ("Application_Start", app, args);
167 void FireOnAppEnd ()
169 if (_appType == null)
170 return; // we didn't even get an application
172 HttpApplication app = (HttpApplication) HttpRuntime.CreateInternalObject (_appType);
173 AttachEvents (app);
174 FireEvent ("Application_End", app, new object [] {this, EventArgs.Empty});
175 app.Dispose ();
178 private void InitializeFactory (HttpContext context)
180 _appFilename = GetAppFilename (context);
182 CompileApp (context);
184 // Create a application object
185 HttpApplication app = (HttpApplication) HttpRuntime.CreateInternalObject (_appType);
187 // Startup
188 app.Startup(context, HttpApplicationFactory.ApplicationState);
190 // Fire OnAppStart
191 HttpApplicationFactory.FireOnAppStart (app);
193 // Recycle our application instance
194 RecyclePublicInstance(app);
197 private void Dispose() {
198 ArrayList torelease = new ArrayList();
199 lock (_appFreePublicList) {
200 while (_appFreePublicList.Count > 0) {
201 torelease.Add(_appFreePublicList.Pop());
202 _appFreePublicInstances--;
206 if (torelease.Count > 0) {
207 foreach (Object obj in torelease) {
208 ((HttpApplication) obj).Cleanup();
212 if (!_appFiredEnd) {
213 lock (this) {
214 if (!_appFiredEnd) {
215 FireOnAppEnd();
216 _appFiredEnd = true;
222 internal static IHttpHandler GetInstance(HttpContext context)
224 if (custApplication != null)
225 return custApplication;
227 if (!s_Factory._appInitialized) {
228 lock (s_Factory) {
229 if (!s_Factory._appInitialized) {
230 s_Factory.InitializeFactory(context);
231 s_Factory._appInitialized = true;
236 return s_Factory.GetPublicInstance(context);
239 internal static void RecycleInstance(HttpApplication app) {
240 if (!s_Factory._appInitialized)
241 throw new InvalidOperationException("Factory not intialized");
243 s_Factory.RecyclePublicInstance(app);
246 internal static void AttachEvents (HttpApplication app)
248 Hashtable possibleEvents = GetApplicationTypeEvents (app);
249 foreach (string key in possibleEvents.Keys) {
250 int pos = key.IndexOf ('_');
251 if (pos == -1 || key.Length <= pos + 1)
252 continue;
254 string moduleName = key.Substring (0, pos);
255 object target;
256 if (moduleName == "Application") {
257 target = app;
258 } else {
259 target = app.Modules [moduleName];
260 if (target == null)
261 continue;
264 string eventName = key.Substring (pos + 1);
265 EventInfo evt = target.GetType ().GetEvent (eventName);
266 if (evt == null)
267 continue;
269 string usualName = moduleName + "_" + eventName;
270 object methodData = possibleEvents [usualName];
271 if (methodData == null)
272 continue;
274 if (methodData is MethodInfo) {
275 AddHandler (evt, target, app, (MethodInfo) methodData);
276 continue;
279 ArrayList list = (ArrayList) methodData;
280 foreach (MethodInfo method in list)
281 AddHandler (evt, target, app, method);
285 static void AddHandler (EventInfo evt, object target, HttpApplication app, MethodInfo method)
287 int length = method.GetParameters ().Length;
289 if (length == 0) {
290 NoParamsInvoker npi = new NoParamsInvoker (app, method.Name);
291 evt.AddEventHandler (target, npi.FakeDelegate);
292 } else {
293 evt.AddEventHandler (target, Delegate.CreateDelegate (
294 typeof (EventHandler), app, method.Name));
298 private IHttpHandler GetPublicInstance(HttpContext context) {
299 HttpApplication app = null;
301 lock (_appFreePublicList) {
302 if (_appFreePublicInstances > 0) {
303 app = (HttpApplication) _appFreePublicList.Pop();
304 _appFreePublicInstances--;
308 if (app == null) {
309 // Create non-public object
310 app = (HttpApplication) HttpRuntime.CreateInternalObject(_appType);
312 app.Startup(context, HttpApplicationFactory.ApplicationState);
315 return (IHttpHandler) app;
318 internal void RecyclePublicInstance(HttpApplication app) {
319 lock (_appFreePublicList) {
320 if (_appFreePublicInstances < _appMaxFreePublicInstances) {
321 _appFreePublicList.Push(app);
322 _appFreePublicInstances++;
324 app = null;
328 if (app != null) {
329 app.Cleanup();
333 static HttpStaticObjectsCollection MakeStaticCollection (ArrayList list)
335 if (list == null || list.Count == 0)
336 return null;
338 HttpStaticObjectsCollection coll = new HttpStaticObjectsCollection ();
339 foreach (ObjectTagBuilder tag in list) {
340 coll.Add (tag);
343 return coll;
346 static internal HttpApplicationState ApplicationState {
347 get {
348 if (null == s_Factory._state) {
349 HttpStaticObjectsCollection app = MakeStaticCollection (GlobalAsaxCompiler.ApplicationObjects);
350 HttpStaticObjectsCollection ses = MakeStaticCollection (GlobalAsaxCompiler.SessionObjects);
351 s_Factory._state = new HttpApplicationState (app, ses);
354 return s_Factory._state;
358 internal static void EndApplication() {
359 s_Factory.Dispose();
362 public static void SetCustomApplication (IHttpHandler customApplication)
364 custApplication = customApplication;
367 internal Type AppType {
368 get { return _appType; }
371 internal static void SignalError(Exception exc) {
372 // TODO: Raise an error (we probably don't have a HttpContext)