2010-05-19 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / mconfig / Mono.MonoConfig / Configuration.cs
blob6cbaa2e689456491540030eabb7dfa40a7a61680
1 //
2 // Authors:
3 // Marek Habersack (mhabersack@novell.com)
4 //
5 // (C) 2007 Novell, Inc
6 //
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 using System;
29 using System.Collections.Generic;
30 using System.Xml;
31 using System.Xml.XPath;
33 namespace Mono.MonoConfig
35 class HandlerDescription
37 Type handlerType;
38 Type handlerStorageType;
39 string section;
41 object handler;
42 object storage;
44 public object Handler {
45 get {
46 if (handler != null)
47 return handler;
48 handler = Activator.CreateInstance (handlerType);
49 return handler;
53 public object Storage {
54 get {
55 if (storage != null)
56 return storage;
58 storage = Activator.CreateInstance (handlerStorageType);
59 return storage;
63 public string Section {
64 get { return section; }
67 public bool Implements (string interfaceName)
69 return handlerType.GetInterface (interfaceName) != null;
72 public HandlerDescription (string handlerTypeName, string handlerStorageTypeName, string section)
74 handlerType = Type.GetType (handlerTypeName, true);
75 if (handlerType.GetInterface ("Mono.MonoConfig.IDocumentNodeHandler") == null)
76 throw new ApplicationException (
77 String.Format ("Handler for section '{0}' must implement the '{1}' interface",
78 section, typeof (Mono.MonoConfig.IDocumentNodeHandler)));
80 handlerStorageType = Type.GetType (handlerStorageTypeName, true);
81 this.section = section;
85 public class Configuration
87 string[] configs;
88 Dictionary <string, HandlerDescription> section_handlers;
89 List <HandlerDescription> section_handlers_ordered;
90 List <XPathDocument> config_documents;
91 bool loaded;
93 public Configuration () : this (null)
96 public Configuration (string[] configs)
98 this.configs = configs;
99 section_handlers = new Dictionary <string, HandlerDescription> ();
100 section_handlers_ordered = new List <HandlerDescription> ();
101 config_documents = new List <XPathDocument> (configs != null ? configs.Length : 1);
104 public void WriteDefaultConfigFile (string name, string path, FeatureTarget target)
106 AssertLoaded ();
108 if (String.IsNullOrEmpty (name))
109 throw new ArgumentException ("name", "Must not be null or empty");
111 IDefaultConfigFileContainer[] containers = GetHandlersForInterface <IDefaultConfigFileContainer> ();
112 if (containers == null || containers.Length == 0)
113 throw new ApplicationException ("Cannot find any handler for writing default config files");
115 IDefaultContainer[] defaults = GetHandlersForInterface <IDefaultContainer> ();
117 bool written = false;
118 foreach (IDefaultConfigFileContainer container in containers) {
119 if (container.HasDefaultConfigFile (name, target)) {
120 container.WriteDefaultConfigFile (name, target, path, defaults);
121 written = true;
122 break;
126 if (!written)
127 throw new ApplicationException (
128 String.Format ("Definition of default config file '{0}' for target '{1}' not found.",
129 name, target));
132 public string[] DefaultConfigFiles {
133 get {
134 AssertLoaded ();
136 IDefaultConfigFileContainer[] containers = GetHandlersForInterface <IDefaultConfigFileContainer> ();
137 if (containers == null || containers.Length == 0)
138 return null;
140 List <string> defaults = new List <string> ();
141 foreach (IDefaultConfigFileContainer container in containers)
142 defaults.AddRange (container.DefaultConfigFiles);
144 defaults.Sort ();
145 return defaults.ToArray ();
149 public void AddFeature (string configFilePath, FeatureTarget target, string featureName)
151 AssertLoaded ();
153 if (String.IsNullOrEmpty (configFilePath))
154 throw new ArgumentException ("configFilePath", "Must not be null or empty");
155 if (String.IsNullOrEmpty (featureName))
156 throw new ArgumentException ("featureName", "Must not be null or empty");
158 IFeatureGenerator[] generators = GetHandlersForInterface <IFeatureGenerator> ();
159 if (generators == null || generators.Length == 0)
160 throw new ApplicationException ("Cannot find any feature generator");
162 IDefaultContainer[] defaults = GetHandlersForInterface <IDefaultContainer> ();
163 IConfigBlockContainer[] configBlocks = GetHandlersForInterface <IConfigBlockContainer> ();
165 bool added = false;
166 foreach (IFeatureGenerator generator in generators) {
167 if (generator.HasFeature (featureName)) {
168 generator.AddFeature (configFilePath, featureName, target, defaults, configBlocks);
169 added = true;
170 break;
174 if (!added)
175 throw new ApplicationException (
176 String.Format ("Definition of feature '{0}' for target '{1}' not found.",
177 featureName, target));
180 public string[] Features {
181 get {
182 AssertLoaded ();
184 IFeatureGenerator[] generators = GetHandlersForInterface <IFeatureGenerator> ();
185 if (generators == null || generators.Length == 0)
186 return null;
188 List <string> features = new List <string> ();
189 foreach (IFeatureGenerator generator in generators)
190 features.AddRange (generator.Features);
192 features.Sort ();
193 return features.ToArray ();
197 public void Load (string[] configs)
199 this.configs = configs;
200 Load ();
203 public void Load ()
205 if (configs == null || configs.Length == 0)
206 return;
208 if (loaded) {
209 section_handlers.Clear ();
210 section_handlers_ordered.Clear ();
211 config_documents.Clear ();
212 loaded = false;
215 XPathDocument doc;
216 foreach (string config in configs) {
217 if (String.IsNullOrEmpty (config))
218 continue;
220 try {
221 doc = new XPathDocument (config);
222 config_documents.Add (doc);
223 } catch (XmlException ex) {
224 throw new ApplicationException (
225 String.Format ("Failed to parse config file '{0}'.", config),
226 ex);
227 } catch (Exception) {
228 continue;
232 XPathNavigator nav;
233 XPathNodeIterator iter;
235 // First configure section handlers
236 List <HandlerDescription> handlers_from_file = new List <HandlerDescription> ();
238 foreach (XPathDocument xpdoc in config_documents) {
239 handlers_from_file.Clear ();
241 nav = xpdoc.CreateNavigator ();
242 iter = nav.Select ("//mconfig/configuration/handlers/handler[string-length (@section) > 0]");
244 while (iter.MoveNext ())
245 AddSectionHandler (iter.Current, handlers_from_file);
246 section_handlers_ordered.InsertRange (0, handlers_from_file);
249 // Process all configs looking for all sections with known handlers
250 foreach (XPathDocument xpdoc in config_documents) {
251 nav = xpdoc.CreateNavigator ();
252 iter = nav.Select ("//mconfig/*");
254 while (iter.MoveNext ())
255 HandleTopLevelNode (iter.Current);
258 loaded = true;
261 public T[] GetHandlersForInterface <T> ()
263 AssertLoaded ();
265 string typeName = typeof (T).ToString ();
266 object handler;
268 List <T> handlers = null;
269 foreach (HandlerDescription hd in section_handlers_ordered) {
270 if (hd.Implements (typeName)) {
271 if (handlers == null)
272 handlers = new List <T> (1);
273 handler = hd.Handler;
274 if (handler is IStorageConsumer)
275 ((IStorageConsumer) handler).SetStorage (hd.Storage);
277 handlers.Add ((T)handler);
281 if (handlers == null)
282 return null;
284 return handlers.ToArray ();
287 void HandleTopLevelNode (XPathNavigator nav)
289 string section = nav.LocalName;
291 if (!section_handlers.ContainsKey (section))
292 return;
294 HandlerDescription hd = section_handlers [section];
295 if (hd == null)
296 return;
298 IDocumentNodeHandler handler = hd.Handler as IDocumentNodeHandler;
299 object storage = hd.Storage;
301 if (handler == null || storage == null)
302 return;
304 if (handler is IStorageConsumer)
305 ((IStorageConsumer) handler).SetStorage (storage);
307 handler.ReadConfiguration (nav);
308 handler.StoreConfiguration ();
311 void AddSectionHandler (XPathNavigator nav, List <HandlerDescription> handlers)
313 string section = Helpers.GetRequiredNonEmptyAttribute (nav, "section");
314 HandlerDescription hd = new HandlerDescription (Helpers.GetRequiredNonEmptyAttribute (nav, "type"),
315 Helpers.GetRequiredNonEmptyAttribute (nav, "storageType"),
316 section);
318 if (section_handlers.ContainsKey (section)) {
319 HandlerDescription old = section_handlers [section];
320 section_handlers [section] = hd;
322 handlers.Remove (old);
323 handlers.Add (hd);
324 } else {
325 section_handlers.Add (section, hd);
326 handlers.Add (hd);
330 void AssertLoaded ()
332 if (!loaded)
333 throw new ApplicationException ("Configuration not loaded yet");