First off, this library looks very cool. I plan to try it out on my next
project.
Second, how about adding support for a "bootstrap" configuration
file? That is, a configuration file that defines where configuration
data can be found (possibly from a multitude of different sources
and/or source types). The application could then call a single static
method, say Nini.Config.Bootstrap.LoadConfigs(), that would
instantiate, load, and merge all of the configuration sources defined
within the bootstrap configuration file. Thus, we remove the
requirement that the application know exactly where its configuration
data is located and how it is distributed across the set of possible
sources.
An obvious first choice would be the .config file for the application,
with something like the following:
<configuration>
<configSections>
<section name="Nini"
type="Nini.Config.BootstrapSectionHandler" />
</configSections>
<Nini>
<Xml path="FactoryWide.xml" />
<Xml path="AreaWide.xml" />
<Xml path="ToolSpecific.xml" />
<Argv />
</Nini>
</configuration>
The example would load and merge the configuration data from the
three XML sources, in order, and then allow any setting to be
overridden by the command line. Configuration sources could be
added, source types could be swapped, all without any extra code
on the part of the application.
Anyway, just a thought I had.
Thanks,
Phillip M. Hoff
phillip.m.hoff@intel.com
phillip@orst.edu
Logged In: YES
user_id=163900
That is an excellent idea. I've been playing around with an
idea like that for some time now. Let me think about how
that might work. If you have any more suggestions for
implementing this feature then please add them here. Thanks!
Logged In: YES
user_id=1240125
Sorry for posting this inline, but I don't see an attach file option for
followups.
Below is a proof-of-concept of the idea (with the added ability for Nini
clients to create their own custom configuration sources and still have the
bootstrapper load them automatically or to override how the bootstrapper
loads the provided configuration sources). I only added support for Ini,
Xml, and Argv configuration sources; too tired to add others.
Files were compiled and executed with Mono 1.1.4.
Thanks,
Phillip M. Hoff
phillip.m.hoff@intel.com
phillip@orst.edu
NiniBootstrap.cs:
using System;
using System.Collections;
using System.Configuration;
using System.Xml;
using Nini.Config;
namespace Nini.Config.Bootstrap
{
public class BootstrapConfigurationSectionHandler :
IConfigurationSectionHandler
{
public BootstrapConfigurationSectionHandler()
{
}
public object Create(object parent, object configContext,
XmlNode section)
{
return section;
}
}
public delegate IConfigSource
BootstrapConfigSourceGenerator(XmlNode section);
public class BootstrapConfiguration
{
private static IConfigSource _source;
private static Hashtable _generators;
public static IConfigSource Source
{
get
{
if (_source == null)
{
XmlNode section = (XmlNode)
ConfigurationSettings.GetConfig("Nini");
foreach (XmlNode childNode in
section.ChildNodes)
{
if
(BootstrapConfiguration.SourceGenerators.Contains(childNode.LocalName)
)
{
IConfigSource childSource =
((BootstrapConfigSourceGenerator)
BootstrapConfiguration.SourceGenerators[childNode.LocalName])(childNod
e);
if (_source == null)
{
_source = childSource;
}
else
{
_source.Merge(childSource);
}
}
}
}
return _source;
}
}
public static Hashtable SourceGenerators
{
get
{
if (_generators == null)
{
_generators = new Hashtable();
_generators["Ini"] = new
BootstrapConfigSourceGenerator(OnGenerateIniConfigSource);
_generators["Xml"] = new
BootstrapConfigSourceGenerator(OnGenerateXmlConfigSource);
_generators["Argv"] = new
BootstrapConfigSourceGenerator(OnGenerateArgvConfigSource);
}
return _generators;
}
}
private static IConfigSource
OnGenerateIniConfigSource(XmlNode node)
{
return new
IniConfigSource(node.Attributes["path"].InnerText);
}
private static IConfigSource
OnGenerateXmlConfigSource(XmlNode node)
{
return new
XmlConfigSource(node.Attributes["path"].InnerText);
}
private static IConfigSource
OnGenerateArgvConfigSource(XmlNode node)
{
ArgvConfigSource source = new
ArgvConfigSource(Environment.GetCommandLineArgs());
foreach (XmlNode switchNode in
node.SelectNodes("Switch"))
{
source.AddSwitch(switchNode.Attributes["config"].InnerText,
switchNode.Attributes["longName"].InnerText);
}
return source;
}
}
public class NiniBootstrap
{
public static void Main()
{
BootstrapConfiguration.SourceGenerators["Custom"] = new
BootstrapConfigSourceGenerator(OnGenerateCustomConfigSource);
IConfigSource source = BootstrapConfiguration.Source;
Console.WriteLine("NiniBootstrap1.ini: Test1: Key: {0}",
source.Configs["Test1"].GetString("Key"));
Console.WriteLine("NiniBootstrap2.ini: Test2: Key: {0}",
source.Configs["Test2"].GetString("Key"));
Console.WriteLine("Custom: Test3: Key: {0}",
source.Configs["Test3"].GetString("Key"));
Console.WriteLine("Overridden: TestOverride: Key: {0}",
source.Configs["TestOverride"].GetString("Key"));
}
private static IConfigSource
OnGenerateCustomConfigSource(XmlNode node)
{
return new
IniConfigSource(node.Attributes["path"].InnerText);
}
}
}
NiniBootstrap.exe.config:
<configuration>
<configSections>
<section name="Nini"
type="Nini.Config.Bootstrap.BootstrapConfigurationSectionHandler,NiniBoo
tstrap" />
</configSections>
<Nini>
<Ini path="NiniBootstrap1.ini" />
<Ini path="NiniBootstrap2.ini" />
<Custom path="NiniBootstrap3.ini" />
<Argv>
<Switch config="TestOverride" longName="Key" />
</Argv>
</Nini>
</configuration>
NiniBootstrap1.ini:
[Test1]
Key=Value1
[TestOverride]
Key=Value1
NiniBootstrap2.ini:
[Test2]
Key=Value2
[TestOverride]
Key=Value2
NiniBootstrap3.ini:
[Test3]
Key=Value3
[TestOverride]
Key=Value3
Output:
$ mcs NiniBootstrap.cs -r:Nini.dll
$ mono NiniBootstrap.exe
NiniBootstrap1.ini: Test1: Key: Value1
NiniBootstrap2.ini: Test2: Key: Value2
Custom: Test3: Key: Value3
Overridden: TestOverride: Key: Value3
$ mono NiniBootstrap.exe -Key:Foo
NiniBootstrap1.ini: Test1: Key: Value1
NiniBootstrap2.ini: Test2: Key: Value2
Custom: Test3: Key: Value3
Overridden: TestOverride: Key: Foo