// Comments from John R. Hicks <angryjohn69@nc.rr.com> original implementation \r
// can be found at: /mcs/docs/apidocs/xml/en/System.Diagnostics\r
//\r
-// Author: \r
+// Authors: \r
// John R. Hicks <angryjohn69@nc.rr.com>\r
+// Jonathan Pryor <jonpryor@vt.edu>\r
//\r
// (C) 2002\r
//\r
using System;\r
+using System.Collections;\r
using System.Configuration;\r
using System.Xml;\r
\r
namespace System.Diagnostics\r
{\r
- public class DiagnosticsConfigurationHandler :\r
- IConfigurationSectionHandler\r
+ internal sealed class DiagnosticsConfiguration\r
{\r
- public DiagnosticsConfigurationHandler()\r
+ private static IDictionary settings = null;\r
+\r
+ public static IDictionary Settings {\r
+ get {\r
+ // TODO: Does anybody know if this is actually thread-safe under .NET?\r
+ // I've heard that this construct isn't safe under Java, but it's used\r
+ // reasonably often under C++, so I'm not sure about .NET.\r
+ if (settings == null) {\r
+ lock (typeof(DiagnosticsConfiguration)) {\r
+ if (settings == null)\r
+ settings = (IDictionary) ConfigurationSettings.GetConfig ("system.diagnostics");\r
+ }\r
+ }\r
+ return settings;\r
+ }\r
+ }\r
+ }\r
+\r
+ public class DiagnosticsConfigurationHandler : IConfigurationSectionHandler\r
+ {\r
+ delegate void ElementHandler (IDictionary d, XmlNode node);\r
+\r
+ IDictionary elementHandlers = new Hashtable ();\r
+\r
+ public DiagnosticsConfigurationHandler ()\r
+ {\r
+ elementHandlers ["assert"] = new ElementHandler (AddAssertNode);\r
+ elementHandlers ["switches"] = new ElementHandler (AddSwitchesNode);\r
+ elementHandlers ["trace"] = new ElementHandler (AddTraceNode);\r
+ }\r
+\r
+ public virtual object Create (object parent, object configContext, XmlNode section)\r
+ {\r
+ IDictionary d;\r
+ if (parent == null)\r
+ d = new Hashtable (CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);\r
+ else\r
+ d = (IDictionary) ((ICloneable)parent).Clone();\r
+\r
+ foreach (XmlNode child in section.ChildNodes) {\r
+ XmlNodeType type = child.NodeType;\r
+\r
+ switch (type) {\r
+ /* ignore */\r
+ case XmlNodeType.Whitespace:\r
+ case XmlNodeType.Comment:\r
+ continue;\r
+ case XmlNodeType.Element:\r
+ ElementHandler eh = (ElementHandler) elementHandlers [child.Name];\r
+ if (eh != null)\r
+ eh (d, child);\r
+ else\r
+ ThrowUnrecognizedElement (child);\r
+ break;\r
+ default:\r
+ ThrowUnrecognizedElement (child);\r
+ break;\r
+ }\r
+ }\r
+\r
+ return d;\r
+ }\r
+\r
+ // Remarks: Both attribute are optional\r
+ private void AddAssertNode (IDictionary d, XmlNode node)\r
{\r
- \r
+ XmlAttributeCollection c = node.Attributes;\r
+ string assertuienabled = GetAttribute (c, "assertuienabled", false, node);\r
+ string logfilename = GetAttribute (c, "logfilename", false, node);\r
+ ValidateInvalidAttributes (c, node);\r
+ try {\r
+ d ["assertuienabled"] = bool.Parse (assertuienabled);\r
+ }\r
+ catch (Exception e) {\r
+ throw new ConfigurationException ("The `assertuienabled' attribute must be `true' or `false'",\r
+ e, node);\r
+ }\r
+ d ["logfilename"] = logfilename;\r
}\r
- \r
- public virtual object Create(\r
- object parent,\r
- object configContext,\r
- XmlNode section)\r
+\r
+ // name attribute is required, value is optional\r
+ // Docs do not define "remove" or "clear" elements, but .NET recognizes\r
+ // them\r
+ private void AddSwitchesNode (IDictionary d, XmlNode node)\r
{\r
- throw new NotImplementedException(); \r
+ // There are no attributes on <switch/>\r
+ ValidateInvalidAttributes (node.Attributes, node);\r
+\r
+ IDictionary newNodes = new Hashtable ();\r
+\r
+ foreach (XmlNode child in node.ChildNodes) {\r
+ XmlNodeType t = child.NodeType;\r
+ if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)\r
+ continue;\r
+ if (t == XmlNodeType.Element) {\r
+ XmlAttributeCollection attributes = child.Attributes;\r
+ string name = null;\r
+ string value = null;\r
+ switch (child.Name) {\r
+ case "add":\r
+ name = GetAttribute (attributes, "name", true, child);\r
+ value = GetAttribute (attributes, "value", false, child);\r
+ newNodes[name] = value;\r
+ break;\r
+ case "remove":\r
+ name = GetAttribute (attributes, "name", true, child);\r
+ newNodes.Remove (name);\r
+ break;\r
+ case "clear":\r
+ newNodes.Clear ();\r
+ break;\r
+ default:\r
+ ThrowUnrecognizedElement (child);\r
+ break;\r
+ }\r
+ ValidateInvalidAttributes (attributes, child);\r
+ }\r
+ else\r
+ ThrowUnrecognizedNode (child);\r
+ }\r
+\r
+ d [node.Name] = newNodes;\r
}\r
- \r
- \r
- ~DiagnosticsConfigurationHandler() \r
+\r
+ private void AddTraceNode (IDictionary d, XmlNode node)\r
+ {\r
+ AddTraceAttributes (d, node);\r
+\r
+ foreach (XmlNode child in node.ChildNodes) {\r
+ XmlNodeType t = child.NodeType;\r
+ if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)\r
+ continue;\r
+ if (t == XmlNodeType.Element) {\r
+ if (child.Name == "listeners")\r
+ AddTraceListeners (child);\r
+ else\r
+ ThrowUnrecognizedElement (child);\r
+ ValidateInvalidAttributes (child.Attributes, child);\r
+ }\r
+ else\r
+ ThrowUnrecognizedNode (child);\r
+ }\r
+ }\r
+\r
+ // all attributes are optional\r
+ private void AddTraceAttributes (IDictionary d, XmlNode node)\r
+ {\r
+ XmlAttributeCollection c = node.Attributes;\r
+ string autoflush = GetAttribute (c, "autoflush", false, node);\r
+ string indentsize = GetAttribute (c, "indentsize", false, node);\r
+ ValidateInvalidAttributes (c, node);\r
+ try {\r
+ d ["autoflush"] = bool.Parse (autoflush);\r
+ }\r
+ catch (Exception e) {\r
+ throw new ConfigurationException ("The `autoflush' attribute must be `true' or `false'",\r
+ e, node);\r
+ }\r
+ try {\r
+ d ["indentsize"] = int.Parse (indentsize);\r
+ }\r
+ catch (Exception e) {\r
+ throw new ConfigurationException ("The `indentsize' attribute must be an integral value.",\r
+ e, node);\r
+ }\r
+ }\r
+\r
+ // only defines "add" and "remove", but "clear" also works\r
+ // for add, "name" and "type" are required; initializeData is optional\r
+ private void AddTraceListeners (XmlNode listenersNode)\r
+ {\r
+ // There are no attributes on <listeners/>\r
+ ValidateInvalidAttributes (listenersNode.Attributes, listenersNode);\r
+\r
+ foreach (XmlNode child in listenersNode.ChildNodes) {\r
+ XmlNodeType t = child.NodeType;\r
+ if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)\r
+ continue;\r
+ if (t == XmlNodeType.Element) {\r
+ XmlAttributeCollection attributes = child.Attributes;\r
+ string name = null;\r
+ string type = null;\r
+ string id = null;\r
+ switch (child.Name) {\r
+ case "add":\r
+ name = GetAttribute (attributes, "name", true, child);\r
+ type = GetAttribute (attributes, "type", true, child);\r
+ id = GetAttribute (attributes, "initializeData", false, child);\r
+ AddTraceListener (name, type, id);\r
+ break;\r
+ case "remove":\r
+ name = GetAttribute (attributes, "name", true, child);\r
+ RemoveTraceListener (name);\r
+ break;\r
+ case "clear":\r
+ TraceImpl.Listeners.Clear ();\r
+ break;\r
+ default:\r
+ ThrowUnrecognizedElement (child);\r
+ break;\r
+ }\r
+ ValidateInvalidAttributes (attributes, child);\r
+ }\r
+ else\r
+ ThrowUnrecognizedNode (child);\r
+ }\r
+ }\r
+\r
+ private void AddTraceListener (string name, string type, string initializeData)\r
+ {\r
+ Type t = Type.GetType (type);\r
+ object[] args = null;\r
+ if (initializeData == string.Empty)\r
+ args = new object[]{name};\r
+ else\r
+ args = new object[]{initializeData, name};\r
+ TraceListener l = (TraceListener) Activator.CreateInstance (t, args);\r
+ TraceImpl.Listeners.Add (l);\r
+ }\r
+\r
+ private void RemoveTraceListener (string name)\r
+ {\r
+ try {\r
+ TraceImpl.Listeners.Remove (name);\r
+ }\r
+ catch (ArgumentException e) {\r
+ // The specified listener wasn't in the collection\r
+ // Ignore this; .NET does.\r
+ }\r
+ }\r
+\r
+ private string GetAttribute (XmlAttributeCollection attrs, string attr, bool required, XmlNode node)\r
+ {\r
+ XmlAttribute a = attrs[attr];\r
+\r
+ string r = string.Empty;\r
+\r
+ if (a != null) {\r
+ r = a.Value;\r
+ if (required)\r
+ ValidateAttribute (attr, r, node);\r
+ attrs.Remove (a);\r
+ }\r
+ else if (required)\r
+ ThrowMissingAttribute (attr, node);\r
+\r
+ return r;\r
+ }\r
+\r
+ private void ValidateAttribute (string attribute, string value, XmlNode node)\r
+ {\r
+ // Don't need to check for null; handled in GetAttribute\r
+ if (value.Length == 0)\r
+ throw new ConfigurationException (string.Format ("Required attribute `{0}' cannot be empty.", attribute), node);\r
+ }\r
+\r
+ private void ValidateInvalidAttributes (XmlAttributeCollection c, XmlNode node)\r
+ {\r
+ if (c.Count != 0)\r
+ ThrowUnrecognizedAttribute (c[0].Name, node);\r
+ }\r
+\r
+ private void ThrowMissingAttribute (string attribute, XmlNode node)\r
+ {\r
+ throw new ConfigurationException (string.Format ("Missing required attribute `{0}'.", attribute), node);\r
+ }\r
+\r
+ private void ThrowUnrecognizedNode (XmlNode node)\r
+ {\r
+ throw new ConfigurationException (\r
+ string.Format ("Unrecognized node `{0}'; nodeType={1}", node.Name, node.NodeType),\r
+ node);\r
+ }\r
+\r
+ private void ThrowUnrecognizedElement (XmlNode node)\r
+ {\r
+ throw new ConfigurationException (\r
+ string.Format ("Unrecognized element <{0}/>", node.Name),\r
+ node);\r
+ }\r
+\r
+ private void ThrowUnrecognizedAttribute (string attribute, XmlNode node)\r
{\r
- \r
+ throw new ConfigurationException (\r
+ string.Format ("Unrecognized attribute `{0}' on element <{1}/>.", attribute, node.Name),\r
+ node);\r
}\r
}\r
}\r