New test.
[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) {
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                                 
318                                 ConfigInfo data = GetConfigInfo (reader, this);
319
320                                 if (data != null)
321                                         data.ReadData (config, reader, overrideAllowed);
322                                 else
323                                         ThrowException ("Unrecognized configuration section <" + reader.LocalName + ">", reader);
324                         }
325                 }
326
327                 ConfigInfo GetConfigInfo (XmlReader reader, SectionGroupInfo current)
328                 {
329                         ConfigInfo data = null;
330                         if (current.sections != null)
331                                 data = current.sections [reader.LocalName];
332                         if (data != null)
333                                 return data;
334                         if (current.groups != null) 
335                                 data = current.groups [reader.LocalName];
336                         if (data != null)
337                                 return data;
338                         if (current.groups == null)
339                                 return null;
340                         // It might be a section in descendant sectionGroups
341                         foreach (string key in current.groups.AllKeys) {
342                                 data = GetConfigInfo (reader, (SectionGroupInfo) current.groups [key]);
343                                 if (data != null)
344                                         return data;
345                         }
346                         // It might be in the root section group
347                         return null;
348                 }
349
350                 internal override void Merge (ConfigInfo newData)
351                 {
352                         SectionGroupInfo data = newData as SectionGroupInfo;
353                         if (data == null)
354                                 return;
355                         ConfigInfo actInfo;
356                         if (data.sections != null && data.sections.Count > 0)
357                                 foreach (string key in data.sections.AllKeys) {
358                                         actInfo = sections[key];
359                                         if (actInfo != null)
360                                                 continue;
361                                         sections.Add (key, data.sections[key]);
362                                 }
363                         
364                         if (data.groups != null && data.sections.Count > 0)
365                                 foreach (string key in data.groups.AllKeys) {
366                                         actInfo = groups[key];
367                                         if (actInfo != null)
368                                                 continue;
369                                         groups.Add (key, data.groups[key]);
370                                 }
371                 }
372                 
373                 public void WriteRootData (XmlWriter writer, Configuration config, ConfigurationSaveMode mode)
374                 {
375                         WriteContent (writer, config, mode, false);
376                 }
377                 
378                 public override void WriteData (Configuration config, XmlWriter writer, ConfigurationSaveMode mode)
379                 {
380                         writer.WriteStartElement (Name);
381                         WriteContent (writer, config, mode, true);
382                         writer.WriteEndElement ();
383                 }
384                 
385                 public void WriteContent (XmlWriter writer, Configuration config, ConfigurationSaveMode mode, bool writeElem)
386                 {
387                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
388                                 foreach (string key in col) {
389                                         ConfigInfo cinfo = col [key];
390                                         if (cinfo.HasDataContent (config))
391                                                 cinfo.WriteData (config, writer, mode);
392                                 }
393                         }
394                 }
395         }
396         
397         internal class ConfigInfoCollection : NameObjectCollectionBase
398         {
399                 public ICollection AllKeys
400                 {
401                         get { return Keys; }
402                 }
403                 
404                 public ConfigInfo this [string name]
405                 {
406                         get { return (ConfigInfo) BaseGet (name); }
407                         set { BaseSet (name, value); }
408                 }
409         
410                 public ConfigInfo this [int index]
411                 {
412                         get { return (ConfigInfo) BaseGet (index); }
413                         set { BaseSet (index, value); }
414                 }
415                 
416                 public void Add (string name, ConfigInfo config)
417                 {
418                         BaseAdd (name, config);
419                 }
420                 
421                 public void Clear ()
422                 {
423                         BaseClear ();
424                 }
425                 
426                 public string GetKey (int index)
427                 {
428                         return BaseGetKey (index);
429                 }
430                 
431                 public void Remove (string name)
432                 {
433                         BaseRemove (name);
434                 }
435                 
436                 public void RemoveAt (int index)
437                 {
438                         BaseRemoveAt (index);
439                 }
440         }
441 }
442
443 #endif