2004-04-22 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Configuration / WebServicesConfigurationSectionHandler.cs
1 //
2 // System.Web.Services.Configuration.WebServicesConfigurationSectionHandler
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2003 Ximian, Inc (http://www.ximian.com)
8 //
9
10 using System;
11 using System.Collections;
12 using System.Configuration;
13 using System.Xml;
14
15 namespace System.Web.Services.Configuration
16 {
17         [Flags]
18         enum WSProtocol
19         {
20                 HttpSoap = 1,
21                 HttpPost = 1 << 1,
22                 HttpGet =  1 << 2,
23                 Documentation = 1 << 3,
24                 All = 0x0F
25         }
26         
27         class WSConfig
28         {
29                 static WSConfig instance;
30                 WSProtocol protocols;
31                 string wsdlHelpPage;
32                 string filePath;
33                 ArrayList extensionTypes = new ArrayList();
34                 ArrayList extensionImporterTypes = new ArrayList();
35                 ArrayList extensionReflectorTypes = new ArrayList();
36                 ArrayList formatExtensionTypes = new ArrayList();
37                 
38                 public WSConfig (WSConfig parent, object context)
39                 {
40                         if (parent == null)
41                                 return;
42                         
43                         protocols = parent.protocols;
44                         wsdlHelpPage = parent.wsdlHelpPage;
45                         if (wsdlHelpPage != null)
46                                 filePath = parent.filePath;
47                         else
48                                 filePath = context as string;
49                 }
50                 
51                 static WSProtocol ParseProtocol (string protoName, out string error)
52                 {
53                         WSProtocol proto;
54                         error = null;
55                         try {
56                                 proto = (WSProtocol) Enum.Parse (typeof (WSProtocol), protoName);
57                         } catch {
58                                 error = "Invalid protocol name";
59                                 return 0;
60                         }
61
62                         return proto;
63                 }
64
65                 // Methods to modify configuration values
66                 public bool AddProtocol (string protoName, out string error)
67                 {
68                         if (protoName == "All") {
69                                 error = "Invalid protocol name";
70                                 return false;
71                         }
72
73                         WSProtocol proto = ParseProtocol (protoName, out error);
74                         if (error != null)
75                                 return false;
76
77                         protocols |= proto;
78                         return true;
79                 }
80
81                 public bool RemoveProtocol (string protoName, out string error)
82                 {
83                         if (protoName == "All") {
84                                 error = "Invalid protocol name";
85                                 return false;
86                         }
87
88                         WSProtocol proto = ParseProtocol (protoName, out error);
89                         if (error != null)
90                                 return false;
91
92                         protocols &= ~proto;
93                         return true;
94                 }
95
96                 public void ClearProtocol ()
97                 {
98                         protocols = 0;
99                 }
100
101                 // Methods to query/get configuration
102                 public static bool IsSupported (WSProtocol proto)
103                 {
104                         return ((Instance.protocols & proto) == proto && (proto != 0) && (proto != WSProtocol.All));
105                 }
106
107                 // Properties
108                 public string WsdlHelpPage {
109                         get { return wsdlHelpPage; }
110                         set { wsdlHelpPage = value; }
111                 }
112
113                 public string ConfigFilePath {
114                         get { return filePath; }
115                         set { filePath = value; }
116                 }
117
118                 static public WSConfig Instance {
119                         get {
120                                 //TODO: use HttpContext to get the configuration
121                                 if (instance != null)
122                                         return instance;
123
124                                 lock (typeof (WSConfig)) {
125                                         if (instance != null)
126                                                 return instance;
127
128                                         instance = (WSConfig) ConfigurationSettings.GetConfig ("system.web/webServices");
129                                 }
130
131                                 return instance;
132                         }
133                 }
134
135                 public ArrayList ExtensionTypes {
136                         get { return extensionTypes; }
137                 }
138
139                 public ArrayList ExtensionImporterTypes {
140                         get { return extensionImporterTypes; }
141                 }
142                 
143                 public ArrayList ExtensionReflectorTypes {
144                         get { return extensionReflectorTypes; }
145                 }
146                 
147                 public ArrayList FormatExtensionTypes {
148                         get { return formatExtensionTypes; }
149                 }
150                 
151         }
152         
153         enum WSExtensionGroup
154         {
155                 High,
156                 Low
157         }
158         
159         class WSExtensionConfig
160         {
161                 Type type;
162                 int priority;
163                 WSExtensionGroup group;
164
165                 public Exception SetType (string typeName)
166                 {
167                         Exception exc = null;
168                         
169                         try {
170                                 type = Type.GetType (typeName, true);
171                         } catch (Exception e) {
172                                 exc = e;
173                         }
174
175                         return exc;
176                 }
177                 
178                 public Exception SetPriority (string prio)
179                 {
180                         if (prio == null || prio == "")
181                                 return null;
182
183                         Exception exc = null;
184                         try {
185                                 priority = Int32.Parse (prio);
186                         } catch (Exception e) {
187                                 exc = e;
188                         }
189
190                         return exc;
191                 }
192                 
193                 public Exception SetGroup (string grp)
194                 {
195                         if (grp == null || grp == "")
196                                 return null;
197
198                         Exception exc = null;
199                         try {
200                                 group = (WSExtensionGroup) Int32.Parse (grp);
201                                 if (group < WSExtensionGroup.High || group > WSExtensionGroup.Low)
202                                         throw new ArgumentOutOfRangeException ("group", "Must be 0 or 1");
203                         } catch (Exception e) {
204                                 exc = e;
205                         }
206
207                         return exc;
208                 }
209                 
210                 // Getters
211                 public Type Type {
212                         get { return type; }
213                 }
214
215                 public int Priority {
216                         get { return priority; }
217                 }
218
219                 public WSExtensionGroup Group {
220                         get { return group; }
221                 }
222         }
223         
224         class WebServicesConfigurationSectionHandler : IConfigurationSectionHandler
225         {
226                 public object Create (object parent, object context, XmlNode section)
227                 {
228                         WSConfig config = new WSConfig (parent as WSConfig, context);
229
230                         if (section.Attributes != null && section.Attributes.Count != 0)
231                                 ThrowException ("Unrecognized attribute", section);
232
233                         XmlNodeList nodes = section.ChildNodes;
234                         foreach (XmlNode child in nodes) {
235                                 XmlNodeType ntype = child.NodeType;
236                                 if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
237                                         continue;
238
239                                 if (ntype != XmlNodeType.Element)
240                                         ThrowException ("Only elements allowed", child);
241                                 
242                                 string name = child.Name;
243                                 if (name == "protocols") {
244                                         ConfigProtocols (child, config);
245                                         continue;
246                                 }
247
248                                 if (name == "soapExtensionTypes") {
249                                         ConfigSoapExtensionTypes (child, config.ExtensionTypes);
250                                         continue;
251                                 }
252
253                                 if (name == "soapExtensionReflectorTypes") {
254                                         ConfigSoapExtensionTypes (child, config.ExtensionReflectorTypes);
255                                         continue;
256                                 }
257
258                                 if (name == "soapExtensionImporterTypes") {
259                                         ConfigSoapExtensionTypes (child, config.ExtensionImporterTypes);
260                                         continue;
261                                 }
262
263                                 if (name == "serviceDescriptionFormatExtensionTypes") {
264                                         ConfigFormatExtensionTypes (child, config);
265                                         continue;
266                                 }
267
268                                 if (name == "wsdlHelpGenerator") {
269                                         string href = AttValue ("href", child, false);
270                                         if (child.Attributes != null && child.Attributes.Count != 0)
271                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
272
273                                         config.ConfigFilePath = context as string;
274                                         config.WsdlHelpPage = href;
275                                         continue;
276                                 }
277
278                                 ThrowException ("Unexpected element", child);
279                         }
280
281                         return config;
282                 }
283
284                 static void ConfigProtocols (XmlNode section, WSConfig config)
285                 {
286                         if (section.Attributes != null && section.Attributes.Count != 0)
287                                 ThrowException ("Unrecognized attribute", section);
288
289                         XmlNodeList nodes = section.ChildNodes;
290                         foreach (XmlNode child in nodes) {
291                                 XmlNodeType ntype = child.NodeType;
292                                 if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
293                                         continue;
294
295                                 if (ntype != XmlNodeType.Element)
296                                         ThrowException ("Only elements allowed", child);
297                                 
298                                 string name = child.Name;
299                                 string error;
300                                 if (name == "add") {
301                                         string protoName = AttValue ("name", child, false);
302                                         if (child.Attributes != null && child.Attributes.Count != 0)
303                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
304
305                                         if (!config.AddProtocol (protoName, out error))
306                                                 ThrowException (error, child);
307                                         
308                                         continue;
309                                 }
310
311                                 if (name == "remove") {
312                                         string protoName = AttValue ("name", child, false);
313                                         if (child.Attributes != null && child.Attributes.Count != 0)
314                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
315
316                                         if (!config.RemoveProtocol (protoName, out error))
317                                                 ThrowException (error, child);
318                                         
319                                         continue;
320                                 }
321
322                                 if (name == "clear") {
323                                         if (child.Attributes != null && child.Attributes.Count != 0)
324                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
325
326                                         config.ClearProtocol ();
327                                         continue;
328                                 }
329
330                                 ThrowException ("Unexpected element", child);
331                         }
332                 }
333                 
334                 static void ConfigSoapExtensionTypes (XmlNode section, ArrayList extensions)
335                 {
336                         if (section.Attributes != null && section.Attributes.Count != 0)
337                                 ThrowException ("Unrecognized attribute", section);
338
339                         XmlNodeList nodes = section.ChildNodes;
340                         foreach (XmlNode child in nodes) {
341                                 XmlNodeType ntype = child.NodeType;
342                                 if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
343                                         continue;
344
345                                 if (ntype != XmlNodeType.Element)
346                                         ThrowException ("Only elements allowed", child);
347                                 
348                                 string name = child.Name;
349                                 string error;
350                                 if (name == "add") {
351                                         string seType = AttValue ("type", child, false);
352                                         string priority = AttValue ("priority", child);
353                                         string group = AttValue ("group", child);
354                                         if (child.Attributes != null && child.Attributes.Count != 0)
355                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
356
357                                         WSExtensionConfig wse = new WSExtensionConfig ();
358                                         Exception e = wse.SetType (seType);
359                                         if (e != null)
360                                                 ThrowException (e.Message, child);
361
362                                         e = wse.SetPriority (priority);
363                                         if (e != null)
364                                                 ThrowException (e.Message, child);
365
366                                         e = wse.SetGroup (group);
367                                         if (e != null)
368                                                 ThrowException (e.Message, child);
369
370                                         extensions.Add (wse);
371                                         continue;
372                                 }
373
374                                 ThrowException ("Unexpected element", child);
375                         }
376                 }
377                 
378                 static void ConfigFormatExtensionTypes (XmlNode section, WSConfig config)
379                 {
380                         if (section.Attributes != null && section.Attributes.Count != 0)
381                                 ThrowException ("Unrecognized attribute", section);
382
383                         XmlNodeList nodes = section.ChildNodes;
384                         foreach (XmlNode child in nodes) {
385                                 XmlNodeType ntype = child.NodeType;
386                                 if (ntype == XmlNodeType.Whitespace || ntype == XmlNodeType.Comment)
387                                         continue;
388
389                                 if (ntype != XmlNodeType.Element)
390                                         ThrowException ("Only elements allowed", child);
391                                 
392                                 string name = child.Name;
393                                 string error;
394                                 if (name == "add") {
395                                         string typeName = AttValue ("name", child, false);
396                                         if (child.Attributes != null && child.Attributes.Count != 0)
397                                                 HandlersUtil.ThrowException ("Unrecognized attribute", child);
398
399                                         try {
400                                                 config.FormatExtensionTypes.Add (Type.GetType (typeName, true));
401                                         } catch (Exception e) {
402                                                 ThrowException (e.Message, child);
403                                         }
404                                         continue;
405                                 }
406
407                                 ThrowException ("Unexpected element", child);
408                         }
409                 }
410                 
411                 // To save some typing...
412                 static string AttValue (string name, XmlNode node, bool optional)
413                 {
414                         return HandlersUtil.ExtractAttributeValue (name, node, optional);
415                 }
416
417                 static string AttValue (string name, XmlNode node)
418                 {
419                         return HandlersUtil.ExtractAttributeValue (name, node, true);
420                 }
421
422                 static void ThrowException (string message, XmlNode node)
423                 {
424                         HandlersUtil.ThrowException (message, node);
425                 }
426                 //
427         }
428         
429         class HandlersUtil
430         {
431                 private HandlersUtil ()
432                 {
433                 }
434
435                 static internal string ExtractAttributeValue (string attKey, XmlNode node)
436                 {
437                         return ExtractAttributeValue (attKey, node, false);
438                 }
439                         
440                 static internal string ExtractAttributeValue (string attKey, XmlNode node, bool optional)
441                 {
442                         if (node.Attributes == null) {
443                                 if (optional)
444                                         return null;
445
446                                 ThrowException ("Required attribute not found: " + attKey, node);
447                         }
448
449                         XmlNode att = node.Attributes.RemoveNamedItem (attKey);
450                         if (att == null) {
451                                 if (optional)
452                                         return null;
453                                 ThrowException ("Required attribute not found: " + attKey, node);
454                         }
455
456                         string value = att.Value;
457                         if (value == String.Empty) {
458                                 string opt = optional ? "Optional" : "Required";
459                                 ThrowException (opt + " attribute is empty: " + attKey, node);
460                         }
461
462                         return value;
463                 }
464
465                 static internal void ThrowException (string msg, XmlNode node)
466                 {
467                         if (node != null && node.Name != String.Empty)
468                                 msg = msg + " (node name: " + node.Name + ") ";
469                         throw new ConfigurationException (msg, node);
470                 }
471         }
472
473 }