You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by bo...@apache.org on 2015/04/05 12:11:47 UTC

svn commit: r1671382 [2/2] - in /logging/log4net/trunk/src: log4net.Tests/Appender/AsyncAppenderTest.cs log4net/Appender/AsyncAppender.cs log4net/Repository/Hierarchy/XmlHierarchyConfigurator.cs

Modified: logging/log4net/trunk/src/log4net/Repository/Hierarchy/XmlHierarchyConfigurator.cs
URL: http://svn.apache.org/viewvc/logging/log4net/trunk/src/log4net/Repository/Hierarchy/XmlHierarchyConfigurator.cs?rev=1671382&r1=1671381&r2=1671382&view=diff
==============================================================================
--- logging/log4net/trunk/src/log4net/Repository/Hierarchy/XmlHierarchyConfigurator.cs (original)
+++ logging/log4net/trunk/src/log4net/Repository/Hierarchy/XmlHierarchyConfigurator.cs Sun Apr  5 10:11:47 2015
@@ -30,69 +30,69 @@ using log4net.ObjectRenderer;
 
 namespace log4net.Repository.Hierarchy
 {
-	/// <summary>
-	/// Initializes the log4net environment using an XML DOM.
-	/// </summary>
-	/// <remarks>
-	/// <para>
-	/// Configures a <see cref="Hierarchy"/> using an XML DOM.
-	/// </para>
-	/// </remarks>
-	/// <author>Nicko Cadell</author>
-	/// <author>Gert Driesen</author>
-	public class XmlHierarchyConfigurator
-	{
-		private enum ConfigUpdateMode
-		{
-			Merge, 
-			Overwrite
-		}
-
-		#region Public Instance Constructors
-
-		/// <summary>
-		/// Construct the configurator for a hierarchy
-		/// </summary>
-		/// <param name="hierarchy">The hierarchy to build.</param>
-		/// <remarks>
-		/// <para>
-		/// Initializes a new instance of the <see cref="XmlHierarchyConfigurator" /> class
-		/// with the specified <see cref="Hierarchy" />.
-		/// </para>
-		/// </remarks>
-		public XmlHierarchyConfigurator(Hierarchy hierarchy) 
-		{
-			m_hierarchy = hierarchy;
-			m_appenderBag = new Hashtable();
-		}
-
-		#endregion Public Instance Constructors
-
-		#region Public Instance Methods
-
-		/// <summary>
-		/// Configure the hierarchy by parsing a DOM tree of XML elements.
-		/// </summary>
-		/// <param name="element">The root element to parse.</param>
-		/// <remarks>
-		/// <para>
-		/// Configure the hierarchy by parsing a DOM tree of XML elements.
-		/// </para>
-		/// </remarks>
-		public void Configure(XmlElement element) 
-		{
-			if (element == null || m_hierarchy == null)
-			{
+    /// <summary>
+    /// Initializes the log4net environment using an XML DOM.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Configures a <see cref="Hierarchy"/> using an XML DOM.
+    /// </para>
+    /// </remarks>
+    /// <author>Nicko Cadell</author>
+    /// <author>Gert Driesen</author>
+    public class XmlHierarchyConfigurator
+    {
+        private enum ConfigUpdateMode
+        {
+            Merge,
+            Overwrite
+        }
+
+        #region Public Instance Constructors
+
+        /// <summary>
+        /// Construct the configurator for a hierarchy
+        /// </summary>
+        /// <param name="hierarchy">The hierarchy to build.</param>
+        /// <remarks>
+        /// <para>
+        /// Initializes a new instance of the <see cref="XmlHierarchyConfigurator" /> class
+        /// with the specified <see cref="Hierarchy" />.
+        /// </para>
+        /// </remarks>
+        public XmlHierarchyConfigurator(Hierarchy hierarchy)
+        {
+            m_hierarchy = hierarchy;
+            m_appenderBag = new Hashtable();
+        }
+
+        #endregion Public Instance Constructors
+
+        #region Public Instance Methods
+
+        /// <summary>
+        /// Configure the hierarchy by parsing a DOM tree of XML elements.
+        /// </summary>
+        /// <param name="element">The root element to parse.</param>
+        /// <remarks>
+        /// <para>
+        /// Configure the hierarchy by parsing a DOM tree of XML elements.
+        /// </para>
+        /// </remarks>
+        public void Configure(XmlElement element)
+        {
+            if (element == null || m_hierarchy == null)
+            {
                 return;
-			}
+            }
 
-			string rootElementName = element.LocalName;
+            string rootElementName = element.LocalName;
 
-			if (rootElementName != CONFIGURATION_TAG)
-			{
-				LogLog.Error(declaringType, "Xml element is - not a <" + CONFIGURATION_TAG + "> element.");
+            if (rootElementName != CONFIGURATION_TAG)
+            {
+                LogLog.Error(declaringType, "Xml element is - not a <" + CONFIGURATION_TAG + "> element.");
                 return;
-			}
+            }
 
             if (!LogLog.EmitInternalMessages)
             {
@@ -110,1007 +110,1009 @@ namespace log4net.Repository.Hierarchy
                 }
             }
 
-		    if (!LogLog.InternalDebugging)
-			{
-				// Look for a debug attribute to enable internal debug
-				string debugAttribute = element.GetAttribute(INTERNAL_DEBUG_ATTR);
-				LogLog.Debug(declaringType, INTERNAL_DEBUG_ATTR+" attribute [" + debugAttribute + "].");
-
-				if (debugAttribute.Length>0 && debugAttribute != "null") 
-				{	  
-					LogLog.InternalDebugging = OptionConverter.ToBoolean(debugAttribute, true);
-				}
-				else 
-				{
-					LogLog.Debug(declaringType, "Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
-				}
-
-				string confDebug = element.GetAttribute(CONFIG_DEBUG_ATTR);
-				if (confDebug.Length>0 && confDebug != "null")
-				{	  
-					LogLog.Warn(declaringType, "The \"" + CONFIG_DEBUG_ATTR + "\" attribute is deprecated.");
-					LogLog.Warn(declaringType, "Use the \"" + INTERNAL_DEBUG_ATTR + "\" attribute instead.");
-					LogLog.InternalDebugging = OptionConverter.ToBoolean(confDebug, true);
-				}
-			}
-
-			// Default mode is merge
-			ConfigUpdateMode configUpdateMode = ConfigUpdateMode.Merge;
-
-			// Look for the config update attribute
-			string configUpdateModeAttribute = element.GetAttribute(CONFIG_UPDATE_MODE_ATTR);
-			if (configUpdateModeAttribute != null && configUpdateModeAttribute.Length > 0)
-			{
-				// Parse the attribute
-				try
-				{
-					configUpdateMode = (ConfigUpdateMode)OptionConverter.ConvertStringTo(typeof(ConfigUpdateMode), configUpdateModeAttribute);
-				}
-				catch
-				{
-					LogLog.Error(declaringType, "Invalid " + CONFIG_UPDATE_MODE_ATTR + " attribute value [" + configUpdateModeAttribute + "]");
-				}
-			}
-
-			// IMPL: The IFormatProvider argument to Enum.ToString() is deprecated in .NET 2.0
-			LogLog.Debug(declaringType, "Configuration update mode [" + configUpdateMode.ToString() + "].");
-
-			// Only reset configuration if overwrite flag specified
-			if (configUpdateMode == ConfigUpdateMode.Overwrite)
-			{
-				// Reset to original unset configuration
-				m_hierarchy.ResetConfiguration();
-				LogLog.Debug(declaringType, "Configuration reset before reading config.");
-			}
-
-			/* Building Appender objects, placing them in a local namespace
-			   for future reference */
-
-			/* Process all the top level elements */
-
-			foreach (XmlNode currentNode in element.ChildNodes)
-			{
-				if (currentNode.NodeType == XmlNodeType.Element) 
-				{
-					XmlElement currentElement = (XmlElement)currentNode;
-
-					if (currentElement.LocalName == LOGGER_TAG)
-					{
-						ParseLogger(currentElement);
-					} 
-					else if (currentElement.LocalName == CATEGORY_TAG)
-					{
-						// TODO: deprecated use of category
-						ParseLogger(currentElement);
-					} 
-					else if (currentElement.LocalName == ROOT_TAG)
-					{
-						ParseRoot(currentElement);
-					} 
-					else if (currentElement.LocalName == RENDERER_TAG)
-					{
-						ParseRenderer(currentElement);
-					}
-					else if (currentElement.LocalName == APPENDER_TAG)
-					{
-						// We ignore appenders in this pass. They will
-						// be found and loaded if they are referenced.
-					}
-					else
-					{
-						// Read the param tags and set properties on the hierarchy
-						SetParameter(currentElement, m_hierarchy);
-					}
-				}
-			}
-
-			// Lastly set the hierarchy threshold
-			string thresholdStr = element.GetAttribute(THRESHOLD_ATTR);
-			LogLog.Debug(declaringType, "Hierarchy Threshold [" + thresholdStr + "]");
-			if (thresholdStr.Length > 0 && thresholdStr != "null") 
-			{
-				Level thresholdLevel = (Level) ConvertStringTo(typeof(Level), thresholdStr);
-				if (thresholdLevel != null)
-				{
-					m_hierarchy.Threshold = thresholdLevel;
-				}
-				else
-				{
-					LogLog.Warn(declaringType, "Unable to set hierarchy threshold using value [" + thresholdStr + "] (with acceptable conversion types)");
-				}
-			}
-
-			// Done reading config
-		}
-
-	    #endregion Public Instance Methods
-
-		#region Protected Instance Methods
-
-		/// <summary>
-		/// Parse appenders by IDREF.
-		/// </summary>
-		/// <param name="appenderRef">The appender ref element.</param>
-		/// <returns>The instance of the appender that the ref refers to.</returns>
-		/// <remarks>
-		/// <para>
-		/// Parse an XML element that represents an appender and return 
-		/// the appender.
-		/// </para>
-		/// </remarks>
-		protected IAppender FindAppenderByReference(XmlElement appenderRef) 
-		{	
-			string appenderName = appenderRef.GetAttribute(REF_ATTR);
-
-			IAppender appender = (IAppender)m_appenderBag[appenderName];
-			if (appender != null) 
-			{
-				return appender;
-			} 
-			else 
-			{
-				// Find the element with that id
-				XmlElement element = null;
-
-				if (appenderName != null && appenderName.Length > 0)
-				{
-					foreach (XmlElement curAppenderElement in appenderRef.OwnerDocument.GetElementsByTagName(APPENDER_TAG))
-					{
-						if (curAppenderElement.GetAttribute("name") == appenderName)
-						{
-							element = curAppenderElement;
-							break;
-						}
-					}
-				}
-
-				if (element == null) 
-				{
-					LogLog.Error(declaringType, "XmlHierarchyConfigurator: No appender named [" + appenderName + "] could be found."); 
-					return null;
-				} 
-				else
-				{
-					appender = ParseAppender(element);
-					if (appender != null)
-					{
-						m_appenderBag[appenderName] = appender;
-					}
-					return appender;
-				}
-			} 
-		}
-
-		/// <summary>
-		/// Parses an appender element.
-		/// </summary>
-		/// <param name="appenderElement">The appender element.</param>
-		/// <returns>The appender instance or <c>null</c> when parsing failed.</returns>
-		/// <remarks>
-		/// <para>
-		/// Parse an XML element that represents an appender and return
-		/// the appender instance.
-		/// </para>
-		/// </remarks>
-		protected IAppender ParseAppender(XmlElement appenderElement) 
-		{
-			string appenderName = appenderElement.GetAttribute(NAME_ATTR);
-			string typeName = appenderElement.GetAttribute(TYPE_ATTR);
-
-			LogLog.Debug(declaringType, "Loading Appender [" + appenderName + "] type: [" + typeName + "]");
-			try 
-			{
-				IAppender appender = (IAppender)Activator.CreateInstance(SystemInfo.GetTypeFromString(typeName, true, true));
-				appender.Name = appenderName;
-
-				foreach (XmlNode currentNode in appenderElement.ChildNodes)
-				{
-					/* We're only interested in Elements */
-					if (currentNode.NodeType == XmlNodeType.Element) 
-					{
-						XmlElement currentElement = (XmlElement)currentNode;
-
-						// Look for the appender ref tag
-						if (currentElement.LocalName == APPENDER_REF_TAG)
-						{
-							string refName = currentElement.GetAttribute(REF_ATTR);
-
-							IAppenderAttachable appenderContainer = appender as IAppenderAttachable;
-							if (appenderContainer != null) 
-							{
-								LogLog.Debug(declaringType, "Attaching appender named [" + refName + "] to appender named [" + appender.Name + "].");
-
-								IAppender referencedAppender = FindAppenderByReference(currentElement);
-								if (referencedAppender != null)
-								{
-									appenderContainer.AddAppender(referencedAppender);
-								}
-							} 
-							else 
-							{
-								LogLog.Error(declaringType, "Requesting attachment of appender named ["+refName+ "] to appender named [" + appender.Name + "] which does not implement log4net.Core.IAppenderAttachable.");
-							}
-						}
-						else
-						{
-							// For all other tags we use standard set param method
-							SetParameter(currentElement, appender);
-						}
-					}
-				}
-
-				IOptionHandler optionHandler = appender as IOptionHandler;
-				if (optionHandler != null) 
-				{
-					optionHandler.ActivateOptions();
-				}
-
-				LogLog.Debug(declaringType, "Created Appender [" + appenderName + "]");	
-				return appender;
-			}
-			catch (Exception ex) 
-			{
-				// Yes, it's ugly.  But all exceptions point to the same problem: we can't create an Appender
-
-				LogLog.Error(declaringType, "Could not create Appender [" + appenderName + "] of type [" + typeName + "]. Reported error follows.", ex);
-				return null;
-			}
-		}
-
-		/// <summary>
-		/// Parses a logger element.
-		/// </summary>
-		/// <param name="loggerElement">The logger element.</param>
-		/// <remarks>
-		/// <para>
-		/// Parse an XML element that represents a logger.
-		/// </para>
-		/// </remarks>
-		protected void ParseLogger(XmlElement loggerElement) 
-		{
-			// Create a new log4net.Logger object from the <logger> element.
-			string loggerName = loggerElement.GetAttribute(NAME_ATTR);
-
-			LogLog.Debug(declaringType, "Retrieving an instance of log4net.Repository.Logger for logger [" + loggerName + "].");
-			Logger log = m_hierarchy.GetLogger(loggerName) as Logger;
-
-			// Setting up a logger needs to be an atomic operation, in order
-			// to protect potential log operations while logger
-			// configuration is in progress.
-			lock(log) 
-			{
-				bool additivity = OptionConverter.ToBoolean(loggerElement.GetAttribute(ADDITIVITY_ATTR), true);
-	
-				LogLog.Debug(declaringType, "Setting [" + log.Name + "] additivity to [" + additivity + "].");
-				log.Additivity = additivity;
-				ParseChildrenOfLoggerElement(loggerElement, log, false);
-			}
-		}
-
-		/// <summary>
-		/// Parses the root logger element.
-		/// </summary>
-		/// <param name="rootElement">The root element.</param>
-		/// <remarks>
-		/// <para>
-		/// Parse an XML element that represents the root logger.
-		/// </para>
-		/// </remarks>
-		protected void ParseRoot(XmlElement rootElement) 
-		{
-			Logger root = m_hierarchy.Root;
-			// logger configuration needs to be atomic
-			lock(root) 
-			{	
-				ParseChildrenOfLoggerElement(rootElement, root, true);
-			}
-		}
-
-		/// <summary>
-		/// Parses the children of a logger element.
-		/// </summary>
-		/// <param name="catElement">The category element.</param>
-		/// <param name="log">The logger instance.</param>
-		/// <param name="isRoot">Flag to indicate if the logger is the root logger.</param>
-		/// <remarks>
-		/// <para>
-		/// Parse the child elements of a &lt;logger&gt; element.
-		/// </para>
-		/// </remarks>
-		protected void ParseChildrenOfLoggerElement(XmlElement catElement, Logger log, bool isRoot) 
-		{
-			// Remove all existing appenders from log. They will be
-			// reconstructed if need be.
-			log.RemoveAllAppenders();
-
-			foreach (XmlNode currentNode in catElement.ChildNodes)
-			{
-				if (currentNode.NodeType == XmlNodeType.Element) 
-				{
-					XmlElement currentElement = (XmlElement) currentNode;
-	
-					if (currentElement.LocalName == APPENDER_REF_TAG)
-					{
-						IAppender appender = FindAppenderByReference(currentElement);
-						string refName =  currentElement.GetAttribute(REF_ATTR);
-						if (appender != null)
-						{
-							LogLog.Debug(declaringType, "Adding appender named [" + refName + "] to logger [" + log.Name + "].");
-							log.AddAppender(appender);
-						}
-						else 
-						{
-							LogLog.Error(declaringType, "Appender named [" + refName + "] not found.");
-						}
-					} 
-					else if (currentElement.LocalName == LEVEL_TAG || currentElement.LocalName == PRIORITY_TAG) 
-					{
-						ParseLevel(currentElement, log, isRoot);	
-					} 
-					else
-					{
-						SetParameter(currentElement, log);
-					}
-				}
-			}
-
-			IOptionHandler optionHandler = log as IOptionHandler;
-			if (optionHandler != null) 
-			{
-				optionHandler.ActivateOptions();
-			}
-		}
-
-		/// <summary>
-		/// Parses an object renderer.
-		/// </summary>
-		/// <param name="element">The renderer element.</param>
-		/// <remarks>
-		/// <para>
-		/// Parse an XML element that represents a renderer.
-		/// </para>
-		/// </remarks>
-		protected void ParseRenderer(XmlElement element) 
-		{
-			string renderingClassName = element.GetAttribute(RENDERING_TYPE_ATTR);
-			string renderedClassName = element.GetAttribute(RENDERED_TYPE_ATTR);
-
-			LogLog.Debug(declaringType, "Rendering class [" + renderingClassName + "], Rendered class [" + renderedClassName + "].");
-			IObjectRenderer renderer = (IObjectRenderer)OptionConverter.InstantiateByClassName(renderingClassName, typeof(IObjectRenderer), null);
-			if (renderer == null) 
-			{
-				LogLog.Error(declaringType, "Could not instantiate renderer [" + renderingClassName + "].");
-				return;
-			} 
-			else 
-			{
-				try 
-				{
-					m_hierarchy.RendererMap.Put(SystemInfo.GetTypeFromString(renderedClassName, true, true), renderer);
-				} 
-				catch(Exception e) 
-				{
-					LogLog.Error(declaringType, "Could not find class [" + renderedClassName + "].", e);
-				}
-			}
-		}
-
-		/// <summary>
-		/// Parses a level element.
-		/// </summary>
-		/// <param name="element">The level element.</param>
-		/// <param name="log">The logger object to set the level on.</param>
-		/// <param name="isRoot">Flag to indicate if the logger is the root logger.</param>
-		/// <remarks>
-		/// <para>
-		/// Parse an XML element that represents a level.
-		/// </para>
-		/// </remarks>
-		protected void ParseLevel(XmlElement element, Logger log, bool isRoot) 
-		{
-			string loggerName = log.Name;
-			if (isRoot) 
-			{
-				loggerName = "root";
-			}
-
-			string levelStr = element.GetAttribute(VALUE_ATTR);
-			LogLog.Debug(declaringType, "Logger [" + loggerName + "] Level string is [" + levelStr + "].");
-	
-			if (INHERITED == levelStr) 
-			{
-				if (isRoot) 
-				{
-					LogLog.Error(declaringType, "Root level cannot be inherited. Ignoring directive.");
-				} 
-				else 
-				{
-					LogLog.Debug(declaringType, "Logger [" + loggerName + "] level set to inherit from parent.");	
-					log.Level = null;
-				}
-			} 
-			else 
-			{
-				log.Level = log.Hierarchy.LevelMap[levelStr];
-				if (log.Level == null)
-				{
-					LogLog.Error(declaringType, "Undefined level [" + levelStr + "] on Logger [" + loggerName + "].");
-				}
-				else
-				{
-					LogLog.Debug(declaringType, "Logger [" + loggerName + "] level set to [name=\"" + log.Level.Name + "\",value=" + log.Level.Value + "].");	
-				}
-			}
-		}
-
-		/// <summary>
-		/// Sets a parameter on an object.
-		/// </summary>
-		/// <param name="element">The parameter element.</param>
-		/// <param name="target">The object to set the parameter on.</param>
-		/// <remarks>
-		/// The parameter name must correspond to a writable property
-		/// on the object. The value of the parameter is a string,
-		/// therefore this function will attempt to set a string
-		/// property first. If unable to set a string property it
-		/// will inspect the property and its argument type. It will
-		/// attempt to call a static method called <c>Parse</c> on the
-		/// type of the property. This method will take a single
-		/// string argument and return a value that can be used to
-		/// set the property.
-		/// </remarks>
-		protected void SetParameter(XmlElement element, object target) 
-		{
-			// Get the property name
-			string name = element.GetAttribute(NAME_ATTR);
-
-			// If the name attribute does not exist then use the name of the element
-			if (element.LocalName != PARAM_TAG || name == null || name.Length == 0)
-			{
-				name = element.LocalName;
-			}
-
-			// Look for the property on the target object
-			Type targetType = target.GetType();
-			Type propertyType = null;
-
-			PropertyInfo propInfo = null;
-			MethodInfo methInfo = null;
-
-			// Try to find a writable property
-			propInfo = targetType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
-			if (propInfo != null && propInfo.CanWrite)
-			{
-				// found a property
-				propertyType = propInfo.PropertyType;
-			}
-			else
-			{
-				propInfo = null;
-
-				// look for a method with the signature Add<property>(type)
-				methInfo = FindMethodInfo(targetType, name);
-
-				if (methInfo != null)
-				{
-					propertyType = methInfo.GetParameters()[0].ParameterType;
-				}
-			}
-
-			if (propertyType == null)
-			{
-				LogLog.Error(declaringType, "XmlHierarchyConfigurator: Cannot find Property [" + name + "] to set object on [" + target.ToString() + "]");
-			}
-			else
-			{
-				string propertyValue = null;
-
-				if (element.GetAttributeNode(VALUE_ATTR) != null)
-				{
-					propertyValue = element.GetAttribute(VALUE_ATTR);
-				}
-				else if (element.HasChildNodes)
-				{
-					// Concatenate the CDATA and Text nodes together
-					foreach(XmlNode childNode in element.ChildNodes)
-					{
-						if (childNode.NodeType == XmlNodeType.CDATA || childNode.NodeType == XmlNodeType.Text)
-						{
-							if (propertyValue == null)
-							{
-								propertyValue = childNode.InnerText;
-							}
-							else
-							{
-								propertyValue += childNode.InnerText;
-							}
-						}
-					}
-				}
-
-				if(propertyValue != null)
-				{
-#if !NETCF	
-					try
-					{
-						// Expand environment variables in the string.
-					    IDictionary environmentVariables = Environment.GetEnvironmentVariables();
-					    if (HasCaseInsensitiveEnvironment) {
-						environmentVariables = CreateCaseInsensitiveWrapper(environmentVariables);
-					    }
-						propertyValue = OptionConverter.SubstituteVariables(propertyValue, environmentVariables);
-					}
-					catch(System.Security.SecurityException)
-					{
-						// This security exception will occur if the caller does not have 
-						// unrestricted environment permission. If this occurs the expansion 
-						// will be skipped with the following warning message.
-						LogLog.Debug(declaringType, "Security exception while trying to expand environment variables. Error Ignored. No Expansion.");
-					}
+            if (!LogLog.InternalDebugging)
+            {
+                // Look for a debug attribute to enable internal debug
+                string debugAttribute = element.GetAttribute(INTERNAL_DEBUG_ATTR);
+                LogLog.Debug(declaringType, INTERNAL_DEBUG_ATTR + " attribute [" + debugAttribute + "].");
+
+                if (debugAttribute.Length > 0 && debugAttribute != "null")
+                {
+                    LogLog.InternalDebugging = OptionConverter.ToBoolean(debugAttribute, true);
+                }
+                else
+                {
+                    LogLog.Debug(declaringType, "Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
+                }
+
+                string confDebug = element.GetAttribute(CONFIG_DEBUG_ATTR);
+                if (confDebug.Length > 0 && confDebug != "null")
+                {
+                    LogLog.Warn(declaringType, "The \"" + CONFIG_DEBUG_ATTR + "\" attribute is deprecated.");
+                    LogLog.Warn(declaringType, "Use the \"" + INTERNAL_DEBUG_ATTR + "\" attribute instead.");
+                    LogLog.InternalDebugging = OptionConverter.ToBoolean(confDebug, true);
+                }
+            }
+
+            // Default mode is merge
+            ConfigUpdateMode configUpdateMode = ConfigUpdateMode.Merge;
+
+            // Look for the config update attribute
+            string configUpdateModeAttribute = element.GetAttribute(CONFIG_UPDATE_MODE_ATTR);
+            if (configUpdateModeAttribute != null && configUpdateModeAttribute.Length > 0)
+            {
+                // Parse the attribute
+                try
+                {
+                    configUpdateMode = (ConfigUpdateMode)OptionConverter.ConvertStringTo(typeof(ConfigUpdateMode), configUpdateModeAttribute);
+                }
+                catch
+                {
+                    LogLog.Error(declaringType, "Invalid " + CONFIG_UPDATE_MODE_ATTR + " attribute value [" + configUpdateModeAttribute + "]");
+                }
+            }
+
+            // IMPL: The IFormatProvider argument to Enum.ToString() is deprecated in .NET 2.0
+            LogLog.Debug(declaringType, "Configuration update mode [" + configUpdateMode.ToString() + "].");
+
+            // Only reset configuration if overwrite flag specified
+            if (configUpdateMode == ConfigUpdateMode.Overwrite)
+            {
+                // Reset to original unset configuration
+                m_hierarchy.ResetConfiguration();
+                LogLog.Debug(declaringType, "Configuration reset before reading config.");
+            }
+
+            /* Building Appender objects, placing them in a local namespace
+               for future reference */
+
+            /* Process all the top level elements */
+
+            foreach (XmlNode currentNode in element.ChildNodes)
+            {
+                if (currentNode.NodeType == XmlNodeType.Element)
+                {
+                    XmlElement currentElement = (XmlElement)currentNode;
+
+                    if (currentElement.LocalName == LOGGER_TAG)
+                    {
+                        ParseLogger(currentElement);
+                    }
+                    else if (currentElement.LocalName == CATEGORY_TAG)
+                    {
+                        // TODO: deprecated use of category
+                        ParseLogger(currentElement);
+                    }
+                    else if (currentElement.LocalName == ROOT_TAG)
+                    {
+                        ParseRoot(currentElement);
+                    }
+                    else if (currentElement.LocalName == RENDERER_TAG)
+                    {
+                        ParseRenderer(currentElement);
+                    }
+                    else if (currentElement.LocalName == APPENDER_TAG)
+                    {
+                        // We ignore appenders in this pass. They will
+                        // be found and loaded if they are referenced.
+                    }
+                    else
+                    {
+                        // Read the param tags and set properties on the hierarchy
+                        SetParameter(currentElement, m_hierarchy);
+                    }
+                }
+            }
+
+            // Lastly set the hierarchy threshold
+            string thresholdStr = element.GetAttribute(THRESHOLD_ATTR);
+            LogLog.Debug(declaringType, "Hierarchy Threshold [" + thresholdStr + "]");
+            if (thresholdStr.Length > 0 && thresholdStr != "null")
+            {
+                Level thresholdLevel = (Level)ConvertStringTo(typeof(Level), thresholdStr);
+                if (thresholdLevel != null)
+                {
+                    m_hierarchy.Threshold = thresholdLevel;
+                }
+                else
+                {
+                    LogLog.Warn(declaringType, "Unable to set hierarchy threshold using value [" + thresholdStr + "] (with acceptable conversion types)");
+                }
+            }
+
+            // Done reading config
+        }
+
+        #endregion Public Instance Methods
+
+        #region Protected Instance Methods
+
+        /// <summary>
+        /// Parse appenders by IDREF.
+        /// </summary>
+        /// <param name="appenderRef">The appender ref element.</param>
+        /// <returns>The instance of the appender that the ref refers to.</returns>
+        /// <remarks>
+        /// <para>
+        /// Parse an XML element that represents an appender and return 
+        /// the appender.
+        /// </para>
+        /// </remarks>
+        protected IAppender FindAppenderByReference(XmlElement appenderRef)
+        {
+            string appenderName = appenderRef.GetAttribute(REF_ATTR);
+
+            IAppender appender = (IAppender)m_appenderBag[appenderName];
+            if (appender != null)
+            {
+                return appender;
+            }
+            else
+            {
+                // Find the element with that id
+                XmlElement element = null;
+
+                if (appenderName != null && appenderName.Length > 0)
+                {
+                    foreach (XmlElement curAppenderElement in appenderRef.OwnerDocument.GetElementsByTagName(APPENDER_TAG))
+                    {
+                        if (curAppenderElement.GetAttribute("name") == appenderName)
+                        {
+                            element = curAppenderElement;
+                            break;
+                        }
+                    }
+                }
+
+                if (element == null)
+                {
+                    LogLog.Error(declaringType, "XmlHierarchyConfigurator: No appender named [" + appenderName + "] could be found.");
+                    return null;
+                }
+                else
+                {
+                    appender = ParseAppender(element);
+                    if (appender != null)
+                    {
+                        m_appenderBag[appenderName] = appender;
+                    }
+                    return appender;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Parses an appender element.
+        /// </summary>
+        /// <param name="appenderElement">The appender element.</param>
+        /// <returns>The appender instance or <c>null</c> when parsing failed.</returns>
+        /// <remarks>
+        /// <para>
+        /// Parse an XML element that represents an appender and return
+        /// the appender instance.
+        /// </para>
+        /// </remarks>
+        protected IAppender ParseAppender(XmlElement appenderElement)
+        {
+            string appenderName = appenderElement.GetAttribute(NAME_ATTR);
+            string typeName = appenderElement.GetAttribute(TYPE_ATTR);
+
+            LogLog.Debug(declaringType, "Loading Appender [" + appenderName + "] type: [" + typeName + "]");
+            try
+            {
+                IAppender appender = (IAppender)Activator.CreateInstance(SystemInfo.GetTypeFromString(typeName, true, true));
+                appender.Name = appenderName;
+
+                foreach (XmlNode currentNode in appenderElement.ChildNodes)
+                {
+                    /* We're only interested in Elements */
+                    if (currentNode.NodeType == XmlNodeType.Element)
+                    {
+                        XmlElement currentElement = (XmlElement)currentNode;
+
+                        // Look for the appender ref tag
+                        if (currentElement.LocalName == APPENDER_REF_TAG)
+                        {
+                            string refName = currentElement.GetAttribute(REF_ATTR);
+
+                            IAppenderAttachable appenderContainer = appender as IAppenderAttachable;
+                            if (appenderContainer != null)
+                            {
+                                LogLog.Debug(declaringType, "Attaching appender named [" + refName + "] to appender named [" + appender.Name + "].");
+
+                                IAppender referencedAppender = FindAppenderByReference(currentElement);
+                                if (referencedAppender != null)
+                                {
+                                    appenderContainer.AddAppender(referencedAppender);
+                                }
+                            }
+                            else
+                            {
+                                LogLog.Error(declaringType, "Requesting attachment of appender named [" + refName + "] to appender named [" + appender.Name + "] which does not implement log4net.Core.IAppenderAttachable.");
+                            }
+                        }
+                        else
+                        {
+                            // For all other tags we use standard set param method
+                            SetParameter(currentElement, appender);
+                        }
+                    }
+                }
+
+                IOptionHandler optionHandler = appender as IOptionHandler;
+                if (optionHandler != null)
+                {
+                    optionHandler.ActivateOptions();
+                }
+
+                LogLog.Debug(declaringType, "Created Appender [" + appenderName + "]");
+                return appender;
+            }
+            catch (Exception ex)
+            {
+                // Yes, it's ugly.  But all exceptions point to the same problem: we can't create an Appender
+
+                LogLog.Error(declaringType, "Could not create Appender [" + appenderName + "] of type [" + typeName + "]. Reported error follows.", ex);
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Parses a logger element.
+        /// </summary>
+        /// <param name="loggerElement">The logger element.</param>
+        /// <remarks>
+        /// <para>
+        /// Parse an XML element that represents a logger.
+        /// </para>
+        /// </remarks>
+        protected void ParseLogger(XmlElement loggerElement)
+        {
+            // Create a new log4net.Logger object from the <logger> element.
+            string loggerName = loggerElement.GetAttribute(NAME_ATTR);
+
+            LogLog.Debug(declaringType, "Retrieving an instance of log4net.Repository.Logger for logger [" + loggerName + "].");
+            Logger log = m_hierarchy.GetLogger(loggerName) as Logger;
+
+            // Setting up a logger needs to be an atomic operation, in order
+            // to protect potential log operations while logger
+            // configuration is in progress.
+            lock (log)
+            {
+                bool additivity = OptionConverter.ToBoolean(loggerElement.GetAttribute(ADDITIVITY_ATTR), true);
+
+                LogLog.Debug(declaringType, "Setting [" + log.Name + "] additivity to [" + additivity + "].");
+                log.Additivity = additivity;
+                ParseChildrenOfLoggerElement(loggerElement, log, false);
+            }
+        }
+
+        /// <summary>
+        /// Parses the root logger element.
+        /// </summary>
+        /// <param name="rootElement">The root element.</param>
+        /// <remarks>
+        /// <para>
+        /// Parse an XML element that represents the root logger.
+        /// </para>
+        /// </remarks>
+        protected void ParseRoot(XmlElement rootElement)
+        {
+            Logger root = m_hierarchy.Root;
+            // logger configuration needs to be atomic
+            lock (root)
+            {
+                ParseChildrenOfLoggerElement(rootElement, root, true);
+            }
+        }
+
+        /// <summary>
+        /// Parses the children of a logger element.
+        /// </summary>
+        /// <param name="catElement">The category element.</param>
+        /// <param name="log">The logger instance.</param>
+        /// <param name="isRoot">Flag to indicate if the logger is the root logger.</param>
+        /// <remarks>
+        /// <para>
+        /// Parse the child elements of a &lt;logger&gt; element.
+        /// </para>
+        /// </remarks>
+        protected void ParseChildrenOfLoggerElement(XmlElement catElement, Logger log, bool isRoot)
+        {
+            // Remove all existing appenders from log. They will be
+            // reconstructed if need be.
+            log.RemoveAllAppenders();
+
+            foreach (XmlNode currentNode in catElement.ChildNodes)
+            {
+                if (currentNode.NodeType == XmlNodeType.Element)
+                {
+                    XmlElement currentElement = (XmlElement)currentNode;
+
+                    if (currentElement.LocalName == APPENDER_REF_TAG)
+                    {
+                        IAppender appender = FindAppenderByReference(currentElement);
+                        string refName = currentElement.GetAttribute(REF_ATTR);
+                        if (appender != null)
+                        {
+                            LogLog.Debug(declaringType, "Adding appender named [" + refName + "] to logger [" + log.Name + "].");
+                            log.AddAppender(appender);
+                        }
+                        else
+                        {
+                            LogLog.Error(declaringType, "Appender named [" + refName + "] not found.");
+                        }
+                    }
+                    else if (currentElement.LocalName == LEVEL_TAG || currentElement.LocalName == PRIORITY_TAG)
+                    {
+                        ParseLevel(currentElement, log, isRoot);
+                    }
+                    else
+                    {
+                        SetParameter(currentElement, log);
+                    }
+                }
+            }
+
+            IOptionHandler optionHandler = log as IOptionHandler;
+            if (optionHandler != null)
+            {
+                optionHandler.ActivateOptions();
+            }
+        }
+
+        /// <summary>
+        /// Parses an object renderer.
+        /// </summary>
+        /// <param name="element">The renderer element.</param>
+        /// <remarks>
+        /// <para>
+        /// Parse an XML element that represents a renderer.
+        /// </para>
+        /// </remarks>
+        protected void ParseRenderer(XmlElement element)
+        {
+            string renderingClassName = element.GetAttribute(RENDERING_TYPE_ATTR);
+            string renderedClassName = element.GetAttribute(RENDERED_TYPE_ATTR);
+
+            LogLog.Debug(declaringType, "Rendering class [" + renderingClassName + "], Rendered class [" + renderedClassName + "].");
+            IObjectRenderer renderer = (IObjectRenderer)OptionConverter.InstantiateByClassName(renderingClassName, typeof(IObjectRenderer), null);
+            if (renderer == null)
+            {
+                LogLog.Error(declaringType, "Could not instantiate renderer [" + renderingClassName + "].");
+                return;
+            }
+            else
+            {
+                try
+                {
+                    m_hierarchy.RendererMap.Put(SystemInfo.GetTypeFromString(renderedClassName, true, true), renderer);
+                }
+                catch (Exception e)
+                {
+                    LogLog.Error(declaringType, "Could not find class [" + renderedClassName + "].", e);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Parses a level element.
+        /// </summary>
+        /// <param name="element">The level element.</param>
+        /// <param name="log">The logger object to set the level on.</param>
+        /// <param name="isRoot">Flag to indicate if the logger is the root logger.</param>
+        /// <remarks>
+        /// <para>
+        /// Parse an XML element that represents a level.
+        /// </para>
+        /// </remarks>
+        protected void ParseLevel(XmlElement element, Logger log, bool isRoot)
+        {
+            string loggerName = log.Name;
+            if (isRoot)
+            {
+                loggerName = "root";
+            }
+
+            string levelStr = element.GetAttribute(VALUE_ATTR);
+            LogLog.Debug(declaringType, "Logger [" + loggerName + "] Level string is [" + levelStr + "].");
+
+            if (INHERITED == levelStr)
+            {
+                if (isRoot)
+                {
+                    LogLog.Error(declaringType, "Root level cannot be inherited. Ignoring directive.");
+                }
+                else
+                {
+                    LogLog.Debug(declaringType, "Logger [" + loggerName + "] level set to inherit from parent.");
+                    log.Level = null;
+                }
+            }
+            else
+            {
+                log.Level = log.Hierarchy.LevelMap[levelStr];
+                if (log.Level == null)
+                {
+                    LogLog.Error(declaringType, "Undefined level [" + levelStr + "] on Logger [" + loggerName + "].");
+                }
+                else
+                {
+                    LogLog.Debug(declaringType, "Logger [" + loggerName + "] level set to [name=\"" + log.Level.Name + "\",value=" + log.Level.Value + "].");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Sets a parameter on an object.
+        /// </summary>
+        /// <param name="element">The parameter element.</param>
+        /// <param name="target">The object to set the parameter on.</param>
+        /// <remarks>
+        /// The parameter name must correspond to a writable property
+        /// on the object. The value of the parameter is a string,
+        /// therefore this function will attempt to set a string
+        /// property first. If unable to set a string property it
+        /// will inspect the property and its argument type. It will
+        /// attempt to call a static method called <c>Parse</c> on the
+        /// type of the property. This method will take a single
+        /// string argument and return a value that can be used to
+        /// set the property.
+        /// </remarks>
+        protected void SetParameter(XmlElement element, object target)
+        {
+            // Get the property name
+            string name = element.GetAttribute(NAME_ATTR);
+
+            // If the name attribute does not exist then use the name of the element
+            if (element.LocalName != PARAM_TAG || name == null || name.Length == 0)
+            {
+                name = element.LocalName;
+            }
+
+            // Look for the property on the target object
+            Type targetType = target.GetType();
+            Type propertyType = null;
+
+            PropertyInfo propInfo = null;
+            MethodInfo methInfo = null;
+
+            // Try to find a writable property
+            propInfo = targetType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
+            if (propInfo != null && propInfo.CanWrite)
+            {
+                // found a property
+                propertyType = propInfo.PropertyType;
+            }
+            else
+            {
+                propInfo = null;
+
+                // look for a method with the signature Add<property>(type)
+                methInfo = FindMethodInfo(targetType, name);
+
+                if (methInfo != null)
+                {
+                    propertyType = methInfo.GetParameters()[0].ParameterType;
+                }
+            }
+
+            if (propertyType == null)
+            {
+                LogLog.Error(declaringType, "XmlHierarchyConfigurator: Cannot find Property [" + name + "] to set object on [" + target.ToString() + "]");
+            }
+            else
+            {
+                string propertyValue = null;
+
+                if (element.GetAttributeNode(VALUE_ATTR) != null)
+                {
+                    propertyValue = element.GetAttribute(VALUE_ATTR);
+                }
+                else if (element.HasChildNodes)
+                {
+                    // Concatenate the CDATA and Text nodes together
+                    foreach (XmlNode childNode in element.ChildNodes)
+                    {
+                        if (childNode.NodeType == XmlNodeType.CDATA || childNode.NodeType == XmlNodeType.Text)
+                        {
+                            if (propertyValue == null)
+                            {
+                                propertyValue = childNode.InnerText;
+                            }
+                            else
+                            {
+                                propertyValue += childNode.InnerText;
+                            }
+                        }
+                    }
+                }
+
+                if (propertyValue != null)
+                {
+#if !NETCF
+                    try
+                    {
+                        // Expand environment variables in the string.
+                        IDictionary environmentVariables = Environment.GetEnvironmentVariables();
+                        if (HasCaseInsensitiveEnvironment)
+                        {
+                            environmentVariables = CreateCaseInsensitiveWrapper(environmentVariables);
+                        }
+                        propertyValue = OptionConverter.SubstituteVariables(propertyValue, environmentVariables);
+                    }
+                    catch (System.Security.SecurityException)
+                    {
+                        // This security exception will occur if the caller does not have 
+                        // unrestricted environment permission. If this occurs the expansion 
+                        // will be skipped with the following warning message.
+                        LogLog.Debug(declaringType, "Security exception while trying to expand environment variables. Error Ignored. No Expansion.");
+                    }
 #endif
 
-					Type parsedObjectConversionTargetType = null;
+                    Type parsedObjectConversionTargetType = null;
+
+                    // Check if a specific subtype is specified on the element using the 'type' attribute
+                    string subTypeString = element.GetAttribute(TYPE_ATTR);
+                    if (subTypeString != null && subTypeString.Length > 0)
+                    {
+                        // Read the explicit subtype
+                        try
+                        {
+                            Type subType = SystemInfo.GetTypeFromString(subTypeString, true, true);
+
+                            LogLog.Debug(declaringType, "Parameter [" + name + "] specified subtype [" + subType.FullName + "]");
+
+                            if (!propertyType.IsAssignableFrom(subType))
+                            {
+                                // Check if there is an appropriate type converter
+                                if (OptionConverter.CanConvertTypeTo(subType, propertyType))
+                                {
+                                    // Must re-convert to the real property type
+                                    parsedObjectConversionTargetType = propertyType;
+
+                                    // Use sub type as intermediary type
+                                    propertyType = subType;
+                                }
+                                else
+                                {
+                                    LogLog.Error(declaringType, "subtype [" + subType.FullName + "] set on [" + name + "] is not a subclass of property type [" + propertyType.FullName + "] and there are no acceptable type conversions.");
+                                }
+                            }
+                            else
+                            {
+                                // The subtype specified is found and is actually a subtype of the property
+                                // type, therefore we can switch to using this type.
+                                propertyType = subType;
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            LogLog.Error(declaringType, "Failed to find type [" + subTypeString + "] set on [" + name + "]", ex);
+                        }
+                    }
+
+                    // Now try to convert the string value to an acceptable type
+                    // to pass to this property.
+
+                    object convertedValue = ConvertStringTo(propertyType, propertyValue);
+
+                    // Check if we need to do an additional conversion
+                    if (convertedValue != null && parsedObjectConversionTargetType != null)
+                    {
+                        LogLog.Debug(declaringType, "Performing additional conversion of value from [" + convertedValue.GetType().Name + "] to [" + parsedObjectConversionTargetType.Name + "]");
+                        convertedValue = OptionConverter.ConvertTypeTo(convertedValue, parsedObjectConversionTargetType);
+                    }
+
+                    if (convertedValue != null)
+                    {
+                        if (propInfo != null)
+                        {
+                            // Got a converted result
+                            LogLog.Debug(declaringType, "Setting Property [" + propInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue.ToString() + "]");
+
+                            try
+                            {
+                                // Pass to the property
+                                propInfo.SetValue(target, convertedValue, BindingFlags.SetProperty, null, null, CultureInfo.InvariantCulture);
+                            }
+                            catch (TargetInvocationException targetInvocationEx)
+                            {
+                                LogLog.Error(declaringType, "Failed to set parameter [" + propInfo.Name + "] on object [" + target + "] using value [" + convertedValue + "]", targetInvocationEx.InnerException);
+                            }
+                        }
+                        else if (methInfo != null)
+                        {
+                            // Got a converted result
+                            LogLog.Debug(declaringType, "Setting Collection Property [" + methInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue.ToString() + "]");
+
+                            try
+                            {
+                                // Pass to the property
+                                methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new object[] { convertedValue }, CultureInfo.InvariantCulture);
+                            }
+                            catch (TargetInvocationException targetInvocationEx)
+                            {
+                                LogLog.Error(declaringType, "Failed to set parameter [" + name + "] on object [" + target + "] using value [" + convertedValue + "]", targetInvocationEx.InnerException);
+                            }
+                        }
+                    }
+                    else
+                    {
+                        LogLog.Warn(declaringType, "Unable to set property [" + name + "] on object [" + target + "] using value [" + propertyValue + "] (with acceptable conversion types)");
+                    }
+                }
+                else
+                {
+                    object createdObject = null;
+
+                    if (propertyType == typeof(string) && !HasAttributesOrElements(element))
+                    {
+                        // If the property is a string and the element is empty (no attributes
+                        // or child elements) then we special case the object value to an empty string.
+                        // This is necessary because while the String is a class it does not have
+                        // a default constructor that creates an empty string, which is the behavior
+                        // we are trying to simulate and would be expected from CreateObjectFromXml
+                        createdObject = "";
+                    }
+                    else
+                    {
+                        // No value specified
+                        Type defaultObjectType = null;
+                        if (IsTypeConstructible(propertyType))
+                        {
+                            defaultObjectType = propertyType;
+                        }
+
+                        createdObject = CreateObjectFromXml(element, defaultObjectType, propertyType);
+                    }
+
+                    if (createdObject == null)
+                    {
+                        LogLog.Error(declaringType, "Failed to create object to set param: " + name);
+                    }
+                    else
+                    {
+                        if (propInfo != null)
+                        {
+                            // Got a converted result
+                            LogLog.Debug(declaringType, "Setting Property [" + propInfo.Name + "] to object [" + createdObject + "]");
+
+                            try
+                            {
+                                // Pass to the property
+                                propInfo.SetValue(target, createdObject, BindingFlags.SetProperty, null, null, CultureInfo.InvariantCulture);
+                            }
+                            catch (TargetInvocationException targetInvocationEx)
+                            {
+                                LogLog.Error(declaringType, "Failed to set parameter [" + propInfo.Name + "] on object [" + target + "] using value [" + createdObject + "]", targetInvocationEx.InnerException);
+                            }
+                        }
+                        else if (methInfo != null)
+                        {
+                            // Got a converted result
+                            LogLog.Debug(declaringType, "Setting Collection Property [" + methInfo.Name + "] to object [" + createdObject + "]");
+
+                            try
+                            {
+                                // Pass to the property
+                                methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new object[] { createdObject }, CultureInfo.InvariantCulture);
+                            }
+                            catch (TargetInvocationException targetInvocationEx)
+                            {
+                                LogLog.Error(declaringType, "Failed to set parameter [" + methInfo.Name + "] on object [" + target + "] using value [" + createdObject + "]", targetInvocationEx.InnerException);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Test if an element has no attributes or child elements
+        /// </summary>
+        /// <param name="element">the element to inspect</param>
+        /// <returns><c>true</c> if the element has any attributes or child elements, <c>false</c> otherwise</returns>
+        private bool HasAttributesOrElements(XmlElement element)
+        {
+            foreach (XmlNode node in element.ChildNodes)
+            {
+                if (node.NodeType == XmlNodeType.Attribute || node.NodeType == XmlNodeType.Element)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Test if a <see cref="Type"/> is constructible with <c>Activator.CreateInstance</c>.
+        /// </summary>
+        /// <param name="type">the type to inspect</param>
+        /// <returns><c>true</c> if the type is creatable using a default constructor, <c>false</c> otherwise</returns>
+        private static bool IsTypeConstructible(Type type)
+        {
+            if (type.IsClass && !type.IsAbstract)
+            {
+                ConstructorInfo defaultConstructor = type.GetConstructor(new Type[0]);
+                if (defaultConstructor != null && !defaultConstructor.IsAbstract && !defaultConstructor.IsPrivate)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
 
-					// Check if a specific subtype is specified on the element using the 'type' attribute
-					string subTypeString = element.GetAttribute(TYPE_ATTR);
-					if (subTypeString != null && subTypeString.Length > 0)
-					{
-						// Read the explicit subtype
-						try
-						{
-							Type subType = SystemInfo.GetTypeFromString(subTypeString, true, true);
-
-							LogLog.Debug(declaringType, "Parameter ["+name+"] specified subtype ["+subType.FullName+"]");
-
-							if (!propertyType.IsAssignableFrom(subType))
-							{
-								// Check if there is an appropriate type converter
-								if (OptionConverter.CanConvertTypeTo(subType, propertyType))
-								{
-									// Must re-convert to the real property type
-									parsedObjectConversionTargetType = propertyType;
-
-									// Use sub type as intermediary type
-									propertyType = subType;
-								}
-								else
-								{
-									LogLog.Error(declaringType, "subtype ["+subType.FullName+"] set on ["+name+"] is not a subclass of property type ["+propertyType.FullName+"] and there are no acceptable type conversions.");
-								}
-							}
-							else
-							{
-								// The subtype specified is found and is actually a subtype of the property
-								// type, therefore we can switch to using this type.
-								propertyType = subType;
-							}
-						}
-						catch(Exception ex)
-						{
-							LogLog.Error(declaringType, "Failed to find type ["+subTypeString+"] set on ["+name+"]", ex);
-						}
-					}
-
-					// Now try to convert the string value to an acceptable type
-					// to pass to this property.
-
-					object convertedValue = ConvertStringTo(propertyType, propertyValue);
-					
-					// Check if we need to do an additional conversion
-					if (convertedValue != null && parsedObjectConversionTargetType != null)
-					{
-						LogLog.Debug(declaringType, "Performing additional conversion of value from [" + convertedValue.GetType().Name + "] to [" + parsedObjectConversionTargetType.Name + "]");
-						convertedValue = OptionConverter.ConvertTypeTo(convertedValue, parsedObjectConversionTargetType);
-					}
-
-					if (convertedValue != null)
-					{
-						if (propInfo != null)
-						{
-							// Got a converted result
-							LogLog.Debug(declaringType, "Setting Property [" + propInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue.ToString() + "]");
-
-							try
-							{
-								// Pass to the property
-								propInfo.SetValue(target, convertedValue, BindingFlags.SetProperty, null, null, CultureInfo.InvariantCulture);
-							}
-							catch(TargetInvocationException targetInvocationEx)
-							{
-								LogLog.Error(declaringType, "Failed to set parameter [" + propInfo.Name + "] on object [" + target + "] using value [" + convertedValue + "]", targetInvocationEx.InnerException);
-							}
-						}
-						else if (methInfo != null)
-						{
-							// Got a converted result
-							LogLog.Debug(declaringType, "Setting Collection Property [" + methInfo.Name + "] to " + convertedValue.GetType().Name + " value [" + convertedValue.ToString() + "]");
-
-							try
-							{
-								// Pass to the property
-								methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new object[] {convertedValue}, CultureInfo.InvariantCulture);
-							}
-							catch(TargetInvocationException targetInvocationEx)
-							{
-								LogLog.Error(declaringType, "Failed to set parameter [" + name + "] on object [" + target + "] using value [" + convertedValue + "]", targetInvocationEx.InnerException);
-							}
-						}
-					}
-					else
-					{
-						LogLog.Warn(declaringType, "Unable to set property [" + name + "] on object [" + target + "] using value [" + propertyValue + "] (with acceptable conversion types)");
-					}
-				}
-				else
-				{
-					object createdObject = null;
-
-					if (propertyType == typeof(string) && !HasAttributesOrElements(element))
-					{
-						// If the property is a string and the element is empty (no attributes
-						// or child elements) then we special case the object value to an empty string.
-						// This is necessary because while the String is a class it does not have
-						// a default constructor that creates an empty string, which is the behavior
-						// we are trying to simulate and would be expected from CreateObjectFromXml
-						createdObject = "";
-					}
-					else
-					{
-						// No value specified
-						Type defaultObjectType = null;
-						if (IsTypeConstructible(propertyType))
-						{
-							defaultObjectType = propertyType;
-						}
-
-						createdObject = CreateObjectFromXml(element, defaultObjectType, propertyType);
-					}
-
-					if (createdObject == null)
-					{
-						LogLog.Error(declaringType, "Failed to create object to set param: "+name);
-					}
-					else
-					{
-						if (propInfo != null)
-						{
-							// Got a converted result
-							LogLog.Debug(declaringType, "Setting Property ["+ propInfo.Name +"] to object ["+ createdObject +"]");
-
-							try
-							{
-								// Pass to the property
-								propInfo.SetValue(target, createdObject, BindingFlags.SetProperty, null, null, CultureInfo.InvariantCulture);
-							}
-							catch(TargetInvocationException targetInvocationEx)
-							{
-								LogLog.Error(declaringType, "Failed to set parameter [" + propInfo.Name + "] on object [" + target + "] using value [" + createdObject + "]", targetInvocationEx.InnerException);
-							}
-						}
-						else if (methInfo != null)
-						{
-							// Got a converted result
-							LogLog.Debug(declaringType, "Setting Collection Property ["+ methInfo.Name +"] to object ["+ createdObject +"]");
-
-							try
-							{
-								// Pass to the property
-								methInfo.Invoke(target, BindingFlags.InvokeMethod, null, new object[] {createdObject}, CultureInfo.InvariantCulture);
-							}
-							catch(TargetInvocationException targetInvocationEx)
-							{
-								LogLog.Error(declaringType, "Failed to set parameter [" + methInfo.Name + "] on object [" + target + "] using value [" + createdObject + "]", targetInvocationEx.InnerException);
-							}
-						}
-					}
-				}
-			}
-		}
-
-		/// <summary>
-		/// Test if an element has no attributes or child elements
-		/// </summary>
-		/// <param name="element">the element to inspect</param>
-		/// <returns><c>true</c> if the element has any attributes or child elements, <c>false</c> otherwise</returns>
-		private bool HasAttributesOrElements(XmlElement element)
-		{
-			foreach(XmlNode node in element.ChildNodes)
-			{
-				if (node.NodeType == XmlNodeType.Attribute || node.NodeType == XmlNodeType.Element)
-				{
-					return true;
-				}
-			}
-			return false;
-		}
-
-		/// <summary>
-		/// Test if a <see cref="Type"/> is constructible with <c>Activator.CreateInstance</c>.
-		/// </summary>
-		/// <param name="type">the type to inspect</param>
-		/// <returns><c>true</c> if the type is creatable using a default constructor, <c>false</c> otherwise</returns>
-		private static bool IsTypeConstructible(Type type)
-		{
-			if (type.IsClass && !type.IsAbstract)
-			{
-				ConstructorInfo defaultConstructor = type.GetConstructor(new Type[0]);
-				if (defaultConstructor != null && !defaultConstructor.IsAbstract && !defaultConstructor.IsPrivate)
-				{
-					return true;
-				}
-			}
-			return false;
-		}
-
-		/// <summary>
-		/// Look for a method on the <paramref name="targetType"/> that matches the <paramref name="name"/> supplied
-		/// </summary>
-		/// <param name="targetType">the type that has the method</param>
-		/// <param name="name">the name of the method</param>
-		/// <returns>the method info found</returns>
-		/// <remarks>
-		/// <para>
-		/// The method must be a public instance method on the <paramref name="targetType"/>.
-		/// The method must be named <paramref name="name"/> or "Add" followed by <paramref name="name"/>.
-		/// The method must take a single parameter.
-		/// </para>
-		/// </remarks>
-		private MethodInfo FindMethodInfo(Type targetType, string name)
-		{
-			string requiredMethodNameA = name;
-			string requiredMethodNameB = "Add" + name;
-
-			MethodInfo[] methods = targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
-
-			foreach(MethodInfo methInfo in methods)
-			{
-				if (!methInfo.IsStatic)
-				{
-					if (string.Compare(methInfo.Name, requiredMethodNameA, true, System.Globalization.CultureInfo.InvariantCulture) == 0 ||
-						string.Compare(methInfo.Name, requiredMethodNameB, true, System.Globalization.CultureInfo.InvariantCulture) == 0)
-					{
-						// Found matching method name
-
-						// Look for version with one arg only
-						System.Reflection.ParameterInfo[] methParams = methInfo.GetParameters();
-						if (methParams.Length == 1)
-						{
-							return methInfo;
-						}
-					}
-				}
-			}
-			return null;
-		}
-
-		/// <summary>
-		/// Converts a string value to a target type.
-		/// </summary>
-		/// <param name="type">The type of object to convert the string to.</param>
-		/// <param name="value">The string value to use as the value of the object.</param>
-		/// <returns>
-		/// <para>
-		/// An object of type <paramref name="type"/> with value <paramref name="value"/> or 
-		/// <c>null</c> when the conversion could not be performed.
-		/// </para>
-		/// </returns>
-		protected object ConvertStringTo(Type type, string value)
-		{
-			// Hack to allow use of Level in property
-			if (typeof(Level) == type)
-			{
-				// Property wants a level
-				Level levelValue = m_hierarchy.LevelMap[value];
-
-				if (levelValue == null)
-				{
-					LogLog.Error(declaringType, "XmlHierarchyConfigurator: Unknown Level Specified ["+ value +"]");
-				}
-
-				return levelValue;
-			}
-			return OptionConverter.ConvertStringTo(type, value);
-		}
-
-		/// <summary>
-		/// Creates an object as specified in XML.
-		/// </summary>
-		/// <param name="element">The XML element that contains the definition of the object.</param>
-		/// <param name="defaultTargetType">The object type to use if not explicitly specified.</param>
-		/// <param name="typeConstraint">The type that the returned object must be or must inherit from.</param>
-		/// <returns>The object or <c>null</c></returns>
-		/// <remarks>
-		/// <para>
-		/// Parse an XML element and create an object instance based on the configuration
-		/// data.
-		/// </para>
-		/// <para>
-		/// The type of the instance may be specified in the XML. If not
-		/// specified then the <paramref name="defaultTargetType"/> is used
-		/// as the type. However the type is specified it must support the
-		/// <paramref name="typeConstraint"/> type.
-		/// </para>
-		/// </remarks>
-		protected object CreateObjectFromXml(XmlElement element, Type defaultTargetType, Type typeConstraint) 
-		{
-			Type objectType = null;
-
-			// Get the object type
-			string objectTypeString = element.GetAttribute(TYPE_ATTR);
-			if (objectTypeString == null || objectTypeString.Length == 0)
-			{
-				if (defaultTargetType == null)
-				{
-					LogLog.Error(declaringType, "Object type not specified. Cannot create object of type ["+typeConstraint.FullName+"]. Missing Value or Type.");
-					return null;
-				}
-				else
-				{
-					// Use the default object type
-					objectType = defaultTargetType;
-				}
-			}
-			else
-			{
-				// Read the explicit object type
-				try
-				{
-					objectType = SystemInfo.GetTypeFromString(objectTypeString, true, true);
-				}
-				catch(Exception ex)
-				{
-					LogLog.Error(declaringType, "Failed to find type ["+objectTypeString+"]", ex);
-					return null;
-				}
-			}
-
-			bool requiresConversion = false;
-
-			// Got the object type. Check that it meets the typeConstraint
-			if (typeConstraint != null)
-			{
-				if (!typeConstraint.IsAssignableFrom(objectType))
-				{
-					// Check if there is an appropriate type converter
-					if (OptionConverter.CanConvertTypeTo(objectType, typeConstraint))
-					{
-						requiresConversion = true;
-					}
-					else
-					{
-						LogLog.Error(declaringType, "Object type ["+objectType.FullName+"] is not assignable to type ["+typeConstraint.FullName+"]. There are no acceptable type conversions.");
-						return null;
-					}
-				}
-			}
-
-			// Create using the default constructor
-			object createdObject = null;
-			try
-			{
-				createdObject = Activator.CreateInstance(objectType);
-			}
-			catch(Exception createInstanceEx)
-			{
-				LogLog.Error(declaringType, "XmlHierarchyConfigurator: Failed to construct object of type [" + objectType.FullName + "] Exception: "+createInstanceEx.ToString());
-			}
-
-			// Set any params on object
-			foreach (XmlNode currentNode in element.ChildNodes)
-			{
-				if (currentNode.NodeType == XmlNodeType.Element) 
-				{
-					SetParameter((XmlElement)currentNode, createdObject);
-				}
-			}
-
-			// Check if we need to call ActivateOptions
-			IOptionHandler optionHandler = createdObject as IOptionHandler;
-			if (optionHandler != null)
-			{
-				optionHandler.ActivateOptions();
-			}
-
-			// Ok object should be initialized
-
-			if (requiresConversion)
-			{
-				// Convert the object type
-				return OptionConverter.ConvertTypeTo(createdObject, typeConstraint);
-			}
-			else
-			{
-				// The object is of the correct type
-				return createdObject;
-			}
-		}
+        /// <summary>
+        /// Look for a method on the <paramref name="targetType"/> that matches the <paramref name="name"/> supplied
+        /// </summary>
+        /// <param name="targetType">the type that has the method</param>
+        /// <param name="name">the name of the method</param>
+        /// <returns>the method info found</returns>
+        /// <remarks>
+        /// <para>
+        /// The method must be a public instance method on the <paramref name="targetType"/>.
+        /// The method must be named <paramref name="name"/> or "Add" followed by <paramref name="name"/>.
+        /// The method must take a single parameter.
+        /// </para>
+        /// </remarks>
+        private MethodInfo FindMethodInfo(Type targetType, string name)
+        {
+            string requiredMethodNameA = name;
+            string requiredMethodNameB = "Add" + name;
 
-		#endregion Protected Instance Methods
+            MethodInfo[] methods = targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+
+            foreach (MethodInfo methInfo in methods)
+            {
+                if (!methInfo.IsStatic)
+                {
+                    if (string.Compare(methInfo.Name, requiredMethodNameA, true, System.Globalization.CultureInfo.InvariantCulture) == 0 ||
+                        string.Compare(methInfo.Name, requiredMethodNameB, true, System.Globalization.CultureInfo.InvariantCulture) == 0)
+                    {
+                        // Found matching method name
+
+                        // Look for version with one arg only
+                        System.Reflection.ParameterInfo[] methParams = methInfo.GetParameters();
+                        if (methParams.Length == 1)
+                        {
+                            return methInfo;
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Converts a string value to a target type.
+        /// </summary>
+        /// <param name="type">The type of object to convert the string to.</param>
+        /// <param name="value">The string value to use as the value of the object.</param>
+        /// <returns>
+        /// <para>
+        /// An object of type <paramref name="type"/> with value <paramref name="value"/> or 
+        /// <c>null</c> when the conversion could not be performed.
+        /// </para>
+        /// </returns>
+        protected object ConvertStringTo(Type type, string value)
+        {
+            // Hack to allow use of Level in property
+            if (typeof(Level) == type)
+            {
+                // Property wants a level
+                Level levelValue = m_hierarchy.LevelMap[value];
+
+                if (levelValue == null)
+                {
+                    LogLog.Error(declaringType, "XmlHierarchyConfigurator: Unknown Level Specified [" + value + "]");
+                }
+
+                return levelValue;
+            }
+            return OptionConverter.ConvertStringTo(type, value);
+        }
+
+        /// <summary>
+        /// Creates an object as specified in XML.
+        /// </summary>
+        /// <param name="element">The XML element that contains the definition of the object.</param>
+        /// <param name="defaultTargetType">The object type to use if not explicitly specified.</param>
+        /// <param name="typeConstraint">The type that the returned object must be or must inherit from.</param>
+        /// <returns>The object or <c>null</c></returns>
+        /// <remarks>
+        /// <para>
+        /// Parse an XML element and create an object instance based on the configuration
+        /// data.
+        /// </para>
+        /// <para>
+        /// The type of the instance may be specified in the XML. If not
+        /// specified then the <paramref name="defaultTargetType"/> is used
+        /// as the type. However the type is specified it must support the
+        /// <paramref name="typeConstraint"/> type.
+        /// </para>
+        /// </remarks>
+        protected object CreateObjectFromXml(XmlElement element, Type defaultTargetType, Type typeConstraint)
+        {
+            Type objectType = null;
+
+            // Get the object type
+            string objectTypeString = element.GetAttribute(TYPE_ATTR);
+            if (objectTypeString == null || objectTypeString.Length == 0)
+            {
+                if (defaultTargetType == null)
+                {
+                    LogLog.Error(declaringType, "Object type not specified. Cannot create object of type [" + typeConstraint.FullName + "]. Missing Value or Type.");
+                    return null;
+                }
+                else
+                {
+                    // Use the default object type
+                    objectType = defaultTargetType;
+                }
+            }
+            else
+            {
+                // Read the explicit object type
+                try
+                {
+                    objectType = SystemInfo.GetTypeFromString(objectTypeString, true, true);
+                }
+                catch (Exception ex)
+                {
+                    LogLog.Error(declaringType, "Failed to find type [" + objectTypeString + "]", ex);
+                    return null;
+                }
+            }
+
+            bool requiresConversion = false;
+
+            // Got the object type. Check that it meets the typeConstraint
+            if (typeConstraint != null)
+            {
+                if (!typeConstraint.IsAssignableFrom(objectType))
+                {
+                    // Check if there is an appropriate type converter
+                    if (OptionConverter.CanConvertTypeTo(objectType, typeConstraint))
+                    {
+                        requiresConversion = true;
+                    }
+                    else
+                    {
+                        LogLog.Error(declaringType, "Object type [" + objectType.FullName + "] is not assignable to type [" + typeConstraint.FullName + "]. There are no acceptable type conversions.");
+                        return null;
+                    }
+                }
+            }
+
+            // Create using the default constructor
+            object createdObject = null;
+            try
+            {
+                createdObject = Activator.CreateInstance(objectType);
+            }
+            catch (Exception createInstanceEx)
+            {
+                LogLog.Error(declaringType, "XmlHierarchyConfigurator: Failed to construct object of type [" + objectType.FullName + "] Exception: " + createInstanceEx.ToString());
+            }
+
+            // Set any params on object
+            foreach (XmlNode currentNode in element.ChildNodes)
+            {
+                if (currentNode.NodeType == XmlNodeType.Element)
+                {
+                    SetParameter((XmlElement)currentNode, createdObject);
+                }
+            }
+
+            // Check if we need to call ActivateOptions
+            IOptionHandler optionHandler = createdObject as IOptionHandler;
+            if (optionHandler != null)
+            {
+                optionHandler.ActivateOptions();
+            }
+
+            // Ok object should be initialized
+
+            if (requiresConversion)
+            {
+                // Convert the object type
+                return OptionConverter.ConvertTypeTo(createdObject, typeConstraint);
+            }
+            else
+            {
+                // The object is of the correct type
+                return createdObject;
+            }
+        }
+
+        #endregion Protected Instance Methods
 
 #if !NETCF
-		private bool HasCaseInsensitiveEnvironment
-	        {
-		    get
-		    {
-			PlatformID platform = Environment.OSVersion.Platform;
-			return platform != PlatformID.Unix && platform != PlatformID.MacOSX;
-		    }
-		}
-
-	        private IDictionary CreateCaseInsensitiveWrapper(IDictionary dict)
-	        {
-		    if (dict == null)
-		    {
-			return dict;
-		    }
-		    Hashtable hash = SystemInfo.CreateCaseInsensitiveHashtable();
-		    foreach (DictionaryEntry entry in dict) {
-			hash[entry.Key] = entry.Value;
-		    }
-		    return hash;
-		}
+        private bool HasCaseInsensitiveEnvironment
+        {
+            get
+            {
+                PlatformID platform = Environment.OSVersion.Platform;
+                return platform != PlatformID.Unix && platform != PlatformID.MacOSX;
+            }
+        }
+
+        private IDictionary CreateCaseInsensitiveWrapper(IDictionary dict)
+        {
+            if (dict == null)
+            {
+                return dict;
+            }
+            Hashtable hash = SystemInfo.CreateCaseInsensitiveHashtable();
+            foreach (DictionaryEntry entry in dict)
+            {
+                hash[entry.Key] = entry.Value;
+            }
+            return hash;
+        }
 #endif
 
-		#region Private Constants
+        #region Private Constants
 
-		// String constants used while parsing the XML data
-		private const string CONFIGURATION_TAG			= "log4net";
-		private const string RENDERER_TAG				= "renderer";
-		private const string APPENDER_TAG 				= "appender";
-		private const string APPENDER_REF_TAG 			= "appender-ref";  
-		private const string PARAM_TAG					= "param";
-
-		// TODO: Deprecate use of category tags
-		private const string CATEGORY_TAG				= "category";
-		// TODO: Deprecate use of priority tag
-		private const string PRIORITY_TAG				= "priority";
-
-		private const string LOGGER_TAG					= "logger";
-		private const string NAME_ATTR					= "name";
-		private const string TYPE_ATTR					= "type";
-		private const string VALUE_ATTR					= "value";
-		private const string ROOT_TAG					= "root";
-		private const string LEVEL_TAG					= "level";
-		private const string REF_ATTR					= "ref";
-		private const string ADDITIVITY_ATTR			= "additivity";  
-		private const string THRESHOLD_ATTR				= "threshold";
-		private const string CONFIG_DEBUG_ATTR			= "configDebug";
-		private const string INTERNAL_DEBUG_ATTR		= "debug";
-		private const string EMIT_INTERNAL_DEBUG_ATTR   = "emitDebug";
-		private const string CONFIG_UPDATE_MODE_ATTR	= "update";
-		private const string RENDERING_TYPE_ATTR		= "renderingClass";
-		private const string RENDERED_TYPE_ATTR			= "renderedClass";
-
-		// flag used on the level element
-		private const string INHERITED = "inherited";
-
-		#endregion Private Constants
-
-		#region Private Instance Fields
-
-		/// <summary>
-		/// key: appenderName, value: appender.
-		/// </summary>
-		private Hashtable m_appenderBag;
-
-		/// <summary>
-		/// The Hierarchy being configured.
-		/// </summary>
-		private readonly Hierarchy m_hierarchy;
-
-		#endregion Private Instance Fields
-
-	    #region Private Static Fields
-
-	    /// <summary>
-	    /// The fully qualified type of the XmlHierarchyConfigurator class.
-	    /// </summary>
-	    /// <remarks>
-	    /// Used by the internal logger to record the Type of the
-	    /// log message.
-	    /// </remarks>
-	    private readonly static Type declaringType = typeof(XmlHierarchyConfigurator);
+        // String constants used while parsing the XML data
+        private const string CONFIGURATION_TAG = "log4net";
+        private const string RENDERER_TAG = "renderer";
+        private const string APPENDER_TAG = "appender";
+        private const string APPENDER_REF_TAG = "appender-ref";
+        private const string PARAM_TAG = "param";
+
+        // TODO: Deprecate use of category tags
+        private const string CATEGORY_TAG = "category";
+        // TODO: Deprecate use of priority tag
+        private const string PRIORITY_TAG = "priority";
+
+        private const string LOGGER_TAG = "logger";
+        private const string NAME_ATTR = "name";
+        private const string TYPE_ATTR = "type";
+        private const string VALUE_ATTR = "value";
+        private const string ROOT_TAG = "root";
+        private const string LEVEL_TAG = "level";
+        private const string REF_ATTR = "ref";
+        private const string ADDITIVITY_ATTR = "additivity";
+        private const string THRESHOLD_ATTR = "threshold";
+        private const string CONFIG_DEBUG_ATTR = "configDebug";
+        private const string INTERNAL_DEBUG_ATTR = "debug";
+        private const string EMIT_INTERNAL_DEBUG_ATTR = "emitDebug";
+        private const string CONFIG_UPDATE_MODE_ATTR = "update";
+        private const string RENDERING_TYPE_ATTR = "renderingClass";
+        private const string RENDERED_TYPE_ATTR = "renderedClass";
+
+        // flag used on the level element
+        private const string INHERITED = "inherited";
+
+        #endregion Private Constants
+
+        #region Private Instance Fields
+
+        /// <summary>
+        /// key: appenderName, value: appender.
+        /// </summary>
+        private Hashtable m_appenderBag;
+
+        /// <summary>
+        /// The Hierarchy being configured.
+        /// </summary>
+        private readonly Hierarchy m_hierarchy;
+
+        #endregion Private Instance Fields
+
+        #region Private Static Fields
+
+        /// <summary>
+        /// The fully qualified type of the XmlHierarchyConfigurator class.
+        /// </summary>
+        /// <remarks>
+        /// Used by the internal logger to record the Type of the
+        /// log message.
+        /// </remarks>
+        private readonly static Type declaringType = typeof(XmlHierarchyConfigurator);
 
-	    #endregion Private Static Fields
-	}
+        #endregion Private Static Fields
+    }
 }