merge -r 96531:96532
[mono.git] / mcs / class / System.Web / System.Web.Configuration_2.0 / WebConfigurationManager.cs
index 8002d813c975cf7b37aeff7e92565c8b9ad90e25..b75adb02b03c0109447ffd3e91d5afd0b4e7d528 100644 (file)
@@ -3,6 +3,7 @@
 //
 // Authors:
 //     Lluis Sanchez Gual (lluis@novell.com)
+//     Chris Toshok (toshok@ximian.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 //
 
 #if NET_2_0
+
 using System;
 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;
@@ -41,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 ()
                {
@@ -51,121 +140,105 @@ namespace System.Web.Configuration {
                                configFactory = prop.GetValue (null, null) as IInternalConfigConfigurationFactory;
                }
 
-               [MonoTODO]
                public static _Configuration OpenMachineConfiguration ()
                {
-                       throw new NotImplementedException ();
+                       return ConfigurationManager.OpenMachineConfiguration ();
                }
                
-               [MonoTODO]
+               [MonoLimitation ("locationSubPath is not handled")]
                public static _Configuration OpenMachineConfiguration (string locationSubPath)
                {
-                       throw new NotImplementedException ();
+                       return OpenMachineConfiguration ();
                }
 
-               [MonoTODO]
+               [MonoLimitation("Mono does not support remote configuration")]
                public static _Configuration OpenMachineConfiguration (string locationSubPath,
                                                                       string server)
                {
-                       throw new NotImplementedException ();
+                       if (server == null)
+                               return OpenMachineConfiguration (locationSubPath);
+
+                       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)
                {
-                       throw new NotImplementedException ();
+                       if (server == null)
+                               return OpenMachineConfiguration (locationSubPath);
+                       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,
                                                                       string password)
                {
-                       throw new NotImplementedException ();
+                       if (server == null)
+                               return OpenMachineConfiguration (locationSubPath);
+                       throw new NotSupportedException ("Mono doesn't support remote configuration");
                }
 
                public static _Configuration OpenWebConfiguration (string path)
                {
-                       return OpenWebConfiguration (path, null, null, null, IntPtr.Zero, null);
+                       return OpenWebConfiguration (path, null, null, null, null, null);
                }
                
                public static _Configuration OpenWebConfiguration (string path, string site)
                {
-                       return OpenWebConfiguration (path, site, null, null, IntPtr.Zero, null);
+                       return OpenWebConfiguration (path, site, null, null, null, null);
                }
                
                public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath)
                {
-                       return OpenWebConfiguration (path, site, locationSubPath, null, IntPtr.Zero, null);
+                       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)
                {
-                       return OpenWebConfiguration (path, site, locationSubPath, server, userToken, null);
+                       return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
                }
                
-               [MonoTODO ("Do something with the extra parameters")]
-               public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, IntPtr userToken, string password)
+               public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password)
                {
-                       string basePath = GetBasePath (path);
+                       if (path == null || path.Length == 0)
+                               path = "/";
+
                        _Configuration conf;
-                       
-                       lock (configurations) {
-                               conf = (_Configuration) configurations [basePath];
-                               if (conf == null) {
-                                       conf = ConfigurationFactory.Create (typeof(WebConfigurationHost), null, path, site, locationSubPath, server, userToken, 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;
                }
 
-               [MonoTODO]
-               public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password)
-               {
-                       throw new NotImplementedException ();
-               }
-
                public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path)
                {
                        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);
@@ -176,68 +249,257 @@ namespace System.Web.Configuration {
                        return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap);
                }
 
-               [MonoTODO]
                public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap,
                                                                             string locationSubPath)
                {
-                       throw new NotImplementedException ();
+                       return OpenMappedMachineConfiguration (fileMap);
+               }
+
+               internal static object SafeGetSection (string sectionName, Type configSectionType)
+               {
+                       try {
+                               return GetSection (sectionName);
+                       } catch (Exception) {
+                               if (configSectionType != null)
+                                       return Activator.CreateInstance (configSectionType);
+                               return null;
+                       }
+               }
+               
+               internal static object SafeGetSection (string sectionName, string path, Type configSectionType)
+               {
+                       try {
+                               return GetSection (sectionName, path);
+                       } catch (Exception) {
+                               if (configSectionType != null)
+                                       return Activator.CreateInstance (configSectionType);
+                               return null;
+                       }
                }
 
-               [MonoTODO ("this shouldn't call ConfigurationManager.GetSection")]
                public static object GetSection (string sectionName)
                {
-                       return ConfigurationManager.GetSection (sectionName);
+                       return GetSection (sectionName, GetCurrentPath (HttpContext.Current));
                }
 
-               [MonoTODO]
                public static object GetSection (string sectionName, string path)
                {
-                       throw new NotImplementedException ();
+                       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;
+                       }
+
+                       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
+               }
+
+               static string GetCurrentPath (HttpContext ctx)
+               {
+                       return (ctx != null && ctx.Request != null) ? ctx.Request.Path : HttpRuntime.AppDomainAppVirtualPath;
+               }
+
+               internal static void RemoveConfigurationFromCache (HttpContext ctx)
+               {
+                       configurations.Remove (GetCurrentPath (ctx));
                }
 
-               [MonoTODO]
+               readonly static MethodInfo get_runtime_object = typeof (ConfigurationSection).GetMethod ("GetRuntimeObject", BindingFlags.NonPublic | BindingFlags.Instance);
+
                public static object GetWebApplicationSection (string sectionName)
                {
-                       _Configuration config = OpenWebConfiguration (HttpContext.Current.Request.PhysicalApplicationPath);
+                       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 config.GetSection (sectionName);
+                       return GetSection (sectionName, path);
                }
 
-               [MonoTODO]
                public static NameValueCollection AppSettings {
-                       get {
-                               throw new NotImplementedException ();
-                       }
+                       get { return ConfigurationManager.AppSettings; }
                }
 
-               [MonoTODO]
                public static ConnectionStringSettingsCollection ConnectionStrings {
-                       get {
-                               throw new NotImplementedException ();
-                       }
+                       get { return ConfigurationManager.ConnectionStrings; }
                }
 
                internal static IInternalConfigConfigurationFactory ConfigurationFactory {
                        get { return configFactory; }
                }
+
+               static void AddSectionToCache (string key, object section)
+               {
+                       if (sectionCache [key] != null)
+                               return;
+
+                       Hashtable tmpTable = (Hashtable) sectionCache.Clone ();
+                       if (tmpTable.Contains (key))
+                               return;
+
+                       tmpTable.Add (key, section);
+                       sectionCache = tmpTable;
+               }
+
+               static string GetSectionCacheKey (string sectionName, string path)
+               {
+                       return string.Concat (path, "/", sectionName);
+               }
+
                
-               static string GetBasePath (string path)
-               {
-                       if (path == "/")
-                               return path;
-                       
-                       string pd = HttpContext.Current.Request.MapPath (path);
-
-                       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;
+#region stuff copied from WebConfigurationSettings
+#if TARGET_J2EE
+               static internal IConfigurationSystem oldConfig {
+                       get {
+                               return (IConfigurationSystem)AppDomain.CurrentDomain.GetData("WebConfigurationManager.oldConfig");
+                       }
+                       set {
+                               AppDomain.CurrentDomain.SetData("WebConfigurationManager.oldConfig", value);
+                       }
+               }
+
+               static private Web20DefaultConfig config {
+                       get {
+                               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 ("IInternalConfigSystem.configSystem", value);
+                       }
+               }
+#else
+               static internal IConfigurationSystem oldConfig;
+               static Web20DefaultConfig config;
+               //static IInternalConfigSystem configSystem;
+#endif
+               const BindingFlags privStatic = BindingFlags.NonPublic | BindingFlags.Static;
+               static readonly object lockobj = new object ();
+
+               internal static void Init ()
+               {
+                       lock (lockobj) {
+                               if (config != null)
+                                       return;
+
+                               /* deal with the ConfigurationSettings stuff */
+                               {
+                                       Web20DefaultConfig settings = Web20DefaultConfig.GetInstance ();
+                                       Type t = typeof (ConfigurationSettings);
+                                       MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
+                                                                              privStatic);
+
+                                       if (changeConfig == null)
+                                               throw new ConfigurationException ("Cannot find method CCS");
+
+                                       object [] args = new object [] {settings};
+                                       oldConfig = (IConfigurationSystem)changeConfig.Invoke (null, args);
+                                       config = settings;
+
+                                       config.Init ();
+                               }
+
+                               /* deal with the ConfigurationManager stuff */
+                               {
+                                       HttpConfigurationSystem system = new HttpConfigurationSystem ();
+                                       Type t = typeof (ConfigurationManager);
+                                       MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
+                                                                              privStatic);
+
+                                       if (changeConfig == null)
+                                               throw new ConfigurationException ("Cannot find method CCS");
+
+                                       object [] args = new object [] {system};
+                                       changeConfig.Invoke (null, args);
+                                       //configSystem = system;
+                               }
+                       }
                }
        }
+
+       class Web20DefaultConfig : IConfigurationSystem
+       {
+#if TARGET_J2EE
+               static private Web20DefaultConfig instance {
+                       get {
+                               Web20DefaultConfig val = (Web20DefaultConfig)AppDomain.CurrentDomain.GetData("Web20DefaultConfig.instance");
+                               if (val == null) {
+                                       val = new Web20DefaultConfig();
+                                       AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", val);
+                               }
+                               return val;
+                       }
+                       set {
+                               AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", value);
+                       }
+               }
+#else
+               static Web20DefaultConfig instance;
+#endif
+
+               static Web20DefaultConfig ()
+               {
+                       instance = new Web20DefaultConfig ();
+               }
+
+               public static Web20DefaultConfig GetInstance ()
+               {
+                       return instance;
+               }
+
+               public object GetConfig (string sectionName)
+               {
+                       object o = WebConfigurationManager.GetWebApplicationSection (sectionName);
+
+                       if (o == null || o is IgnoreSection) {
+                               /* this can happen when the section
+                                * handler doesn't subclass from
+                                * ConfigurationSection.  let's be
+                                * nice and try to load it using the
+                                * 1.x style routines in case there's
+                                * a 1.x section handler registered
+                                * for it.
+                                */
+                               object o1 = WebConfigurationManager.oldConfig.GetConfig (sectionName);
+                               if (o1 != null)
+                                       return o1;
+                       }
+
+                       return o;
+               }
+
+               public void Init ()
+               {
+                       // nothing. We need a context.
+               }
+       }
+
+#endregion
 }
 
 #endif