1 //------------------------------------------------------------------------------ 2 // <copyright file="ConfigurationLockCollection.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 using System; 8 using System.Configuration.Internal; 9 using System.Collections; 10 using System.Collections.Specialized; 11 using System.Collections.Generic; 12 using System.IO; 13 using System.Reflection; 14 using System.Security.Permissions; 15 using System.Xml; 16 using System.Globalization; 17 using System.ComponentModel; 18 using System.Security; 19 using System.Text; 20 21 namespace System.Configuration { 22 23 public sealed class ConfigurationLockCollection : IEnumerable, ICollection { 24 private HybridDictionary internalDictionary; 25 private ArrayList internalArraylist; 26 private bool _bModified = false; 27 private bool _bExceptionList = false; 28 private string _ignoreName = String.Empty; 29 private ConfigurationElement _thisElement = null; 30 private ConfigurationLockCollectionType _lockType; 31 private string SeedList = String.Empty; 32 private const string LockAll = "*"; 33 ConfigurationLockCollection(ConfigurationElement thisElement)34 internal ConfigurationLockCollection(ConfigurationElement thisElement) 35 : this(thisElement, ConfigurationLockCollectionType.LockedAttributes) { 36 } 37 ConfigurationLockCollection(ConfigurationElement thisElement, ConfigurationLockCollectionType lockType)38 internal ConfigurationLockCollection(ConfigurationElement thisElement, ConfigurationLockCollectionType lockType) 39 : this(thisElement, lockType, String.Empty) { 40 } 41 ConfigurationLockCollection(ConfigurationElement thisElement, ConfigurationLockCollectionType lockType, string ignoreName)42 internal ConfigurationLockCollection(ConfigurationElement thisElement, ConfigurationLockCollectionType lockType, string ignoreName) 43 : this(thisElement, lockType, ignoreName, null) { 44 } 45 ConfigurationLockCollection(ConfigurationElement thisElement, ConfigurationLockCollectionType lockType, string ignoreName, ConfigurationLockCollection parentCollection)46 internal ConfigurationLockCollection(ConfigurationElement thisElement, ConfigurationLockCollectionType lockType, 47 string ignoreName, ConfigurationLockCollection parentCollection) { 48 _thisElement = thisElement; 49 _lockType = lockType; 50 internalDictionary = new HybridDictionary(); 51 internalArraylist = new ArrayList(); 52 _bModified = false; 53 54 _bExceptionList = _lockType == ConfigurationLockCollectionType.LockedExceptionList || 55 _lockType == ConfigurationLockCollectionType.LockedElementsExceptionList; 56 _ignoreName = ignoreName; 57 58 if (parentCollection != null) { 59 foreach (string key in parentCollection) // seed the new collection 60 { 61 Add(key, ConfigurationValueFlags.Inherited); // add the local copy 62 if (_bExceptionList) { 63 if (SeedList.Length != 0) 64 SeedList += ","; 65 SeedList += key; 66 } 67 } 68 } 69 70 } 71 ClearSeedList()72 internal void ClearSeedList() 73 { 74 SeedList = String.Empty; 75 } 76 77 internal ConfigurationLockCollectionType LockType { 78 get { return _lockType; } 79 } 80 Add(string name)81 public void Add(string name) { 82 83 if (((_thisElement.ItemLocked & ConfigurationValueFlags.Locked) != 0) && 84 ((_thisElement.ItemLocked & ConfigurationValueFlags.Inherited) != 0)) { 85 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, name)); 86 } 87 88 ConfigurationValueFlags flags = ConfigurationValueFlags.Modified; 89 90 string attribToLockTrim = name.Trim(); 91 ConfigurationProperty propToLock = _thisElement.Properties[attribToLockTrim]; 92 if (propToLock == null && attribToLockTrim != LockAll) { 93 ConfigurationElementCollection collection = _thisElement as ConfigurationElementCollection; 94 if (collection == null && _thisElement.Properties.DefaultCollectionProperty != null) { // this is not a collection but it may contain a default collection 95 collection = _thisElement[_thisElement.Properties.DefaultCollectionProperty] as ConfigurationElementCollection; 96 } 97 98 if (collection == null || 99 _lockType == ConfigurationLockCollectionType.LockedAttributes || // If the collection type is not element then the lock is bogus 100 _lockType == ConfigurationLockCollectionType.LockedExceptionList) { 101 _thisElement.ReportInvalidLock(attribToLockTrim, _lockType, null, null); 102 } 103 else if (!collection.IsLockableElement(attribToLockTrim)) { 104 _thisElement.ReportInvalidLock(attribToLockTrim, _lockType, null, collection.LockableElements); 105 } 106 } 107 else { // the lock is in the property bag but is it the correct type? 108 if (propToLock != null && propToLock.IsRequired) 109 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_required_attribute_lock_attempt, propToLock.Name)); 110 111 if (attribToLockTrim != LockAll) { 112 if ((_lockType == ConfigurationLockCollectionType.LockedElements) || 113 (_lockType == ConfigurationLockCollectionType.LockedElementsExceptionList)) { 114 // If it is an element then it must be derived from ConfigurationElement 115 if (!typeof(ConfigurationElement).IsAssignableFrom(propToLock.Type)) { 116 _thisElement.ReportInvalidLock(attribToLockTrim, _lockType, null, null); 117 } 118 } 119 else { 120 // if it is a property then it cannot be derived from ConfigurationElement 121 if (typeof(ConfigurationElement).IsAssignableFrom(propToLock.Type)) { 122 _thisElement.ReportInvalidLock(attribToLockTrim, _lockType, null, null); 123 } 124 } 125 } 126 } 127 128 if (internalDictionary.Contains(name)) { 129 flags = ConfigurationValueFlags.Modified | (ConfigurationValueFlags)internalDictionary[name]; 130 internalDictionary.Remove(name); // not from parent 131 internalArraylist.Remove(name); 132 } 133 internalDictionary.Add(name, flags); // not from parent 134 internalArraylist.Add(name); 135 _bModified = true; 136 } 137 138 Add(string name, ConfigurationValueFlags flags)139 internal void Add(string name, ConfigurationValueFlags flags) { 140 if ((flags != ConfigurationValueFlags.Inherited) && (internalDictionary.Contains(name))) { 141 // the user has an item declared as locked below a level where it is already locked 142 // keep enough info so we can write out the lock if they save in modified mode 143 flags = ConfigurationValueFlags.Modified | (ConfigurationValueFlags)internalDictionary[name]; 144 internalDictionary.Remove(name); 145 internalArraylist.Remove(name); 146 } 147 148 internalDictionary.Add(name, flags); // not from parent 149 internalArraylist.Add(name); 150 } 151 DefinedInParent(string name)152 internal bool DefinedInParent(string name) { 153 if (name == null) 154 return false; 155 if (_bExceptionList) 156 { 157 string ParentListEnclosed = "," + SeedList + ","; 158 if (name.Equals(_ignoreName) || ParentListEnclosed.IndexOf("," + name + ",", StringComparison.Ordinal) >= 0) { 159 return true; 160 } 161 } 162 return (internalDictionary.Contains(name) && 163 ((ConfigurationValueFlags)internalDictionary[name] & ConfigurationValueFlags.Inherited) != 0); 164 } 165 IsValueModified(string name)166 internal bool IsValueModified(string name) { 167 return (internalDictionary.Contains(name) && 168 ((ConfigurationValueFlags)internalDictionary[name] & ConfigurationValueFlags.Modified) != 0); 169 } 170 RemoveInheritedLocks()171 internal void RemoveInheritedLocks() { 172 StringCollection removeList = new StringCollection(); 173 foreach (string key in this) { 174 if (DefinedInParent(key)) { 175 removeList.Add(key); 176 } 177 } 178 foreach (string key in removeList) { 179 internalDictionary.Remove(key); 180 internalArraylist.Remove(key); 181 } 182 } 183 184 Remove(string name)185 public void Remove(string name) { 186 if (!internalDictionary.Contains(name)) { 187 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_not_found, name)); 188 } 189 // in a locked list you cannot remove items that were locked in the parent 190 // in an exception list this is legal because it makes the list more restrictive 191 192 if (_bExceptionList == false && 193 ((ConfigurationValueFlags)internalDictionary[name] & ConfigurationValueFlags.Inherited) != 0) { 194 if (((ConfigurationValueFlags)internalDictionary[name] & ConfigurationValueFlags.Modified) != 0) { 195 // allow the local one to be "removed" so it won't write out but throw if they try and remove 196 // one that is only inherited 197 ConfigurationValueFlags flags = (ConfigurationValueFlags)internalDictionary[name]; 198 flags &= ~ConfigurationValueFlags.Modified; 199 internalDictionary[name] = flags; 200 _bModified = true; 201 return; 202 } 203 else { 204 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, name)); 205 } 206 } 207 208 internalDictionary.Remove(name); 209 internalArraylist.Remove(name); 210 _bModified = true; 211 } 212 GetEnumerator()213 public IEnumerator GetEnumerator() { 214 return internalArraylist.GetEnumerator(); 215 } 216 ClearInternal(bool useSeedIfAvailble)217 internal void ClearInternal(bool useSeedIfAvailble) { 218 ArrayList removeList = new ArrayList(); 219 foreach (DictionaryEntry de in internalDictionary) { 220 if ((((ConfigurationValueFlags)de.Value & ConfigurationValueFlags.Inherited) == 0) 221 || _bExceptionList == true) { 222 removeList.Add(de.Key); 223 } 224 } 225 foreach (object removeKey in removeList) { 226 internalDictionary.Remove(removeKey); 227 internalArraylist.Remove(removeKey); 228 } 229 230 // Clearing an Exception list really means revert to parent 231 if (useSeedIfAvailble && !String.IsNullOrEmpty(SeedList)) { 232 string[] Keys = SeedList.Split(new char[] { ',' }); 233 foreach (string key in Keys) { 234 Add(key, ConfigurationValueFlags.Inherited); // 235 } 236 } 237 _bModified = true; 238 } 239 Clear()240 public void Clear() { 241 ClearInternal(true); 242 } 243 Contains(string name)244 public bool Contains(string name) { 245 if (_bExceptionList && name.Equals(_ignoreName)) { 246 return true; 247 } 248 return internalDictionary.Contains(name); 249 } 250 251 public int Count { 252 get { 253 return internalDictionary.Count; 254 } 255 } 256 257 public bool IsSynchronized { 258 get { 259 return false; 260 } 261 } 262 263 public object SyncRoot { 264 get { 265 return this; 266 } 267 } 268 CopyTo(string[] array, int index)269 public void CopyTo(string[] array, int index) { 270 ((ICollection)this).CopyTo(array, index); 271 } 272 ICollection.CopyTo(Array array, int index)273 void ICollection.CopyTo(Array array, int index) { 274 internalArraylist.CopyTo(array, index); 275 } 276 277 public bool IsModified { 278 get { 279 return _bModified; 280 } 281 } 282 ResetModified()283 internal void ResetModified() { 284 _bModified = false; 285 } 286 IsReadOnly(string name)287 public bool IsReadOnly(string name) { 288 if (!internalDictionary.Contains(name)) { 289 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_not_found, name)); 290 } 291 return (bool)(((ConfigurationValueFlags)internalDictionary[name] & ConfigurationValueFlags.Inherited) != 0); 292 } 293 294 internal bool ExceptionList { 295 get { 296 return _bExceptionList; 297 } 298 } 299 300 public string AttributeList { 301 get { 302 StringBuilder sb; 303 sb = new StringBuilder(); 304 305 foreach (DictionaryEntry de in internalDictionary) { 306 if (sb.Length != 0) { 307 sb.Append(','); 308 } 309 sb.Append(de.Key); 310 } 311 return sb.ToString(); 312 } 313 } 314 SetFromList(string attributeList)315 public void SetFromList(string attributeList) { 316 string[] splits = attributeList.Split(new char[] { ',', ';', ':' }); 317 Clear(); 318 foreach (string name in splits) { 319 string attribTrim = name.Trim(); 320 if (!Contains(attribTrim)) { 321 Add(attribTrim); 322 } 323 } 324 } 325 public bool HasParentElements { 326 get { 327 // return true if there is at least one element that was defined in the parent 328 bool result = false; 329 // Check to see if the exception list is empty as a result of a merge from config 330 // If so the there were some parent elements because empty string is invalid in config. 331 // and the only way to get an empty list is for the merged config to have no elements 332 // in common. 333 if (ExceptionList && internalDictionary.Count == 0 && !String.IsNullOrEmpty(SeedList)) 334 return true; 335 336 foreach (DictionaryEntry de in internalDictionary) { 337 if ((bool)(((ConfigurationValueFlags)de.Value & ConfigurationValueFlags.Inherited) != 0)) { 338 result = true; 339 break; 340 } 341 } 342 343 return result; 344 } 345 } 346 } 347 } 348