X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem%2FSystem.Configuration%2FConfigurationSettings.cs;h=ba1420340fc38366cf9e7aced0b1ec785c548685;hb=fdf2ccc675b73008c93dde94303f3d0406973d00;hp=15919d618738cc0690ddde621b68760f01fdd73f;hpb=05d7507da31cd3cb0e0b3355a4220927f131cfa2;p=mono.git diff --git a/mcs/class/System/System.Configuration/ConfigurationSettings.cs b/mcs/class/System/System.Configuration/ConfigurationSettings.cs index 15919d61873..ba1420340fc 100644 --- a/mcs/class/System/System.Configuration/ConfigurationSettings.cs +++ b/mcs/class/System/System.Configuration/ConfigurationSettings.cs @@ -3,194 +3,426 @@ // // Author: // Christopher Podurgiel (cpodurgiel@msn.com) +// Gonzalo Paniagua Javier (gonzalo@ximian.com) // // C) Christopher Podurgiel +// (c) 2002 Ximian, Inc. (http://www.ximian.com) // using System; +using System.Collections; using System.Collections.Specialized; +using System.IO; using System.Reflection; using System.Xml; using System.Xml.XPath; namespace System.Configuration { - /// - /// Component class. - /// - /// - /// Longer description - /// - public sealed class ConfigurationSettings { + static IConfigurationSystem config; + + private ConfigurationSettings () + { + } - private static string applicationConfigFileName; - - /// - /// ConfigurationSettings Constructor. - /// - public ConfigurationSettings () + public static object GetConfig (string sectionName) { - + if (config == null) + config = DefaultConfig.GetInstance (); + + return config.GetConfig (sectionName); } - /// - /// Returns configuration settings for a user-defined configuration section. - /// - /// The name of the configuration section that configuration settings are read from. - /// - public static object GetConfig(string sectionName) - { - //Create an instance of an XML Document. - XmlDocument ConfigurationDocument = new XmlDocument(); - - /* - * LAMESPEC: The .config file that needs to be parsed is the name of the application, plus ".config" - * ie. "Myapplication.exe.config" - * The only way I could find to get the name of the application is through System.Forms.Application.ExecutablePath, this - * may be an incorrect way to get this information. It works properly on a windows machine when building an executable, - * however, I'm not sure how this would work under other platforms. - */ - //Get the full path to the Applicaton Configuration File. - applicationConfigFileName = "FIXME:ConfigurationSettings" + ".config"; - - //Try to load the XML Document. - try - { - ConfigurationDocument.Load(applicationConfigFileName); + public static NameValueCollection AppSettings + { + get { + object appSettings = GetConfig ("appSettings"); + if (appSettings == null) + appSettings = new NameValueCollection (); + + return (NameValueCollection) appSettings; } - catch(XmlException e) - { - //Error loading the XML Document. Throw a ConfigurationException. - throw(new ConfigurationException(e.Message, applicationConfigFileName, e.LineNumber)); + } + + } + + // + // class DefaultConfig: read configuration from machine.config file and application + // config file if available. + // + class DefaultConfig : IConfigurationSystem + { + static string creatingInstance = "137213797382-asad"; + static string buildingData = "1797382-ladgasjkdg"; + static DefaultConfig instance; + ConfigurationData config; + + private DefaultConfig () + { + } + + public static DefaultConfig GetInstance () + { + if (instance == null) { + lock (creatingInstance) { + if (instance == null) { + instance = new DefaultConfig (); + instance.Init (); + } + + } } - string sectionHandlerName = GetSectionHanderType(ConfigurationDocument, sectionName); - - XmlNode sectionNode = ConfigurationDocument.SelectSingleNode("/configuration/" + sectionName); - - - - //If the specified sectionName is not found, then sectionNode will be null. When calling objNVSHandler.Create(), - //sectionNode cannot be null. - if(sectionNode == null) - { + return instance; + } + + public object GetConfig (string sectionName) + { + return config.GetConfig (sectionName); + } + + public void Init () + { + if (config == null) + lock (buildingData) { + if (config != null) + return; + + ConfigurationData data = new ConfigurationData (); + if (data.Load (GetMachineConfigPath ())) { + ConfigurationData appData = new ConfigurationData (data); + appData.Load (GetAppConfigPath ()); + config = appData; + } + } + } + + private static string GetMachineConfigPath () + { + string location = typeof (string).Assembly.Location; + // Workaround for bug #31730 + int index = location.IndexOf ("install"); + location = Path.Combine (location.Substring (0, index + 7), "lib"); + // + return Path.Combine (location, "machine.config"); + } + + private static string GetAppConfigPath () + { + AppDomainSetup currentInfo = AppDomain.CurrentDomain.SetupInformation; + + string appBase = currentInfo.ApplicationBase; + string configFile = currentInfo.ConfigurationFile; + // FIXME: need to check out default domain configuration file name + if (configFile == null || configFile.Length == 0) return null; + + return Path.Combine (appBase, configFile); + } + } + + class ConfigurationData + { + ConfigurationData parent; + Hashtable factories; + string fileName; + object removedMark = new object (); + object groupMark = new object (); + + public ConfigurationData () : this (null) + { + } + + public ConfigurationData (ConfigurationData parent) + { + this.parent = parent; + factories = new Hashtable (); + } + + public bool Load (string fileName) + { + if (fileName == null) + return false; + + this.fileName = fileName; + XmlTextReader reader = null; + + try { + reader = new XmlTextReader (fileName); + InitRead (reader); + MoveToNextElement (reader); + ReadSections (reader, null); + } finally { + if (reader == null) + reader.Close(); + } + + return true; + } + + IConfigurationSectionHandler GetSectionHandler (string sectionName) + { + if (!factories.Contains (sectionName)) { + if (parent == null) + return null; + + return parent.GetConfig (sectionName) as IConfigurationSectionHandler; } + object o = factories [sectionName]; + if (o == removedMark) + return null; - //Create a new SectionHandler - - //According to the Docs provided by Microsoft, the user can create their own configuration sections, and create a custom - //handler class for it. The user would specify the class and its assebly in the section. These would be - //seperated by a comma. - - string sectionHandlerClassName = sectionHandlerName; - string sectionHandlerAssemblyName = "System"; - - //Split the SectionHandler Class Name from the Assembly Name (if provided). - string[] sectionHandlerArray = sectionHandlerName.Split(new char[]{','}, 2); - if(sectionHandlerArray.Length == 2) - { - sectionHandlerClassName = sectionHandlerArray[0]; - sectionHandlerAssemblyName = sectionHandlerArray[1]; + if (o is IConfigurationSectionHandler) + return (IConfigurationSectionHandler) o; + + Type iconfig = typeof (IConfigurationSectionHandler); + string [] typeInfo = ((string) o).Split (','); + Type t; + + // Hack. Type.GetType should be enough + if (typeInfo.Length > 1) { + Assembly ass = Assembly.Load (typeInfo [1].Trim ()); + t = ass.GetType (typeInfo [0].Trim ()); + } else { + t = Type.GetType (typeInfo [0]); } - // Load the assembly to use. - Assembly assem = Assembly.Load(sectionHandlerAssemblyName); - //Get the class type. - Type handlerObjectType = assem.GetType(sectionHandlerClassName); - //Get a reference to the method "Create" - MethodInfo createMethod = handlerObjectType.GetMethod("Create"); - //Create an Instance of this SectionHandler. - Object objSectionHandler = Activator.CreateInstance(handlerObjectType); + if (t == null) + throw new ConfigurationException ("Cannot get Type for " + o); + + if (!iconfig.IsAssignableFrom (t)) + throw new ConfigurationException (sectionName + " does not implement " + iconfig); + + o = Activator.CreateInstance (t, true); + if (o == null) + throw new ConfigurationException ("Cannot get instance for " + t); + + return (IConfigurationSectionHandler) o; + } + + //TODO: Should use XPath when it works properly for this. + XmlDocument GetDocumentForSection (string sectionName) + { + ConfigXmlDocument doc = new ConfigXmlDocument (); + XmlTextReader reader = new XmlTextReader (fileName); + InitRead (reader); + string [] sectionPath = sectionName.Split ('/'); + int i = 0; + if (!reader.EOF) { + reader.Skip (); + while (!reader.EOF) { + if (reader.NodeType == XmlNodeType.Element && + reader.Name == sectionPath [i]) { + if (++i == sectionPath.Length) { + doc.LoadSingleElement (fileName, reader); + break; + } + MoveToNextElement (reader); + continue; + } + reader.Skip (); + if (reader.NodeType != XmlNodeType.Element) + MoveToNextElement (reader); + } + } + + reader.Close (); + return doc; + } + + public object GetConfig (string sectionName) + { + IConfigurationSectionHandler handler = GetSectionHandler (sectionName); + if (handler == null) + return null; - //define the arguments to be passed to the "Create" Method. - Object[] args = new Object[3]; - args[0] = null; - args[1] = null; - args[2] = sectionNode; + factories [sectionName] = handler; - object sectionHandlerCollection = createMethod.Invoke(objSectionHandler, args); + XmlDocument doc = GetDocumentForSection (sectionName); + if (doc == null) + throw new ConfigurationException ("Section not found: " + sectionName); - //Return the collection - return sectionHandlerCollection; + return handler.Create (null, null, doc); + } + + private object LookForFactory (string key) + { + object o = factories [key]; + if (o != null) + return o; + + if (parent != null) + return parent.LookForFactory (key); + return null; } + + private void InitRead (XmlTextReader reader) + { + reader.MoveToContent (); + if (reader.NodeType != XmlNodeType.Element || reader.Name != "configuration") + ThrowException ("Configuration file does not have a valid root element", reader); + if (reader.HasAttributes) + ThrowException ("Unrecognized attribute in root element", reader); + + MoveToNextElement (reader); + if (reader.Depth == 1 && reader.Name == "configSections") { + if (reader.HasAttributes) + ThrowException ("Unrecognized attribute in configSections element.", + reader); + } + } - /// - /// Gets the name of the SectionHander Class that will handle this section. - /// - /// An xml Configuration Document. - /// The name of the configuration section that configuration settings are read from. - /// The name of the Handler Object for this configuration section, including the name if its Assembly. - private static string GetSectionHanderType(XmlDocument xmlDoc, string sectionName) + private void MoveToNextElement (XmlTextReader reader) { - //TODO: This method does not account for sectionGroups yet. - string handlerName = null; + while (reader.Read ()) { + XmlNodeType ntype = reader.NodeType; + if (ntype == XmlNodeType.Element) + return; - // is a predefined configuration section. It does not have a definition - // in the section, and will always be handled by the NameValueSectionHandler. - if(sectionName == "appSettings") - { - handlerName = "System.Configuration.NameValueSectionHandler"; + if (ntype != XmlNodeType.Whitespace && + ntype != XmlNodeType.Comment && + ntype != XmlNodeType.SignificantWhitespace && + ntype != XmlNodeType.EndElement) + ThrowException ("Unrecognized element", reader); } - else - { - - string[] sectionPathArray = sectionName.Split(new char[]{'/'}); - - //Build an XPath statement. - string xpathStatement = "/configuration/configSections"; - for (int i=0; i < sectionPathArray.Length; i++) - { - if(i < sectionPathArray.Length - 1) - { - xpathStatement = xpathStatement + "/sectionGroup[@name='" + sectionPathArray[i] + "']"; - } - else - { - xpathStatement = xpathStatement + "/section[@name='" + sectionPathArray[i] + "']"; - } + } + + private void ReadSection (XmlTextReader reader, string sectionName) + { + string attName; + string nameValue = null; + string typeValue = null; + + while (reader.MoveToNextAttribute ()) { + attName = reader.Name; + if (attName == null) + continue; + + if (attName == "allowLocation" || attName == "allowDefinition") + continue; + + if (attName == "type") { + if (typeValue != null) + ThrowException ("Duplicated type attribute.", reader); + typeValue = reader.Value; + continue; } - //Get all of the
node using the xpath statement. - XmlNode sectionNode = xmlDoc.SelectSingleNode(xpathStatement); - - // if this section isn't found, then there was something wrong with the config document, - // or the sectionName didn't have a proper definition. - if(sectionNode == null) - { - - throw (new ConfigurationException("Unrecognized element.")); + if (attName == "name") { + if (nameValue != null) + ThrowException ("Duplicated name attribute.", reader); + nameValue = reader.Value; + continue; } - handlerName = sectionNode.Attributes["type"].Value; + ThrowException ("Unrecognized attribute.", reader); + } + + if (nameValue == null || typeValue == null) + ThrowException ("Required attribute missing", reader); - } + if (sectionName != null) + nameValue = sectionName + '/' + nameValue; - //Return the name of the handler. - return handlerName; + reader.MoveToElement(); + object o = LookForFactory (nameValue); + if (o != null && o != removedMark) + ThrowException ("Already have a factory for " + nameValue, reader); + + factories [nameValue] = typeValue; + MoveToNextElement (reader); } + private void ReadRemoveSection (XmlTextReader reader, string sectionName) + { + if (!reader.MoveToNextAttribute () || reader.Name != "name") + ThrowException ("Unrecognized attribute.", reader); + + string removeValue = reader.Value; + if (removeValue == null || removeValue.Length == 0) + ThrowException ("Empty name to remove", reader); + reader.MoveToElement (); - /// - /// Get the Application Configuration Settings. - /// - public static NameValueCollection AppSettings + if (sectionName != null) + removeValue = sectionName + '/' + removeValue; + + object o = LookForFactory (removeValue); + if (o != null && o != removedMark) + ThrowException ("No factory for " + removeValue, reader); + + factories [removeValue] = removedMark; + MoveToNextElement (reader); + } + + private void ReadSectionGroup (XmlTextReader reader, string configSection) + { + if (!reader.MoveToNextAttribute ()) + ThrowException ("sectionGroup must have a 'name' attribute.", reader); + + if (reader.Name != "name") + ThrowException ("Unrecognized attribute.", reader); + + if (reader.MoveToNextAttribute ()) + ThrowException ("Unrecognized attribute.", reader); + + string value = reader.Value; + if (configSection != null) + value = configSection + '/' + value; + + object o = LookForFactory (value); + if (o != null && o != removedMark) + ThrowException ("Already have a factory for " + value, reader); + + factories [value] = groupMark; + MoveToNextElement (reader); + ReadSections (reader, value); + } + + private void ReadSections (XmlTextReader reader, string configSection) { - get - { - //Get the Configuration Settings for the "appSettings" section. - NameValueCollection appSettings = (NameValueCollection)GetConfig("appSettings");; + int depth = reader.Depth; + while (reader.Depth == depth) { + string name = reader.Name; + if (reader.Name == null) + continue; + + if (name == "section") { + ReadSection (reader, configSection); + continue; + } + + if (name == "remove") { + ReadRemoveSection (reader, configSection); + continue; + } + + if (name == "clear") { + if (reader.HasAttributes) + ThrowException ("Unrecognized attribute.", reader); + + factories.Clear (); + continue; + } - return appSettings; + if (name == "sectionGroup") { + ReadSectionGroup (reader, configSection); + continue; + } + + ThrowException ("Unrecognized element", reader); } } + private void ThrowException (string text, XmlTextReader reader) + { + throw new ConfigurationException (text, fileName, reader.LineNumber); + } } }