f70212dbe39ab2fb671715bd185e224b1346b8c1
[mono.git] / mcs / class / System.Configuration / System.Configuration / SectionGroupInfo.cs
1 //
2 // System.Configuration.SectionGroupInfo.cs
3 //
4 // Authors:
5 //      Lluis Sanchez (lluis@novell.com)
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
14 // 
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 // 
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 //
26 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
27 //
28 #if NET_2_0
29 using System;
30 using System.Collections;
31 using System.Collections.Specialized;
32 using System.Xml;
33 using System.IO;
34 using System.Text;
35
36 namespace System.Configuration
37 {
38         internal class SectionGroupInfo: ConfigInfo
39         {
40                 ConfigInfoCollection sections;
41                 ConfigInfoCollection groups;
42                 static ConfigInfoCollection emptyList = new ConfigInfoCollection ();
43
44                 public SectionGroupInfo ()
45                 {
46                         Type = typeof (ConfigurationSectionGroup);
47                 }
48                 
49                 public SectionGroupInfo (string groupName, string typeName)
50                 {
51                         Name = groupName;
52                         TypeName = typeName;
53                 }
54                 
55                 public void AddChild (ConfigInfo data)
56                 {
57                         data.Parent = this;
58                         if (data is SectionInfo) {
59                                 if (sections == null) sections = new ConfigInfoCollection ();
60                                 sections [data.Name] = data;
61                         }
62                         else {
63                                 if (groups == null) groups = new ConfigInfoCollection ();
64                                 groups [data.Name] = data;
65                         }
66                 }
67                 
68                 public void Clear ()
69                 {
70                         if (sections != null) sections.Clear ();
71                         if (groups != null) groups.Clear ();
72                 }
73                 
74                 public bool HasChild (string name)
75                 {
76                         if (sections != null && sections [name] != null) return true;
77                         return (groups != null && groups [name] != null);
78                 }
79                 
80                 public void RemoveChild (string name)
81                 {
82                         if (sections != null)
83                                 sections.Remove (name);
84                         if (groups != null)
85                                 groups.Remove (name);
86                 }
87                 
88                 public SectionInfo GetChildSection (string name)
89                 {
90                         if (sections != null)
91                                 return sections [name] as SectionInfo;
92                         else
93                                 return null;
94                 }
95                 
96                 public SectionGroupInfo GetChildGroup (string name)
97                 {
98                         if (groups != null)
99                                 return groups [name] as SectionGroupInfo;
100                         else
101                                 return null;
102                 }
103                 
104                 public ConfigInfoCollection Sections
105                 {
106                         get { if (sections == null) return emptyList; else return sections; }
107                 }
108                 
109                 public ConfigInfoCollection Groups
110                 {
111                         get { if (groups == null) return emptyList; else return groups; }
112                 }
113                 
114                 public override bool HasDataContent (Configuration config)
115                 {
116                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
117                                 foreach (string key in col) {
118                                         ConfigInfo cinfo = col [key];
119                                         if (cinfo.HasDataContent (config))
120                                                 return true;
121                                 }
122                         }
123                         return false;
124                 }
125                 
126                 public override bool HasConfigContent (Configuration cfg)
127                 {
128                         if (StreamName == cfg.FileName) return true;
129                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
130                                 foreach (string key in col) {
131                                         ConfigInfo cinfo = col [key];
132                                         if (cinfo.HasConfigContent (cfg))
133                                                 return true;
134                                 }
135                         }
136                         return false;
137                 }
138                 
139                 public override void ReadConfig (Configuration cfg, string streamName, XmlTextReader reader)
140                 {
141                         StreamName = streamName;
142                         ConfigHost = cfg.ConfigHost;
143                         
144                         if (reader.LocalName != "configSections")
145                         {
146                                 while (reader.MoveToNextAttribute ()) {
147                                         if (reader.Name == "name")
148                                                 Name = reader.Value;
149                                         else if (reader.Name == "type") {
150                                                 TypeName = reader.Value;
151                                                 Type = null;
152                                         }
153                                         else
154                                                 ThrowException ("Unrecognized attribute", reader);
155                                 }
156                                 
157                                 if (Name == null)
158                                         ThrowException ("sectionGroup must have a 'name' attribute", reader);
159         
160                                 if (Name == "location")
161                                         ThrowException ("location is a reserved section name", reader);
162                         }
163                         
164                         if (TypeName == null)
165                                 TypeName = "System.Configuration.ConfigurationSectionGroup";
166                         
167                         if (reader.IsEmptyElement) {
168                                 reader.Skip ();
169                                 return;
170                         }
171                         
172                         reader.ReadStartElement ();
173                         reader.MoveToContent ();
174                         
175                         while (reader.NodeType != XmlNodeType.EndElement)
176                         {
177                                 if (reader.NodeType != XmlNodeType.Element) {
178                                         reader.Skip ();
179                                         continue;
180                                 }
181                                 
182                                 string name = reader.LocalName;
183                                 ConfigInfo cinfo = null;
184                                 
185                                 if (name == "remove") {
186                                         ReadRemoveSection (reader);
187                                         continue;
188                                 }
189
190                                 if (name == "clear") {
191                                         if (reader.HasAttributes)
192                                                 ThrowException ("Unrecognized attribute.", reader);
193
194                                         Clear ();
195                                         reader.Skip ();
196                                         continue;
197                                 }
198
199                                 if (name == "section")
200                                         cinfo = new SectionInfo ();
201                                 else if (name == "sectionGroup") {
202                                         cinfo = new SectionGroupInfo ();
203                                 } else
204                                         ThrowException ("Unrecognized element: " + reader.Name, reader);
205                                         
206                                 cinfo.ReadConfig (cfg, streamName, reader);
207                                 ConfigInfo actInfo = Groups [cinfo.Name];
208                                 if (actInfo == null) actInfo = Sections [cinfo.Name];
209                                 
210                                 if (actInfo != null) {
211                                         if (actInfo.GetType () != cinfo.GetType ())
212                                                 ThrowException ("A section or section group named '" + cinfo.Name + "' already exists", reader);
213                                         // Merge all the new data
214                                         actInfo.Merge (cinfo);
215                                         
216                                         // Make sure that this section is saved in this configuration file:
217                                         actInfo.StreamName = streamName;
218                                 }
219                                 else
220                                         AddChild (cinfo);
221                         }
222                         
223                         reader.ReadEndElement ();
224                 }
225                 
226                 public override void WriteConfig (Configuration cfg, XmlWriter writer, ConfigurationSaveMode mode)
227                 {
228                         if (Name != null) {
229                                 writer.WriteStartElement ("sectionGroup");
230                                 writer.WriteAttributeString ("name", Name);
231                                 if (TypeName != null && TypeName != "" && TypeName != "System.Configuration.ConfigurationSectionGroup")
232                                         writer.WriteAttributeString ("type", TypeName);
233                         }
234                         else
235                                 writer.WriteStartElement ("configSections");
236                         
237                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
238                                 foreach (string key in col) {
239                                         ConfigInfo cinfo = col [key];
240                                         if (cinfo.HasConfigContent (cfg))
241                                                 cinfo.WriteConfig (cfg, writer, mode);
242                                 }
243                         }
244                         
245                         writer.WriteEndElement ();
246                 }
247
248                 private void ReadRemoveSection (XmlTextReader reader)
249                 {
250                         if (!reader.MoveToNextAttribute () || reader.Name != "name")
251                                 ThrowException ("Unrecognized attribute.", reader);
252
253                         string removeValue = reader.Value;
254                         if (removeValue == null || removeValue.Length == 0)
255                                 ThrowException ("Empty name to remove", reader);
256
257                         reader.MoveToElement ();
258
259                         if (!HasChild (removeValue))
260                                 ThrowException ("No factory for " + removeValue, reader);
261
262                         RemoveChild (removeValue);
263                         reader.Skip ();
264                 }
265
266                 public void ReadRootData (XmlTextReader reader, Configuration config, bool overrideAllowed)
267                 {
268                         reader.MoveToContent ();
269                         ReadContent (reader, config, overrideAllowed, true);
270                 }
271                 
272                 public override void ReadData (Configuration config, XmlTextReader reader, bool overrideAllowed)
273                 {
274                         reader.MoveToContent ();
275                         reader.ReadStartElement ();
276                         ReadContent (reader, config, overrideAllowed, false);
277                         reader.MoveToContent ();
278                         reader.ReadEndElement ();
279                 }
280                 
281                 void ReadContent (XmlTextReader reader, Configuration config, bool overrideAllowed, bool root)
282                 {
283                         StringBuilder spacing = new StringBuilder ();
284                         while (reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.None) {
285                                 if (reader.NodeType != XmlNodeType.Element) {
286                                         if (reader.NodeType == XmlNodeType.Whitespace)
287                                                 spacing.Append (reader.Value);
288                                         reader.Skip ();
289                                         continue;
290                                 }
291
292                                 if (reader.LocalName == "dllmap") {
293                                         reader.Skip ();
294                                         continue;
295                                 }
296
297                                 if (reader.LocalName == "location") {
298                                         if (!root)
299                                                 ThrowException ("<location> elements are only allowed in <configuration> elements.", reader);
300
301                                         string allowOverrideAttr = reader.GetAttribute ("allowOverride");
302                                         bool allowOverride = allowOverrideAttr == null || allowOverrideAttr.Length == 0 || bool.Parse (allowOverrideAttr);
303                                         string path = reader.GetAttribute ("path");
304                                         if (path != null && path.Length > 0) {
305                                                 string xml = reader.ReadOuterXml ();
306                                                 string[] pathList = path.Split (',');
307                                                 foreach (string p in pathList) {
308                                                         ConfigurationLocation loc = new ConfigurationLocation (p.Trim (), xml, config, allowOverride);
309                                                         config.Locations.Add (loc);
310                                                 }
311                                         } else {
312                                                 ReadData (config, reader, allowOverride);
313                                         }
314                                         continue;
315                                 }
316                                 
317                                 if (reader.IsEmptyElement) {
318                                         reader.Skip ();
319                                         continue;
320                                 }
321                         
322                                 ConfigInfo data = GetConfigInfo (reader, this);
323                                 if (data != null)
324                                         data.ReadData (config, reader, overrideAllowed);
325                                 else
326                                         ThrowException ("Unrecognized configuration section <" + reader.LocalName + ">", reader);
327                         }
328                 }
329
330                 ConfigInfo GetConfigInfo (XmlReader reader, SectionGroupInfo current)
331                 {
332                         ConfigInfo data = null;
333                         if (current.sections != null)
334                                 data = current.sections [reader.LocalName];
335                         if (data != null)
336                                 return data;
337                         if (current.groups != null)
338                                 data = current.groups [reader.LocalName];
339                         if (data != null)
340                                 return data;
341                         if (current.groups == null)
342                                 return null;
343                         // It might be a section in descendant sectionGroups
344                         foreach (string key in current.groups.AllKeys) {
345                                 data = GetConfigInfo (reader, (SectionGroupInfo) current.groups [key]);
346                                 if (data != null)
347                                         return data;
348                         }
349                         
350                         // It might be in the root section group
351                         return null;
352                 }
353
354                 internal override void Merge (ConfigInfo newData)
355                 {
356                         SectionGroupInfo data = newData as SectionGroupInfo;
357                         if (data == null)
358                                 return;
359                         ConfigInfo actInfo;
360                         if (data.sections != null && data.sections.Count > 0)
361                                 foreach (string key in data.sections.AllKeys) {
362                                         actInfo = sections[key];
363                                         if (actInfo != null)
364                                                 continue;
365                                         sections.Add (key, data.sections[key]);
366                                 }
367                         
368                         if (data.groups != null && data.sections.Count > 0)
369                                 foreach (string key in data.groups.AllKeys) {
370                                         actInfo = groups[key];
371                                         if (actInfo != null)
372                                                 continue;
373                                         groups.Add (key, data.groups[key]);
374                                 }
375                 }
376                 
377                 public void WriteRootData (XmlWriter writer, Configuration config, ConfigurationSaveMode mode)
378                 {
379                         WriteContent (writer, config, mode, false);
380                 }
381                 
382                 public override void WriteData (Configuration config, XmlWriter writer, ConfigurationSaveMode mode)
383                 {
384                         writer.WriteStartElement (Name);
385                         WriteContent (writer, config, mode, true);
386                         writer.WriteEndElement ();
387                 }
388                 
389                 public void WriteContent (XmlWriter writer, Configuration config, ConfigurationSaveMode mode, bool writeElem)
390                 {
391                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
392                                 foreach (string key in col) {
393                                         ConfigInfo cinfo = col [key];
394                                         if (cinfo.HasDataContent (config))
395                                                 cinfo.WriteData (config, writer, mode);
396                                 }
397                         }
398                 }
399         }
400         
401         internal class ConfigInfoCollection : NameObjectCollectionBase
402         {
403                 public ConfigInfoCollection ()
404                         : base (StringComparer.Ordinal)
405                 {
406                 }
407
408                 public ICollection AllKeys
409                 {
410                         get { return Keys; }
411                 }
412                 
413                 public ConfigInfo this [string name]
414                 {
415                         get { return (ConfigInfo) BaseGet (name); }
416                         set { BaseSet (name, value); }
417                 }
418         
419                 public ConfigInfo this [int index]
420                 {
421                         get { return (ConfigInfo) BaseGet (index); }
422                         set { BaseSet (index, value); }
423                 }
424                 
425                 public void Add (string name, ConfigInfo config)
426                 {
427                         BaseAdd (name, config);
428                 }
429                 
430                 public void Clear ()
431                 {
432                         BaseClear ();
433                 }
434                 
435                 public string GetKey (int index)
436                 {
437                         return BaseGetKey (index);
438                 }
439                 
440                 public void Remove (string name)
441                 {
442                         BaseRemove (name);
443                 }
444                 
445                 public void RemoveAt (int index)
446                 {
447                         BaseRemoveAt (index);
448                 }
449         }
450 }
451
452 #endif