The Labs \ Source Viewer \ SSCLI \ System.Configuration.Internal \ InternalConfigRoot

  1. //------------------------------------------------------------------------------
  2. // <copyright file="InternalConfigRoot.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Configuration.Internal
  16. {
  17.     using System.Configuration.Internal;
  18.     using System.Collections;
  19.     using System.Collections.Specialized;
  20.     using System.Configuration;
  21.     using System.Globalization;
  22.     using System.IO;
  23.     using System.Runtime.InteropServices;
  24.     using System.Security.Permissions;
  25.     using System.Security;
  26.     using System.Text;
  27.     using System.Xml;
  28.     using System.Threading;
  29.    
  30.     //
  31.     // InternalConfigRoot holds the root of a configuration hierarchy.
  32.     // It managed creation, removal, and the search for BaseConfigurationRecord's.
  33.     // in a thread-safe manner.
  34.     //
  35.     // The BaseConfigurationRecord hierarchy is protected with the
  36.     // _hierarchyLock. Functions that assume that the lock as been
  37.     // taken begin with the prefix "hl", for example, "hlFindConfigRecord".
  38.     //
  39.     internal sealed class InternalConfigRoot : IInternalConfigRoot
  40.     {
  41.         IInternalConfigHost _host;
  42.         // host, need to create records
  43.         ReaderWriterLock _hierarchyLock;
  44.         // lock to protect hierarchy
  45.         BaseConfigurationRecord _rootConfigRecord;
  46.         // root config record, one level above machine.config.
  47.         bool _isDesignTime;
  48.         // Is the hierarchy for runtime or designtime?
  49.         public event InternalConfigEventHandler ConfigChanged;
  50.         public event InternalConfigEventHandler ConfigRemoved;
  51.        
  52.         internal InternalConfigRoot()
  53.         {
  54.         }
  55.        
  56.         void IInternalConfigRoot.Init(IInternalConfigHost host, bool isDesignTime)
  57.         {
  58.             _host = host;
  59.             _isDesignTime = isDesignTime;
  60.             _hierarchyLock = new ReaderWriterLock();
  61.            
  62.             // Dummy record to hold _children for root
  63.             if (_isDesignTime) {
  64.                 _rootConfigRecord = MgmtConfigurationRecord.Create(this, null, string.Empty, null);
  65.             }
  66.             else {
  67.                 _rootConfigRecord = (BaseConfigurationRecord)RuntimeConfigurationRecord.Create(this, null, string.Empty);
  68.             }
  69.         }
  70.        
  71.         internal IInternalConfigHost Host {
  72.             get { return _host; }
  73.         }
  74.        
  75.         internal BaseConfigurationRecord RootConfigRecord {
  76.             get { return _rootConfigRecord; }
  77.         }
  78.        
  79.         bool IInternalConfigRoot.IsDesignTime {
  80.             get { return _isDesignTime; }
  81.         }
  82.        
  83.         private void AcquireHierarchyLockForRead()
  84.         {
  85.             // Protect against unexpected recursive entry on this thread.
  86.             // We do this in retail, too, because the results would be very bad if this were to fail,
  87.             // and the testing for this is not easy for all scenarios.
  88.             Debug.Assert(!_hierarchyLock.IsReaderLockHeld, "!_hierarchyLock.IsReaderLockHeld");
  89.             if (_hierarchyLock.IsReaderLockHeld) {
  90.                 throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForRead - reader lock already held by this thread");
  91.             }
  92.            
  93.             Debug.Assert(!_hierarchyLock.IsWriterLockHeld, "!_hierarchyLock.IsWriterLockHeld");
  94.             if (_hierarchyLock.IsWriterLockHeld) {
  95.                 throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForRead - writer lock already held by this thread");
  96.             }
  97.            
  98.             _hierarchyLock.AcquireReaderLock(-1);
  99.         }
  100.        
  101.         private void ReleaseHierarchyLockForRead()
  102.         {
  103.             Debug.Assert(!_hierarchyLock.IsWriterLockHeld, "!_hierarchyLock.IsWriterLockHeld");
  104.            
  105.             if (_hierarchyLock.IsReaderLockHeld) {
  106.                 _hierarchyLock.ReleaseReaderLock();
  107.             }
  108.         }
  109.        
  110.         private void AcquireHierarchyLockForWrite()
  111.         {
  112.             // Protect against unexpected recursive entry on this thread.
  113.             // We do this in retail, too, because the results would be very bad if this were to fail,
  114.             // and the testing for this is not easy for all scenarios.
  115.             if (_hierarchyLock.IsReaderLockHeld) {
  116.                 throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForWrite - reader lock already held by this thread");
  117.             }
  118.            
  119.             if (_hierarchyLock.IsWriterLockHeld) {
  120.                 throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForWrite - writer lock already held by this thread");
  121.             }
  122.            
  123.             _hierarchyLock.AcquireWriterLock(-1);
  124.         }
  125.        
  126.         private void ReleaseHierarchyLockForWrite()
  127.         {
  128.             Debug.Assert(!_hierarchyLock.IsReaderLockHeld, "!_hierarchyLock.IsReaderLockHeld");
  129.            
  130.             if (_hierarchyLock.IsWriterLockHeld) {
  131.                 _hierarchyLock.ReleaseWriterLock();
  132.             }
  133.         }
  134.        
  135.         //
  136.         // Find a config record.
  137.         // If found, nextIndex == parts.Length and the resulting record is in currentRecord.
  138.         // If not found, nextIndex is the index of the part of the path not found, and currentRecord
  139.         // is the record that has been found so far (nexIndex - 1).
  140.         //
  141.         private void hlFindConfigRecord(string[] parts, out int nextIndex, out BaseConfigurationRecord currentRecord)
  142.         {
  143.             currentRecord = _rootConfigRecord;
  144.             nextIndex = 0;
  145.             for (; nextIndex < parts.Length; nextIndex++) {
  146.                 BaseConfigurationRecord childRecord = currentRecord.hlGetChild(parts[nextIndex]);
  147.                 if (childRecord == null)
  148.                     break;
  149.                
  150.                 currentRecord = childRecord;
  151.             }
  152.         }
  153.        
  154.         //
  155.         // Get a config section.
  156.         //
  157.         public object GetSection(string section, string configPath)
  158.         {
  159.             BaseConfigurationRecord configRecord = (BaseConfigurationRecord)GetUniqueConfigRecord(configPath);
  160.             object result = configRecord.GetSection(section);
  161.             return result;
  162.         }
  163.        
  164.         //
  165.         // Get the nearest ancestor path (including self) which contains unique configuration information.
  166.         //
  167.         public string GetUniqueConfigPath(string configPath)
  168.         {
  169.             IInternalConfigRecord configRecord = GetUniqueConfigRecord(configPath);
  170.             if (configRecord == null) {
  171.                 return null;
  172.             }
  173.            
  174.             return configRecord.ConfigPath;
  175.         }
  176.        
  177.         //
  178.         // Get the nearest ancestor record (including self) which contains unique configuration information.
  179.         //
  180.         public IInternalConfigRecord GetUniqueConfigRecord(string configPath)
  181.         {
  182.             BaseConfigurationRecord configRecord = (BaseConfigurationRecord)GetConfigRecord(configPath);
  183.             while (configRecord.IsEmpty) {
  184.                 BaseConfigurationRecord parentConfigRecord = configRecord.Parent;
  185.                
  186.                 // If all config records are empty, return the immediate child of the
  187.                 // root placeholder (e.g. machine.config)
  188.                 if (parentConfigRecord.IsRootConfig) {
  189.                     break;
  190.                 }
  191.                
  192.                 configRecord = parentConfigRecord;
  193.             }
  194.            
  195.             return configRecord;
  196.         }
  197.        
  198.         //
  199.         // Get the config record for a path.
  200.         // If the record does not exist, create it if it is needed.
  201.         //
  202.         public IInternalConfigRecord GetConfigRecord(string configPath)
  203.         {
  204.             if (!ConfigPathUtility.IsValid(configPath)) {
  205.                 throw ExceptionUtil.ParameterInvalid("configPath");
  206.             }
  207.            
  208.             string[] parts = ConfigPathUtility.GetParts(configPath);
  209.            
  210.             //
  211.             // First search under the reader lock, so that multiple searches
  212.             // can proceed in parallel.
  213.             //
  214.             try {
  215.                 int index;
  216.                 BaseConfigurationRecord currentRecord;
  217.                
  218.                 AcquireHierarchyLockForRead();
  219.                
  220.                 hlFindConfigRecord(parts, out index, out currentRecord);
  221.                
  222.                 // check if found
  223.                 if (index == parts.Length || !currentRecord.hlNeedsChildFor(parts[index])) {
  224.                     return currentRecord;
  225.                 }
  226.             }
  227.             finally {
  228.                 ReleaseHierarchyLockForRead();
  229.             }
  230.            
  231.             //
  232.             // Not found, so search again under exclusive writer lock so that
  233.             // we can create the record.
  234.             //
  235.             try {
  236.                 int index;
  237.                 BaseConfigurationRecord currentRecord;
  238.                
  239.                 AcquireHierarchyLockForWrite();
  240.                
  241.                 hlFindConfigRecord(parts, out index, out currentRecord);
  242.                
  243.                 if (index == parts.Length) {
  244.                     return currentRecord;
  245.                 }
  246.                
  247.                 string currentConfigPath = String.Join(BaseConfigurationRecord.ConfigPathSeparatorString, parts, 0, index);
  248.                
  249.                 //
  250.                 // create new records
  251.                 //
  252.                
  253.                 while (index < parts.Length && currentRecord.hlNeedsChildFor(parts[index])) {
  254.                     string configName = parts[index];
  255.                     currentConfigPath = ConfigPathUtility.Combine(currentConfigPath, configName);
  256.                     BaseConfigurationRecord childRecord;
  257.                    
  258.                     Debug.Trace("ConfigurationCreate", "Creating config record for " + currentConfigPath);
  259.                     if (_isDesignTime) {
  260.                         childRecord = MgmtConfigurationRecord.Create(this, currentRecord, currentConfigPath, null);
  261.                     }
  262.                     else {
  263.                         childRecord = (BaseConfigurationRecord)RuntimeConfigurationRecord.Create(this, currentRecord, currentConfigPath);
  264.                     }
  265.                    
  266.                     currentRecord.hlAddChild(configName, childRecord);
  267.                    
  268.                     index++;
  269.                     currentRecord = childRecord;
  270.                 }
  271.                
  272.                 return currentRecord;
  273.             }
  274.             finally {
  275.                 ReleaseHierarchyLockForWrite();
  276.             }
  277.         }
  278.        
  279.         //
  280.         // Find and remove the config record and all its children for the config path.
  281.         // Optionally ensure the config record matches a desired config record.
  282.         //
  283.         void RemoveConfigImpl(string configPath, BaseConfigurationRecord configRecord)
  284.         {
  285.             if (!ConfigPathUtility.IsValid(configPath)) {
  286.                 throw ExceptionUtil.ParameterInvalid("configPath");
  287.             }
  288.            
  289.             string[] parts = ConfigPathUtility.GetParts(configPath);
  290.            
  291.             BaseConfigurationRecord currentRecord;
  292.            
  293.             // search under exclusive writer lock
  294.             try {
  295.                 int index;
  296.                
  297.                 AcquireHierarchyLockForWrite();
  298.                
  299.                 hlFindConfigRecord(parts, out index, out currentRecord);
  300.                
  301.                 // Return if not found, or does not match the one we are trying to remove.
  302.                 if (index != parts.Length || (configRecord != null && !Object.ReferenceEquals(configRecord, currentRecord)))
  303.                     return;
  304.                
  305.                 // Remove it from the hierarchy.
  306.                 currentRecord.Parent.hlRemoveChild(parts[parts.Length - 1]);
  307.             }
  308.             finally {
  309.                 ReleaseHierarchyLockForWrite();
  310.             }
  311.            
  312.             OnConfigRemoved(new InternalConfigEventArgs(configPath));
  313.            
  314.             // Close the record. This is safe to do outside the lock.
  315.             currentRecord.CloseRecursive();
  316.         }
  317.        
  318.         //
  319.         // Find and remove the config record and all its children for the config path.
  320.         //
  321.         public void RemoveConfig(string configPath)
  322.         {
  323.             RemoveConfigImpl(configPath, null);
  324.         }
  325.        
  326.         //
  327.         // Remove the config record and all its children for the config path.
  328.         //
  329.         public void RemoveConfigRecord(BaseConfigurationRecord configRecord)
  330.         {
  331.             RemoveConfigImpl(configRecord.ConfigPath, configRecord);
  332.         }
  333.        
  334.        
  335.         //
  336.         // Clear the result of a configSection evaluation at a particular point
  337.         // in the hierarchy.
  338.         //
  339.         public void ClearResult(BaseConfigurationRecord configRecord, string configKey, bool forceEvaluation)
  340.         {
  341.             string[] parts = ConfigPathUtility.GetParts(configRecord.ConfigPath);
  342.            
  343.             try {
  344.                 int index;
  345.                 BaseConfigurationRecord currentRecord;
  346.                
  347.                 AcquireHierarchyLockForRead();
  348.                
  349.                 hlFindConfigRecord(parts, out index, out currentRecord);
  350.                
  351.                 // clear result only if configRecord it is still in the hierarchy
  352.                 if (index == parts.Length && Object.ReferenceEquals(configRecord, currentRecord)) {
  353.                     currentRecord.hlClearResultRecursive(configKey, forceEvaluation);
  354.                 }
  355.             }
  356.             finally {
  357.                 ReleaseHierarchyLockForRead();
  358.             }
  359.         }
  360.        
  361.         // Fire the ConfigRemoved event.
  362.         private void OnConfigRemoved(InternalConfigEventArgs e)
  363.         {
  364.             InternalConfigEventHandler handler = ConfigRemoved;
  365.             if (handler != null) {
  366.                 handler(this, e);
  367.             }
  368.         }
  369.        
  370.         // Fire the ConfigChanged event for a configPath.
  371.         internal void FireConfigChanged(string configPath)
  372.         {
  373.             OnConfigChanged(new InternalConfigEventArgs(configPath));
  374.         }
  375.        
  376.         // Fire the ConfigChanged event.
  377.         private void OnConfigChanged(InternalConfigEventArgs e)
  378.         {
  379.             InternalConfigEventHandler handler = ConfigChanged;
  380.             if (handler != null) {
  381.                 handler(this, e);
  382.             }
  383.         }
  384.     }
  385. }

Developer Fusion