X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Web%2FSystem.Web%2FHttpApplicationFactory.cs;h=d57384dd1c87a3be1b9639d43fb3e9defb112b82;hb=311746b41cf500aef15a68bf4a37bddcbba86ef4;hp=e63e8beeb580a9a3bd6fabd17b2d7c13670496de;hpb=dc38ee1658afdd06858c2d61ec51a1f43e7ff82b;p=mono.git diff --git a/mcs/class/System.Web/System.Web/HttpApplicationFactory.cs b/mcs/class/System.Web/System.Web/HttpApplicationFactory.cs index e63e8beeb58..d57384dd1c8 100644 --- a/mcs/class/System.Web/System.Web/HttpApplicationFactory.cs +++ b/mcs/class/System.Web/System.Web/HttpApplicationFactory.cs @@ -1,14 +1,15 @@ // // System.Web.HttpApplicationFactory // +// TODO: +// bin_watcher must work. +// +// // Author: -// Patrik Torstensson (ptorsten@hotmail.com) // Gonzalo Paniagua Javier (gonzalo@ximian.com) // // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com) // (c) Copyright 2004 Novell, Inc. (http://www.novell.com) -// - // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -34,121 +35,111 @@ using System.Collections; using System.IO; using System.Reflection; using System.Web.UI; -using System.Web.Compilation; using System.Web.SessionState; +using System.Web.Configuration; + +#if !TARGET_J2EE +using System.Web.Compilation; +#else +using vmw.common; +#endif namespace System.Web { class HttpApplicationFactory { - private string _appFilename; - private Type _appType; + // Initialized in InitType +#if TARGET_J2EE + static HttpApplicationFactory theFactory { + get + { + HttpApplicationFactory factory = (HttpApplicationFactory)AppDomain.CurrentDomain.GetData("HttpApplicationFactory"); + if (factory == null) { + lock(typeof(HttpApplicationFactory)) { + factory = (HttpApplicationFactory)AppDomain.CurrentDomain.GetData("HttpApplicationFactory"); + if (factory == null) { + factory = new HttpApplicationFactory(); + System.Threading.Thread.Sleep(1); + AppDomain.CurrentDomain.SetData("HttpApplicationFactory", factory); + } + } + } + return factory; + } + } +#else + static HttpApplicationFactory theFactory = new HttpApplicationFactory(); +#endif + + bool needs_init = true; + Type app_type; + HttpApplicationState app_state; +#if !TARGET_JVM + FileSystemWatcher app_file_watcher; + FileSystemWatcher bin_watcher; +#endif + Stack available = new Stack (); + + // Watch this thing out when getting an instance + IHttpHandler custom_application; + + bool IsEventHandler (MethodInfo m) + { + if (m.ReturnType != typeof (void)) + return false; + + ParameterInfo [] pi = m.GetParameters (); + int length = pi.Length; + if (length == 0) + return true; + + if (length != 2) + return false; + + if (pi [0].ParameterType != typeof (object) || + pi [1].ParameterType != typeof (EventArgs)) + return false; + + return true; + } - private bool _appInitialized; - private bool _appFiredEnd; + void AddEvent (MethodInfo method, Hashtable appTypeEventHandlers) + { + string name = method.Name.Replace ("_On", "_"); + if (appTypeEventHandlers [name] == null) { + appTypeEventHandlers [name] = method; + return; + } - private Stack _appFreePublicList; - private int _appFreePublicInstances; + MethodInfo old_method = appTypeEventHandlers [name] as MethodInfo; + ArrayList list; + if (old_method != null){ + list = new ArrayList (4); + list.Add (old_method); + appTypeEventHandlers [name] = list; + } else + list = appTypeEventHandlers [name] as ArrayList; - FileSystemWatcher appFileWatcher; - FileSystemWatcher binWatcher; + list.Add (method); + } - static private int _appMaxFreePublicInstances = 32; - - private HttpApplicationState _state; - - static IHttpHandler custApplication; - - static private HttpApplicationFactory s_Factory = new HttpApplicationFactory(); - - public HttpApplicationFactory() { - _appInitialized = false; - _appFiredEnd = false; - - _appFreePublicList = new Stack(); - _appFreePublicInstances = 0; - } - - static private string GetAppFilename (HttpContext context) - { - string physicalAppPath = context.Request.PhysicalApplicationPath; - string appFilePath = Path.Combine (physicalAppPath, "Global.asax"); - if (File.Exists (appFilePath)) - return appFilePath; - - return Path.Combine (physicalAppPath, "global.asax"); - } - - void CompileApp (HttpContext context) + Hashtable GetApplicationTypeEvents (HttpApplication app) { - if (File.Exists (_appFilename)) { - _appType = ApplicationFileParser.GetCompiledApplicationType (_appFilename, context); - if (_appType == null) { - string msg = String.Format ("Error compiling application file ({0}).", _appFilename); - throw new ApplicationException (msg); - } + Type appType = app.GetType (); + Hashtable appTypeEventHandlers = new Hashtable (); + BindingFlags flags = BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.Static; - appFileWatcher = CreateWatcher (_appFilename, new FileSystemEventHandler (OnAppFileChanged)); - } else { - _appType = typeof (System.Web.HttpApplication); - _state = new HttpApplicationState (); + MethodInfo [] methods = appType.GetMethods (flags); + foreach (MethodInfo m in methods) { + if (IsEventHandler (m)) + AddEvent (m, appTypeEventHandlers); } + + return appTypeEventHandlers; } - static bool IsEventHandler (MethodInfo m) - { - if (m.ReturnType != typeof (void)) - return false; - - ParameterInfo [] pi = m.GetParameters (); - int length = pi.Length; - if (length == 0) - return true; - - if (length != 2) - return false; - - if (pi [0].ParameterType != typeof (object) || - pi [1].ParameterType != typeof (EventArgs)) - return false; - - return true; - } - - static void AddEvent (MethodInfo method, Hashtable appTypeEventHandlers) - { - string name = method.Name.Replace ("_On", "_"); - if (appTypeEventHandlers [name] == null) { - appTypeEventHandlers [name] = method; - return; - } - - ArrayList list; - if (appTypeEventHandlers [name] is MethodInfo) - list = new ArrayList (); - else - list = appTypeEventHandlers [name] as ArrayList; - - list.Add (method); - } - - static Hashtable GetApplicationTypeEvents (HttpApplication app) - { - Type appType = app.GetType (); - Hashtable appTypeEventHandlers = new Hashtable (); - BindingFlags flags = BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.Static; - - MethodInfo [] methods = appType.GetMethods (flags); - foreach (MethodInfo m in methods) { - if (IsEventHandler (m)) - AddEvent (m, appTypeEventHandlers); - } - - return appTypeEventHandlers; - } - - static bool FireEvent (string method_name, object target, object [] args) + bool FireEvent (string method_name, object target, object [] args) { Hashtable possibleEvents = GetApplicationTypeEvents ((HttpApplication) target); MethodInfo method = possibleEvents [method_name] as MethodInfo; @@ -158,31 +149,40 @@ namespace System.Web { if (method.GetParameters ().Length == 0) args = null; - try { - method.Invoke (target, args); - } catch { - // Ignore any exception here - } + method.Invoke (target, args); + return true; } - internal static void FireOnAppStart (HttpApplication app) + void FireOnAppStart (HttpContext context) { - object [] args = new object [] {app, EventArgs.Empty}; - FireEvent ("Application_Start", app, args); + HttpApplication app = (HttpApplication) Activator.CreateInstance (app_type, true); + app.SetContext (context); + object [] args = new object [] {app, EventArgs.Empty}; + FireEvent ("Application_Start", app, args); + Recycle (app); } void FireOnAppEnd () { - if (_appType == null) + if (app_type == null) return; // we didn't even get an application - HttpApplication app = (HttpApplication) HttpRuntime.CreateInternalObject (_appType); - AttachEvents (app); - FireEvent ("Application_End", app, new object [] {this, EventArgs.Empty}); + HttpApplication app = (HttpApplication) Activator.CreateInstance (app_type, true); + FireEvent ("Application_End", app, new object [] {new object (), EventArgs.Empty}); app.Dispose (); } + // + // This is invoked by HttpRuntime.Dispose, when we unload an AppDomain + // To reproduce this in action, touch "global.asax" while XSP is running. + // + public static void Dispose () + { + theFactory.FireOnAppEnd (); + } + +#if !TARGET_JVM FileSystemWatcher CreateWatcher (string file, FileSystemEventHandler hnd) { FileSystemWatcher watcher = new FileSystemWatcher (); @@ -201,213 +201,184 @@ namespace System.Web { void OnAppFileChanged (object sender, FileSystemEventArgs args) { - binWatcher.EnableRaisingEvents = false; - appFileWatcher.EnableRaisingEvents = false; + bin_watcher.EnableRaisingEvents = false; + app_file_watcher.EnableRaisingEvents = false; HttpRuntime.UnloadAppDomain (); } +#endif + + internal static void AttachEvents (HttpApplication app) + { + HttpApplicationFactory factory = theFactory; + Hashtable possibleEvents = factory.GetApplicationTypeEvents (app); + foreach (string key in possibleEvents.Keys) { + int pos = key.IndexOf ('_'); + if (pos == -1 || key.Length <= pos + 1) + continue; + + string moduleName = key.Substring (0, pos); + object target; + if (moduleName == "Application") { + target = app; + } else { + target = app.Modules [moduleName]; + if (target == null) + continue; + } + + string eventName = key.Substring (pos + 1); + EventInfo evt = target.GetType ().GetEvent (eventName); + if (evt == null) + continue; + + string usualName = moduleName + "_" + eventName; + object methodData = possibleEvents [usualName]; + if (methodData == null) + continue; + + if (methodData is MethodInfo) { + factory.AddHandler (evt, target, app, (MethodInfo) methodData); + continue; + } + + ArrayList list = (ArrayList) methodData; + foreach (MethodInfo method in list) + factory.AddHandler (evt, target, app, method); + } + } - private void InitializeFactory (HttpContext context) - { - _appFilename = GetAppFilename (context); - - CompileApp (context); - - // Create a application object - HttpApplication app = (HttpApplication) HttpRuntime.CreateInternalObject (_appType); - - // Startup - app.Startup(context, HttpApplicationFactory.ApplicationState); - - // Shutdown the application if bin directory changes. - string binFiles = HttpRuntime.BinDirectory; - if (Directory.Exists (binFiles)) - binFiles = Path.Combine (binFiles, "*.*"); - - binWatcher = CreateWatcher (binFiles, new FileSystemEventHandler (OnAppFileChanged)); - - // Fire OnAppStart - HttpApplicationFactory.FireOnAppStart (app); - - // Recycle our application instance - RecyclePublicInstance(app); - } - - private void Dispose() { - ArrayList torelease = new ArrayList(); - lock (_appFreePublicList) { - while (_appFreePublicList.Count > 0) { - torelease.Add(_appFreePublicList.Pop()); - _appFreePublicInstances--; - } - } - - if (torelease.Count > 0) { - foreach (Object obj in torelease) { - ((HttpApplication) obj).Cleanup(); - } - } - - if (!_appFiredEnd) { - lock (this) { - if (!_appFiredEnd) { - FireOnAppEnd(); - _appFiredEnd = true; - } - } - } - } - - internal static IHttpHandler GetInstance(HttpContext context) - { - if (custApplication != null) - return custApplication; - - if (!s_Factory._appInitialized) { - lock (s_Factory) { - if (!s_Factory._appInitialized) { - s_Factory.InitializeFactory(context); - s_Factory._appInitialized = true; - } - } - } - - return s_Factory.GetPublicInstance(context); - } - - internal static void RecycleInstance(HttpApplication app) { - if (!s_Factory._appInitialized) - throw new InvalidOperationException("Factory not intialized"); - - s_Factory.RecyclePublicInstance(app); - } - - internal static void AttachEvents (HttpApplication app) - { - Hashtable possibleEvents = GetApplicationTypeEvents (app); - foreach (string key in possibleEvents.Keys) { - int pos = key.IndexOf ('_'); - if (pos == -1 || key.Length <= pos + 1) - continue; - - string moduleName = key.Substring (0, pos); - object target; - if (moduleName == "Application") { - target = app; - } else { - target = app.Modules [moduleName]; - if (target == null) - continue; - } - - string eventName = key.Substring (pos + 1); - EventInfo evt = target.GetType ().GetEvent (eventName); - if (evt == null) - continue; - - string usualName = moduleName + "_" + eventName; - object methodData = possibleEvents [usualName]; - if (methodData == null) - continue; - - if (methodData is MethodInfo) { - AddHandler (evt, target, app, (MethodInfo) methodData); - continue; - } - - ArrayList list = (ArrayList) methodData; - foreach (MethodInfo method in list) - AddHandler (evt, target, app, method); - } - } - - static void AddHandler (EventInfo evt, object target, HttpApplication app, MethodInfo method) - { - int length = method.GetParameters ().Length; - - if (length == 0) { - NoParamsInvoker npi = new NoParamsInvoker (app, method.Name); - evt.AddEventHandler (target, npi.FakeDelegate); - } else { - evt.AddEventHandler (target, Delegate.CreateDelegate ( - typeof (EventHandler), app, method.Name)); - } - } - - private IHttpHandler GetPublicInstance(HttpContext context) { - HttpApplication app = null; - - lock (_appFreePublicList) { - if (_appFreePublicInstances > 0) { - app = (HttpApplication) _appFreePublicList.Pop(); - _appFreePublicInstances--; - } - } - - if (app == null) { - // Create non-public object - app = (HttpApplication) HttpRuntime.CreateInternalObject(_appType); - - app.Startup(context, HttpApplicationFactory.ApplicationState); - } - - return (IHttpHandler) app; - } - - internal void RecyclePublicInstance(HttpApplication app) { - lock (_appFreePublicList) { - if (_appFreePublicInstances < _appMaxFreePublicInstances) { - _appFreePublicList.Push(app); - _appFreePublicInstances++; - - app = null; - } - } - - if (app != null) { - app.Cleanup(); - } - } - - static HttpStaticObjectsCollection MakeStaticCollection (ArrayList list) - { - if (list == null || list.Count == 0) - return null; - - HttpStaticObjectsCollection coll = new HttpStaticObjectsCollection (); - foreach (ObjectTagBuilder tag in list) { - coll.Add (tag); - } - - return coll; - } - - static internal HttpApplicationState ApplicationState { - get { - if (null == s_Factory._state) { - HttpStaticObjectsCollection app = MakeStaticCollection (GlobalAsaxCompiler.ApplicationObjects); - HttpStaticObjectsCollection ses = MakeStaticCollection (GlobalAsaxCompiler.SessionObjects); - s_Factory._state = new HttpApplicationState (app, ses); - } - - return s_Factory._state; - } - } - - internal static void EndApplication() { - s_Factory.Dispose(); - } - - public static void SetCustomApplication (IHttpHandler customApplication) - { - custApplication = customApplication; - } - - internal Type AppType { - get { return _appType; } - } - - internal static void SignalError(Exception exc) { - // TODO: Raise an error (we probably don't have a HttpContext) - } - } -} + void AddHandler (EventInfo evt, object target, HttpApplication app, MethodInfo method) + { + int length = method.GetParameters ().Length; + + if (length == 0) { + NoParamsInvoker npi = new NoParamsInvoker (app, method.Name); + evt.AddEventHandler (target, npi.FakeDelegate); + } else { + evt.AddEventHandler (target, Delegate.CreateDelegate ( + typeof (EventHandler), app, method.Name)); + } + } + + static HttpStaticObjectsCollection MakeStaticCollection (ArrayList list) + { + if (list == null || list.Count == 0) + return null; + + HttpStaticObjectsCollection coll = new HttpStaticObjectsCollection (); + foreach (ObjectTagBuilder tag in list) { + coll.Add (tag); + } + + return coll; + } + + internal static HttpApplicationState ApplicationState { +#if TARGET_J2EE + get { + HttpApplicationFactory factory = theFactory; + if (factory.app_state == null) + factory.app_state = new HttpApplicationState (null, null); + return factory.app_state; + } +#else + get { + if (theFactory.app_state == null) { + HttpStaticObjectsCollection app = MakeStaticCollection (GlobalAsaxCompiler.ApplicationObjects); + HttpStaticObjectsCollection ses = MakeStaticCollection (GlobalAsaxCompiler.SessionObjects); + + theFactory.app_state = new HttpApplicationState (app, ses); + } + return theFactory.app_state; + } +#endif + } + + public static void SetCustomApplication (IHttpHandler customApplication) + { + theFactory.custom_application = customApplication; + } + + internal static Type AppType { + get { + return theFactory.app_type; + } + } + + void InitType (HttpContext context) + { + lock (this) { + if (!needs_init) + return; + + string physical_app_path = context.Request.PhysicalApplicationPath; + string app_file; + + app_file = Path.Combine (physical_app_path, "Global.asax"); + if (!File.Exists (app_file)) + app_file = Path.Combine (physical_app_path, "global.asax"); + + WebConfigurationSettings.Init (context); + + if (File.Exists (app_file)) { +#if TARGET_J2EE + app_type = System.Web.J2EE.PageMapper.GetObjectType(app_file); +#else + app_type = ApplicationFileParser.GetCompiledApplicationType (app_file, context); + if (app_type == null) { + string msg = String.Format ("Error compiling application file ({0}).", app_file); + throw new ApplicationException (msg); + } + + app_file_watcher = CreateWatcher (app_file, new FileSystemEventHandler (OnAppFileChanged)); +#endif + } else { + app_type = typeof (System.Web.HttpApplication); + app_state = new HttpApplicationState (); + } + needs_init = false; + + // + // Now init the settings + // + + } + } + + // + // Multiple-threads might hit this one on startup, and we have + // to delay-initialize until we have the HttpContext + // + internal static HttpApplication GetApplication (HttpContext context) + { + HttpApplicationFactory factory = theFactory; + if (factory.needs_init){ + if (context == null) + return null; + + factory.InitType (context); + factory.FireOnAppStart (context); + } + + lock (factory) { + if (factory.available.Count > 0) + return (HttpApplication) factory.available.Pop (); + } + + HttpApplication app = (HttpApplication) Activator.CreateInstance (factory.app_type, true); + + return app; + } + + internal static void Recycle (HttpApplication app) + { + HttpApplicationFactory factory = theFactory; + lock (factory) { + if (factory.available.Count < 32) + factory.available.Push (app); + else + app.Dispose (); + } + } + } +}