2009-02-28 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpApplicationFactory.cs
1 //
2 // System.Web.HttpApplicationFactory
3 //
4 // Author:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
8 // (c) Copyright 2004 Novell, Inc. (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.Collections;
31 using System.IO;
32 using System.Reflection;
33 using System.Web.UI;
34 using System.Web.SessionState;
35 using System.Web.Configuration;
36 using System.Threading;
37
38 using System.Web.Compilation;
39 #if TARGET_J2EE
40 using vmw.common;
41 #endif
42
43 #if NET_2_0 && !TARGET_J2EE
44 using System.CodeDom.Compiler;
45 #endif
46
47 namespace System.Web {
48         class HttpApplicationFactory {
49                 object this_lock = new object ();
50                 
51                 // Initialized in InitType
52 #if TARGET_J2EE
53                 static HttpApplicationFactory theFactory {
54                         get
55                         {
56                                 HttpApplicationFactory factory = (HttpApplicationFactory)AppDomain.CurrentDomain.GetData("HttpApplicationFactory");
57                                 if (factory == null) {
58                                         lock(typeof(HttpApplicationFactory)) {
59                                                 factory = (HttpApplicationFactory)AppDomain.CurrentDomain.GetData("HttpApplicationFactory");
60                                                 if (factory == null) {
61                                                         factory = new HttpApplicationFactory();
62                                                         System.Threading.Thread.Sleep(1);
63                                                         AppDomain.CurrentDomain.SetData("HttpApplicationFactory", factory);
64                                                 }
65                                         }
66                                 }
67                                 return factory;
68                         }
69                 }
70 #else
71                 static HttpApplicationFactory theFactory = new HttpApplicationFactory();
72 #endif
73                 object session_end; // This is a MethodInfo
74                 bool needs_init = true;
75                 bool app_start_needed = true;
76                 bool have_app_events;
77                 Type app_type;
78                 HttpApplicationState app_state;
79                 Hashtable app_event_handlers;
80                 static ArrayList watchers = new ArrayList();
81                 static object watchers_lock = new object();
82                 static bool app_shutdown = false;
83 #if NET_2_0
84                 static bool app_disabled = false;
85                 static string[] app_browsers_files = new string[0];
86                 static string[] default_machine_browsers_files = new string[0];
87                 static string[] app_mono_machine_browsers_files = new string[0];
88 #endif
89                 Stack available = new Stack ();
90                 object next_free;
91                 Stack available_for_end = new Stack ();
92                 
93                 bool IsEventHandler (MethodInfo m)
94                 {
95                         int pos = m.Name.IndexOf ('_');
96                         if (pos == -1 || (m.Name.Length - 1) <= pos)
97                                 return false;
98
99                         if (m.ReturnType != typeof (void))
100                                 return false;
101
102                         ParameterInfo [] pi = m.GetParameters ();
103                         int length = pi.Length;
104                         if (length == 0)
105                                 return true;
106
107                         if (length != 2)
108                                 return false;
109
110                         if (pi [0].ParameterType != typeof (object) ||
111                             pi [1].ParameterType != typeof (EventArgs))
112                                 return false;
113                         
114                         return true;
115                 }
116
117                 void AddEvent (MethodInfo method, Hashtable appTypeEventHandlers)
118                 {
119                         string name = method.Name.Replace ("_On", "_");
120                         if (appTypeEventHandlers [name] == null) {
121                                 appTypeEventHandlers [name] = method;
122                                 return;
123                         }
124
125                         MethodInfo old_method = appTypeEventHandlers [name] as MethodInfo;
126                         ArrayList list;
127                         if (old_method != null){
128                                 list = new ArrayList (4);
129                                 list.Add (old_method);
130                                 appTypeEventHandlers [name] = list;
131                         } else 
132                                 list = appTypeEventHandlers [name] as ArrayList;
133
134                         list.Add (method);
135                 }
136
137                 ArrayList GetMethodsDeep (Type type)
138                 {
139                         ArrayList al = new ArrayList ();
140                         MethodInfo[] methods = type.GetMethods (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance  | BindingFlags.Static | BindingFlags.FlattenHierarchy);
141                         al.AddRange (methods);
142
143                         Type t = type.BaseType;
144                         while (t != null) {
145                                 methods = t.GetMethods (BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
146                                 al.AddRange (methods);
147                                 t = t.BaseType;
148                         }
149
150                         return al;
151                 }
152                 
153                 Hashtable GetApplicationTypeEvents (Type type)
154                 {
155                         if (have_app_events)
156                                 return app_event_handlers;
157
158                         lock (this_lock) {
159                                 if (app_event_handlers != null)
160                                         return app_event_handlers;
161
162                                 app_event_handlers = new Hashtable ();
163                                 ArrayList methods = GetMethodsDeep (type);
164                                 Hashtable used = null;
165                                 MethodInfo m;
166                                 string mname;
167                                 
168                                 foreach (object o in methods) {
169                                         m = o as MethodInfo;
170                                         if (m.DeclaringType != typeof (HttpApplication) && IsEventHandler (m)) {
171                                                 mname = m.ToString ();
172                                                 if (used == null)
173                                                         used = new Hashtable ();
174                                                 else if (used.ContainsKey (mname))
175                                                         continue;
176                                                 used.Add (mname, m);
177                                                 AddEvent (m, app_event_handlers);
178                                         }
179                                 }
180                                 used = null;
181                                 have_app_events = true;
182                         }
183
184                         return app_event_handlers;
185                 }
186
187                 Hashtable GetApplicationTypeEvents (HttpApplication app)
188                 {
189                         if (have_app_events)
190                                 return app_event_handlers;
191
192                         return GetApplicationTypeEvents (app.GetType ());
193                 }
194
195                 bool FireEvent (string method_name, object target, object [] args)
196                 {
197                         Hashtable possibleEvents = GetApplicationTypeEvents ((HttpApplication) target);
198                         MethodInfo method = possibleEvents [method_name] as MethodInfo;
199                         if (method == null)
200                                 return false;
201
202                         if (method.GetParameters ().Length == 0)
203                                 args = null;
204
205                         method.Invoke (target, args);
206
207                         return true;
208                 }
209
210                 HttpApplication FireOnAppStart (HttpContext context)
211                 {
212                         HttpApplication app = (HttpApplication) Activator.CreateInstance (app_type, true);
213                         context.ApplicationInstance = app;
214                         app.SetContext (context);
215                         object [] args = new object [] {app, EventArgs.Empty};
216                         app.InApplicationStart = true;
217                         FireEvent ("Application_Start", app, args);
218                         app.InApplicationStart = false;
219                         return app;
220                 }
221
222                 void FireOnAppEnd ()
223                 {
224                         if (app_type == null)
225                                 return; // we didn't even get an application
226
227                         HttpApplication app = (HttpApplication) Activator.CreateInstance (app_type, true);
228                         FireEvent ("Application_End", app, new object [] {new object (), EventArgs.Empty});
229                         app.DisposeInternal ();
230                         app_type = null;
231                 }
232
233                 //
234                 // This is invoked by HttpRuntime.Dispose, when we unload an AppDomain
235                 // To reproduce this in action, touch "global.asax" while XSP is running.
236                 //
237                 public static void Dispose ()
238                 {
239                         theFactory.FireOnAppEnd ();
240                 }
241
242                 static FileSystemWatcher CreateWatcher (string file, FileSystemEventHandler hnd, RenamedEventHandler reh)
243                 {
244                         FileSystemWatcher watcher = new FileSystemWatcher ();
245
246                         watcher.Path = Path.GetFullPath (Path.GetDirectoryName (file));
247                         watcher.Filter = Path.GetFileName (file);
248                         
249                         // This will enable the Modify flag for Linux/inotify
250                         watcher.NotifyFilter |= NotifyFilters.Size;
251                         
252                         watcher.Changed += hnd;
253                         watcher.Created += hnd;
254                         watcher.Deleted += hnd;
255                         watcher.Renamed += reh;
256
257                         watcher.EnableRaisingEvents = true;
258
259                         return watcher;
260                 }
261
262                 internal static void AttachEvents (HttpApplication app)
263                 {
264                         HttpApplicationFactory factory = theFactory;
265                         Hashtable possibleEvents = factory.GetApplicationTypeEvents (app);
266                         foreach (string key in possibleEvents.Keys) {
267                                 int pos = key.IndexOf ('_');
268                                 string moduleName = key.Substring (0, pos);
269                                 object target;
270                                 if (moduleName == "Application") {
271                                         target = app;
272                                 } else {
273                                         target = app.Modules [moduleName];
274                                         if (target == null)
275                                                 continue;
276                                 }
277
278                                 string eventName = key.Substring (pos + 1);
279                                 EventInfo evt = target.GetType ().GetEvent (eventName);
280                                 if (evt == null)
281                                         continue;
282
283                                 string usualName = moduleName + "_" + eventName;
284                                 object methodData = possibleEvents [usualName];
285                                 if (methodData == null)
286                                         continue;
287
288                                 if (eventName == "End" && moduleName == "Session") {
289                                         Interlocked.CompareExchange (ref factory.session_end, methodData, null);
290                                         continue;
291                                 }
292
293                                 if (methodData is MethodInfo) {
294                                         factory.AddHandler (evt, target, app, (MethodInfo) methodData);
295                                         continue;
296                                 }
297
298                                 ArrayList list = (ArrayList) methodData;
299                                 foreach (MethodInfo method in list)
300                                         factory.AddHandler (evt, target, app, method);
301                         }
302                 }
303
304                 void AddHandler (EventInfo evt, object target, HttpApplication app, MethodInfo method)
305                 {
306                         int length = method.GetParameters ().Length;
307
308                         if (length == 0) {
309                                 NoParamsInvoker npi = new NoParamsInvoker (app, method);
310                                 evt.AddEventHandler (target, npi.FakeDelegate);
311                         } else {
312                                 if (method.IsStatic) {
313                                         evt.AddEventHandler (target, Delegate.CreateDelegate (
314                                                 evt.EventHandlerType, method));
315                                 } else {
316                                         evt.AddEventHandler (target, Delegate.CreateDelegate (
317                                                                      evt.EventHandlerType, app,
318 #if NET_2_0
319                                                                      method
320 #else
321                                                                      method.Name
322 #endif
323                                                              ));
324                                 }
325                         }
326                         
327                 }
328
329                 internal static void InvokeSessionEnd (object state)
330                 {
331                         InvokeSessionEnd (state, null, EventArgs.Empty);
332                 }
333                 
334                 internal static void InvokeSessionEnd (object state, object source, EventArgs e)
335                 {
336                         HttpApplicationFactory factory = theFactory;
337                         MethodInfo method = null;
338                         HttpApplication app = null;
339                         lock (factory.available_for_end) {
340                                 method = (MethodInfo) factory.session_end;
341                                 if (method == null)
342                                         return;
343
344                                 app = GetApplicationForSessionEnd ();
345                         }
346
347                         app.SetSession ((HttpSessionState) state);
348                         try {
349                                 method.Invoke (app, new object [] {(source == null ? app : source), e});
350                         } catch (Exception) {
351                                 // Ignore
352                         }
353                         RecycleForSessionEnd (app);
354                 }
355
356                 static HttpStaticObjectsCollection MakeStaticCollection (ArrayList list)
357                 {
358                         if (list == null || list.Count == 0)
359                                 return null;
360
361                         HttpStaticObjectsCollection coll = new HttpStaticObjectsCollection ();
362                         foreach (ObjectTagBuilder tag in list) {
363                                 coll.Add (tag);
364                         }
365
366                         return coll;
367                 }
368                 
369                 internal static HttpApplicationState ApplicationState {
370 #if TARGET_J2EE
371                         get {
372                                 HttpApplicationFactory factory = theFactory;
373                                 if (factory.app_state == null)
374                                         factory.app_state = new HttpApplicationState (null, null);
375                                 return factory.app_state;
376                         }
377 #else
378                         get {
379                                 if (theFactory.app_state == null) {
380                                         HttpStaticObjectsCollection app = MakeStaticCollection (GlobalAsaxCompiler.ApplicationObjects);
381                                         HttpStaticObjectsCollection ses = MakeStaticCollection (GlobalAsaxCompiler.SessionObjects);
382
383                                         theFactory.app_state = new HttpApplicationState (app, ses);
384                                 }
385                                 return theFactory.app_state;
386                         }
387 #endif
388                 }
389
390                 internal static Type AppType {
391                         get {
392                                 return theFactory.app_type;
393                         }
394                 }
395                 
396                 void InitType (HttpContext context)
397                 {
398                         lock (this_lock) {
399                                 if (!needs_init)
400                                         return;
401
402 #if NET_2_0
403                                 try {
404 #endif
405                                         string physical_app_path = HttpRuntime.AppDomainAppPath;
406                                         string app_file = null;
407                                         
408                                         app_file = Path.Combine (physical_app_path, "Global.asax");
409                                         if (!File.Exists (app_file)) {
410                                                 app_file = Path.Combine (physical_app_path, "global.asax");
411                                                 if (!File.Exists (app_file))
412                                                         app_file = null;
413                                         }
414                         
415 #if !NET_2_0
416                                         WebConfigurationSettings.Init (context);
417 #endif
418                 
419 #if NET_2_0 && !TARGET_J2EE
420                                         AppResourcesCompiler ac = new AppResourcesCompiler (context);
421                                         ac.Compile ();
422
423 #if WEBSERVICES_DEP
424                                         AppWebReferencesCompiler awrc = new AppWebReferencesCompiler ();
425                                         awrc.Compile ();
426 #endif
427                                         
428                                         // Todo: Generate profile properties assembly from Web.config here
429                                 
430                                         AppCodeCompiler acc = new AppCodeCompiler ();
431                                         acc.Compile ();
432
433                                         // Get the default machine *.browser files.
434                                         string default_machine_browsers_path = Path.Combine (HttpRuntime.MachineConfigurationDirectory, "Browsers");
435                                         default_machine_browsers_files = new string[0];
436                                         if (Directory.Exists (default_machine_browsers_path)) {
437                                                 default_machine_browsers_files 
438                                                         = Directory.GetFiles (default_machine_browsers_path, "*.browser");
439                                         }
440                                         
441                                         // Note whether there are any App_Data/Mono_Machine_Browsers/*.browser files.  If there
442                                         // are we will be using them instead of the default machine *.browser files.
443                                         string app_mono_machine_browsers_path = Path.Combine (Path.Combine (physical_app_path, "App_Data"), "Mono_Machine_Browsers");
444                                         app_mono_machine_browsers_files = new string[0];
445                                         if (Directory.Exists (app_mono_machine_browsers_path)) {
446                                                 app_mono_machine_browsers_files 
447                                                         = Directory.GetFiles (app_mono_machine_browsers_path, "*.browser");
448                                         }
449                                                 
450                                         // Note whether there are any App_Browsers/*.browser files.  If there
451                                         // are we will be using *.browser files for sniffing in addition to browscap.ini
452                                         string app_browsers_path = Path.Combine (physical_app_path, "App_Browsers");
453                                         app_browsers_files = new string[0];
454                                         if (Directory.Exists (app_browsers_path)) {
455                                                 app_browsers_files = Directory.GetFiles (app_browsers_path, "*.browser");
456                                         }
457 #endif
458
459 #if NET_2_0
460                                         app_type = BuildManager.GetPrecompiledApplicationType ();
461 #endif
462                                         if (app_type == null && app_file != null) {
463 #if TARGET_J2EE
464                                                 app_file = System.Web.Util.UrlUtils.ResolveVirtualPathFromAppAbsolute("~/" + Path.GetFileName(app_file));
465                                                 app_type = System.Web.J2EE.PageMapper.GetObjectType(context, app_file);
466 #else
467 #if NET_2_0
468                                                 app_type = BuildManager.GetCompiledType ("~/" + Path.GetFileName (app_file));
469 #else
470                                                 app_type = ApplicationFileParser.GetCompiledApplicationType (app_file, context);
471 #endif
472 #endif
473                                                 if (app_type == null) {
474                                                         string msg = String.Format ("Error compiling application file ({0}).", app_file);
475                                                         throw new ApplicationException (msg);
476                                                 }
477                                         } else if (app_type == null) {
478                                                 app_type = typeof (System.Web.HttpApplication);
479                                                 app_state = new HttpApplicationState ();
480                                         }
481
482                                         WatchLocationForRestart("Global.asax");
483                                         WatchLocationForRestart("global.asax");
484                                         WatchLocationForRestart(String.Empty, "Web.config", true);
485                                         WatchLocationForRestart(String.Empty, "web.config", true);
486                                         WatchLocationForRestart(String.Empty, "Web.Config", true);
487                                         needs_init = false;
488 #if NET_2_0
489                                 } catch (Exception) {
490                                         if (BuildManager.CodeAssemblies != null)
491                                                 BuildManager.CodeAssemblies.Clear ();
492                                         if (BuildManager.TopLevelAssemblies != null)
493                                                 BuildManager.TopLevelAssemblies.Clear ();
494                                         if (WebConfigurationManager.ExtraAssemblies != null)
495                                                 WebConfigurationManager.ExtraAssemblies.Clear ();
496                                         throw;
497                                 }
498 #endif
499                                 
500                                 //
501                                 // Now init the settings
502                                 //
503
504                         }
505                 }
506                 
507                 //
508                 // Multiple-threads might hit this one on startup, and we have
509                 // to delay-initialize until we have the HttpContext
510                 //
511                 internal static HttpApplication GetApplication (HttpContext context)
512                 {
513 #if TARGET_J2EE
514                         if (context.ApplicationInstance!=null)
515                                 return context.ApplicationInstance;
516 #endif
517                         HttpApplicationFactory factory = theFactory;
518                         HttpApplication app = null;
519                         if (factory.app_start_needed){
520                                 if (context == null)
521                                         return null;
522
523                                 factory.InitType (context);
524                                 lock (factory) {
525                                         if (factory.app_start_needed) {
526                                                 foreach (string dir in HttpApplication.BinDirs)
527                                                         WatchLocationForRestart (dir, "*.dll");
528 #if NET_2_0
529                                                                         // Restart if the App_* directories are created...
530                                                 WatchLocationForRestart (".", "App_Code");
531                                                 WatchLocationForRestart (".", "App_Browsers");
532                                                 WatchLocationForRestart (".", "App_GlobalResources");
533                                                 // ...or their contents is changed.
534                                                 WatchLocationForRestart ("App_Code", "*", true);
535                                                 WatchLocationForRestart ("App_Browsers", "*");
536                                                 WatchLocationForRestart ("App_GlobalResources", "*");
537 #endif
538                                                 app = factory.FireOnAppStart (context);
539                                                 factory.app_start_needed = false;
540                                                 return app;
541                                         }
542                                 }
543                         }
544
545                         app = (HttpApplication) Interlocked.Exchange (ref factory.next_free, null);
546                         if (app != null) {
547                                 app.RequestCompleted = false;
548                                 return app;
549                         }
550
551                         lock (factory.available) {
552                                 if (factory.available.Count > 0) {
553                                         app = (HttpApplication) factory.available.Pop ();
554                                         app.RequestCompleted = false;
555                                         return app;
556                                 }
557                         }
558                         
559                         return (HttpApplication) Activator.CreateInstance (factory.app_type, true);
560                 }
561
562                 // The lock is in InvokeSessionEnd
563                 static HttpApplication GetApplicationForSessionEnd ()
564                 {
565                         HttpApplicationFactory factory = theFactory;
566                         if (factory.available_for_end.Count > 0)
567                                 return (HttpApplication) factory.available_for_end.Pop ();
568
569                         HttpApplication app = (HttpApplication) Activator.CreateInstance (factory.app_type, true);
570                         app.InitOnce (false);
571
572                         return app;
573                 }
574
575                 internal static void RecycleForSessionEnd (HttpApplication app)
576                 {
577                         bool dispose = false;
578                         HttpApplicationFactory factory = theFactory;
579                         lock (factory.available_for_end) {
580                                 if (factory.available_for_end.Count < 64)
581                                         factory.available_for_end.Push (app);
582                                 else
583                                         dispose = true;
584                         }
585                         if (dispose)
586                                 app.Dispose ();
587                 }
588
589                 internal static void Recycle (HttpApplication app)
590                 {
591                         bool dispose = false;
592                         HttpApplicationFactory factory = theFactory;
593                         if (Interlocked.CompareExchange (ref factory.next_free, app, null) == null)
594                                 return;
595
596                         lock (factory.available) {
597                                 if (factory.available.Count < 64)
598                                         factory.available.Push (app);
599                                 else
600                                         dispose = true;
601                         }
602                         if (dispose)
603                                 app.Dispose ();
604                 }
605
606                 internal static bool ContextAvailable {
607                         get { return theFactory != null && !theFactory.app_start_needed; }
608                 }
609
610
611                 internal static bool WatchLocationForRestart (string filter)
612                 {
613                         return WatchLocationForRestart ("", filter, false);
614                 }
615
616                 internal static bool WatchLocationForRestart (string virtualPath, string filter)
617                 {
618                         return WatchLocationForRestart (virtualPath, filter, false);
619                 }
620                 
621                 internal static bool WatchLocationForRestart(string virtualPath, string filter, bool watchSubdirs)
622                 {
623                         // map the path to the physical one
624                         string physicalPath = HttpRuntime.AppDomainAppPath;
625                         physicalPath = Path.Combine(physicalPath, virtualPath);
626                         bool isDir = Directory.Exists(physicalPath);
627                         bool isFile = isDir ? false : File.Exists(physicalPath);
628
629                         if (isDir || isFile) {
630                                 // create the watcher
631                                 FileSystemEventHandler fseh = new FileSystemEventHandler(OnFileChanged);
632                                 RenamedEventHandler reh = new RenamedEventHandler(OnFileRenamed);
633                                 FileSystemWatcher watcher = CreateWatcher(Path.Combine(physicalPath, filter), fseh, reh);
634                                 if (isDir)
635                                         watcher.IncludeSubdirectories = watchSubdirs;
636                                 
637                                 lock (watchers_lock) {
638                                         watchers.Add(watcher);
639                                 }
640                                 return true;
641                         } else {
642                                 return false;
643                         }
644                 }
645
646 #if NET_2_0
647                 internal static bool ApplicationDisabled {
648                         get { return app_disabled; }
649                         set { app_disabled = value; }
650                 }
651
652                 internal static string[] AppBrowsersFiles {
653                         get { return app_browsers_files; }
654                 }
655                 
656                 static System.Web.Configuration.nBrowser.Build capabilities_processor = null;
657                 static object capabilities_processor_lock = new object();
658                 internal static System.Web.Configuration.ICapabilitiesProcess CapabilitiesProcessor {
659                         get {
660                                 lock (capabilities_processor_lock) {
661                                         if (capabilities_processor == null) {
662                                                 capabilities_processor = new System.Web.Configuration.nBrowser.Build();
663                                                 string[] machine_browsers_files = app_mono_machine_browsers_files;
664                                                 if (machine_browsers_files.Length == 0) {
665                                                         machine_browsers_files = default_machine_browsers_files;
666                                                 }
667                                                 foreach (string f in machine_browsers_files) {
668                                                         capabilities_processor.AddBrowserFile(f);
669                                                 }
670                                                 foreach (string f in app_browsers_files) {
671                                                         capabilities_processor.AddBrowserFile(f);
672                                                 }
673                                         }
674                                 }
675                                 return capabilities_processor;
676                         }
677                 }
678 #endif
679                 
680                 internal static void DisableWatchers ()
681                 {
682                         lock (watchers_lock) {
683                                 foreach (FileSystemWatcher watcher in watchers)
684                                         watcher.EnableRaisingEvents = false;
685                         }
686                 }
687
688                 internal static void EnableWatchers ()
689                 {
690                         lock (watchers_lock) {
691                                 foreach (FileSystemWatcher watcher in watchers)
692                                         watcher.EnableRaisingEvents = true;
693                         }
694                 }
695                 
696                 static void OnFileRenamed(object sender, RenamedEventArgs args)
697                 {
698                         OnFileChanged(sender, args);
699                 }
700
701                 static void OnFileChanged(object sender, FileSystemEventArgs args)
702                 {
703                         lock (watchers_lock) {
704                                 if(app_shutdown)
705                                         return;
706                                 app_shutdown = true;
707
708                                 // Disable event raising to avoid concurrent restarts
709                                 DisableWatchers ();
710                                 
711                                 // Restart application
712                                 HttpRuntime.UnloadAppDomain();
713                         }
714                 }
715         }
716 }
717