merge -r 96531:96532
[mono.git] / mcs / class / System.Web / System.Web.Configuration_2.0 / WebConfigurationManager.cs
index a57d1bf983ed7892f3c3ba7623088d1e8a298fae..b75adb02b03c0109447ffd3e91d5afd0b4e7d528 100644 (file)
@@ -34,6 +34,7 @@ using System.IO;
 using System.Collections;
 using System.Collections.Specialized;
 using System.Reflection;
+using System.Web.Util;
 using System.Xml;
 using System.Configuration;
 using System.Configuration.Internal;
@@ -43,8 +44,94 @@ namespace System.Web.Configuration {
 
        public static class WebConfigurationManager
        {
+#if !TARGET_J2EE
                static IInternalConfigConfigurationFactory configFactory;
-               static Hashtable configurations = new Hashtable ();
+               static Hashtable configurations = Hashtable.Synchronized (new Hashtable ());
+               static Hashtable sectionCache = new Hashtable (StringComparer.OrdinalIgnoreCase);
+#else
+               const string AppSettingsKey = "WebConfigurationManager.AppSettings";
+               static internal IInternalConfigConfigurationFactory configFactory
+               {
+                       get{
+                               IInternalConfigConfigurationFactory factory = (IInternalConfigConfigurationFactory)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory");
+                               if (factory == null){
+                                       lock (AppDomain.CurrentDomain){
+                                               object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory.initialized");
+                                               if (initialized == null){
+                                                       PropertyInfo prop = typeof(ConfigurationManager).GetProperty("ConfigurationFactory", BindingFlags.Static | BindingFlags.NonPublic);
+                                                       if (prop != null){
+                                                               factory = prop.GetValue(null, null) as IInternalConfigConfigurationFactory;
+                                                               configFactory = factory;
+                                                       }
+                                               }
+                                       }
+                               }
+                               return factory != null ? factory : configFactory;
+                       }
+                       set{
+                               AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory", value);
+                               AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory.initialized", true);
+                       }
+               }
+
+               static internal Hashtable configurations
+               {
+                       get{
+                               Hashtable table = (Hashtable)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations");
+                               if (table == null){
+                                       lock (AppDomain.CurrentDomain){
+                                               object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations.initialized");
+                                               if (initialized == null){
+                                                       table = Hashtable.Synchronized (new Hashtable (StringComparer.OrdinalIgnoreCase));
+                                                       configurations = table;
+                                               }
+                                       }
+                               }
+                               return table != null ? table : configurations;
+
+                       }
+                       set{
+                               AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations", value);
+                               AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations.initialized", true);
+                       }
+               }
+
+               static Hashtable sectionCache
+               {
+                       get
+                       {
+                               Hashtable sectionCache = (Hashtable) AppDomain.CurrentDomain.GetData ("sectionCache");
+                               if (sectionCache == null) {
+                                       sectionCache = new Hashtable (StringComparer.OrdinalIgnoreCase);
+                                       AppDomain.CurrentDomain.SetData ("sectionCache", sectionCache);
+                               }
+                               return sectionCache;
+                       }
+                       set
+                       {
+                               AppDomain.CurrentDomain.SetData ("sectionCache", value);
+                       }
+               }
+#endif
+
+               static ArrayList extra_assemblies = null;
+               static internal ArrayList ExtraAssemblies {
+                       get {
+                               if (extra_assemblies == null)
+                                       extra_assemblies = new ArrayList();
+                               return extra_assemblies;
+                       }
+               }
+
+               static bool hasConfigErrors = false;
+               static object hasConfigErrorsLock = new object ();
+               static internal bool HasConfigErrors {
+                       get {
+                               lock (hasConfigErrorsLock) {
+                                       return hasConfigErrors;
+                               }
+                       }
+               }
                
                static WebConfigurationManager ()
                {
@@ -58,13 +145,13 @@ namespace System.Web.Configuration {
                        return ConfigurationManager.OpenMachineConfiguration ();
                }
                
-               [MonoTODO ("need to handle locationSubPath")]
+               [MonoLimitation ("locationSubPath is not handled")]
                public static _Configuration OpenMachineConfiguration (string locationSubPath)
                {
                        return OpenMachineConfiguration ();
                }
 
-               [MonoTODO]
+               [MonoLimitation("Mono does not support remote configuration")]
                public static _Configuration OpenMachineConfiguration (string locationSubPath,
                                                                       string server)
                {
@@ -74,7 +161,7 @@ namespace System.Web.Configuration {
                        throw new NotSupportedException ("Mono doesn't support remote configuration");
                }
 
-               [MonoTODO]
+               [MonoLimitation("Mono does not support remote configuration")]
                public static _Configuration OpenMachineConfiguration (string locationSubPath,
                                                                       string server,
                                                                       IntPtr userToken)
@@ -84,7 +171,7 @@ namespace System.Web.Configuration {
                        throw new NotSupportedException ("Mono doesn't support remote configuration");
                }
 
-               [MonoTODO]
+               [MonoLimitation("Mono does not support remote configuration")]
                public static _Configuration OpenMachineConfiguration (string locationSubPath,
                                                                       string server,
                                                                       string userName,
@@ -110,10 +197,9 @@ namespace System.Web.Configuration {
                        return OpenWebConfiguration (path, site, locationSubPath, null, null, null);
                }
 
-               [MonoTODO]
                public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server)
                {
-                       throw new NotImplementedException ();
+                       return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
                }
 
                public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, IntPtr userToken)
@@ -121,40 +207,23 @@ namespace System.Web.Configuration {
                        return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
                }
                
-               [MonoTODO]
                public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password)
                {
-                       if (path == null)
-                               path = "";
+                       if (path == null || path.Length == 0)
+                               path = "/";
 
-                       string basePath = GetBasePath (path);
                        _Configuration conf;
 
-                       
-                       lock (configurations) {
-                               conf = (_Configuration) configurations [basePath];
-                               if (conf == null) {
-                                       conf = ConfigurationFactory.Create (typeof(WebConfigurationHost), null, basePath, site, locationSubPath, server, userName, password);
-                                       configurations [basePath] = conf;
-                               }
-                       }
-                       if (basePath.Length < path.Length) {
-                       
-                               // If the path has a file name, look for a location specific configuration
-                               
-                               int dif = path.Length - basePath.Length;
-                               string file = path.Substring (path.Length - dif);
-                               int i=0;
-                               while (i < file.Length && file [i] == '/')
-                                       i++;
-                               if (i != 0)
-                                       file = file.Substring (i);
-
-                               if (file.Length != 0) {
-                                       foreach (ConfigurationLocation loc in conf.Locations) {
-                                               if (loc.Path == file)
-                                                       return loc.OpenConfiguration ();
+                       conf = (_Configuration) configurations [path];
+                       if (conf == null) {
+                               try {
+                                       conf = ConfigurationFactory.Create (typeof (WebConfigurationHost), null, path, site, locationSubPath, server, userName, password);
+                                       configurations [path] = conf;
+                               } catch (Exception ex) {
+                                       lock (hasConfigErrorsLock) {
+                                               hasConfigErrors = true;
                                        }
+                                       throw ex;
                                }
                        }
                        return conf;
@@ -165,13 +234,11 @@ namespace System.Web.Configuration {
                        return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path);
                }
                
-               [MonoTODO ("Do something with the extra parameters")]
                public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site)
                {
                        return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site);
                }
                
-               [MonoTODO ("Do something with the extra parameters")]
                public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site, string locationSubPath)
                {
                        return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site, locationSubPath);
@@ -182,62 +249,89 @@ namespace System.Web.Configuration {
                        return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap);
                }
 
-               [MonoTODO ("need to handle locationSubPath")]
                public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap,
                                                                             string locationSubPath)
                {
                        return OpenMappedMachineConfiguration (fileMap);
                }
 
-               [MonoTODO ("apparently this bad boy can return null, but GetWebApplicationSection doesn't")]
-               public static object GetSection (string sectionName)
+               internal static object SafeGetSection (string sectionName, Type configSectionType)
                {
                        try {
-                               _Configuration c = OpenWebConfiguration (HttpContext.Current.Request.Path);
-                               return c.GetSection (sectionName);
-                       }
-                       catch {
-                               return GetWebApplicationSection (sectionName);
+                               return GetSection (sectionName);
+                       } catch (Exception) {
+                               if (configSectionType != null)
+                                       return Activator.CreateInstance (configSectionType);
+                               return null;
                        }
                }
-
-               [MonoTODO]
-               public static object GetSection (string sectionName, string path)
+               
+               internal static object SafeGetSection (string sectionName, string path, Type configSectionType)
                {
                        try {
-                               _Configuration c = OpenWebConfiguration (path);
-                               return c.GetSection (sectionName);
-                       }
-                       catch {
+                               return GetSection (sectionName, path);
+                       } catch (Exception) {
+                               if (configSectionType != null)
+                                       return Activator.CreateInstance (configSectionType);
                                return null;
                        }
                }
 
-               static _Configuration GetWebApplicationConfiguration ()
+               public static object GetSection (string sectionName)
                {
-                       _Configuration config;
+                       return GetSection (sectionName, GetCurrentPath (HttpContext.Current));
+               }
 
-                       if (HttpContext.Current == null
-                           || HttpContext.Current.Request == null
-                           || HttpContext.Current.Request.ApplicationPath == null
-                           || HttpContext.Current.Request.ApplicationPath == "") {
-                               config = OpenWebConfiguration ("");
-                       }
-                       else {
-                               config = OpenWebConfiguration (HttpContext.Current.Request.ApplicationPath);
+               public static object GetSection (string sectionName, string path)
+               {
+                       object cachedSection = sectionCache [GetSectionCacheKey (sectionName, path)];
+                       if (cachedSection != null)
+                               return cachedSection;
+
+                       _Configuration c = OpenWebConfiguration (path);
+                       ConfigurationSection section = c.GetSection (sectionName);
+
+                       if (section == null)
+                               return null;
+
+#if TARGET_J2EE
+                       object value = get_runtime_object.Invoke (section, new object [0]);
+                       if (String.CompareOrdinal ("appSettings", sectionName) == 0) {
+                               NameValueCollection collection;
+                               collection = new KeyValueMergedCollection (HttpContext.Current, (NameValueCollection) value);
+                               value = collection;
                        }
 
-                       return config;
+                       AddSectionToCache (GetSectionCacheKey (sectionName, path), value);
+                       return value;
+#else
+                       object value = SettingsMappingManager.MapSection (get_runtime_object.Invoke (section, new object [0]));
+                       AddSectionToCache (GetSectionCacheKey (sectionName, path), value);
+                       return value;
+#endif
                }
 
-               [MonoTODO]
-               public static object GetWebApplicationSection (string sectionName)
+               static string GetCurrentPath (HttpContext ctx)
+               {
+                       return (ctx != null && ctx.Request != null) ? ctx.Request.Path : HttpRuntime.AppDomainAppVirtualPath;
+               }
+
+               internal static void RemoveConfigurationFromCache (HttpContext ctx)
                {
-                       _Configuration config = GetWebApplicationConfiguration ();
+                       configurations.Remove (GetCurrentPath (ctx));
+               }
 
-                       ConfigurationSection section = config.GetSection (sectionName);
+               readonly static MethodInfo get_runtime_object = typeof (ConfigurationSection).GetMethod ("GetRuntimeObject", BindingFlags.NonPublic | BindingFlags.Instance);
 
-                       return section;
+               public static object GetWebApplicationSection (string sectionName)
+               {
+                       string path = (HttpContext.Current == null
+                               || HttpContext.Current.Request == null
+                               || HttpContext.Current.Request.ApplicationPath == null
+                               || HttpContext.Current.Request.ApplicationPath == "") ?
+                               String.Empty : HttpContext.Current.Request.ApplicationPath;
+
+                       return GetSection (sectionName, path);
                }
 
                public static NameValueCollection AppSettings {
@@ -251,25 +345,26 @@ namespace System.Web.Configuration {
                internal static IInternalConfigConfigurationFactory ConfigurationFactory {
                        get { return configFactory; }
                }
-               
-               static string GetBasePath (string path)
+
+               static void AddSectionToCache (string key, object section)
                {
-                       if (path == "/" || path == "")
-                               return path;
-                       
-                       string pd = HttpContext.Current.Request.MapPath (path);
+                       if (sectionCache [key] != null)
+                               return;
+
+                       Hashtable tmpTable = (Hashtable) sectionCache.Clone ();
+                       if (tmpTable.Contains (key))
+                               return;
 
-                       if (!Directory.Exists (pd)) {
-                               int i = path.LastIndexOf ('/');
-                               path = path.Substring (0, i);
-                       } 
-                       
-                       while (path [path.Length - 1] == '/')
-                               path = path.Substring (0, path.Length - 1);
-                       return path;
+                       tmpTable.Add (key, section);
+                       sectionCache = tmpTable;
                }
 
+               static string GetSectionCacheKey (string sectionName, string path)
+               {
+                       return string.Concat (path, "/", sectionName);
+               }
 
+               
 #region stuff copied from WebConfigurationSettings
 #if TARGET_J2EE
                static internal IConfigurationSystem oldConfig {
@@ -283,16 +378,25 @@ namespace System.Web.Configuration {
 
                static private Web20DefaultConfig config {
                        get {
-                               return (Web20DefaultConfig)AppDomain.CurrentDomain.GetData("WebConfigurationManager.config");
+                               return (Web20DefaultConfig) AppDomain.CurrentDomain.GetData ("Web20DefaultConfig.config");
+                       }
+                       set {
+                               AppDomain.CurrentDomain.SetData ("Web20DefaultConfig.config", value);
+                       }
+               }
+
+               static private IInternalConfigSystem configSystem {
+                       get {
+                               return (IInternalConfigSystem) AppDomain.CurrentDomain.GetData ("IInternalConfigSystem.configSystem");
                        }
                        set {
-                               AppDomain.CurrentDomain.SetData("WebConfigurationManager.config", value);
+                               AppDomain.CurrentDomain.SetData ("IInternalConfigSystem.configSystem", value);
                        }
                }
 #else
                static internal IConfigurationSystem oldConfig;
                static Web20DefaultConfig config;
-               static IInternalConfigSystem configSystem;
+               //static IInternalConfigSystem configSystem;
 #endif
                const BindingFlags privStatic = BindingFlags.NonPublic | BindingFlags.Static;
                static readonly object lockobj = new object ();
@@ -332,7 +436,7 @@ namespace System.Web.Configuration {
 
                                        object [] args = new object [] {system};
                                        changeConfig.Invoke (null, args);
-                                       configSystem = system;
+                                       //configSystem = system;
                                }
                        }
                }