2 // System.Diagnostics.DiagnosticsConfigurationHandler.cs
4 // Comments from John R. Hicks <angryjohn69@nc.rr.com> original implementation
5 // can be found at: /mcs/docs/apidocs/xml/en/System.Diagnostics
8 // John R. Hicks <angryjohn69@nc.rr.com>
9 // Jonathan Pryor <jonpryor@vt.edu>
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:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
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.
35 using System
.Collections
;
36 using System
.Configuration
;
40 namespace System
.Diagnostics
42 internal sealed class DiagnosticsConfiguration
44 private static IDictionary settings
= null;
46 public static IDictionary Settings
{
48 // TODO: Does anybody know if this is actually thread-safe under .NET?
49 // I've heard that this construct isn't safe under Java, but it's used
50 // reasonably often under C++, so I'm not sure about .NET.
51 if (settings
== null) {
52 lock (typeof(DiagnosticsConfiguration
)) {
54 settings
= (IDictionary
) ConfigurationSettings
.GetConfig ("system.diagnostics");
62 public class DiagnosticsConfigurationHandler
: IConfigurationSectionHandler
64 delegate void ElementHandler (IDictionary d
, XmlNode node
);
66 IDictionary elementHandlers
= new Hashtable ();
68 public DiagnosticsConfigurationHandler ()
70 elementHandlers
["assert"] = new ElementHandler (AddAssertNode
);
71 elementHandlers
["switches"] = new ElementHandler (AddSwitchesNode
);
72 elementHandlers
["trace"] = new ElementHandler (AddTraceNode
);
75 public virtual object Create (object parent
, object configContext
, XmlNode section
)
79 d
= new Hashtable (CaseInsensitiveHashCodeProvider
.Default
, CaseInsensitiveComparer
.Default
);
81 d
= (IDictionary
) ((ICloneable
)parent
).Clone();
83 foreach (XmlNode child
in section
.ChildNodes
) {
84 XmlNodeType type
= child
.NodeType
;
88 case XmlNodeType
.Whitespace
:
89 case XmlNodeType
.Comment
:
91 case XmlNodeType
.Element
:
92 ElementHandler eh
= (ElementHandler
) elementHandlers
[child
.Name
];
96 ThrowUnrecognizedElement (child
);
99 ThrowUnrecognizedElement (child
);
107 // Remarks: Both attribute are optional
108 private void AddAssertNode (IDictionary d
, XmlNode node
)
110 XmlAttributeCollection c
= node
.Attributes
;
111 string assertuienabled
= GetAttribute (c
, "assertuienabled", false, node
);
112 string logfilename
= GetAttribute (c
, "logfilename", false, node
);
113 ValidateInvalidAttributes (c
, node
);
114 if (assertuienabled
!= null) {
116 d
["assertuienabled"] = bool.Parse (assertuienabled
);
118 catch (Exception e
) {
119 throw new ConfigurationException ("The `assertuienabled' attribute must be `true' or `false'",
124 if (logfilename
!= null)
125 d
["logfilename"] = logfilename
;
127 DefaultTraceListener dtl
= (DefaultTraceListener
) TraceImpl
.Listeners
["Default"];
129 if (assertuienabled
!= null)
130 dtl
.AssertUiEnabled
= (bool) d
["assertuienabled"];
131 if (logfilename
!= null)
132 dtl
.LogFileName
= logfilename
;
135 if (node
.ChildNodes
.Count
> 0)
136 ThrowUnrecognizedElement (node
.ChildNodes
[0]);
139 // name attribute is required, value is optional
140 // Docs do not define "remove" or "clear" elements, but .NET recognizes
142 private void AddSwitchesNode (IDictionary d
, XmlNode node
)
144 // There are no attributes on <switch/>
145 ValidateInvalidAttributes (node
.Attributes
, node
);
147 IDictionary newNodes
= new Hashtable ();
149 foreach (XmlNode child
in node
.ChildNodes
) {
150 XmlNodeType t
= child
.NodeType
;
151 if (t
== XmlNodeType
.Whitespace
|| t
== XmlNodeType
.Comment
)
153 if (t
== XmlNodeType
.Element
) {
154 XmlAttributeCollection attributes
= child
.Attributes
;
157 switch (child
.Name
) {
159 name
= GetAttribute (attributes
, "name", true, child
);
160 value = GetAttribute (attributes
, "value", false, child
);
161 newNodes
[name
] = AsString (value);
164 name
= GetAttribute (attributes
, "name", true, child
);
165 newNodes
.Remove (name
);
171 ThrowUnrecognizedElement (child
);
174 ValidateInvalidAttributes (attributes
, child
);
177 ThrowUnrecognizedNode (child
);
180 d
[node
.Name
] = newNodes
;
183 private void AddTraceNode (IDictionary d
, XmlNode node
)
185 AddTraceAttributes (d
, node
);
187 foreach (XmlNode child
in node
.ChildNodes
) {
188 XmlNodeType t
= child
.NodeType
;
189 if (t
== XmlNodeType
.Whitespace
|| t
== XmlNodeType
.Comment
)
191 if (t
== XmlNodeType
.Element
) {
192 if (child
.Name
== "listeners")
193 AddTraceListeners (child
);
195 ThrowUnrecognizedElement (child
);
196 ValidateInvalidAttributes (child
.Attributes
, child
);
199 ThrowUnrecognizedNode (child
);
203 // all attributes are optional
204 private void AddTraceAttributes (IDictionary d
, XmlNode node
)
206 XmlAttributeCollection c
= node
.Attributes
;
207 string autoflush
= GetAttribute (c
, "autoflush", false, node
);
208 string indentsize
= GetAttribute (c
, "indentsize", false, node
);
209 ValidateInvalidAttributes (c
, node
);
210 if (autoflush
!= null) {
212 bool b
= bool.Parse (autoflush
);
214 TraceImpl
.AutoFlush
= b
;
216 catch (Exception e
) {
217 throw new ConfigurationException ("The `autoflush' attribute must be `true' or `false'",
221 if (indentsize
!= null) {
223 int n
= int.Parse (indentsize
);
224 d
["indentsize"] = n
;
225 TraceImpl
.IndentSize
= n
;
227 catch (Exception e
) {
228 throw new ConfigurationException ("The `indentsize' attribute must be an integral value.",
234 // only defines "add" and "remove", but "clear" also works
235 // for add, "name" and "type" are required; initializeData is optional
236 private void AddTraceListeners (XmlNode listenersNode
)
238 // There are no attributes on <listeners/>
239 ValidateInvalidAttributes (listenersNode
.Attributes
, listenersNode
);
241 foreach (XmlNode child
in listenersNode
.ChildNodes
) {
242 XmlNodeType t
= child
.NodeType
;
243 if (t
== XmlNodeType
.Whitespace
|| t
== XmlNodeType
.Comment
)
245 if (t
== XmlNodeType
.Element
) {
246 XmlAttributeCollection attributes
= child
.Attributes
;
250 switch (child
.Name
) {
252 name
= GetAttribute (attributes
, "name", true, child
);
253 type
= GetAttribute (attributes
, "type", true, child
);
254 id
= GetAttribute (attributes
, "initializeData", false, child
);
255 AddTraceListener (name
, type
, id
);
258 name
= GetAttribute (attributes
, "name", true, child
);
259 RemoveTraceListener (name
);
262 TraceImpl
.Listeners
.Clear ();
265 ThrowUnrecognizedElement (child
);
268 ValidateInvalidAttributes (attributes
, child
);
271 ThrowUnrecognizedNode (child
);
275 private void AddTraceListener (string name
, string type
, string initializeData
)
277 Type t
= Type
.GetType (type
);
279 throw new ConfigurationException (string.Format ("Invalid Type Specified: {0}", type
));
284 if (initializeData
!= null) {
285 args
= new object[] { initializeData }
;
286 types
= new Type
[] { typeof(string) }
;
293 System
.Reflection
.ConstructorInfo ctor
= t
.GetConstructor (types
);
295 throw new ConfigurationException ("Couldn't find constructor for class " + type
);
297 TraceListener l
= (TraceListener
) ctor
.Invoke (args
);
299 TraceImpl
.Listeners
.Add (l
);
302 private void RemoveTraceListener (string name
)
305 TraceImpl
.Listeners
.Remove (name
);
307 catch (ArgumentException
) {
308 // The specified listener wasn't in the collection
309 // Ignore this; .NET does.
311 catch (Exception e
) {
312 throw new ConfigurationException (
313 string.Format ("Unknown error removing listener: {0}", name
),
318 private string GetAttribute (XmlAttributeCollection attrs
, string attr
, bool required
, XmlNode node
)
320 XmlAttribute a
= attrs
[attr
];
327 ValidateAttribute (attr
, r
, node
);
331 ThrowMissingAttribute (attr
, node
);
336 private string AsString (string s
)
338 return s
== null ? string.Empty
: s
;
341 private void ValidateAttribute (string attribute
, string value, XmlNode node
)
343 if (value == null || value.Length
== 0)
344 throw new ConfigurationException (string.Format ("Required attribute `{0}' cannot be empty.", attribute
), node
);
347 private void ValidateInvalidAttributes (XmlAttributeCollection c
, XmlNode node
)
350 ThrowUnrecognizedAttribute (c
[0].Name
, node
);
353 private void ThrowMissingAttribute (string attribute
, XmlNode node
)
355 throw new ConfigurationException (string.Format ("Missing required attribute `{0}'.", attribute
), node
);
358 private void ThrowUnrecognizedNode (XmlNode node
)
360 throw new ConfigurationException (
361 string.Format ("Unrecognized node `{0}'; nodeType={1}", node
.Name
, node
.NodeType
),
365 private void ThrowUnrecognizedElement (XmlNode node
)
367 throw new ConfigurationException (
368 string.Format ("Unrecognized element <{0}/>", node
.Name
),
372 private void ThrowUnrecognizedAttribute (string attribute
, XmlNode node
)
374 throw new ConfigurationException (
375 string.Format ("Unrecognized attribute `{0}' on element <{1}/>.", attribute
, node
.Name
),