Implemented Servlet session management. Servlet hosting moved to Mainsoft.Web package
[mono.git] / mcs / class / System.Configuration / System.Configuration / ConfigurationElementCollection.cs
1 //
2 // System.Configuration.ConfigurationElementCollection.cs
3 //
4 // Authors:
5 //      Tim Coleman (tim@timcoleman.com)
6 //
7 // Copyright (C) Tim Coleman, 2004
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
30 //
31
32 #if NET_2_0
33
34 using System.Collections;
35 using System.Diagnostics;
36 using System.Xml;
37
38 namespace System.Configuration 
39 {
40         [DebuggerDisplayAttribute ("Count = {Count}")]
41         public abstract partial class ConfigurationElementCollection : ConfigurationElement, ICollection, IEnumerable
42         {
43                 ArrayList list = new ArrayList ();
44                 ArrayList removed;
45                 ArrayList inherited;
46                 bool emitClear;
47                 bool modified;
48                 IComparer comparer;
49                 int inheritedLimitIndex;
50                 
51                 string addElementName = "add";
52                 string clearElementName = "clear";
53                 string removeElementName = "remove";
54                 
55                 #region Constructors
56
57                 protected ConfigurationElementCollection ()
58                 {
59                 }
60
61                 protected ConfigurationElementCollection (IComparer comparer)
62                 {
63                         this.comparer = comparer;
64                 }
65
66                 internal override void InitFromProperty (PropertyInformation propertyInfo)
67                 {
68                         ConfigurationCollectionAttribute colat = propertyInfo.Property.CollectionAttribute;
69                         if (colat == null)
70                                 colat = ElementMap.GetMap (GetType ()).CollectionAttribute;
71                         if (colat != null) {
72                                 addElementName = colat.AddItemName;
73                                 clearElementName = colat.ClearItemsName;
74                                 removeElementName = colat.RemoveItemName;
75                         }
76                         base.InitFromProperty (propertyInfo);
77                 }
78                 
79                 #endregion // Constructors
80
81                 #region Properties
82                 
83                 public virtual ConfigurationElementCollectionType CollectionType {
84                         get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
85                 }
86                 
87                 bool IsBasic {
88                         get {
89                                 return CollectionType == ConfigurationElementCollectionType.BasicMap ||
90                                                 CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
91                         }
92                 }
93                 
94                 bool IsAlternate {
95                         get {
96                                 return CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate ||
97                                                 CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
98                         }
99                 }
100
101                 public int Count {
102                         get { return list.Count; }
103                 }
104
105                 protected virtual string ElementName {
106                         get { return string.Empty; }
107                 }
108
109                 public bool EmitClear {
110                         get { return emitClear; }
111                         set { emitClear = value; }
112                 }
113
114                 public bool IsSynchronized {
115                         get { return false; }
116                 }
117
118                 public object SyncRoot {
119                         get { return this; }
120                 }
121
122                 protected virtual bool ThrowOnDuplicate {
123                         get { return true; }
124                 }
125                 
126                 protected internal string AddElementName {
127                         get { return addElementName; }
128                         set { addElementName = value; }
129                 }
130
131                 protected internal string ClearElementName {
132                         get { return clearElementName; }
133                         set { clearElementName = value; }
134                 }
135
136                 protected internal string RemoveElementName {
137                         get { return removeElementName; }
138                         set { removeElementName = value; }
139                 }
140
141                 #endregion // Properties
142
143                 #region Methods
144
145                 protected virtual void BaseAdd (ConfigurationElement element)
146                 {
147                         BaseAdd (element, ThrowOnDuplicate);
148                 }
149
150                 protected void BaseAdd (ConfigurationElement element, bool throwIfExists)
151                 {
152                         if (IsReadOnly ())
153                                 throw new ConfigurationErrorsException ("Collection is read only.");
154                         
155                         int old_index = IndexOfKey (GetElementKey (element));
156                         if (old_index >= 0) {
157                                 if (element.Equals (list [old_index]))
158                                         return;
159                                 if (throwIfExists)
160                                         throw new ConfigurationException ("Duplicate element in collection");
161                         }
162                         if (IsAlternate) {
163                                 list.Insert (inheritedLimitIndex, element);
164                                 inheritedLimitIndex++;
165                         }
166                         else {
167                                 list.Add (element);
168                         }
169                         if (!IsAlternate && old_index != -1)
170                                 list.RemoveAt (old_index);
171                         modified = true;
172                 }
173
174                 protected virtual void BaseAdd (int index, ConfigurationElement element)
175                 {
176                         if (ThrowOnDuplicate && BaseIndexOf (element) != -1)
177                                 throw new ConfigurationException ("Duplicate element in collection");
178                         if (IsReadOnly ())
179                                 throw new ConfigurationErrorsException ("Collection is read only.");
180                         
181                         if (IsAlternate && (index > inheritedLimitIndex))
182                                 throw new ConfigurationErrorsException ("Can't insert new elements below the inherited elements.");
183                         if (!IsAlternate && (index <= inheritedLimitIndex))
184                                 throw new ConfigurationErrorsException ("Can't insert new elements above the inherited elements.");
185                         
186                         list.Insert (index, element);
187                         modified = true;
188                 }
189
190                 protected internal void BaseClear ()
191                 {
192                         if (IsReadOnly ())
193                                 throw new ConfigurationErrorsException ("Collection is read only.");
194                                 
195                         list.Clear ();
196                         modified = true;
197                 }
198
199                 protected internal ConfigurationElement BaseGet (int index)
200                 {
201                         return (ConfigurationElement) list [index];
202                 }
203
204                 protected internal ConfigurationElement BaseGet (object key)
205                 {
206                         int index = IndexOfKey (key);
207                         if (index != -1) return (ConfigurationElement) list [index];
208                         else return null;
209                 }
210
211                 protected internal object[] BaseGetAllKeys ()
212                 {
213                         object[] keys = new object [list.Count];
214                         for (int n=0; n<list.Count; n++)
215                                 keys [n] = BaseGetKey (n);
216                         return keys;
217                 }
218
219                 protected internal object BaseGetKey (int index)
220                 {
221                         if (index < 0 || index >= list.Count)
222                                 throw new ConfigurationErrorsException (String.Format ("Index {0} is out of range", index));
223
224                         return GetElementKey ((ConfigurationElement) list[index]).ToString ();
225                 }
226
227                 protected int BaseIndexOf (ConfigurationElement element)
228                 {
229                         return list.IndexOf (element);
230                 }
231                 
232                 int IndexOfKey (object key)
233                 {
234                         for (int n=0; n<list.Count; n++) {
235                                 if (CompareKeys (GetElementKey ((ConfigurationElement) list[n]), key))
236                                         return n;
237                         }
238                         return -1;
239                 }
240
241                 protected internal bool BaseIsRemoved (object key)
242                 {
243                         if (removed == null)
244                                 return false;
245                         foreach (ConfigurationElement elem in removed) {
246                                 if (CompareKeys (GetElementKey (elem), key))
247                                         return true;
248                         }
249                         return false;
250                 }
251
252                 protected internal void BaseRemove (object key)
253                 {
254                         if (IsReadOnly ())
255                                 throw new ConfigurationErrorsException ("Collection is read only.");
256                                 
257                         int index = IndexOfKey (key);
258                         if (index != -1) {
259                                 BaseRemoveAt (index);
260                                 modified = true;
261                         }
262                 }
263
264                 protected internal void BaseRemoveAt (int index)
265                 {
266                         if (IsReadOnly ())
267                                 throw new ConfigurationErrorsException ("Collection is read only.");
268                                 
269                         ConfigurationElement elem = (ConfigurationElement) list [index];
270                         if (!IsElementRemovable (elem))
271                                 throw new ConfigurationErrorsException ("Element can't be removed from element collection.");
272                         
273                         if (inherited != null && inherited.Contains (elem))
274                                 throw new ConfigurationErrorsException ("Inherited items can't be removed.");
275                         
276                         list.RemoveAt (index);
277                         modified = true;
278                 }
279
280                 bool CompareKeys (object key1, object key2)
281                 {
282                         if (comparer != null)
283                                 return comparer.Compare (key1, key2) == 0;
284                         else
285                                 return object.Equals (key1, key2);
286                 }
287
288                 public void CopyTo (ConfigurationElement[] array, int index)
289                 {
290                         list.CopyTo (array, index);
291                 }
292                 
293                 protected abstract ConfigurationElement CreateNewElement ();
294
295                 protected virtual ConfigurationElement CreateNewElement (string elementName)
296                 {
297                         return CreateNewElement ();
298                 }
299                 
300                 ConfigurationElement CreateNewElementInternal (string elementName)
301                 {
302                         ConfigurationElement elem;
303                         if (elementName == null)
304                                 elem = CreateNewElement ();
305                         else
306                                 elem = CreateNewElement (elementName);
307                         elem.Init ();
308                         return elem;
309                 }
310                 
311                 public override bool Equals (object compareTo)
312                 {
313                         ConfigurationElementCollection other = compareTo as ConfigurationElementCollection;
314                         if (other == null) return false;
315                         if (GetType() != other.GetType()) return false;
316                         if (Count != other.Count) return false;
317                         
318                         for (int n=0; n<Count; n++) {
319                                 if (!BaseGet (n).Equals (other.BaseGet (n)))
320                                         return false;
321                         }
322                         return true;
323                 }
324
325                 protected abstract object GetElementKey (ConfigurationElement element);
326
327                 public override int GetHashCode ()
328                 {
329                         int code = 0;
330                         for (int n=0; n<Count; n++)
331                                 code += BaseGet (n).GetHashCode ();
332                         return code;
333                 }
334                 
335                 void ICollection.CopyTo (Array arr, int index)
336                 {
337                         list.CopyTo (arr, index);
338                 }
339                 
340                 public IEnumerator GetEnumerator ()
341                 {
342                         return list.GetEnumerator ();
343                 }
344
345                 protected virtual bool IsElementName (string elementName)
346                 {
347                         return false;
348                 }
349
350                 protected virtual bool IsElementRemovable (ConfigurationElement element)
351                 {
352                         return !IsReadOnly ();
353                 }
354
355                 protected internal override bool IsModified ()
356                 {
357                         return modified;
358                 }
359
360                 [MonoTODO]
361                 public override bool IsReadOnly ()
362                 {
363                         return base.IsReadOnly ();
364                 }
365
366                 internal override bool HasValues ()
367                 {
368                         return list.Count > 0;
369                 }
370
371                 protected internal override void Reset (ConfigurationElement parentElement)
372                 {
373                         bool basic = IsBasic;
374                                 
375                         ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
376                         for (int n=0; n<parent.Count; n++)
377                         {
378                                 ConfigurationElement parentItem = parent.BaseGet (n);
379                                 ConfigurationElement item = CreateNewElementInternal (null);
380                                 item.Reset (parentItem);
381                                 BaseAdd (item);
382                                 
383                                 if (basic) {
384                                         if (inherited == null)
385                                                 inherited = new ArrayList ();
386                                         inherited.Add (item);
387                                 }
388                         }
389                         if (IsAlternate)
390                                 inheritedLimitIndex = 0;
391                         else
392                                 inheritedLimitIndex = Count - 1;
393                         modified = false;
394                 }
395
396                 protected internal override void ResetModified ()
397                 {
398                         modified = false;
399                 }
400
401                 [MonoTODO]
402                 protected internal override void SetReadOnly ()
403                 {
404                         base.SetReadOnly ();
405                 }
406
407                 protected internal override bool SerializeElement (XmlWriter writer, bool serializeCollectionKey)
408                 {
409                         if (serializeCollectionKey) {
410                                 return base.SerializeElement (writer, serializeCollectionKey);
411                         }
412                         
413                         bool wroteData = false;
414                         
415                         if (IsBasic)
416                         {
417                                 for (int n=0; n<list.Count; n++) {
418                                         ConfigurationElement elem = (ConfigurationElement) list [n];
419                                         if (ElementName != string.Empty)
420                                                 wroteData = elem.SerializeToXmlElement (writer, ElementName) || wroteData;
421                                         else
422                                                 wroteData = elem.SerializeElement (writer, false) || wroteData;
423                                 }
424                         }
425                         else
426                         {
427                                 if (emitClear) {
428                                         writer.WriteElementString (clearElementName, "");
429                                         wroteData = true;
430                                 }
431                                 
432                                 if (removed != null) {
433                                         for (int n=0; n<removed.Count; n++) {
434                                                 writer.WriteStartElement (removeElementName);
435                                                 ((ConfigurationElement)removed[n]).SerializeElement (writer, true);
436                                                 writer.WriteEndElement ();
437                                         }
438                                         wroteData = wroteData || removed.Count > 0;
439                                 }
440                                 
441                                 for (int n=0; n<list.Count; n++) {
442                                         ConfigurationElement elem = (ConfigurationElement) list [n];
443                                         elem.SerializeToXmlElement (writer, addElementName);
444                                 }
445                                 
446                                 wroteData = wroteData || list.Count > 0;
447                         }
448                         return wroteData;
449                 }
450
451                 protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
452                 {
453                         if (IsBasic)
454                         {
455                                 ConfigurationElement elem = null;
456                                 
457                                 if (elementName == ElementName)
458                                         elem = CreateNewElementInternal (null);
459                                 if (IsElementName (elementName))
460                                         elem = CreateNewElementInternal (elementName);
461
462                                 if (elem != null) {
463                                         elem.DeserializeElement (reader, false);
464                                         BaseAdd (elem);
465                                         modified = false;
466                                         return true;
467                                 }
468                         }
469                         else {
470                                 if (elementName == clearElementName) {
471                                         reader.MoveToContent ();
472                                         if (reader.MoveToNextAttribute ())
473                                                 throw new ConfigurationErrorsException ("Unrecognized attribute '" + reader.LocalName + "'.");
474                                         reader.MoveToElement ();
475                                         reader.Skip ();
476                                         BaseClear ();
477                                         emitClear = true;
478                                         modified = false;
479                                         return true;
480                                 }
481                                 else if (elementName == removeElementName) {
482                                         ConfigurationElement elem = CreateNewElementInternal (null);
483                                         ConfigurationRemoveElement removeElem = new ConfigurationRemoveElement (elem, this);
484                                         removeElem.DeserializeElement (reader, true);
485                                         BaseRemove (removeElem.KeyValue);
486                                         modified = false;
487                                         return true;
488                                 }
489                                 else if (elementName == addElementName) {
490                                         ConfigurationElement elem = CreateNewElementInternal (null);
491                                         elem.DeserializeElement (reader, false);
492                                         BaseAdd (elem);
493                                         modified = false;
494                                         return true;
495                                 }
496                         }
497                         
498                         return false;
499                 }
500                 
501                 protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode)
502                 {
503                         ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement;
504                         ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
505                         
506                         for (int n=0; n<source.Count; n++) {
507                                 ConfigurationElement sitem = source.BaseGet (n);
508                                 object key = source.GetElementKey (sitem);
509                                 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
510                                 if (pitem != null && updateMode != ConfigurationSaveMode.Full) {
511                                         ConfigurationElement nitem = CreateNewElementInternal (null);
512                                         nitem.Unmerge (sitem, pitem, ConfigurationSaveMode.Minimal);
513                                         if (nitem.HasValues ())
514                                                 BaseAdd (nitem);
515                                 }
516                                 else {
517                                         ConfigurationElement nitem = CreateNewElementInternal (null);
518                                         nitem.Unmerge (sitem, null, ConfigurationSaveMode.Full);
519                                         BaseAdd (nitem);
520                                 }
521                         }
522                         
523                         if (updateMode == ConfigurationSaveMode.Full)
524                                 EmitClear = true;
525                         else if (parent != null) {
526                                 for (int n=0; n<parent.Count; n++) {
527                                         ConfigurationElement pitem = parent.BaseGet (n);
528                                         object key = parent.GetElementKey (pitem);
529                                         if (source.IndexOfKey (key) == -1) {
530                                                 if (removed == null) removed = new ArrayList ();
531                                                 removed.Add (pitem);
532                                         }
533                                 }
534                         }
535                 }
536
537                 #endregion // Methods
538         }
539 }
540
541 #endif