2 // System.Configuration.ConfigurationElement.cs
5 // Duncan Mak (duncan@ximian.com)
6 // Lluis Sanchez Gual (lluis@novell.com)
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
30 #if NET_2_0 && XML_DEP
32 using System.Collections;
34 using System.Reflection;
36 using System.ComponentModel;
38 namespace System.Configuration
40 public abstract class ConfigurationElement
42 static Hashtable elementMaps = new Hashtable ();
44 string[] readProperties;
48 ConfigurationPropertyCollection keyProps;
50 protected ConfigurationElement ()
54 internal string RawXml {
55 get { return rawXml; }
56 set { rawXml = value; }
59 protected internal virtual ConfigurationPropertyCollection CollectionKeyProperties {
65 internal ConfigurationPropertyCollection GetKeyProperties ()
67 if (keyProps != null) return keyProps;
68 keyProps = CollectionKeyProperties;
69 if (keyProps != null) return keyProps;
71 if (map.Properties == Properties)
72 keyProps = map.KeyProperties;
74 keyProps = new ConfigurationPropertyCollection ();
75 foreach (ConfigurationProperty prop in Properties) {
83 protected internal object this [ConfigurationProperty property] {
85 if (values == null || !values.ContainsKey (property)) {
86 if (property.IsElement) {
87 object elem = Activator.CreateInstance (property.Type);
88 this [property] = elem;
92 return property.DefaultValue;
95 return values [property];
99 if (object.Equals (value, property.DefaultValue)) {
100 if (values == null) return;
101 values.Remove (property);
104 if (values == null) values = new Hashtable ();
105 values [property] = value;
111 protected internal object this [string property_name] {
113 ConfigurationProperty prop = Properties [property_name];
114 if (prop == null) throw new InvalidOperationException ("Property '" + property_name + "' not found in configuration section");
119 ConfigurationProperty prop = Properties [property_name];
120 if (prop == null) throw new InvalidOperationException ("Property '" + property_name + "' not found in configuration section");
125 protected internal virtual ConfigurationPropertyCollection Properties {
128 map = GetMap (GetType());
129 return map.Properties;
133 public override bool Equals (object compareTo)
135 ConfigurationElement other = compareTo as ConfigurationElement;
136 if (other == null) return false;
137 if (GetType() != other.GetType()) return false;
139 foreach (ConfigurationProperty prop in Properties) {
140 if (!object.Equals (this [prop], other [prop]))
146 public override int GetHashCode ()
149 foreach (ConfigurationProperty prop in Properties)
150 code += this [prop].GetHashCode ();
154 public bool HasValue (string key)
156 if (values == null) return false;
157 ConfigurationProperty prop = Properties [key];
158 if (prop == null) return false;
159 return values.ContainsKey (prop);
162 internal virtual bool HasValues ()
164 return values != null && values.Count > 0;
168 public string PropertyFileName ()
170 throw new NotImplementedException ();
174 public int PropertyLineNumber ()
176 throw new NotImplementedException ();
180 protected internal virtual void Deserialize (XmlReader reader, bool serializeCollectionKey)
182 Hashtable readProps = new Hashtable ();
184 reader.MoveToContent ();
185 while (reader.MoveToNextAttribute ())
187 ConfigurationProperty prop = Properties [reader.LocalName];
188 if (prop == null || (serializeCollectionKey && !prop.IsKey)) {
189 if (!HandleUnrecognizedAttribute (reader.LocalName, reader.Value))
190 throw new ConfigurationException ("Unrecognized attribute '" + reader.LocalName + "'.");
194 if (readProps.ContainsKey (prop))
195 throw new ConfigurationException ("The attribute '" + prop.Name + "' may only appear once in this element.");
197 object val = prop.ConvertFromString (reader.Value);
198 if (!object.Equals (val, prop.DefaultValue))
200 readProps [prop] = prop.Name;
203 reader.MoveToElement ();
204 if (reader.IsEmptyElement) {
208 reader.ReadStartElement ();
209 reader.MoveToContent ();
211 while (reader.NodeType != XmlNodeType.EndElement)
213 if (reader.NodeType != XmlNodeType.Element) {
218 ConfigurationProperty prop = Properties [reader.LocalName];
219 if (prop == null || (serializeCollectionKey && !prop.IsKey)) {
220 if (!HandleUnrecognizedElement (reader.LocalName, reader))
221 throw new ConfigurationException ("Unrecognized element '" + reader.LocalName + "'.");
226 throw new ConfigurationException ("Property '" + prop.Name + "' is not a ConfigurationElement.");
228 if (readProps.Contains (prop))
229 throw new ConfigurationException ("The element <" + prop.Name + "> may only appear once in this section.");
231 ConfigurationElement val = this [prop] as ConfigurationElement;
232 val.Deserialize (reader, serializeCollectionKey);
233 readProps [prop] = prop.Name;
239 if (readProps.Count > 0) {
240 readProperties = new string [readProps.Count];
241 readProps.Values.CopyTo ((object[])readProperties, 0);
245 protected virtual bool HandleUnrecognizedAttribute (string name, string value)
250 protected virtual bool HandleUnrecognizedElement (string element, XmlReader reader)
255 protected internal virtual void InitializeDefault ()
260 protected internal virtual bool IsModified ()
265 protected internal virtual void ReadXml (XmlReader reader, object context)
267 Deserialize (reader, false);
270 protected internal virtual void Reset (ConfigurationElement parentElement, object context)
272 if (parentElement != null) {
274 foreach (ConfigurationProperty prop in Properties) {
275 if (parentElement.HasValue (prop.Name)) {
276 if (prop.IsElement) {
277 ConfigurationElement parentValue = parentElement [prop.Name] as ConfigurationElement;
278 ConfigurationElement value = Activator.CreateInstance (parentValue.GetType()) as ConfigurationElement;
279 value.Reset (parentValue, context);
283 this [prop] = parentElement [prop.Name];
288 InitializeDefault ();
291 protected internal virtual void ResetModified ()
296 [MonoTODO ("Return value?")]
297 protected internal virtual bool Serialize (XmlWriter writer, bool serializeCollectionKey)
299 if (values == null) return true;
301 if (serializeCollectionKey) {
302 foreach (ConfigurationProperty prop in GetKeyProperties ())
303 writer.WriteAttributeString (prop.Name, prop.ConvertToString (this[prop]));
307 ArrayList elems = new ArrayList ();
308 foreach (DictionaryEntry entry in values)
310 ConfigurationProperty prop = (ConfigurationProperty) entry.Key;
311 if (prop.IsElement) continue;
313 if (!object.Equals (entry.Value, prop.DefaultValue))
314 writer.WriteAttributeString (prop.Name, prop.ConvertToString (entry.Value));
317 foreach (DictionaryEntry entry in values)
319 ConfigurationProperty prop = (ConfigurationProperty) entry.Key;
320 if (!prop.IsElement) continue;
322 ConfigurationElement val = entry.Value as ConfigurationElement;
323 if (val != null && val.HasValues ())
324 val.SerializeToXmlElement (writer, prop.Name);
330 protected internal virtual bool SerializeAttributeOnRemove (
331 ConfigurationProperty property)
333 throw new NotImplementedException ();
336 protected internal virtual bool SerializeToXmlElement (
337 XmlWriter writer, string elementName)
339 writer.WriteStartElement (elementName);
340 Serialize (writer, false);
341 writer.WriteEndElement ();
345 protected internal virtual void UnMerge (
346 ConfigurationElement source, ConfigurationElement parent,
347 bool serializeCollectionKey, object context,
348 ConfigurationUpdateMode updateMode)
350 if (source.GetType() != parent.GetType())
351 throw new ConfigurationException ("Can't unmerge two elements of different type");
353 foreach (ConfigurationProperty prop in source.Properties)
355 if (!source.HasValue (prop.Name)) continue;
357 object sourceValue = source [prop];
358 if (!parent.HasValue (prop.Name)) {
359 this [prop] = sourceValue;
362 else if (sourceValue != null) {
363 object parentValue = parent [prop];
364 if (prop.IsElement) {
365 if (parentValue != null) {
366 ConfigurationElement copy = (ConfigurationElement) Activator.CreateInstance (prop.Type);
367 copy.UnMerge ((ConfigurationElement) sourceValue, (ConfigurationElement) parentValue, serializeCollectionKey, context, updateMode);
371 this [prop] = sourceValue;
374 if (!object.Equals (sourceValue, parentValue) ||
375 (updateMode == ConfigurationUpdateMode.Full) ||
376 (updateMode == ConfigurationUpdateMode.Modified && source.IsReadFromConfig (prop.Name)))
377 this [prop] = sourceValue;
383 bool IsReadFromConfig (string propName)
385 return readProperties != null && Array.IndexOf (readProperties, propName) != -1;
389 protected virtual void ValidateRequiredProperties (
390 ConfigurationPropertyCollection properties,
391 bool serialize_collection_key)
393 throw new NotImplementedException ();
396 protected internal virtual string WriteXml (
397 ConfigurationElement parent,
398 object context, string name,
399 ConfigurationUpdateMode updateMode)
401 ConfigurationElement elem;
402 if (parent != null) {
403 elem = (ConfigurationElement) Activator.CreateInstance (GetType());
404 elem.UnMerge (this, parent, false, context, updateMode);
409 StringWriter sw = new StringWriter ();
410 XmlTextWriter tw = new XmlTextWriter (sw);
411 tw.Formatting = Formatting.Indented;
412 elem.SerializeToXmlElement (tw, name);
414 return sw.ToString ();
417 internal static ElementMap GetMap (Type t)
420 ElementMap map = elementMaps [t] as ElementMap;
421 if (map != null) return map;
422 map = new ElementMap (t);
423 elementMaps [t] = map;
429 internal class ElementMap
431 ConfigurationPropertyCollection properties;
432 ConfigurationPropertyCollection keyProperties;
434 public ElementMap (Type t)
436 ReflectProperties (t);
439 protected void ReflectProperties (Type t)
441 PropertyInfo[] props = t.GetProperties ();
442 foreach (PropertyInfo prop in props)
444 ConfigurationPropertyAttribute at = (ConfigurationPropertyAttribute) Attribute.GetCustomAttribute (prop, typeof(ConfigurationPropertyAttribute)) as ConfigurationPropertyAttribute;
445 if (at == null) continue;
446 string name = at.Name != null ? at.Name : prop.Name;
448 ConfigurationValidationAttribute validator = (ConfigurationValidationAttribute) Attribute.GetCustomAttribute (t, typeof(ConfigurationValidationAttribute)) as ConfigurationValidationAttribute;
449 TypeConverter converter = TypeDescriptor.GetConverter (prop.PropertyType);
450 ConfigurationProperty cp = new ConfigurationProperty (name, prop.PropertyType, at.DefaultValue, converter, validator, at.Flags);
452 if (properties == null) properties = new ConfigurationPropertyCollection ();
457 public bool HasProperties
459 get { return properties != null && properties.Count > 0; }
462 public ConfigurationPropertyCollection Properties
465 if (properties == null) properties = new ConfigurationPropertyCollection ();
470 public ConfigurationPropertyCollection KeyProperties {
472 if (keyProperties == null) {
473 keyProperties = new ConfigurationPropertyCollection ();
475 if (properties != null)
476 foreach (ConfigurationProperty p in properties)
477 if (p.IsKey) keyProperties.Add (p);
479 return keyProperties;