File: InternalConfigRoot.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (370 lines) | stat: -rw-r--r-- 14,599 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
//------------------------------------------------------------------------------
// <copyright file="InternalConfigRoot.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

namespace System.Configuration.Internal {
    using System.Configuration.Internal;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Configuration;
    using System.Globalization;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Security;
    using System.Text;
    using System.Xml;
    using System.Threading;

    //
    // InternalConfigRoot holds the root of a configuration hierarchy.
    // It managed creation, removal, and the search for BaseConfigurationRecord's.
    // in a thread-safe manner.
    //
    // The BaseConfigurationRecord hierarchy is protected with the
    // _hierarchyLock. Functions that assume that the lock as been
    // taken begin with the prefix "hl", for example, "hlFindConfigRecord".
    //
    internal sealed class InternalConfigRoot : IInternalConfigRoot {
        IInternalConfigHost                 _host;                  // host, need to create records
        IInternalConfigurationBuilderHost   _configBuilderHost;     // _configBuilderHost, need to create records
        ReaderWriterLock                    _hierarchyLock;         // lock to protect hierarchy
        BaseConfigurationRecord     _rootConfigRecord;      // root config record, one level above machine.config.
        bool                        _isDesignTime;          // Is the hierarchy for runtime or designtime?
        private Configuration       _CurrentConfiguration      = null;

        public event InternalConfigEventHandler ConfigChanged;
        public event InternalConfigEventHandler ConfigRemoved;

        internal InternalConfigRoot() { }

        internal InternalConfigRoot(Configuration currentConfiguration) {
            _CurrentConfiguration = currentConfiguration;
        }

        void IInternalConfigRoot.Init(IInternalConfigHost host, bool isDesignTime) {
            _host = host;
            _configBuilderHost = host as IInternalConfigurationBuilderHost;
            _isDesignTime = isDesignTime;
            _hierarchyLock = new ReaderWriterLock();

            // Dummy record to hold _children for root
            if (_isDesignTime) {
                _rootConfigRecord = MgmtConfigurationRecord.Create(this, null, string.Empty, null);
            }
            else {
                _rootConfigRecord = (BaseConfigurationRecord) RuntimeConfigurationRecord.Create(this, null, string.Empty);
            }
        }

        internal IInternalConfigHost Host {
            get {return _host;}
        }

        internal IInternalConfigurationBuilderHost ConfigBuilderHost {
            get { return _configBuilderHost; }
        }

        internal BaseConfigurationRecord RootConfigRecord {
            get {return _rootConfigRecord;}
        }

        bool IInternalConfigRoot.IsDesignTime {
            get {return _isDesignTime;}
        }

        private void AcquireHierarchyLockForRead() {
            // Protect against unexpected recursive entry on this thread.
            // We do this in retail, too, because the results would be very bad if this were to fail,
            // and the testing for this is not easy for all scenarios.
            Debug.Assert(!_hierarchyLock.IsReaderLockHeld, "!_hierarchyLock.IsReaderLockHeld");
            if (_hierarchyLock.IsReaderLockHeld) {
                throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForRead - reader lock already held by this thread");
            }

            Debug.Assert(!_hierarchyLock.IsWriterLockHeld, "!_hierarchyLock.IsWriterLockHeld");
            if (_hierarchyLock.IsWriterLockHeld) {
                throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForRead - writer lock already held by this thread");
            }

            _hierarchyLock.AcquireReaderLock(-1);
        }

        private void ReleaseHierarchyLockForRead() {
            Debug.Assert(!_hierarchyLock.IsWriterLockHeld, "!_hierarchyLock.IsWriterLockHeld");

            if (_hierarchyLock.IsReaderLockHeld) {
                _hierarchyLock.ReleaseReaderLock();
            }
        }

        private void AcquireHierarchyLockForWrite() {
            // Protect against unexpected recursive entry on this thread.
            // We do this in retail, too, because the results would be very bad if this were to fail,
            // and the testing for this is not easy for all scenarios.
            if (_hierarchyLock.IsReaderLockHeld) {
                throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForWrite - reader lock already held by this thread");
            }

            if (_hierarchyLock.IsWriterLockHeld) {
                throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForWrite - writer lock already held by this thread");
            }

            _hierarchyLock.AcquireWriterLock(-1);
        }

        private void ReleaseHierarchyLockForWrite() {
            Debug.Assert(!_hierarchyLock.IsReaderLockHeld, "!_hierarchyLock.IsReaderLockHeld");

            if (_hierarchyLock.IsWriterLockHeld) {
                _hierarchyLock.ReleaseWriterLock();
            }
        }

        //
        // Find a config record.
        // If found, nextIndex == parts.Length and the resulting record is in currentRecord.
        // If not found, nextIndex is the index of the part of the path not found, and currentRecord
        // is the record that has been found so far (nexIndex - 1).
        //
        private void hlFindConfigRecord(string[] parts, out int nextIndex, out BaseConfigurationRecord currentRecord) {
            currentRecord = _rootConfigRecord;
            nextIndex = 0;
            for (; nextIndex < parts.Length; nextIndex++) {
                BaseConfigurationRecord childRecord = currentRecord.hlGetChild(parts[nextIndex]);
                if (childRecord == null)
                    break;

                currentRecord = childRecord;
            }
        }

        //
        // Get a config section.
        //
        public object GetSection(string section, string configPath) {
            BaseConfigurationRecord configRecord = (BaseConfigurationRecord) GetUniqueConfigRecord(configPath);
            object result = configRecord.GetSection(section);
            return result;
        }

        //
        // Get the nearest ancestor path (including self) which contains unique configuration information.
        //
        public string GetUniqueConfigPath(string configPath) {
            IInternalConfigRecord configRecord = GetUniqueConfigRecord(configPath);
            if (configRecord == null) {
                return null;
            }

            return configRecord.ConfigPath;
        }

        //
        // Get the nearest ancestor record (including self) which contains unique configuration information.
        //
        public IInternalConfigRecord GetUniqueConfigRecord(string configPath) {
            BaseConfigurationRecord configRecord = (BaseConfigurationRecord) GetConfigRecord(configPath);
            while (configRecord.IsEmpty) {
                BaseConfigurationRecord parentConfigRecord = configRecord.Parent;

                // If all config records are empty, return the immediate child of the
                // root placeholder (e.g. machine.config)
                if (parentConfigRecord.IsRootConfig) {
                    break;
                }

                configRecord = parentConfigRecord;
            }

            return configRecord;
        }

        //
        // Get the config record for a path.
        // If the record does not exist, create it if it is needed.
        //
        public IInternalConfigRecord GetConfigRecord(string configPath) {
            if (!ConfigPathUtility.IsValid(configPath)) {
                throw ExceptionUtil.ParameterInvalid("configPath");
            }

            string[] parts = ConfigPathUtility.GetParts(configPath);

            //
            // First search under the reader lock, so that multiple searches
            // can proceed in parallel.
            //
            try {
                int index;
                BaseConfigurationRecord currentRecord;

                AcquireHierarchyLockForRead();

                hlFindConfigRecord(parts, out index, out currentRecord);

                // check if found
                if (index == parts.Length || !currentRecord.hlNeedsChildFor(parts[index])) {
                    return currentRecord;
                }
            }
            finally {
                ReleaseHierarchyLockForRead();
            }

            //
            // Not found, so search again under exclusive writer lock so that
            // we can create the record.
            //
            try {
                int index;
                BaseConfigurationRecord currentRecord;

                AcquireHierarchyLockForWrite();

                hlFindConfigRecord(parts, out index, out currentRecord);

                if (index == parts.Length) {
                    return currentRecord;
                }

                string currentConfigPath = String.Join(BaseConfigurationRecord.ConfigPathSeparatorString, parts, 0, index);

                //
                // create new records
                //

                while (index < parts.Length && currentRecord.hlNeedsChildFor(parts[index])) {
                    string configName = parts[index];
                    currentConfigPath = ConfigPathUtility.Combine(currentConfigPath, configName);
                    BaseConfigurationRecord childRecord;

                    Debug.Trace("ConfigurationCreate", "Creating config record for " + currentConfigPath);
                    if (_isDesignTime) {
                        childRecord = MgmtConfigurationRecord.Create(this, currentRecord, currentConfigPath, null);
                    }
                    else {
                        childRecord = (BaseConfigurationRecord) RuntimeConfigurationRecord.Create(this, currentRecord, currentConfigPath);
                    }

                    currentRecord.hlAddChild(configName, childRecord);

                    index++;
                    currentRecord = childRecord;
                }

                return currentRecord;
            }
            finally {
                ReleaseHierarchyLockForWrite();
            }
        }

        //
        // Find and remove the config record and all its children for the config path.
        // Optionally ensure the config record matches a desired config record.
        //
        void RemoveConfigImpl(string configPath, BaseConfigurationRecord configRecord) {
            if (!ConfigPathUtility.IsValid(configPath)) {
                throw ExceptionUtil.ParameterInvalid("configPath");
            }

            string[] parts = ConfigPathUtility.GetParts(configPath);

            BaseConfigurationRecord currentRecord;

            // search under exclusive writer lock
            try {
                int index;

                AcquireHierarchyLockForWrite();

                hlFindConfigRecord(parts, out index, out currentRecord);

                // Return if not found, or does not match the one we are trying to remove.
                if (index != parts.Length || (configRecord != null && !Object.ReferenceEquals(configRecord, currentRecord)))
                    return;

                // Remove it from the hierarchy.
                currentRecord.Parent.hlRemoveChild(parts[parts.Length - 1]);
            }
            finally {
                ReleaseHierarchyLockForWrite();
            }

            OnConfigRemoved(new InternalConfigEventArgs(configPath));

            // Close the record. This is safe to do outside the lock.
            currentRecord.CloseRecursive();
        }

        //
        // Find and remove the config record and all its children for the config path.
        //
        public void RemoveConfig(string configPath) {
            RemoveConfigImpl(configPath, null);
        }

        //
        // Remove the config record and all its children for the config path.
        //
        public void RemoveConfigRecord(BaseConfigurationRecord configRecord) {
            RemoveConfigImpl(configRecord.ConfigPath, configRecord);
        }


        //
        // Clear the result of a configSection evaluation at a particular point
        // in the hierarchy.
        //
        public void ClearResult(BaseConfigurationRecord configRecord, string configKey, bool forceEvaluation) {
            string[] parts = ConfigPathUtility.GetParts(configRecord.ConfigPath);

            try {
                int index;
                BaseConfigurationRecord currentRecord;

                AcquireHierarchyLockForRead();

                hlFindConfigRecord(parts, out index, out currentRecord);

                // clear result only if configRecord it is still in the hierarchy
                if (index == parts.Length && Object.ReferenceEquals(configRecord, currentRecord)) {
                    currentRecord.hlClearResultRecursive(configKey, forceEvaluation);
                }
            }
            finally {
                ReleaseHierarchyLockForRead();
            }
        }

        // Fire the ConfigRemoved event.
        private void OnConfigRemoved(InternalConfigEventArgs e) {
            InternalConfigEventHandler handler = ConfigRemoved;
            if (handler != null) {
                handler(this, e);
            }
        }

        // Fire the ConfigChanged event for a configPath.
        internal void FireConfigChanged(string configPath) {
            OnConfigChanged(new InternalConfigEventArgs(configPath));
        }

        // Fire the ConfigChanged event.
        private void OnConfigChanged(InternalConfigEventArgs e) {
            InternalConfigEventHandler handler = ConfigChanged;
            if (handler != null) {
                handler(this, e);
            }
        }

        internal Configuration CurrentConfiguration {
            get {
                return _CurrentConfiguration;
            }
        }
    }
}