2010-03-12 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Configuration_2.0 / WebConfigurationManager.cs
1 //
2 // System.Web.Configuration.WebConfigurationManager.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //      Chris Toshok (toshok@ximian.com)
7 //      Marek Habersack <mhabersack@novell.com>
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
29 //
30
31 #if NET_2_0
32
33 using System;
34 using System.IO;
35 using System.Collections;
36 using System.Collections.Generic;
37 using System.Collections.Specialized;
38 using System.Reflection;
39 #if MONOWEB_DEP
40 using Mono.Web.Util;
41 #endif
42 using System.Xml;
43 using System.Configuration;
44 using System.Configuration.Internal;
45 using _Configuration = System.Configuration.Configuration;
46 using System.Web.Util;
47 using System.Threading;
48
49 namespace System.Web.Configuration {
50
51         public static class WebConfigurationManager
52         {
53                 const int SAVE_LOCATIONS_CHECK_INTERVAL = 6000; // milliseconds
54
55                 static readonly char[] pathTrimChars = { '/' };
56                 static readonly object suppressAppReloadLock = new object ();
57                 static readonly object saveLocationsCacheLock = new object ();
58                 static readonly ReaderWriterLockSlim sectionCacheLock;
59                 
60 #if !TARGET_J2EE
61                 static IInternalConfigConfigurationFactory configFactory;
62                 static Hashtable configurations = Hashtable.Synchronized (new Hashtable ());
63                 static Dictionary <int, object> sectionCache = new Dictionary <int, object> ();
64                 static Hashtable configPaths = Hashtable.Synchronized (new Hashtable ());
65                 static bool suppressAppReload;
66 #else
67                 const string AppSettingsKey = "WebConfigurationManager.AppSettings";
68                 
69                 static internal IInternalConfigConfigurationFactory configFactory
70                 {
71                         get{
72                                 IInternalConfigConfigurationFactory factory = (IInternalConfigConfigurationFactory)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory");
73                                 if (factory == null){
74                                         lock (AppDomain.CurrentDomain){
75                                                 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory.initialized");
76                                                 if (initialized == null){
77                                                         PropertyInfo prop = typeof(ConfigurationManager).GetProperty("ConfigurationFactory", BindingFlags.Static | BindingFlags.NonPublic);
78                                                         if (prop != null){
79                                                                 factory = prop.GetValue(null, null) as IInternalConfigConfigurationFactory;
80                                                                 configFactory = factory;
81                                                         }
82                                                 }
83                                         }
84                                 }
85                                 return factory != null ? factory : configFactory;
86                         }
87                         set{
88                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory", value);
89                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory.initialized", true);
90                         }
91                 }
92
93                 static internal Hashtable configurations
94                 {
95                         get{
96                                 Hashtable table = (Hashtable)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations");
97                                 if (table == null){
98                                         lock (AppDomain.CurrentDomain){
99                                                 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations.initialized");
100                                                 if (initialized == null){
101                                                         table = Hashtable.Synchronized (new Hashtable (StringComparer.OrdinalIgnoreCase));
102                                                         configurations = table;
103                                                 }
104                                         }
105                                 }
106                                 return table != null ? table : configurations;
107
108                         }
109                         set{
110                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations", value);
111                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations.initialized", true);
112                         }
113                 }
114
115                 static Dictionary <int, object> sectionCache
116                 {
117                         get
118                         {
119                                 Dictionary <int, object> sectionCache = AppDomain.CurrentDomain.GetData ("sectionCache") as Dictionary <int, object>;
120                                 if (sectionCache == null) {
121                                         sectionCache = new Dictionary <int, object> ();
122                                         AppDomain.CurrentDomain.SetData ("sectionCache", sectionCache);
123                                 }
124                                 return sectionCache;
125                         }
126                         set
127                         {
128                                 AppDomain.CurrentDomain.SetData ("sectionCache", value);
129                         }
130                 }
131
132                 static internal Hashtable configPaths
133                 {
134                         get{
135                                 Hashtable table = (Hashtable)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configPaths");
136                                 if (table == null){
137                                         lock (AppDomain.CurrentDomain){
138                                                 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configPaths.initialized");
139                                                 if (initialized == null){
140                                                         table = Hashtable.Synchronized (new Hashtable (StringComparer.OrdinalIgnoreCase));
141                                                         configPaths = table;
142                                                 }
143                                         }
144                                 }
145                                 return table != null ? table : configPaths;
146
147                         }
148                         set{
149                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configPaths", value);
150                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configPaths.initialized", true);
151                         }
152                 }
153 #endif
154                 static Dictionary <string, DateTime> saveLocationsCache;
155                 static Timer saveLocationsTimer;
156                 
157                 static ArrayList extra_assemblies = null;
158                 static internal ArrayList ExtraAssemblies {
159                         get {
160                                 if (extra_assemblies == null)
161                                         extra_assemblies = new ArrayList();
162                                 return extra_assemblies;
163                         }
164                 }
165
166                 static bool hasConfigErrors = false;
167                 static object hasConfigErrorsLock = new object ();
168                 static internal bool HasConfigErrors {
169                         get {
170                                 lock (hasConfigErrorsLock) {
171                                         return hasConfigErrors;
172                                 }
173                         }
174                 }
175                 
176                 static WebConfigurationManager ()
177                 {
178                         configFactory = ConfigurationManager.ConfigurationFactory;
179                         _Configuration.SaveStart += ConfigurationSaveHandler;
180                         _Configuration.SaveEnd += ConfigurationSaveHandler;
181                         
182                         // Part of fix for bug #491531
183                         Type type = Type.GetType ("System.Configuration.CustomizableFileSettingsProvider, System", false);
184                         if (type != null) {
185                                 FieldInfo fi = type.GetField ("webConfigurationFileMapType", BindingFlags.Static | BindingFlags.NonPublic);
186                                 if (fi != null && fi.FieldType == Type.GetType ("System.Type"))
187                                         fi.SetValue (null, typeof (ApplicationSettingsConfigurationFileMap));
188                         }
189
190                         sectionCacheLock = new ReaderWriterLockSlim ();
191                 }
192
193                 static void ReenableWatcherOnConfigLocation (object state)
194                 {
195                         string path = state as string;
196                         if (String.IsNullOrEmpty (path))
197                                 return;
198
199                         DateTime lastWrite;
200                         lock (saveLocationsCacheLock) {
201                                 if (!saveLocationsCache.TryGetValue (path, out lastWrite))
202                                         lastWrite = DateTime.MinValue;
203                         }
204
205                         DateTime now = DateTime.Now;
206                         if (lastWrite == DateTime.MinValue || now.Subtract (lastWrite).TotalMilliseconds >= SAVE_LOCATIONS_CHECK_INTERVAL) {
207                                 saveLocationsTimer.Dispose ();
208                                 saveLocationsTimer = null;
209                                 HttpApplicationFactory.EnableWatcher (VirtualPathUtility.RemoveTrailingSlash (HttpRuntime.AppDomainAppPath), "?eb.?onfig");
210                         } else
211                                 saveLocationsTimer.Change (SAVE_LOCATIONS_CHECK_INTERVAL, SAVE_LOCATIONS_CHECK_INTERVAL);
212                 }
213                 
214                 static void ConfigurationSaveHandler (_Configuration sender, ConfigurationSaveEventArgs args)
215                 {
216                         bool locked = false;
217                         try {
218                                 sectionCacheLock.EnterWriteLock ();
219                                 locked = true;
220                                 sectionCache.Clear ();
221                         } finally {
222                                 if (locked)
223                                         sectionCacheLock.ExitWriteLock ();
224                         }
225                         
226                         lock (suppressAppReloadLock) {
227                                 string rootConfigPath = WebConfigurationHost.GetWebConfigFileName (HttpRuntime.AppDomainAppPath);
228                                 if (String.Compare (args.StreamPath, rootConfigPath, StringComparison.OrdinalIgnoreCase) == 0) {
229                                         SuppressAppReload (args.Start);
230                                         if (args.Start) {
231                                                 HttpApplicationFactory.DisableWatcher (VirtualPathUtility.RemoveTrailingSlash (HttpRuntime.AppDomainAppPath), "?eb.?onfig");
232
233                                                 lock (saveLocationsCacheLock) {
234                                                         if (saveLocationsCache == null)
235                                                                 saveLocationsCache = new Dictionary <string, DateTime> (StringComparer.Ordinal);
236                                                         if (saveLocationsCache.ContainsKey (rootConfigPath))
237                                                                 saveLocationsCache [rootConfigPath] = DateTime.Now;
238                                                         else
239                                                                 saveLocationsCache.Add (rootConfigPath, DateTime.Now);
240
241                                                         if (saveLocationsTimer == null)
242                                                                 saveLocationsTimer = new Timer (ReenableWatcherOnConfigLocation,
243                                                                                                 rootConfigPath,
244                                                                                                 SAVE_LOCATIONS_CHECK_INTERVAL,
245                                                                                                 SAVE_LOCATIONS_CHECK_INTERVAL);
246                                                 }
247                                         }
248                                 }
249                         }
250                 }
251                 
252                 public static _Configuration OpenMachineConfiguration ()
253                 {
254                         return ConfigurationManager.OpenMachineConfiguration ();
255                 }
256                 
257                 [MonoLimitation ("locationSubPath is not handled")]
258                 public static _Configuration OpenMachineConfiguration (string locationSubPath)
259                 {
260                         return OpenMachineConfiguration ();
261                 }
262
263                 [MonoLimitation("Mono does not support remote configuration")]
264                 public static _Configuration OpenMachineConfiguration (string locationSubPath,
265                                                                        string server)
266                 {
267                         if (server == null)
268                                 return OpenMachineConfiguration (locationSubPath);
269
270                         throw new NotSupportedException ("Mono doesn't support remote configuration");
271                 }
272
273                 [MonoLimitation("Mono does not support remote configuration")]
274                 public static _Configuration OpenMachineConfiguration (string locationSubPath,
275                                                                        string server,
276                                                                        IntPtr userToken)
277                 {
278                         if (server == null)
279                                 return OpenMachineConfiguration (locationSubPath);
280                         throw new NotSupportedException ("Mono doesn't support remote configuration");
281                 }
282
283                 [MonoLimitation("Mono does not support remote configuration")]
284                 public static _Configuration OpenMachineConfiguration (string locationSubPath,
285                                                                        string server,
286                                                                        string userName,
287                                                                        string password)
288                 {
289                         if (server == null)
290                                 return OpenMachineConfiguration (locationSubPath);
291                         throw new NotSupportedException ("Mono doesn't support remote configuration");
292                 }
293
294                 public static _Configuration OpenWebConfiguration (string path)
295                 {
296                         return OpenWebConfiguration (path, null, null, null, null, null);
297                 }
298                 
299                 public static _Configuration OpenWebConfiguration (string path, string site)
300                 {
301                         return OpenWebConfiguration (path, site, null, null, null, null);
302                 }
303                 
304                 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath)
305                 {
306                         return OpenWebConfiguration (path, site, locationSubPath, null, null, null);
307                 }
308
309                 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server)
310                 {
311                         return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
312                 }
313
314                 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, IntPtr userToken)
315                 {
316                         return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
317                 }
318                 
319                 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password)
320                 {
321                         return OpenWebConfiguration (path, site, locationSubPath, server, null, null, false);
322                 }
323
324                 static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password, bool fweb)
325                 {
326                         if (String.IsNullOrEmpty (path))
327                                 path = "/";
328
329                         if (!fweb && !String.IsNullOrEmpty (path))
330                                 path = FindWebConfig (path);
331
332                         string confKey = path + site + locationSubPath + server + userName + password;
333                         _Configuration conf = null;
334                         conf = (_Configuration) configurations [confKey];
335                         if (conf == null) {
336                                 try {
337                                         conf = ConfigurationFactory.Create (typeof (WebConfigurationHost), null, path, site, locationSubPath, server, userName, password);
338                                         configurations [confKey] = conf;
339                                 } catch (Exception ex) {
340                                         lock (hasConfigErrorsLock) {
341                                                 hasConfigErrors = true;
342                                         }
343                                         throw ex;
344                                 }
345                         }
346                         return conf;
347                 }
348
349                 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path)
350                 {
351                         return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path);
352                 }
353                 
354                 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site)
355                 {
356                         return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site);
357                 }
358                 
359                 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site, string locationSubPath)
360                 {
361                         return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site, locationSubPath);
362                 }
363                 
364                 public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap)
365                 {
366                         return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap);
367                 }
368
369                 public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap,
370                                                                              string locationSubPath)
371                 {
372                         return OpenMappedMachineConfiguration (fileMap);
373                 }
374
375                 internal static object SafeGetSection (string sectionName, Type configSectionType)
376                 {
377                         try {
378                                 return GetSection (sectionName);
379                         } catch (Exception) {
380                                 if (configSectionType != null)
381                                         return Activator.CreateInstance (configSectionType);
382                                 return null;
383                         }
384                 }
385                 
386                 internal static object SafeGetSection (string sectionName, string path, Type configSectionType)
387                 {
388                         try {
389                                 return GetSection (sectionName, path);
390                         } catch (Exception) {
391                                 if (configSectionType != null)
392                                         return Activator.CreateInstance (configSectionType);
393                                 return null;
394                         }
395                 }
396                 
397                 public static object GetSection (string sectionName)
398                 {
399                         HttpContext context = HttpContext.Current;
400                         return GetSection (sectionName, GetCurrentPath (context), context);
401                 }
402
403                 public static object GetSection (string sectionName, string path)
404                 {
405                         return GetSection (sectionName, path, HttpContext.Current);
406                 }
407
408                 static bool LookUpLocation (string relativePath, ref _Configuration defaultConfiguration)
409                 {
410                         if (String.IsNullOrEmpty (relativePath))
411                                 return false;
412
413                         _Configuration cnew = defaultConfiguration.FindLocationConfiguration (relativePath, defaultConfiguration);
414                         if (cnew == defaultConfiguration)
415                                 return false;
416
417                         defaultConfiguration = cnew;
418                         return true;
419                 }
420                 
421                 internal static object GetSection (string sectionName, string path, HttpContext context)
422                 {
423                         if (String.IsNullOrEmpty (sectionName))
424                                 return null;
425                         
426                         _Configuration c = OpenWebConfiguration (path, null, null, null, null, null, false);
427                         string configPath = c.ConfigPath;
428                         int baseCacheKey = 0;
429                         int cacheKey;
430                         bool pathPresent = !String.IsNullOrEmpty (path);
431                         string locationPath = null;
432                         bool locked = false;
433
434                         if (pathPresent)
435                                 locationPath = "location_" + path;
436                         
437                         baseCacheKey = sectionName.GetHashCode ();
438                         if (configPath != null)
439                                 baseCacheKey ^= configPath.GetHashCode ();
440                         
441                         try {
442                                 sectionCacheLock.EnterReadLock ();
443                                 locked = true;
444                                 
445                                 object o;
446                                 if (pathPresent) {
447                                         cacheKey = baseCacheKey ^ locationPath.GetHashCode ();
448                                         if (sectionCache.TryGetValue (cacheKey, out o))
449                                                 return o;
450                                 
451                                         cacheKey = baseCacheKey ^ path.GetHashCode ();
452                                         if (sectionCache.TryGetValue (cacheKey, out o))
453                                                 return o;
454                                 }
455                                 
456                                 if (sectionCache.TryGetValue (baseCacheKey, out o))
457                                         return o;
458                         } finally {
459                                 if (locked)
460                                         sectionCacheLock.ExitReadLock ();
461                         }
462
463                         string cachePath = null;
464                         if (pathPresent) {
465                                 string relPath;
466                                 
467                                 if (VirtualPathUtility.IsRooted (path)) {
468                                         if (path [0] == '~')
469                                                 relPath = path.Substring (2);
470                                         else if (path [0] == '/')
471                                                 relPath = path.Substring (1);
472                                         else
473                                                 relPath = path;
474                                 } else
475                                         relPath = path;
476
477                                 HttpRequest req = context != null ? context.Request : null;
478                                 if (req != null) {
479                                         string vdir = VirtualPathUtility.GetDirectory (req.PathNoValidation);
480                                         if (vdir != null) {
481                                                 vdir = vdir.TrimEnd (pathTrimChars);
482                                                 if (String.Compare (c.ConfigPath, vdir, StringComparison.Ordinal) != 0 && LookUpLocation (vdir.Trim (pathTrimChars), ref c))
483                                                         cachePath = path;
484                                         }
485                                 }
486                                 
487                                 if (LookUpLocation (relPath, ref c))
488                                         cachePath = locationPath;
489                                 else
490                                         cachePath = path;
491                         }
492
493                         ConfigurationSection section = c.GetSection (sectionName);
494                         if (section == null)
495                                 return null;
496
497 #if TARGET_J2EE
498                         object value = get_runtime_object.Invoke (section, new object [0]);
499                         if (String.CompareOrdinal ("appSettings", sectionName) == 0) {
500                                 NameValueCollection collection;
501                                 collection = new KeyValueMergedCollection (HttpContext.Current, (NameValueCollection) value);
502                                 value = collection;
503                         }
504 #else
505 #if MONOWEB_DEP
506                         object value = SettingsMappingManager.MapSection (get_runtime_object.Invoke (section, new object [0]));
507 #else
508                         object value = null;
509 #endif
510 #endif
511                         if (cachePath != null)
512                                 cacheKey = baseCacheKey ^ cachePath.GetHashCode ();
513                         else
514                                 cacheKey = baseCacheKey;
515                         
516                         AddSectionToCache (cacheKey, value);
517                         return value;
518                 }
519                 
520                 static string MapPath (HttpRequest req, string virtualPath)
521                 {
522                         if (req != null)
523                                 return req.MapPath (virtualPath);
524
525                         string appRoot = HttpRuntime.AppDomainAppVirtualPath;
526                         if (!String.IsNullOrEmpty (appRoot) && virtualPath.StartsWith (appRoot, StringComparison.Ordinal)) {
527                                 if (String.Compare (virtualPath, appRoot, StringComparison.Ordinal) == 0)
528                                         return HttpRuntime.AppDomainAppPath;
529                                 return UrlUtils.Combine (HttpRuntime.AppDomainAppPath, virtualPath.Substring (appRoot.Length));
530                         }
531                         
532                         return null;
533                 }
534
535                 static string GetParentDir (string rootPath, string curPath)
536                 {
537                         int len = curPath.Length - 1;
538                         if (len > 0 && curPath [len] == '/')
539                                 curPath = curPath.Substring (0, len);
540
541                         if (String.Compare (curPath, rootPath, StringComparison.Ordinal) == 0)
542                                 return null;
543                         
544                         int idx = curPath.LastIndexOf ('/');
545                         if (idx == -1)
546                                 return curPath;
547
548                         if (idx == 0)
549                                 return "/";
550                         
551                         return curPath.Substring (0, idx);
552                 }
553                 
554                 internal static string FindWebConfig (string path)
555                 {
556                         if (String.IsNullOrEmpty (path))
557                                 return path;
558
559                         string dir;
560                         if (path [path.Length - 1] == '/')
561                                 dir = path;
562                         else {
563                                 dir = VirtualPathUtility.GetDirectory (path, false);
564                                 if (dir == null)
565                                         return path;
566                         }
567                         
568                         string curPath = configPaths [dir] as string;
569                         if (curPath != null)
570                                 return curPath;
571                         
572                         HttpContext ctx = HttpContext.Current;
573                         HttpRequest req = ctx != null ? ctx.Request : null;
574                         if (req == null)
575                                 return path;
576
577                         curPath = path;
578                         string rootPath = HttpRuntime.AppDomainAppVirtualPath;
579                         string physPath;
580
581                         while (String.Compare (curPath, rootPath, StringComparison.Ordinal) != 0) {
582                                 physPath = MapPath (req, curPath);
583                                 if (physPath == null) {
584                                         curPath = rootPath;
585                                         break;
586                                 }
587
588                                 if (WebConfigurationHost.GetWebConfigFileName (physPath) != null)
589                                         break;
590                                 
591                                 curPath = GetParentDir (rootPath, curPath);
592                                 if (curPath == null || curPath == "~") {
593                                         curPath = rootPath;
594                                         break;
595                                 }
596                         }
597
598                         configPaths [dir] = curPath;
599                         return curPath;
600                 }
601                 
602                 static string GetCurrentPath (HttpContext ctx)
603                 {
604                         HttpRequest req = ctx != null ? ctx.Request : null;
605                         return req != null ? req.PathNoValidation : HttpRuntime.AppDomainAppVirtualPath;
606                 }
607                 
608                 internal static bool SuppressAppReload (bool newValue)
609                 {
610                         bool ret;
611                         
612                         lock (suppressAppReloadLock) {
613                                 ret = suppressAppReload;
614                                 suppressAppReload = newValue;
615                         }
616
617                         return ret;
618                 }
619                 
620                 internal static void RemoveConfigurationFromCache (HttpContext ctx)
621                 {
622                         configurations.Remove (GetCurrentPath (ctx));
623                 }
624
625 #if TARGET_J2EE || MONOWEB_DEP
626                 readonly static MethodInfo get_runtime_object = typeof (ConfigurationSection).GetMethod ("GetRuntimeObject", BindingFlags.NonPublic | BindingFlags.Instance);
627 #endif          
628
629                 public static object GetWebApplicationSection (string sectionName)
630                 {
631                         HttpContext ctx = HttpContext.Current;
632                         HttpRequest req = ctx != null ? ctx.Request : null;
633                         string applicationPath = req != null ? req.ApplicationPath : null;
634                         return GetSection (sectionName, String.IsNullOrEmpty (applicationPath) ? String.Empty : applicationPath);
635                 }
636
637                 public static NameValueCollection AppSettings {
638                         get { return ConfigurationManager.AppSettings; }
639                 }
640
641                 public static ConnectionStringSettingsCollection ConnectionStrings {
642                         get { return ConfigurationManager.ConnectionStrings; }
643                 }
644
645                 internal static IInternalConfigConfigurationFactory ConfigurationFactory {
646                         get { return configFactory; }
647                 }
648
649                 static void AddSectionToCache (int key, object section)
650                 {
651                         object cachedSection;
652                         bool locked = false;
653
654                         try {
655                                 sectionCacheLock.EnterUpgradeableReadLock ();
656                                 locked = true;
657                                         
658                                 if (sectionCache.TryGetValue (key, out cachedSection) && cachedSection != null)
659                                         return;
660
661                                 bool innerLocked = false;
662                                 try {
663                                         sectionCacheLock.EnterWriteLock ();
664                                         innerLocked = true;
665                                         sectionCache.Add (key, section);
666                                 } finally {
667                                         if (innerLocked)
668                                                 sectionCacheLock.ExitWriteLock ();
669                                 }
670                         } finally {
671                                 if (locked)
672                                         sectionCacheLock.ExitUpgradeableReadLock ();
673                         }
674                 }
675                 
676 #region stuff copied from WebConfigurationSettings
677 #if TARGET_J2EE
678                 static internal IConfigurationSystem oldConfig {
679                         get {
680                                 return (IConfigurationSystem)AppDomain.CurrentDomain.GetData("WebConfigurationManager.oldConfig");
681                         }
682                         set {
683                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.oldConfig", value);
684                         }
685                 }
686
687                 static Web20DefaultConfig config {
688                         get {
689                                 return (Web20DefaultConfig) AppDomain.CurrentDomain.GetData ("Web20DefaultConfig.config");
690                         }
691                         set {
692                                 AppDomain.CurrentDomain.SetData ("Web20DefaultConfig.config", value);
693                         }
694                 }
695
696                 static IInternalConfigSystem configSystem {
697                         get {
698                                 return (IInternalConfigSystem) AppDomain.CurrentDomain.GetData ("IInternalConfigSystem.configSystem");
699                         }
700                         set {
701                                 AppDomain.CurrentDomain.SetData ("IInternalConfigSystem.configSystem", value);
702                         }
703                 }
704 #else
705                 static internal IConfigurationSystem oldConfig;
706                 static Web20DefaultConfig config;
707                 //static IInternalConfigSystem configSystem;
708 #endif
709                 const BindingFlags privStatic = BindingFlags.NonPublic | BindingFlags.Static;
710                 static readonly object lockobj = new object ();
711
712                 internal static void Init ()
713                 {
714                         lock (lockobj) {
715                                 if (config != null)
716                                         return;
717
718                                 /* deal with the ConfigurationSettings stuff */
719                                 {
720                                         Web20DefaultConfig settings = Web20DefaultConfig.GetInstance ();
721                                         Type t = typeof (ConfigurationSettings);
722                                         MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
723                                                                                privStatic);
724
725                                         if (changeConfig == null)
726                                                 throw new ConfigurationException ("Cannot find method CCS");
727
728                                         object [] args = new object [] {settings};
729                                         oldConfig = (IConfigurationSystem)changeConfig.Invoke (null, args);
730                                         config = settings;
731
732                                         config.Init ();
733                                 }
734
735                                 /* deal with the ConfigurationManager stuff */
736                                 {
737                                         HttpConfigurationSystem system = new HttpConfigurationSystem ();
738                                         Type t = typeof (ConfigurationManager);
739                                         MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
740                                                                                privStatic);
741
742                                         if (changeConfig == null)
743                                                 throw new ConfigurationException ("Cannot find method CCS");
744
745                                         object [] args = new object [] {system};
746                                         changeConfig.Invoke (null, args);
747                                         //configSystem = system;
748                                 }
749                         }
750                 }
751         }
752
753         class Web20DefaultConfig : IConfigurationSystem
754         {
755 #if TARGET_J2EE
756                 static Web20DefaultConfig instance {
757                         get {
758                                 Web20DefaultConfig val = (Web20DefaultConfig)AppDomain.CurrentDomain.GetData("Web20DefaultConfig.instance");
759                                 if (val == null) {
760                                         val = new Web20DefaultConfig();
761                                         AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", val);
762                                 }
763                                 return val;
764                         }
765                         set {
766                                 AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", value);
767                         }
768                 }
769 #else
770                 static Web20DefaultConfig instance;
771 #endif
772
773                 static Web20DefaultConfig ()
774                 {
775                         instance = new Web20DefaultConfig ();
776                 }
777
778                 public static Web20DefaultConfig GetInstance ()
779                 {
780                         return instance;
781                 }
782
783                 public object GetConfig (string sectionName)
784                 {
785                         object o = WebConfigurationManager.GetWebApplicationSection (sectionName);
786
787                         if (o == null || o is IgnoreSection) {
788                                 /* this can happen when the section
789                                  * handler doesn't subclass from
790                                  * ConfigurationSection.  let's be
791                                  * nice and try to load it using the
792                                  * 1.x style routines in case there's
793                                  * a 1.x section handler registered
794                                  * for it.
795                                  */
796                                 object o1 = WebConfigurationManager.oldConfig.GetConfig (sectionName);
797                                 if (o1 != null)
798                                         return o1;
799                         }
800
801                         return o;
802                 }
803
804                 public void Init ()
805                 {
806                         // nothing. We need a context.
807                 }
808         }
809 #endregion
810 }
811
812 #endif