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 <logger> 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 <logger> 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
+ }
}