Mark tests as not working under TARGET_JVM
[mono.git] / mcs / class / System / System.Diagnostics / DiagnosticsConfigurationHandler.cs
1 //
2 // System.Diagnostics.DiagnosticsConfigurationHandler.cs
3 //
4 // Comments from John R. Hicks <angryjohn69@nc.rr.com> original implementation 
5 // can be found at: /mcs/docs/apidocs/xml/en/System.Diagnostics
6 //
7 // Authors: 
8 //      John R. Hicks <angryjohn69@nc.rr.com>
9 //      Jonathan Pryor <jonpryor@vt.edu>
10 //
11 // (C) 2002, 2005
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34 using System;
35 using System.Collections;
36 using System.Collections.Specialized;
37 using System.Configuration;
38 using System.Threading;
39 #if (XML_DEP)
40 using System.Xml;
41 #endif
42 namespace System.Diagnostics
43 {
44         internal sealed class DiagnosticsConfiguration
45         {
46 #if NO_LOCK_FREE
47                 private static object lock_ = new object();
48 #endif
49                 private static object settings;
50
51                 public static IDictionary Settings {
52                         get {
53 #if !NO_LOCK_FREE
54                                 if (settings == null) {
55                                         object s = ConfigurationSettings.GetConfig ("system.diagnostics");
56                                         if (s == null)
57                                                 throw new Exception ("INTERNAL configuration error: failed to get configuration 'system.diagnostics'");
58                                         Thread.MemoryBarrier ();
59                                         while (Interlocked.CompareExchange (ref settings, s, null) == null) {
60                                                 // do nothing; we're just setting settings.
61                                         }
62                                         Thread.MemoryBarrier ();
63                                 }
64 #else
65                                 lock (lock_) {
66                                         if (settings == null)
67                                                 settings = ConfigurationSettings.GetConfig ("system.diagnostics");
68                                 }
69 #endif
70                                 return (IDictionary) settings;
71                         }
72                 }
73         }
74 #if (XML_DEP)
75         public class DiagnosticsConfigurationHandler : IConfigurationSectionHandler
76         {
77                 delegate void ElementHandler (IDictionary d, XmlNode node);
78
79                 IDictionary elementHandlers = new Hashtable ();
80
81                 public DiagnosticsConfigurationHandler ()
82                 {
83                         elementHandlers ["assert"] = new ElementHandler (AddAssertNode);
84                         elementHandlers ["switches"] = new ElementHandler (AddSwitchesNode);
85                         elementHandlers ["trace"] = new ElementHandler (AddTraceNode);
86 #if NET_2_0
87                         elementHandlers ["sources"] = new ElementHandler (AddSourcesNode);
88                         elementHandlers ["sharedListeners"] = new ElementHandler (AddSharedListenersNode);
89 #endif
90                 }
91
92                 public virtual object Create (object parent, object configContext, XmlNode section)
93                 {
94                         IDictionary d;
95                         if (parent == null)
96                                 d = new Hashtable (CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
97                         else
98                                 d = (IDictionary) ((ICloneable)parent).Clone();
99
100                         foreach (XmlNode child in section.ChildNodes) {
101                                 XmlNodeType type = child.NodeType;
102
103                                 switch (type) {
104                                 /* ignore */
105                                 case XmlNodeType.Whitespace:
106                                 case XmlNodeType.Comment:
107                                         continue;
108                                 case XmlNodeType.Element:
109                                         ElementHandler eh = (ElementHandler) elementHandlers [child.Name];
110                                         if (eh != null)
111                                                 eh (d, child);
112                                         else
113                                                 ThrowUnrecognizedElement (child);
114                                         break;
115                                 default:
116                                         ThrowUnrecognizedElement (child);
117                                         break;
118                                 }
119                         }
120
121                         return d;
122                 }
123
124                 // Remarks: Both attribute are optional
125                 private void AddAssertNode (IDictionary d, XmlNode node)
126                 {
127                         XmlAttributeCollection c = node.Attributes;
128                         string assertuienabled = GetAttribute (c, "assertuienabled", false, node);
129                         string logfilename = GetAttribute (c, "logfilename", false, node);
130                         ValidateInvalidAttributes (c, node);
131                         if (assertuienabled != null) {
132                                 try {
133                                         d ["assertuienabled"] = bool.Parse (assertuienabled);
134                                 }
135                                 catch (Exception e) {
136                                         throw new ConfigurationException ("The `assertuienabled' attribute must be `true' or `false'",
137                                                         e, node);
138                                 }
139                         }
140
141                         if (logfilename != null)
142                                 d ["logfilename"] = logfilename;
143
144                         DefaultTraceListener dtl = (DefaultTraceListener) TraceImpl.Listeners["Default"];
145                         if (dtl != null) {
146                                 if (assertuienabled != null)
147                                         dtl.AssertUiEnabled = (bool) d ["assertuienabled"];
148                                 if (logfilename != null)
149                                         dtl.LogFileName = logfilename;
150                         }
151
152                         if (node.ChildNodes.Count > 0)
153                                 ThrowUnrecognizedElement (node.ChildNodes[0]);
154                 }
155
156                 // name and value attributes are required
157                 // Docs do not define "remove" or "clear" elements, but .NET recognizes
158                 // them
159                 private void AddSwitchesNode (IDictionary d, XmlNode node)
160                 {
161 #if !TARGET_JVM
162                         // There are no attributes on <switch/>
163                         ValidateInvalidAttributes (node.Attributes, node);
164
165                         IDictionary newNodes = new Hashtable ();
166
167                         foreach (XmlNode child in node.ChildNodes) {
168                                 XmlNodeType t = child.NodeType;
169                                 if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)
170                                         continue;
171                                 if (t == XmlNodeType.Element) {
172                                         XmlAttributeCollection attributes = child.Attributes;
173                                         string name = null;
174                                         string value = null;
175                                         switch (child.Name) {
176                                                 case "add":
177                                                         name = GetAttribute (attributes, "name", true, child);
178                                                         value = GetAttribute (attributes, "value", true, child);
179                                                         value = AsString (value); ValidateIntegralValue (name, value);
180                                                         newNodes [name] = value;
181                                                         break;
182                                                 case "remove":
183                                                         name = GetAttribute (attributes, "name", true, child);
184                                                         newNodes.Remove (name);
185                                                         break;
186                                                 case "clear":
187                                                         newNodes.Clear ();
188                                                         break;
189                                                 default:
190                                                         ThrowUnrecognizedElement (child);
191                                                         break;
192                                         }
193                                         ValidateInvalidAttributes (attributes, child);
194                                 }
195                                 else
196                                         ThrowUnrecognizedNode (child);
197                         }
198
199                         d [node.Name] = newNodes;
200 #endif
201                 }
202
203                 private static int ValidateIntegralValue (string name, string value)
204                 {
205                         try {
206                                 return int.Parse (value);
207                         } catch {
208                                 throw new ConfigurationException (string.Format (
209                                                         "Error in '{0}': " + 
210                                                         "The value of a switch must be integral", name));
211                         }
212                 }
213
214                 private void AddTraceNode (IDictionary d, XmlNode node)
215                 {
216                         AddTraceAttributes (d, node);
217
218                         foreach (XmlNode child in node.ChildNodes) {
219                                 XmlNodeType t = child.NodeType;
220                                 if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)
221                                         continue;
222                                 if (t == XmlNodeType.Element) {
223                                         if (child.Name == "listeners")
224                                                 AddTraceListeners (child);
225                                         else
226                                                 ThrowUnrecognizedElement (child);
227                                         ValidateInvalidAttributes (child.Attributes, child);
228                                 }
229                                 else
230                                         ThrowUnrecognizedNode (child);
231                         }
232                 }
233
234                 // all attributes are optional
235                 private void AddTraceAttributes (IDictionary d, XmlNode node)
236                 {
237                         XmlAttributeCollection c = node.Attributes;
238                         string autoflush = GetAttribute (c, "autoflush", false, node);
239                         string indentsize = GetAttribute (c, "indentsize", false, node);
240                         ValidateInvalidAttributes (c, node);
241                         if (autoflush != null) {
242                                 try {
243                                         bool b = bool.Parse (autoflush);
244                                         d ["autoflush"] = b;
245                                         TraceImpl.AutoFlush = b;
246                                 }
247                                 catch (Exception e) {
248                                         throw new ConfigurationException ("The `autoflush' attribute must be `true' or `false'",
249                                                         e, node);
250                                 }
251                         }
252                         if (indentsize != null) {
253                                 try {
254                                         int n = int.Parse (indentsize);
255                                         d ["indentsize"] = n;
256                                         TraceImpl.IndentSize = n;
257                                 }
258                                 catch (ConfigurationException e) {
259                                         throw;
260                                 }
261                                 catch (Exception e) {
262                                         throw new ConfigurationException ("The `indentsize' attribute must be an integral value.",
263                                                         e, node);
264                                 }
265                         }
266                 }
267
268 #if NET_2_0
269                 static readonly Hashtable static_sources = new Hashtable ();
270
271                 [MonoTODO]
272                 private void AddSharedListenersNode (IDictionary d, XmlNode node)
273                 {
274                 }
275
276                 private void AddSourcesNode (IDictionary d, XmlNode node)
277                 {
278                         // FIXME: are there valid attributes?
279                         ValidateInvalidAttributes (node.Attributes, node);
280                         Hashtable sources = d ["sources"] as Hashtable;
281                         if (sources == null) {
282                                 sources = new Hashtable ();
283                                 d ["sources"] = sources;
284                         }
285                         // FIXME: here I replace the table with fake static variable.
286                         sources = static_sources;
287
288                         foreach (XmlNode child in node.ChildNodes) {
289                                 XmlNodeType t = child.NodeType;
290                                 if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)
291                                         continue;
292                                 if (t == XmlNodeType.Element) {
293                                         if (child.Name == "source")
294                                                 AddTraceSource (sources, child);
295                                         else
296                                                 ThrowUnrecognizedElement (child);
297 //                                      ValidateInvalidAttributes (child.Attributes, child);
298                                 }
299                                 else
300                                         ThrowUnrecognizedNode (child);
301                         }
302                 }
303
304                 private void AddTraceSource (Hashtable sources, XmlNode node)
305                 {
306                         string name = null;
307                         SourceLevels levels = SourceLevels.Error;
308                         StringDictionary atts = new StringDictionary ();
309                         foreach (XmlAttribute a in node.Attributes) {
310                                 switch (a.Name) {
311                                 case "name":
312                                         name = a.Value;
313                                         break;
314                                 case "switchValue":
315                                         levels = (SourceLevels) Enum.Parse (typeof (SourceLevels), a.Value);
316                                         break;
317                                 default:
318                                         atts [a.Name] = a.Value;
319                                         break;
320                                 }
321                         }
322                         if (name == null)
323                                 throw new ConfigurationException ("Mandatory attribute 'name' is missing in 'source' element.");
324
325                         // FIXME: it should raise an error for duplicate name sources.
326                         if (sources.ContainsKey (name))
327                                 return;
328
329                         TraceSource source = new TraceSource (name, levels);
330                         sources.Add (source.Name, source);
331                         
332                         foreach (XmlNode child in node.ChildNodes) {
333                                 XmlNodeType t = child.NodeType;
334                                 if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)
335                                         continue;
336                                 if (t == XmlNodeType.Element) {
337                                         if (child.Name == "listeners")
338                                                 AddTraceListeners (child);
339                                         else
340                                                 ThrowUnrecognizedElement (child);
341                                         ValidateInvalidAttributes (child.Attributes, child);
342                                 }
343                                 else
344                                         ThrowUnrecognizedNode (child);
345                         }
346                 }
347 #endif
348
349                 // only defines "add" and "remove", but "clear" also works
350                 // for add, "name" and "type" are required; initializeData is optional
351                 private void AddTraceListeners (XmlNode listenersNode)
352                 {
353 #if !TARGET_JVM
354                         // There are no attributes on <listeners/>
355                         ValidateInvalidAttributes (listenersNode.Attributes, listenersNode);
356
357                         foreach (XmlNode child in listenersNode.ChildNodes) {
358                                 XmlNodeType t = child.NodeType;
359                                 if (t == XmlNodeType.Whitespace || t == XmlNodeType.Comment)
360                                         continue;
361                                 if (t == XmlNodeType.Element) {
362                                         XmlAttributeCollection attributes = child.Attributes;
363                                         string name = null;
364                                         string type = null;
365                                         string id = null;
366                                         switch (child.Name) {
367                                                 case "add":
368                                                         name = GetAttribute (attributes, "name", true, child);
369                                                         type = GetAttribute (attributes, "type", true, child);
370                                                         id = GetAttribute (attributes, "initializeData", false, child);
371                                                         AddTraceListener (name, type, id);
372                                                         break;
373                                                 case "remove":
374                                                         name = GetAttribute (attributes, "name", true, child);
375                                                         RemoveTraceListener (name);
376                                                         break;
377                                                 case "clear":
378                                                         TraceImpl.Listeners.Clear ();
379                                                         break;
380                                                 default:
381                                                         ThrowUnrecognizedElement (child);
382                                                         break;
383                                         }
384                                         ValidateInvalidAttributes (attributes, child);
385                                 }
386                                 else
387                                         ThrowUnrecognizedNode (child);
388                         }
389 #endif
390                 }
391
392                 private void AddTraceListener (string name, string type, string initializeData)
393                 {
394                         Type t = Type.GetType (type);
395                         if (t == null)
396                                 throw new ConfigurationException (string.Format ("Invalid Type Specified: {0}", type));
397
398                         object[] args;
399                         Type[] types;
400                         
401                         if (initializeData != null) {
402                                 args = new object[] { initializeData };
403                                 types = new Type[] { typeof(string) };
404                         }
405                         else {
406                                 args = null;
407                                 types = new Type[0];
408                         }
409                                 
410                         System.Reflection.ConstructorInfo ctor = t.GetConstructor (types);
411                         if (ctor == null) 
412                                 throw new ConfigurationException ("Couldn't find constructor for class " + type);
413                         
414                         TraceListener l = (TraceListener) ctor.Invoke (args);
415                         l.Name = name;
416                         TraceImpl.Listeners.Add (l);
417                 }
418
419                 private void RemoveTraceListener (string name)
420                 {
421                         try {
422                                 TraceImpl.Listeners.Remove (name);
423                         }
424                         catch (ArgumentException) {
425                                 // The specified listener wasn't in the collection
426                                 // Ignore this; .NET does.
427                         }
428                         catch (Exception e) {
429                                 throw new ConfigurationException (
430                                                 string.Format ("Unknown error removing listener: {0}", name),
431                                                 e);
432                         }
433                 }
434
435                 private string GetAttribute (XmlAttributeCollection attrs, string attr, bool required, XmlNode node)
436                 {
437                         XmlAttribute a = attrs[attr];
438
439                         string r = null;
440
441                         if (a != null) {
442                                 r = a.Value;
443                                 if (required)
444                                         ValidateAttribute (attr, r, node);
445                                 attrs.Remove (a);
446                         }
447                         else if (required)
448                                 ThrowMissingAttribute (attr, node);
449
450                         return r;
451                 }
452                 
453                 private string AsString (string s)
454                 {
455                         return s == null ? string.Empty : s;
456                 }
457
458                 private void ValidateAttribute (string attribute, string value, XmlNode node)
459                 {
460                         if (value == null || value.Length == 0)
461                                 throw new ConfigurationException (string.Format ("Required attribute `{0}' cannot be empty.", attribute), node);
462                 }
463
464                 private void ValidateInvalidAttributes (XmlAttributeCollection c, XmlNode node)
465                 {
466                         if (c.Count != 0)
467                                 ThrowUnrecognizedAttribute (c[0].Name, node);
468                 }
469
470                 private void ThrowMissingAttribute (string attribute, XmlNode node)
471                 {
472                         throw new ConfigurationException (string.Format ("Missing required attribute `{0}'.", attribute), node);
473                 }
474
475                 private void ThrowUnrecognizedNode (XmlNode node)
476                 {
477                         throw new ConfigurationException (
478                                         string.Format ("Unrecognized node `{0}'; nodeType={1}", node.Name, node.NodeType),
479                                         node);
480                 }
481
482                 private void ThrowUnrecognizedElement (XmlNode node)
483                 {
484                         throw new ConfigurationException (
485                                         string.Format ("Unrecognized element <{0}/>", node.Name),
486                                         node);
487                 }
488
489                 private void ThrowUnrecognizedAttribute (string attribute, XmlNode node)
490                 {
491                         throw new ConfigurationException (
492                                         string.Format ("Unrecognized attribute `{0}' on element <{1}/>.", attribute, node.Name),
493                                         node);
494                 }
495         }
496 #endif
497 }
498