Reverting r121536
[mono.git] / mcs / class / System.Configuration / System.Configuration / Configuration.cs
index 1b84a74efc0904df5239b1430112c3478051822e..4ec8e5ad01e6654a4390ce51ad131a37f68ee0aa 100644 (file)
@@ -47,13 +47,18 @@ namespace System.Configuration {
                SectionGroupInfo rootGroup;
                IConfigSystem system;
                bool hasFile;
+               string rootNamespace;
                
                string configPath;
                string locationConfigPath;
-                       
-               internal Configuration (Configuration parent)
+               string locationSubPath;
+
+               internal Configuration (Configuration parent, string locationSubPath)
                {
-                       Init (parent.system, null, parent);
+                       this.parent = parent;
+                       this.system = parent.system;
+                       this.rootGroup = parent.rootGroup;
+                       this.locationSubPath = locationSubPath;
                }
                
                internal Configuration (InternalConfigurationSystem system, string locationSubPath)
@@ -98,6 +103,7 @@ namespace System.Configuration {
                internal void Init (IConfigSystem system, string configPath, Configuration parent)
                {
                        this.system = system;
+                       this.configPath = configPath;
                        streamName = system.Host.GetStreamName (configPath);
                        this.parent = parent;
                        if (parent != null)
@@ -107,7 +113,7 @@ namespace System.Configuration {
                                rootGroup.StreamName = streamName;
                        }
                        
-                       if (configPath != null)
+                       if (streamName != null)
                                Load ();
                }
                
@@ -136,20 +142,40 @@ namespace System.Configuration {
                        get { return locationConfigPath; }
                }
 
+               internal string GetLocationSubPath ()
+               {
+                       Configuration confg = parent;
+                       string path = null;
+                       while (confg != null) {
+                               path = confg.locationSubPath;
+                               if (!String.IsNullOrEmpty (path))
+                                       return path;
+                               confg = confg.parent;
+                       }
+                       return path;
+               }
+
                internal string ConfigPath {
                        get { return configPath; }
                }
 
                public AppSettingsSection AppSettings {
-                       get { return Sections ["appSettings"] as AppSettingsSection; }
+                       get { return (AppSettingsSection) GetSection ("appSettings"); }
                }
 
                public ConnectionStringsSection ConnectionStrings {
                        get { return (ConnectionStringsSection) GetSection ("connectionStrings"); }
                }
 
+               // MSDN: If the value for this FilePath property represents a merged view and 
+               // no actual file exists for the application, the path to the parent configuration 
+               // file is returned.
                public string FilePath {
-                       get { return streamName; }
+                       get {
+                               if (streamName == null && parent != null)
+                                       return parent.FilePath;
+                               return streamName;
+                       }
                }
 
                public bool HasFile {
@@ -157,6 +183,19 @@ namespace System.Configuration {
                                return hasFile;
                        }
                }
+
+               ContextInformation evaluationContext;
+               public ContextInformation EvaluationContext {
+                       get {
+                               if (evaluationContext == null) {
+                                       object ctx = system.Host.CreateConfigurationContext (configPath, GetLocationSubPath() );
+                                       evaluationContext = new ContextInformation (this, ctx);
+                               }
+
+
+                               return evaluationContext;
+                       }
+               }
                
                public ConfigurationLocationCollection Locations {
                        get {
@@ -165,6 +204,11 @@ namespace System.Configuration {
                        }
                }
 
+               public bool NamespaceDeclared {
+                       get { return rootNamespace != null; }
+                       set { rootNamespace = value ? "http://schemas.microsoft.com/.NetConfiguration/v2.0" : null; }
+               }
+
                public ConfigurationSectionGroup RootSectionGroup {
                        get {
                                if (rootSectionGroup == null) {
@@ -172,11 +216,11 @@ namespace System.Configuration {
                                        rootSectionGroup.Initialize (this, rootGroup);
                                }
                                return rootSectionGroup;
-                       }                        
+                       }
                }
 
                public ConfigurationSectionGroupCollection SectionGroups {
-                       get { return RootSectionGroup.SectionGroups; }                        
+                       get { return RootSectionGroup.SectionGroups; }
                }
 
                public ConfigurationSectionCollection Sections {
@@ -214,21 +258,35 @@ namespace System.Configuration {
                        ConfigurationSection sec = data as ConfigurationSection;
                        if (sec != null || !createDefaultInstance) return sec;
                        
-                       object secObj = config.CreateInstance () as ConfigurationSection;
-                       if (!(secObj is ConfigurationSection))
-                               sec = new RuntimeOnlySection ();
-                       else {
-                               sec = (ConfigurationSection) secObj;
+                       object secObj = config.CreateInstance ();
+                       sec = secObj as ConfigurationSection;
+                       if (sec == null) {
+                               DefaultSection ds = new DefaultSection ();
+                               ds.SectionHandler = secObj as IConfigurationSectionHandler;
+                               sec = ds;
                        }
-                               
-                       ConfigurationSection parentSection = parent != null ? parent.GetSectionInstance (config, true) : null;
-                       sec.RawXml = data as string;
-                       sec.Reset (parentSection);
+                       sec.Configuration = this;
+
+                       ConfigurationSection parentSection = null;
+                       if (parent != null) {
+                               parentSection = parent.GetSectionInstance (config, true);
+                               sec.SectionInformation.SetParentSection (parentSection);
+                       }
+                       sec.SectionInformation.ConfigFilePath = FilePath;
+
+                       sec.ConfigContext = system.Host.CreateDeprecatedConfigContext(configPath);
                        
-                       if (data != null) {
-                               XmlTextReader r = new XmlTextReader (new StringReader (data as string));
+                       string xml = data as string;
+                       sec.RawXml = xml;
+                       sec.Reset (parentSection);
+
+                       if (xml != null && xml == data) {
+                               XmlTextReader r = new ConfigXmlTextReader (new StringReader (xml), FilePath);
                                sec.DeserializeSection (r);
                                r.Close ();
+
+                               if (!String.IsNullOrEmpty (sec.SectionInformation.ConfigSource) && !String.IsNullOrEmpty (FilePath))
+                                       sec.DeserializeConfigSource (Path.GetDirectoryName (FilePath));
                        }
                        
                        elementData [config] = sec;
@@ -269,13 +327,11 @@ namespace System.Configuration {
                                object ctx = sec.SectionInformation.AllowExeDefinition != ConfigurationAllowExeDefinition.MachineToApplication ? (object) sec.SectionInformation.AllowExeDefinition : (object) sec.SectionInformation.AllowDefinition;
                                throw new ConfigurationErrorsException ("The section <" + name + "> can't be defined in this configuration file (the allowed definition context is '" + ctx + "').");
                        }
-                                               
+
                        if (sec.SectionInformation.Type == null)
                                sec.SectionInformation.Type = system.Host.GetConfigTypeName (sec.GetType ());
-                       
-                       sec.SectionInformation.SetName (name);
 
-                       SectionInfo section = new SectionInfo (name, sec.SectionInformation.Type, sec.SectionInformation.AllowLocation, sec.SectionInformation.AllowDefinition, sec.SectionInformation.AllowExeDefinition);
+                       SectionInfo section = new SectionInfo (name, sec.SectionInformation);
                        section.StreamName = streamName;
                        section.ConfigHost = system.Host;
                        group.AddChild (section);
@@ -293,6 +349,8 @@ namespace System.Configuration {
                        section.ConfigHost = system.Host;
                        parentGroup.AddChild (section);
                        elementData [section] = sec;
+
+                       sec.Initialize (this, section);
                }
                
                internal void RemoveConfigInfo (ConfigInfo config)
@@ -317,7 +375,7 @@ namespace System.Configuration {
                        try {
                                Save (stream, mode, forceUpdateAll);
                                system.Host.WriteCompleted (streamName, true, ctx);
-                       } catch (Exception ex) {
+                       } catch (Exception) {
                                system.Host.WriteCompleted (streamName, false, ctx);
                                throw;
                        } finally {
@@ -334,19 +392,26 @@ namespace System.Configuration {
                {
                        SaveAs (filename, mode, false);
                }
-               
-               [MonoTODO ("Detect if file has changed")]
+
+               [MonoInternalNote ("Detect if file has changed")]
                public void SaveAs (string filename, ConfigurationSaveMode mode, bool forceUpdateAll)
                {
-                       Save (new FileStream (filename, FileMode.Open, FileAccess.Write), mode, forceUpdateAll);
+                       string dir = Path.GetDirectoryName (Path.GetFullPath (filename));
+                       if (!Directory.Exists (dir))
+                               Directory.CreateDirectory (dir);
+                       Save (new FileStream (filename, FileMode.OpenOrCreate, FileAccess.Write), mode, forceUpdateAll);
                }
-               
+
                void Save (Stream stream, ConfigurationSaveMode mode, bool forceUpdateAll)
                {
                        XmlTextWriter tw = new XmlTextWriter (new StreamWriter (stream));
                        tw.Formatting = Formatting.Indented;
                        try {
-                               tw.WriteStartElement ("configuration");
+                               tw.WriteStartDocument ();
+                               if (rootNamespace != null)
+                                       tw.WriteStartElement ("configuration", rootNamespace);
+                               else
+                                       tw.WriteStartElement ("configuration");
                                if (rootGroup.HasConfigContent (this)) {
                                        rootGroup.WriteConfig (this, tw, mode);
                                }
@@ -381,35 +446,43 @@ namespace System.Configuration {
                
                bool Load ()
                {
-                       if (streamName == null)
+                       if (String.IsNullOrEmpty (streamName))
                                return true;
-                       
-                       Stream stream = system.Host.OpenStreamForRead (streamName);
-                       XmlTextReader reader = null;
 
+                       Stream stream = null;
+                       
+                       // FIXME: we should remove this kind of hack that
+                       // hides the actual error
                        try {
-                               reader = new XmlTextReader (stream);
+                               stream = system.Host.OpenStreamForRead (streamName);
+                       } catch (Exception) {
+                               return false;
+                       }
+
+                       using (XmlTextReader reader = new ConfigXmlTextReader (stream, streamName)) {
                                ReadConfigFile (reader, streamName);
-/*                     } catch (ConfigurationException) {
-                               throw;
-                       } catch (Exception e) {
-                               throw new ConfigurationException ("Error reading " + fileName, e);
-*/                     } finally {
-                               if (reader != null)
-                                       reader.Close();
                        }
                        return true;
                }
 
-
-               internal void ReadConfigFile (XmlTextReader reader, string fileName)
+               void ReadConfigFile (XmlReader reader, string fileName)
                {
                        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);
+                       if (reader.HasAttributes) {
+                               while (reader.MoveToNextAttribute ()) {
+                                       if (reader.LocalName == "xmlns") {
+                                               rootNamespace = reader.Value;
+                                               continue;
+                                       }
+                                       ThrowException (String.Format ("Unrecognized attribute '{0}' in root element", reader.LocalName), reader);
+                               }
+                       }
+
+                       reader.MoveToElement ();
 
                        if (reader.IsEmptyElement) {
                                reader.Skip ();
@@ -428,16 +501,17 @@ namespace System.Configuration {
                        
                        rootGroup.ReadRootData (reader, this, true);
                }
-               
-               internal void ReadData (XmlTextReader reader, bool allowOverride)
+
+               internal void ReadData (XmlReader reader, bool allowOverride)
                {
-                       rootGroup.ReadRootData (reader, this, allowOverride);
+                       rootGroup.ReadData (this, reader, allowOverride);
                }
                
 
-               private void ThrowException (string text, XmlTextReader reader)
+               private void ThrowException (string text, XmlReader reader)
                {
-                       throw new ConfigurationException (text, streamName, reader.LineNumber);
+                       IXmlLineInfo li = reader as IXmlLineInfo;
+                       throw new ConfigurationException (text, streamName, li != null ? li.LineNumber : 0);
                }
        }
 }