3 // Marek Habersack (mhabersack@novell.com)
5 // (C) 2007 Novell, Inc
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 using System
.Collections
.Generic
;
31 using System
.Xml
.XPath
;
33 namespace Mono
.MonoConfig
35 class HandlerDescription
38 Type handlerStorageType
;
44 public object Handler
{
48 handler
= Activator
.CreateInstance (handlerType
);
53 public object Storage
{
58 storage
= Activator
.CreateInstance (handlerStorageType
);
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
88 Dictionary
<string, HandlerDescription
> section_handlers
;
89 List
<HandlerDescription
> section_handlers_ordered
;
90 List
<XPathDocument
> config_documents
;
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
)
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
);
127 throw new ApplicationException (
128 String
.Format ("Definition of default config file '{0}' for target '{1}' not found.",
132 public string[] DefaultConfigFiles
{
136 IDefaultConfigFileContainer
[] containers
= GetHandlersForInterface
<IDefaultConfigFileContainer
> ();
137 if (containers
== null || containers
.Length
== 0)
140 List
<string> defaults
= new List
<string> ();
141 foreach (IDefaultConfigFileContainer container
in containers
)
142 defaults
.AddRange (container
.DefaultConfigFiles
);
145 return defaults
.ToArray ();
149 public void AddFeature (string configFilePath
, FeatureTarget target
, string featureName
)
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
> ();
166 foreach (IFeatureGenerator generator
in generators
) {
167 if (generator
.HasFeature (featureName
)) {
168 generator
.AddFeature (configFilePath
, featureName
, target
, defaults
, configBlocks
);
175 throw new ApplicationException (
176 String
.Format ("Definition of feature '{0}' for target '{1}' not found.",
177 featureName
, target
));
180 public string[] Features
{
184 IFeatureGenerator
[] generators
= GetHandlersForInterface
<IFeatureGenerator
> ();
185 if (generators
== null || generators
.Length
== 0)
188 List
<string> features
= new List
<string> ();
189 foreach (IFeatureGenerator generator
in generators
)
190 features
.AddRange (generator
.Features
);
193 return features
.ToArray ();
197 public void Load (string[] configs
)
199 this.configs
= configs
;
205 if (configs
== null || configs
.Length
== 0)
209 section_handlers
.Clear ();
210 section_handlers_ordered
.Clear ();
211 config_documents
.Clear ();
216 foreach (string config
in configs
) {
217 if (String
.IsNullOrEmpty (config
))
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
),
227 } catch (Exception
) {
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
);
261 public T
[] GetHandlersForInterface
<T
> ()
265 string typeName
= typeof (T
).ToString ();
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)
284 return handlers
.ToArray ();
287 void HandleTopLevelNode (XPathNavigator nav
)
289 string section
= nav
.LocalName
;
291 if (!section_handlers
.ContainsKey (section
))
294 HandlerDescription hd
= section_handlers
[section
];
298 IDocumentNodeHandler handler
= hd
.Handler
as IDocumentNodeHandler
;
299 object storage
= hd
.Storage
;
301 if (handler
== null || storage
== null)
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"),
318 if (section_handlers
.ContainsKey (section
)) {
319 HandlerDescription old
= section_handlers
[section
];
320 section_handlers
[section
] = hd
;
322 handlers
.Remove (old
);
325 section_handlers
.Add (section
, hd
);
333 throw new ApplicationException ("Configuration not loaded yet");