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