Proposed Future Kepler Configuration System
This page documents ideas for configuration system that simplifies the configuration of Kepler and also provides more robust support for multiple modules. See bug 3948 for more information.
For modules to be effective, they need to be able to be configured at run time. They need to be able to store configuration properties about their own state, and they must be able to read configuration properties about the other modules running in Kepler. They also need to be able to modify existing configuration properties that control Kepler's existing extension points without overriding the entire global configuration set, as that almost instantly guarantees modules will be incompatible with one another. Addressing these needs will be the focus of the Configuration system for Kepler 2.0. However, changing the set of extension points and refactoring the GUI to provide new extension capabilities will not be part of this release. The principal needs to be addressed by the configuration system should be: Need for modules to be able to manage their own configuration properties. This should include a simple API for setting and reading configuration, a standardized approach for the system to load module configuration values at run time, and a way for modules to listen for property change events that might be initiated by other modules. Need to consolidate configuration file serialization formats to allow easier management of configurations. Need to be able to let modules set configuration properties in the *existing* Kepler system, allowing them to set configuration values that are compatible with the existing architecture and GUI (e.g., such as the names of factory classes) 1) The configuration system will serialize each configuration property as a string 2) The configuration system will read default values from a module's resources/configurations directory 3) The configuration system will NOT write files to a module's resources/configurations directory because that directory can be inaccessible at runtime (i.e. in a jar file or in an administrator controlled directory). 4) The configuration system will write files to the appropriate location (TBD) in .kepler (using the DotKeplerManager.getModuleWriteableDirectory() or similar method to determine where to store files) 5) The configuration system will notify all listeners when a configuration property is changed 6) A module will define a configuration property within a unique namespaces. There will be a default namespace within each module for simplicity of use. 7) A module will listen for updates to its own as well as other modules' configuration changes 8) The system will not allow modules to change the value of a property based solely on its name. *Note: even though these structures are represented in XML, that does not mean that XML will be used as the serialization format for the configuration system. These are just general structures found in the current Kepler configuration files. Because the use of nested getProperty() calls can be cumbersome, the getProperty and getProperties methods should also include the ability to use a shortcut naming system. The Apache Commons Configuration project uses a system of dot notations do do this. See the code below for an example. Goals (from #)
Configuration System Requirements
1) A module is able to add configuration properties to the configuration
2) A module is able to read its own configuration properties
3) A module is able to add or override configuration properties added by other modules.
4) A module is able to overwrite another module's configuration properties
5) A module can indicate whether a property is mutable (i.e., if property changes are noticed and incorporated without restarting the application). At runtime, only mutable properties can be overwritten. It is the responsibility of all modules to utilize mutable properties to monitor those properties and respond appropriately to changes.
6) A configuration property can have either or both of a single scalar value or a list of subordinate configuration properties. Subordinate configuration properties must have unique names within their parent property.
7) The configuration system is able to notify modules or other registered listeners that a configuration change has taken place
8) The configuration system is able to serialize each module's configuration properties as text
9) The configuration serialization should be able to store different language versions of each property file (internationalizable)
10) Each module can have its own configuration and can organize its configuration into any number of namespaces, allowing the module to organize its properties into groups. One use case for this is to allow a module to separate its UI strings from other configuration properties.
11) The configuration system is able to tell which module owns a configuration property
12) The configuration system is able to store default configuration properties separately from user-modified configuration properties. Consider whether user preference files, including loading and sharing of such files, is in scope or not.
13) The configuration system should be loaded under all variants of the Kepler application and should have minimal dependencies.
14) The configuration system should be able to store and make accessible documentation about configuration properties (name, description(s), etc.)
15) The configuration system stores strings only. It is up to a module to cast strings to implied value types.
-- desire to include data types as as part of the model (rather than only accept strings)
-- desire to have utility methods for doing casting (e.g., getValueAsInt)
-- change this requirement to: The configuration system will support basic types. If no type is specified, the type will default to String.
-- basic types TBD.
16) The config system should define the set of allowable characters for use in names (e.g., no spaces, or should be java identifiers)
17) The configuration system should specifically consider if and how configuration values or sets of values from the command-line, environment variables, module.txt and other sources should be merged or provided with values from configuration files
Configuration Implementation Details
Preliminary Proposed Class Structure
Misc Notes
Example configuration entries in the current config.xml file:
<viewPaneTabPanes>
<viewPane>
<name>Kepler Classic</name>
<viewPaneLocation>
<location>W</location>
<tabPane>Components</tabPane>
<tabPane>Data</tabPane>
<tabPane>Outline</tabPane>
</viewPaneLocation>
<viewPaneLocation>
<location>E</location>
</viewPaneLocation>
</viewPane>
</viewPaneTabPanes>
<property>
<name>_about</name>
<class>ptolemy.kernel.attributes.FileAttribute</class>
<value>$CLASSPATH/ptolemy/configs/kepler/intro.htm</value>
</property>
<property>
<name>_applicationCopyright</name>
<class>ptolemy.kernel.util.StringAttribute</class>
<value>ptolemy/configs/kepler/copyright.htm</value>
</property>
<log_file>false</log_file>
Example of how this entry would map into the proposed structure:
//Example to get the location property and associated properties
//Assume this information is stored in the 'core' Module
Module core = moduleTree.getModule("core");
ConfigurationManager config = ConfigurationManager.getInstance();
//get the list of 'veiewPaneTabPanes' from the configuration manager
List l = config.getProperty(core, "viewPaneTabPanes")
.getProperty("viewPane")
.getProperties("viewPaneLocation");
//get the first viewPaneLocation
ConfigurationProperty viewPaneLocationProp = (ConfigurationProperty)l.get(0);
//returns "W"
String location = viewPaneLocationProp.getProperty("location").getValue();
//note you could also iterate through this structure to get the other
//values that exist within the viewPaneLocation element
//example to get the values in all 'properties' elements
List l = config.getProperties(core, "property");
ConfigurationProperty prop1 = (ConfigurationProperty)l.get(0);
//returns "_about"
String name = prop1.getProperty("name").getValue();
//returns "$CLASSPATH/ptolemy/configs/kepler/intro.htm"
String value = prop1.getProperty("value").getValue();
ConfigurationProperty newprop2 = (ConfigurationProperty)l.get(1);
//get the values for the 2nd property
ConfigurationProperty prop2 = (ConfigurationProperty)l.get(1);
//returns _applicationCopyright
String name2 = prop2.getProperty("name").getValue();
//returns "ptolemy.kernel.util.StringAttribute"
String class2 = prop2.getProperty("class").getValue();
//example to get the log_file value
//returns "false"
String logFileValue = config.getProperty(core, "log_file").getValue();
Shortcut Naming
//The call
List l = config.getProperty(core, "viewPaneTabPanes")
.getProperty("viewPane")
.getProperties("viewPaneLocation");
//would be replaced by
List l = config.getProperties(core, "viewPaneTabPanes.viewPane.ViewPaneLocation");
This would make the code much more readable and be less cumbersome to program.
foo.yaml foo-string_en_US.yaml foo-string_en_UK.yaml foo-string_de.yaml See also the Java i18n tutorial at http://java.sun.com/docs/books/tutorial/i18n/index.html http://yaml.org/type/index.html http://commons.apache.org/configuration/userguide/howto_xml.html http://commons.apache.org/sandbox/i18n/quickstart.html http://java.sun.com/docs/books/tutorial/i18n/resbundle/concept.htmlStandard naming conventions for i18n internationalized files
Technologies to consider for serialization
YAML
Apache Commons Configuration
Double double = config.getDouble("number");
Java Resource Bundles
JFig
<configuration>
<include name=”base.config.xml”/>
<section name=”locos”>
<entry key=”instance” value=”development” />
</section>
<section name=”Paths”>
<entry key=”locosHome” value=”d:/[locos]{instance}/project/” />
<entry key=”locosExternal” value=”d:/external/[locos]{instance}/” />
</section>
<section name=”attachments”>
<entry key=”attachmentDirectory” value=”[paths]{locosExternal}attachments/”/>
</section>
</configuration>