2008-01-16 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / System.Configuration / System.Configuration / ConfigurationElement.cs
index 9fd0cced8a5eeb1543916f854d704cf4b5559f13..afd9d1811c771349f6da23634cd304aa8443264d 100644 (file)
@@ -67,7 +67,12 @@ namespace System.Configuration
 
                internal string RawXml {
                        get { return rawXml; }
-                       set { rawXml = value; }
+                       set {
+                               // FIXME: this hack is nasty. We should make
+                               // some refactory on the entire assembly.
+                               if (rawXml == null || value != null)
+                                       rawXml = value;
+                       }
                }
 
                protected internal virtual void Init ()
@@ -140,13 +145,13 @@ namespace System.Configuration
                }
 
                [MonoTODO]
-               public void ListErrors (IList list)
+               protected virtual void ListErrors (IList list)
                {
                        throw new NotImplementedException ();
                }
 
                [MonoTODO]
-               public void SetPropertyValue (ConfigurationProperty prop, object value, bool ignoreLocks)
+               protected void SetPropertyValue (ConfigurationProperty prop, object value, bool ignoreLocks)
                {
                        try {
                                /* XXX all i know for certain is that Validation happens here */
@@ -169,16 +174,13 @@ namespace System.Configuration
                {
                        if (keyProps != null) return keyProps;
                        
-                       if (map != null && map.Properties == Properties)
-                               keyProps = map.KeyProperties;
-                       else {
-                               keyProps = new ConfigurationPropertyCollection ();
+                       ConfigurationPropertyCollection tmpkeyProps = new ConfigurationPropertyCollection ();
                                foreach (ConfigurationProperty prop in Properties) {
                                        if (prop.IsKey)
-                                               keyProps.Add (prop);
+                                       tmpkeyProps.Add (prop);
                                }
-                       }
-                       return keyProps;
+
+                       return keyProps = tmpkeyProps;
                }
 
                internal ConfigurationElementCollection GetDefaultCollection ()
@@ -187,15 +189,10 @@ namespace System.Configuration
 
                        ConfigurationProperty defaultCollectionProp = null;
 
-                       if (map != null && map.Properties == Properties) {
-                               defaultCollectionProp = map.DefaultCollectionProperty;
-                       }
-                       else {
-                               foreach (ConfigurationProperty prop in Properties) {
-                                       if (prop.IsDefaultCollection) {
-                                               defaultCollectionProp = prop;
-                                               break;
-                                       }
+                       foreach (ConfigurationProperty prop in Properties) {
+                               if (prop.IsDefaultCollection) {
+                                       defaultCollectionProp = prop;
+                                       break;
                                }
                        }
 
@@ -256,8 +253,16 @@ namespace System.Configuration
                public override int GetHashCode ()
                {
                        int code = 0;
-                       foreach (ConfigurationProperty prop in Properties)
-                               code += this [prop].GetHashCode ();
+                       object o;
+                       
+                       foreach (ConfigurationProperty prop in Properties) {
+                               o = this [prop];
+                               if (o == null)
+                                       continue;
+                               
+                               code += o.GetHashCode ();
+                       }
+                       
                        return code;
                }
 
@@ -292,7 +297,10 @@ namespace System.Configuration
                                                LockElements.SetFromList (reader.Value);
                                        }
                                        else if (reader.LocalName == "lockItem") {
-                                               LockItem = (reader.Value.ToLower() == "true");
+                                               LockItem = (reader.Value.ToLowerInvariant () == "true");
+                                       }
+                                       else if (reader.LocalName == "xmlns") {
+                                               /* ignore */
                                        }
                                        else if (!OnDeserializeUnrecognizedAttribute (reader.LocalName, reader.Value))
                                                throw new ConfigurationException ("Unrecognized attribute '" + reader.LocalName + "'.");
@@ -302,17 +310,27 @@ namespace System.Configuration
                                
                                if (readProps.ContainsKey (prop))
                                        throw new ConfigurationException ("The attribute '" + prop.Name + "' may only appear once in this element.");
-                               
-                               prop.SetStringValue (reader.Value);
+
+                               string value = null;
+                               try {
+                                       value = reader.Value;
+                                       ValidateValue (prop.Property, value);
+                                       prop.SetStringValue (value);
+                               } catch (ConfigurationErrorsException) {
+                                       throw;
+                               } catch (ConfigurationException) {
+                                       throw;
+                               } catch (Exception ex) {
+                                       string msg = String.Format ("The value of the property '{0}' cannot be parsed.", prop.Name);
+                                       throw new ConfigurationErrorsException (msg, ex, reader);
+                               }
                                readProps [prop] = prop.Name;
                        }
                        
                        reader.MoveToElement ();
                        if (reader.IsEmptyElement) {
                                reader.Skip ();
-                       }
-                       else {
-
+                       } else {
                                int depth = reader.Depth;
 
                                reader.ReadStartElement ();
@@ -326,13 +344,12 @@ namespace System.Configuration
                                        
                                        PropertyInformation prop = ElementInformation.Properties [reader.LocalName];
                                        if (prop == null || (serializeCollectionKey && !prop.IsKey)) {
-                                               if (prop == null) {
-                                                       ConfigurationElementCollection c = GetDefaultCollection ();
-                                                       if (c != null && c.OnDeserializeUnrecognizedElement (reader.LocalName, reader))
-                                                               continue;
-                                               }
-
                                                if (!OnDeserializeUnrecognizedElement (reader.LocalName, reader)) {
+                                                       if (prop == null) {
+                                                               ConfigurationElementCollection c = GetDefaultCollection ();
+                                                               if (c != null && c.OnDeserializeUnrecognizedElement (reader.LocalName, reader))
+                                                                       continue;
+                                                       }
                                                        throw new ConfigurationException ("Unrecognized element '" + reader.LocalName + "'.");
                                                }
                                                continue;
@@ -359,7 +376,7 @@ namespace System.Configuration
                        modified = false;
                                
                        foreach (PropertyInformation prop in ElementInformation.Properties)
-                               if (prop.IsRequired && !readProps.ContainsKey (prop)) {
+                               if (!String.IsNullOrEmpty(prop.Name) && prop.IsRequired && !readProps.ContainsKey (prop)) {
                                        object val = OnRequiredPropertyNotFound (prop.Name);
                                        if (!object.Equals (val, prop.DefaultValue)) {
                                                prop.Value = val;
@@ -457,9 +474,8 @@ namespace System.Configuration
                                        continue;
                                
                                ConfigurationElement val = (ConfigurationElement) prop.Value;
-                               if (val != null && val.HasValues ()) {
+                               if (val != null)
                                        wroteData = val.SerializeToXmlElement (writer, prop.Name) || wroteData;
-                               }
                        }
                        return wroteData;
                }
@@ -467,6 +483,9 @@ namespace System.Configuration
                protected internal virtual bool SerializeToXmlElement (
                                XmlWriter writer, string elementName)
                {
+                       if (!HasValues ())
+                               return false;
+
                        if (elementName != null && elementName != "")
                                writer.WriteStartElement (elementName);
                        bool res = SerializeElement (writer, false);
@@ -525,114 +544,98 @@ namespace System.Configuration
                        PropertyInformation info = ElementInformation.Properties [propName];
                        return info != null && info.ValueOrigin == PropertyValueOrigin.SetHere;
                }
+
+               void ValidateValue (ConfigurationProperty p, string value)
+               {
+                       ConfigurationValidatorBase validator;
+                       if (p == null || (validator = p.Validator) == null)
+                               return;
+                       
+                       if (!validator.CanValidate (p.Type))
+                               throw new ConfigurationException (
+                                       String.Format ("Validator does not support type {0}", p.Type));
+                       validator.Validate (p.ConvertFromString (value));
+               }
        }
        
        internal class ElementMap
        {
-               static Hashtable elementMaps = new Hashtable ();
-               
-               ConfigurationPropertyCollection properties;
-               ConfigurationPropertyCollection keyProperties;
-               ConfigurationProperty defaultCollectionProperty;
+#if TARGET_JVM
+               const string elementMapsKey = "ElementMap_elementMaps";
+               static Hashtable elementMaps
+               {
+                       get
+                       {
+                               Hashtable tbl = (Hashtable) AppDomain.CurrentDomain.GetData (elementMapsKey);
+                               if (tbl == null) {
+                                       lock (typeof (ElementMap)) {
+                                               tbl = (Hashtable) AppDomain.CurrentDomain.GetData (elementMapsKey);
+                                               if (tbl == null) {
+                                                       tbl = Hashtable.Synchronized (new Hashtable ());
+                                                       AppDomain.CurrentDomain.SetData (elementMapsKey, tbl);
+                                               }
+                                       }
+                               }
+                               return tbl;
+                       }
+               }
+#else
+               static readonly Hashtable elementMaps = Hashtable.Synchronized (new Hashtable ());
+#endif
+
+               readonly ConfigurationPropertyCollection properties;
+               readonly ConfigurationCollectionAttribute collectionAttribute;
 
-               ConfigurationCollectionAttribute collectionAttribute;
-               
                public static ElementMap GetMap (Type t)
                {
-                       lock (elementMaps) {
-                               ElementMap map = elementMaps [t] as ElementMap;
-                               if (map != null) return map;
-                               map = new ElementMap (t);
-                               elementMaps [t] = map;
-                               return map;
-                       }
+                       ElementMap map = elementMaps [t] as ElementMap;
+                       if (map != null) return map;
+                       map = new ElementMap (t);
+                       elementMaps [t] = map;
+                       return map;
                }
                
                public ElementMap (Type t)
                {
-                       ReflectProperties (t);
-               }
+                       properties = new ConfigurationPropertyCollection ();
                
-               protected void ReflectProperties (Type t)
-               {
                        collectionAttribute = Attribute.GetCustomAttribute (t, typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
                        
-                       PropertyInfo[] props = t.GetProperties ();
+                       PropertyInfo[] props = t.GetProperties (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance);
                        foreach (PropertyInfo prop in props)
                        {
                                ConfigurationPropertyAttribute at = Attribute.GetCustomAttribute (prop, typeof(ConfigurationPropertyAttribute)) as ConfigurationPropertyAttribute;
                                if (at == null) continue;
                                string name = at.Name != null ? at.Name : prop.Name;
 
-                               if (
-                                   /* if we have no default value, don't bother to check further */
-                                   at.DefaultValue != null && at.DefaultValue != ConfigurationProperty.NoDefaultValue
-                                   )
-                               {
-                                       try {
-                                               Convert.ChangeType (at.DefaultValue, prop.PropertyType);
-                                       }
-                                       catch {
-                                               throw new ConfigurationErrorsException (String.Format ("The default value for property '{0}' has a different type than the one of the property itself",
-                                                                                                      name));
-                                       }
-                               }
+                               ConfigurationValidatorAttribute validatorAttr = Attribute.GetCustomAttribute (prop, typeof (ConfigurationValidatorAttribute)) as ConfigurationValidatorAttribute;
+                               ConfigurationValidatorBase validator = validatorAttr != null ? validatorAttr.ValidatorInstance : null;
 
-                               ConfigurationValidatorAttribute validatorAttr = Attribute.GetCustomAttribute (t, typeof(ConfigurationValidatorAttribute)) as ConfigurationValidatorAttribute;
-                               ConfigurationValidatorBase validator = validatorAttr != null ? validatorAttr.ValidatorInstance : new DefaultValidator();
-                               
-                               TypeConverter converter = TypeDescriptor.GetConverter (prop.PropertyType);
+                               TypeConverterAttribute convertAttr = (TypeConverterAttribute) Attribute.GetCustomAttribute (prop, typeof (TypeConverterAttribute));
+                               TypeConverter converter = convertAttr != null ? (TypeConverter) Activator.CreateInstance (Type.GetType (convertAttr.ConverterTypeName), true) : null;
                                ConfigurationProperty cp = new ConfigurationProperty (name, prop.PropertyType, at.DefaultValue, converter, validator, at.Options);
-                               
-                               cp.CollectionAttribute = Attribute.GetCustomAttribute (prop, typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
-                               
-                               if (properties == null) properties = new ConfigurationPropertyCollection ();
+
+                               cp.CollectionAttribute = Attribute.GetCustomAttribute (prop, typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;                             
                                properties.Add (cp);
                        }
                }
+
+               public ConfigurationCollectionAttribute CollectionAttribute
+               {
+                       get { return collectionAttribute; }
+               }
                
                public bool HasProperties
                {
-                       get { return properties != null && properties.Count > 0; }
+                       get { return properties.Count > 0; }
                }
                
                public ConfigurationPropertyCollection Properties
                {
                        get {
-                               if (properties == null) properties = new ConfigurationPropertyCollection ();
                                return properties;
                        }
                }
-               
-               public ConfigurationPropertyCollection KeyProperties {
-                       get {
-                               if (keyProperties == null) {
-                                       keyProperties = new ConfigurationPropertyCollection ();
-                                       
-                                       if (properties != null)
-                                               foreach (ConfigurationProperty p in properties)
-                                                       if (p.IsKey) keyProperties.Add (p);
-                               }
-                               return keyProperties;
-                       }
-               }
-               
-               public ConfigurationCollectionAttribute CollectionAttribute {
-                       get { return collectionAttribute; }
-               }
-               
-               public ConfigurationProperty DefaultCollectionProperty {
-                       get {
-                               if (defaultCollectionProperty == null) {
-                                       if (properties != null)
-                                               foreach (ConfigurationProperty p in properties) {
-                                                       if (p.IsDefaultCollection) defaultCollectionProperty = p;
-                                                       break;
-                                               }
-                               }
-                               return defaultCollectionProperty;
-                       }
-               }
        }
 }