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
;
49 protected ConfigurationElement ()
51 map
= GetMap (GetType());
54 internal string RawXml
{
55 get { return rawXml; }
56 set { rawXml = value; }
59 protected internal virtual ConfigurationPropertyCollection CollectionKeyProperties
{
61 return map
.KeyProperties
;
65 protected internal object this [ConfigurationProperty property
] {
67 if (values
== null || !values
.ContainsKey (property
)) {
68 if (property
.IsElement
) {
69 object elem
= Activator
.CreateInstance (property
.Type
);
70 this [property
] = elem
;
74 return property
.DefaultValue
;
77 return values
[property
];
81 if (object.Equals (value, property
.DefaultValue
)) {
82 if (values
== null) return;
83 values
.Remove (property
);
86 if (values
== null) values
= new Hashtable ();
87 values
[property
] = value;
93 protected internal object this [string property_name
] {
95 ConfigurationProperty prop
= map
.Properties
[property_name
];
96 if (prop
== null) throw new InvalidOperationException ("Property '" + property_name
+ "' not found in configuration section");
101 ConfigurationProperty prop
= map
.Properties
[property_name
];
102 if (prop
== null) throw new InvalidOperationException ("Property '" + property_name
+ "' not found in configuration section");
107 protected internal virtual ConfigurationPropertyCollection Properties
{
109 return map
.Properties
;
114 public override bool Equals (object compareTo
)
116 return base.Equals (compareTo
);
120 public override int GetHashCode ()
122 return base.GetHashCode ();
125 public bool HasValue (string key
)
127 if (values
== null) return false;
128 ConfigurationProperty prop
= map
.Properties
[key
];
129 if (prop
== null) return false;
130 return values
.ContainsKey (prop
);
133 internal bool HasValues ()
135 return values
!= null && values
.Count
> 0;
139 public string PropertyFileName ()
141 throw new NotImplementedException ();
145 public int PropertyLineNumber ()
147 throw new NotImplementedException ();
151 protected internal virtual void Deserialize (XmlReader reader
, bool serializeCollectionKey
)
153 Hashtable readProps
= new Hashtable ();
155 reader
.MoveToContent ();
156 if (!map
.HasProperties
) {
161 while (reader
.MoveToNextAttribute ())
163 ConfigurationProperty prop
= map
.Properties
[reader
.LocalName
];
165 if (!HandleUnrecognizedAttribute (reader
.LocalName
, reader
.Value
))
166 throw new ConfigurationException ("Unrecognized attribute '" + reader
.LocalName
+ "'.");
170 if (readProps
.Contains (prop
))
171 throw new ConfigurationException ("The attribute '" + prop
.Name
+ "' may only appear once in this element.");
173 object val
= prop
.ConvertFromString (reader
.Value
);
174 if (!object.Equals (val
, prop
.DefaultValue
))
176 readProps
[prop
] = prop
.Name
;
179 reader
.MoveToElement ();
180 if (reader
.IsEmptyElement
) {
184 reader
.ReadStartElement ();
185 reader
.MoveToContent ();
187 while (reader
.NodeType
!= XmlNodeType
.EndElement
)
189 if (reader
.NodeType
!= XmlNodeType
.Element
) {
194 ConfigurationProperty prop
= map
.Properties
[reader
.LocalName
];
196 if (!HandleUnrecognizedElement (reader
.LocalName
, reader
))
197 throw new ConfigurationException ("Unrecognized element '" + reader
.LocalName
+ "'.");
202 throw new ConfigurationException ("Property '" + prop
.Name
+ "' is not a ConfigurationElement.");
204 if (readProps
.Contains (prop
))
205 throw new ConfigurationException ("The element <" + prop
.Name
+ "> may only appear once in this section.");
207 ConfigurationElement val
= this [prop
] as ConfigurationElement
;
208 val
.Deserialize (reader
, serializeCollectionKey
);
209 readProps
[prop
] = prop
.Name
;
215 if (readProps
.Count
> 0) {
216 readProperties
= new string [readProps
.Count
];
217 readProps
.Values
.CopyTo ((object[])readProperties
, 0);
221 protected virtual bool HandleUnrecognizedAttribute (string name
, string value)
226 protected virtual bool HandleUnrecognizedElement (string element
, XmlReader reader
)
232 protected internal virtual void InitializeDefault ()
237 protected internal virtual bool IsModified ()
243 protected internal virtual void ReadXml (XmlReader reader
, object context
)
245 Deserialize (reader
, false);
249 protected internal virtual void Reset (ConfigurationElement parent_element
, object context
)
251 if (parent_element
!= null) {
252 if (!map
.HasProperties
) return;
254 foreach (ConfigurationProperty prop
in map
.Properties
) {
255 if (parent_element
.HasValue (prop
.Name
))
256 this [prop
] = parent_element
[prop
.Name
];
260 InitializeDefault ();
263 protected internal virtual void ResetModified ()
268 [MonoTODO ("Return value?")]
269 protected internal virtual bool Serialize (XmlWriter writer
, bool serializeCollectionKey
)
271 if (values
== null || !map
.HasProperties
) return true;
273 ArrayList elems
= new ArrayList ();
274 foreach (DictionaryEntry entry
in values
)
276 ConfigurationProperty prop
= (ConfigurationProperty
) entry
.Key
;
277 if (serializeCollectionKey
&& !prop
.IsKey
) continue;
278 if (prop
.IsElement
) continue;
280 if (!object.Equals (entry
.Value
, prop
.DefaultValue
))
281 writer
.WriteAttributeString (prop
.Name
, prop
.ConvertToString (entry
.Value
));
283 if (serializeCollectionKey
) return true;
285 foreach (DictionaryEntry entry
in values
)
287 ConfigurationProperty prop
= (ConfigurationProperty
) entry
.Key
;
288 if (!prop
.IsElement
) continue;
290 ConfigurationElement val
= entry
.Value
as ConfigurationElement
;
291 if (val
!= null && val
.HasValues ())
292 val
.SerializeToXmlElement (writer
, prop
.Name
);
298 protected internal virtual bool SerializeAttributeOnRemove (
299 ConfigurationProperty property
)
301 throw new NotImplementedException ();
304 protected internal virtual bool SerializeToXmlElement (
305 XmlWriter writer
, string elementName
)
307 writer
.WriteStartElement (elementName
);
308 Serialize (writer
, false);
309 writer
.WriteEndElement ();
313 protected internal virtual void UnMerge (
314 ConfigurationElement source
, ConfigurationElement parent
,
315 bool serializeCollectionKey
, object context
,
316 ConfigurationUpdateMode updateMode
)
318 if (source
.map
!= parent
.map
)
319 throw new ConfigurationException ("Can't unmerge two elements of different type");
321 ElementMap map
= source
.map
;
322 if (!map
.HasProperties
) return;
324 foreach (ConfigurationProperty prop
in map
.Properties
)
326 if (!source
.HasValue (prop
.Name
)) continue;
328 object sourceValue
= source
[prop
];
329 if (!parent
.HasValue (prop
.Name
) || updateMode
== ConfigurationUpdateMode
.Full
) {
330 this [prop
] = sourceValue
;
333 else if (sourceValue
!= null) {
334 object parentValue
= parent
[prop
];
335 if (prop
.IsElement
) {
336 if (parentValue
!= null) {
337 ConfigurationElement copy
= (ConfigurationElement
) Activator
.CreateInstance (prop
.Type
);
338 copy
.UnMerge ((ConfigurationElement
) sourceValue
, (ConfigurationElement
) parentValue
, serializeCollectionKey
, context
, updateMode
);
342 this [prop
] = sourceValue
;
345 if (!object.Equals (sourceValue
, parentValue
) ||
346 (updateMode
== ConfigurationUpdateMode
.Modified
&& source
.IsReadFromConfig (prop
.Name
)))
347 this [prop
] = sourceValue
;
353 bool IsReadFromConfig (string propName
)
355 return readProperties
!= null && Array
.IndexOf (readProperties
, propName
) != -1;
359 protected virtual void ValidateRequiredProperties (
360 ConfigurationPropertyCollection properties
,
361 bool serialize_collection_key
)
363 throw new NotImplementedException ();
366 protected internal virtual string WriteXml (
367 ConfigurationElement parent
,
368 object context
, string name
,
369 ConfigurationUpdateMode updateMode
)
371 ConfigurationElement elem
;
372 if (parent
!= null) {
373 elem
= (ConfigurationElement
) Activator
.CreateInstance (GetType());
374 elem
.UnMerge (this, parent
, false, context
, updateMode
);
379 StringWriter sw
= new StringWriter ();
380 XmlTextWriter tw
= new XmlTextWriter (sw
);
381 tw
.Formatting
= Formatting
.Indented
;
382 elem
.SerializeToXmlElement (tw
, name
);
384 return sw
.ToString ();
387 internal static ElementMap
GetMap (Type t
)
390 ElementMap map
= elementMaps
[t
] as ElementMap
;
391 if (map
!= null) return map
;
393 if (typeof(ConfigurationElementCollection
).IsAssignableFrom (t
))
394 map
= new CollectionElementMap (t
);
396 map
= new ElementMap (t
);
397 elementMaps
[t
] = map
;
403 internal class ElementMap
405 ConfigurationPropertyCollection properties
;
406 ConfigurationPropertyCollection keyProperties
;
408 public ElementMap (Type t
)
410 ReflectProperties (t
);
413 protected void ReflectProperties (Type t
)
415 PropertyInfo
[] props
= t
.GetProperties ();
416 foreach (PropertyInfo prop
in props
)
418 ConfigurationPropertyAttribute at
= (ConfigurationPropertyAttribute
) Attribute
.GetCustomAttribute (prop
, typeof(ConfigurationPropertyAttribute
)) as ConfigurationPropertyAttribute
;
419 if (at
== null) continue;
420 string name
= at
.Name
!= null ? at
.Name
: prop
.Name
;
422 ConfigurationValidationAttribute validator
= (ConfigurationValidationAttribute
) Attribute
.GetCustomAttribute (t
, typeof(ConfigurationValidationAttribute
)) as ConfigurationValidationAttribute
;
423 TypeConverter converter
= TypeDescriptor
.GetConverter (prop
.PropertyType
);
424 ConfigurationProperty cp
= new ConfigurationProperty (name
, prop
.PropertyType
, at
.DefaultValue
, converter
, validator
, at
.Flags
);
426 if (properties
== null) properties
= new ConfigurationPropertyCollection ();
431 public bool HasProperties
433 get { return properties != null && properties.Count > 0; }
436 public ConfigurationPropertyCollection Properties
439 if (properties
== null) properties
= new ConfigurationPropertyCollection ();
444 public ConfigurationPropertyCollection KeyProperties
{
446 if (keyProperties
== null) {
447 keyProperties
= new ConfigurationPropertyCollection ();
449 if (properties
!= null)
450 foreach (ConfigurationProperty p
in properties
)
451 if (p
.IsKey
) keyProperties
.Add (p
);
453 return keyProperties
;
458 internal class CollectionElementMap
: ElementMap
460 public CollectionElementMap (Type t
): base (t
)