2006-06-10 Atsushi Enomoto <atsushi@ximian.com>
[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                                         // Make sure that this section is saved in this configuration file:
214                                         actInfo.StreamName = streamName;
215                                 }
216                                 else
217                                         AddChild (cinfo);
218                         }
219                         
220                         reader.ReadEndElement ();
221                 }
222                 
223                 public override void WriteConfig (Configuration cfg, XmlWriter writer, ConfigurationSaveMode mode)
224                 {
225                         if (Name != null) {
226                                 writer.WriteStartElement ("sectionGroup");
227                                 writer.WriteAttributeString ("name", Name);
228                                 if (TypeName != null && TypeName != "" && TypeName != "System.Configuration.ConfigurationSectionGroup")
229                                         writer.WriteAttributeString ("type", TypeName);
230                         }
231                         else
232                                 writer.WriteStartElement ("configSections");
233                         
234                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
235                                 foreach (string key in col) {
236                                         ConfigInfo cinfo = col [key];
237                                         if (cinfo.HasConfigContent (cfg))
238                                                 cinfo.WriteConfig (cfg, writer, mode);
239                                 }
240                         }
241                         
242                         writer.WriteEndElement ();
243                 }
244
245                 private void ReadRemoveSection (XmlTextReader reader)
246                 {
247                         if (!reader.MoveToNextAttribute () || reader.Name != "name")
248                                 ThrowException ("Unrecognized attribute.", reader);
249
250                         string removeValue = reader.Value;
251                         if (removeValue == null || removeValue.Length == 0)
252                                 ThrowException ("Empty name to remove", reader);
253
254                         reader.MoveToElement ();
255
256                         if (!HasChild (removeValue))
257                                 ThrowException ("No factory for " + removeValue, reader);
258
259                         RemoveChild (removeValue);
260                         reader.Skip ();
261                 }
262
263                 public void ReadRootData (XmlTextReader reader, Configuration config, bool overrideAllowed)
264                 {
265                         reader.MoveToContent ();
266                         ReadContent (reader, config, overrideAllowed, true);
267                 }
268                 
269                 public override void ReadData (Configuration config, XmlTextReader reader, bool overrideAllowed)
270                 {
271                         reader.MoveToContent ();
272                         reader.ReadStartElement ();
273                         ReadContent (reader, config, overrideAllowed, false);
274                         reader.MoveToContent ();
275                         reader.ReadEndElement ();
276                 }
277                 
278                 void ReadContent (XmlTextReader reader, Configuration config, bool overrideAllowed, bool root)
279                 {
280                         StringBuilder spacing = new StringBuilder ();
281                         while (reader.NodeType != XmlNodeType.EndElement) {
282                                 if (reader.NodeType != XmlNodeType.Element) {
283                                         if (reader.NodeType == XmlNodeType.Whitespace)
284                                                 spacing.Append (reader.Value);
285                                         reader.Skip ();
286                                         continue;
287                                 }
288
289                                 if (reader.LocalName == "dllmap") {
290                                         reader.Skip ();
291                                         continue;
292                                 }
293
294                                 if (reader.LocalName == "location") {
295                                         if (!root)
296                                                 ThrowException ("<location> elements are only allowed in <configuration> elements.", reader);
297
298                                         string allowOverrideAttr = reader.GetAttribute ("allowOverride");
299                                         bool allowOverride = allowOverrideAttr == null || allowOverrideAttr.Length == 0 || bool.Parse (allowOverrideAttr);
300                                         string path = reader.GetAttribute ("path");
301                                         if (path != null && path.Length > 0) {
302                                                 string xml = reader.ReadOuterXml ();
303                                                 string[] pathList = path.Split (',');
304                                                 foreach (string p in pathList) {
305                                                         ConfigurationLocation loc = new ConfigurationLocation (p.Trim (), xml, config, allowOverride);
306                                                         config.Locations.Add (loc);
307                                                 }
308                                         } else {
309                                                 ReadData (config, reader, allowOverride);
310                                         }
311                                         continue;
312                                 }
313
314                                 
315                                 ConfigInfo data = GetConfigInfo (reader, this);
316
317                                 if (data != null)
318                                         data.ReadData (config, reader, overrideAllowed);
319                                 else
320                                         ThrowException ("Unrecognized configuration section <" + reader.LocalName + ">", reader);
321                         }
322                 }
323
324                 ConfigInfo GetConfigInfo (XmlReader reader, SectionGroupInfo current)
325                 {
326                         ConfigInfo data = null;
327                         if (current.sections != null)
328                                 data = current.sections [reader.LocalName];
329                         if (data != null)
330                                 return data;
331                         if (current.groups != null) 
332                                 data = current.groups [reader.LocalName];
333                         if (data != null)
334                                 return data;
335                         if (current.groups == null)
336                                 return null;
337                         // It might be a section in descendant sectionGroups
338                         foreach (string key in current.groups.AllKeys) {
339                                 data = GetConfigInfo (reader, (SectionGroupInfo) current.groups [key]);
340                                 if (data != null)
341                                         return data;
342                         }
343                         return null;
344                 }
345
346                 public void WriteRootData (XmlWriter writer, Configuration config, ConfigurationSaveMode mode)
347                 {
348                         WriteContent (writer, config, mode, false);
349                 }
350                 
351                 public override void WriteData (Configuration config, XmlWriter writer, ConfigurationSaveMode mode)
352                 {
353                         writer.WriteStartElement (Name);
354                         WriteContent (writer, config, mode, true);
355                         writer.WriteEndElement ();
356                 }
357                 
358                 public void WriteContent (XmlWriter writer, Configuration config, ConfigurationSaveMode mode, bool writeElem)
359                 {
360                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
361                                 foreach (string key in col) {
362                                         ConfigInfo cinfo = col [key];
363                                         if (cinfo.HasDataContent (config))
364                                                 cinfo.WriteData (config, writer, mode);
365                                 }
366                         }
367                 }
368         }
369         
370         internal class ConfigInfoCollection : NameObjectCollectionBase
371         {
372                 public ICollection AllKeys
373                 {
374                         get { return Keys; }
375                 }
376                 
377                 public ConfigInfo this [string name]
378                 {
379                         get { return (ConfigInfo) BaseGet (name); }
380                         set { BaseSet (name, value); }
381                 }
382         
383                 public ConfigInfo this [int index]
384                 {
385                         get { return (ConfigInfo) BaseGet (index); }
386                         set { BaseSet (index, value); }
387                 }
388                 
389                 public void Add (string name, ConfigInfo config)
390                 {
391                         BaseAdd (name, config);
392                 }
393                 
394                 public void Clear ()
395                 {
396                         BaseClear ();
397                 }
398                 
399                 public string GetKey (int index)
400                 {
401                         return BaseGetKey (index);
402                 }
403                 
404                 public void Remove (string name)
405                 {
406                         BaseRemove (name);
407                 }
408                 
409                 public void RemoveAt (int index)
410                 {
411                         BaseRemoveAt (index);
412                 }
413         }
414 }
415
416 #endif