DiagnosticsConfigurationHandler.cs:
[mono.git] / mcs / class / System / System.Diagnostics / DiagnosticsConfigurationHandler.cs
1 //\r
2 // System.Diagnostics.DiagnosticsConfigurationHandler.cs\r
3 //\r
4 // Comments from John R. Hicks <angryjohn69@nc.rr.com> original implementation \r
5 // can be found at: /mcs/docs/apidocs/xml/en/System.Diagnostics\r
6 //\r
7 // Authors: \r
8 //      John R. Hicks <angryjohn69@nc.rr.com>\r
9 //      Jonathan Pryor <jonpryor@vt.edu>\r
10 //\r
11 // (C) 2002\r
12 //\r
13 using System;\r
14 using System.Collections;\r
15 using System.Configuration;\r
16 using System.Xml;\r
17 \r
18 namespace System.Diagnostics\r
19 {\r
20         internal sealed class DiagnosticsConfiguration\r
21         {\r
22                 private static IDictionary settings = null;\r
23 \r
24                 public static IDictionary Settings {\r
25                         get {\r
26                                 // TODO: Does anybody know if this is actually thread-safe under .NET?\r
27                                 // I've heard that this construct isn't safe under Java, but it's used\r
28                                 // reasonably often under C++, so I'm not sure about .NET.\r
29                                 if (settings == null) {\r
30                                         lock (typeof(DiagnosticsConfiguration)) {\r
31                                                 if (settings == null)\r
32                                                         settings = (IDictionary) ConfigurationSettings.GetConfig ("system.diagnostics");\r
33                                         }\r
34                                 }\r
35                                 return settings;\r
36                         }\r
37                 }\r
38         }\r
39 \r
40         public class DiagnosticsConfigurationHandler : IConfigurationSectionHandler\r
41         {\r
42                 delegate void ElementHandler (IDictionary d, XmlNode node);\r
43 \r
44                 IDictionary elementHandlers = new Hashtable ();\r
45 \r
46                 public DiagnosticsConfigurationHandler ()\r
47                 {\r
48                         elementHandlers ["assert"] = new ElementHandler (AddAssertNode);\r
49                         elementHandlers ["switches"] = new ElementHandler (AddSwitchesNode);\r
50                         elementHandlers ["trace"] = new ElementHandler (AddTraceNode);\r
51                 }\r
52 \r
53                 public virtual object Create (object parent, object configContext, XmlNode section)\r
54                 {\r
55                         IDictionary d;\r
56                         if (parent == null)\r
57                                 d = new Hashtable (CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);\r
58                         else\r
59                                 d = (IDictionary) ((ICloneable)parent).Clone();\r
60 \r
61                         foreach (XmlNode child in section.ChildNodes) {\r
62                                 XmlNodeType type = child.NodeType;\r
63 \r
64                                 switch (type) {\r
65                                 /* ignore */\r
66                                 case XmlNodeType.Whitespace:\r
67                                 case XmlNodeType.Comment:\r
68                                         continue;\r
69                                 case XmlNodeType.Element:\r
70                                         ElementHandler eh = (ElementHandler) elementHandlers [child.Name];\r
71                                         if (eh != null)\r
72                                                 eh (d, child);\r
73                                         else\r
74                                                 ThrowUnrecognizedElement (child);\r
75                                         break;\r
76                                 default:\r
77                                         ThrowUnrecognizedElement (child);\r
78                                         break;\r
79                                 }\r
80                         }\r
81 \r
82                         return d;\r
83                 }\r
84 \r
85                 // Remarks: Both attribute are optional\r
86                 private void AddAssertNode (IDictionary d, XmlNode node)\r
87                 {\r
88                         XmlAttributeCollection c = node.Attributes;\r
89                         string assertuienabled = GetAttribute (c, "assertuienabled", false, node);\r
90                         string logfilename = GetAttribute (c, "logfilename", false, node);\r
91                         ValidateInvalidAttributes (c, node);\r
92                         if (assertuienabled != null) {\r
93                                 try {\r
94                                         d ["assertuienabled"] = bool.Parse (assertuienabled);\r
95                                 }\r
96                                 catch (Exception e) {\r
97                                         throw new ConfigurationException ("The `assertuienabled' attribute must be `true' or `false'",\r
98                                                         e, node);\r
99                                 }\r
100                         }\r
101 \r
102                         if (logfilename != null)\r
103                                 d ["logfilename"] = logfilename;\r
104 \r
105                         DefaultTraceListener dtl = (DefaultTraceListener) TraceImpl.Listeners["Default"];\r
106                         if (dtl != null) {\r
107                                 if (assertuienabled != null)\r
108                                         dtl.AssertUiEnabled = (bool) d ["assertuienabled"];\r
109                                 if (logfilename != null)\r
110                                         dtl.LogFileName = logfilename;\r
111                         }\r
112 \r
113                         if (node.ChildNodes.Count > 0)\r
114                                 ThrowUnrecognizedElement (node.ChildNodes[0]);\r
115                 }\r
116 \r
117                 // name attribute is required, value is optional\r
118                 // Docs do not define "remove" or "clear" elements, but .NET recognizes\r
119                 // them\r
120                 private void AddSwitchesNode (IDictionary d, XmlNode node)\r
121                 {\r
122                         // There are no attributes on <switch/>\r
123                         ValidateInvalidAttributes (node.Attributes, node);\r
124 \r
125                         IDictionary newNodes = new Hashtable ();\r
126 \r
127                         foreach (XmlNode child in node.ChildNodes) {\r
128                                 XmlNodeType t = child.NodeType;\r
129                                 if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)\r
130                                         continue;\r
131                                 if (t == XmlNodeType.Element) {\r
132                                         XmlAttributeCollection attributes = child.Attributes;\r
133                                         string name = null;\r
134                                         string value = null;\r
135                                         switch (child.Name) {\r
136                                                 case "add":\r
137                                                         name = GetAttribute (attributes, "name", true, child);\r
138                                                         value = GetAttribute (attributes, "value", false, child);\r
139                                                         newNodes[name] = AsString (value);\r
140                                                         break;\r
141                                                 case "remove":\r
142                                                         name = GetAttribute (attributes, "name", true, child);\r
143                                                         newNodes.Remove (name);\r
144                                                         break;\r
145                                                 case "clear":\r
146                                                         newNodes.Clear ();\r
147                                                         break;\r
148                                                 default:\r
149                                                         ThrowUnrecognizedElement (child);\r
150                                                         break;\r
151                                         }\r
152                                         ValidateInvalidAttributes (attributes, child);\r
153                                 }\r
154                                 else\r
155                                         ThrowUnrecognizedNode (child);\r
156                         }\r
157 \r
158                         d [node.Name] = newNodes;\r
159                 }\r
160 \r
161                 private void AddTraceNode (IDictionary d, XmlNode node)\r
162                 {\r
163                         AddTraceAttributes (d, node);\r
164 \r
165                         foreach (XmlNode child in node.ChildNodes) {\r
166                                 XmlNodeType t = child.NodeType;\r
167                                 if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)\r
168                                         continue;\r
169                                 if (t == XmlNodeType.Element) {\r
170                                         if (child.Name == "listeners")\r
171                                                 AddTraceListeners (child);\r
172                                         else\r
173                                                 ThrowUnrecognizedElement (child);\r
174                                         ValidateInvalidAttributes (child.Attributes, child);\r
175                                 }\r
176                                 else\r
177                                         ThrowUnrecognizedNode (child);\r
178                         }\r
179                 }\r
180 \r
181                 // all attributes are optional\r
182                 private void AddTraceAttributes (IDictionary d, XmlNode node)\r
183                 {\r
184                         XmlAttributeCollection c = node.Attributes;\r
185                         string autoflush = GetAttribute (c, "autoflush", false, node);\r
186                         string indentsize = GetAttribute (c, "indentsize", false, node);\r
187                         ValidateInvalidAttributes (c, node);\r
188                         if (autoflush != null) {\r
189                                 try {\r
190                                         bool b = bool.Parse (autoflush);\r
191                                         d ["autoflush"] = b;\r
192                                         TraceImpl.AutoFlush = b;\r
193                                 }\r
194                                 catch (Exception e) {\r
195                                         throw new ConfigurationException ("The `autoflush' attribute must be `true' or `false'",\r
196                                                         e, node);\r
197                                 }\r
198                         }\r
199                         if (indentsize != null) {\r
200                                 try {\r
201                                         int n = int.Parse (indentsize);\r
202                                         d ["indentsize"] = n;\r
203                                         TraceImpl.IndentSize = n;\r
204                                 }\r
205                                 catch (Exception e) {\r
206                                         throw new ConfigurationException ("The `indentsize' attribute must be an integral value.",\r
207                                                         e, node);\r
208                                 }\r
209                         }\r
210                 }\r
211 \r
212                 // only defines "add" and "remove", but "clear" also works\r
213                 // for add, "name" and "type" are required; initializeData is optional\r
214                 private void AddTraceListeners (XmlNode listenersNode)\r
215                 {\r
216                         // There are no attributes on <listeners/>\r
217                         ValidateInvalidAttributes (listenersNode.Attributes, listenersNode);\r
218 \r
219                         foreach (XmlNode child in listenersNode.ChildNodes) {\r
220                                 XmlNodeType t = child.NodeType;\r
221                                 if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)\r
222                                         continue;\r
223                                 if (t == XmlNodeType.Element) {\r
224                                         XmlAttributeCollection attributes = child.Attributes;\r
225                                         string name = null;\r
226                                         string type = null;\r
227                                         string id = null;\r
228                                         switch (child.Name) {\r
229                                                 case "add":\r
230                                                         name = GetAttribute (attributes, "name", true, child);\r
231                                                         type = GetAttribute (attributes, "type", true, child);\r
232                                                         id = GetAttribute (attributes, "initializeData", false, child);\r
233                                                         AddTraceListener (name, type, id);\r
234                                                         break;\r
235                                                 case "remove":\r
236                                                         name = GetAttribute (attributes, "name", true, child);\r
237                                                         RemoveTraceListener (name);\r
238                                                         break;\r
239                                                 case "clear":\r
240                                                         TraceImpl.Listeners.Clear ();\r
241                                                         break;\r
242                                                 default:\r
243                                                         ThrowUnrecognizedElement (child);\r
244                                                         break;\r
245                                         }\r
246                                         ValidateInvalidAttributes (attributes, child);\r
247                                 }\r
248                                 else\r
249                                         ThrowUnrecognizedNode (child);\r
250                         }\r
251                 }\r
252 \r
253                 private void AddTraceListener (string name, string type, string initializeData)\r
254                 {\r
255                         Type t = Type.GetType (type);\r
256                         object[] args = null;\r
257                         if (initializeData == null)\r
258                                 args = new object[]{name};\r
259                         else\r
260                                 args = new object[]{initializeData, name};\r
261                         try {\r
262                                 TraceListener l = (TraceListener) Activator.CreateInstance (t, args);\r
263                                 TraceImpl.Listeners.Add (l);\r
264                         }\r
265                         catch (Exception e) {\r
266                                 throw new ConfigurationException (\r
267                                                 string.Format ("Invalid Type Specified: {0}", type),\r
268                                                 e);\r
269                         }\r
270                 }\r
271 \r
272                 private void RemoveTraceListener (string name)\r
273                 {\r
274                         try {\r
275                                 TraceImpl.Listeners.Remove (name);\r
276                         }\r
277                         catch (ArgumentException e) {\r
278                                 // The specified listener wasn't in the collection\r
279                                 // Ignore this; .NET does.\r
280                         }\r
281                         catch (Exception e) {\r
282                                 throw new ConfigurationException (\r
283                                                 string.Format ("Unknown error removing listener: {0}", name),\r
284                                                 e);\r
285                         }\r
286                 }\r
287 \r
288                 private string GetAttribute (XmlAttributeCollection attrs, string attr, bool required, XmlNode node)\r
289                 {\r
290                         XmlAttribute a = attrs[attr];\r
291 \r
292                         string r = null;\r
293 \r
294                         if (a != null) {\r
295                                 r = a.Value;\r
296                                 if (required)\r
297                                         ValidateAttribute (attr, r, node);\r
298                                 attrs.Remove (a);\r
299                         }\r
300                         else if (required)\r
301                                 ThrowMissingAttribute (attr, node);\r
302 \r
303                         return r;\r
304                 }\r
305                 \r
306                 private string AsString (string s)\r
307                 {\r
308                         return s == null ? string.Empty : s;\r
309                 }\r
310 \r
311                 private void ValidateAttribute (string attribute, string value, XmlNode node)\r
312                 {\r
313                         if (value == null || value.Length == 0)\r
314                                 throw new ConfigurationException (string.Format ("Required attribute `{0}' cannot be empty.", attribute), node);\r
315                 }\r
316 \r
317                 private void ValidateInvalidAttributes (XmlAttributeCollection c, XmlNode node)\r
318                 {\r
319                         if (c.Count != 0)\r
320                                 ThrowUnrecognizedAttribute (c[0].Name, node);\r
321                 }\r
322 \r
323                 private void ThrowMissingAttribute (string attribute, XmlNode node)\r
324                 {\r
325                         throw new ConfigurationException (string.Format ("Missing required attribute `{0}'.", attribute), node);\r
326                 }\r
327 \r
328                 private void ThrowUnrecognizedNode (XmlNode node)\r
329                 {\r
330                         throw new ConfigurationException (\r
331                                         string.Format ("Unrecognized node `{0}'; nodeType={1}", node.Name, node.NodeType),\r
332                                         node);\r
333                 }\r
334 \r
335                 private void ThrowUnrecognizedElement (XmlNode node)\r
336                 {\r
337                         throw new ConfigurationException (\r
338                                         string.Format ("Unrecognized element <{0}/>", node.Name),\r
339                                         node);\r
340                 }\r
341 \r
342                 private void ThrowUnrecognizedAttribute (string attribute, XmlNode node)\r
343                 {\r
344                         throw new ConfigurationException (\r
345                                         string.Format ("Unrecognized attribute `{0}' on element <{1}/>.", attribute, node.Name),\r
346                                         node);\r
347                 }\r
348         }\r
349 }\r
350 \r