This package provides tools to read and write configuration data using different mechanisms. In short, the features are:
Class Configuration and Plug-ins:
The plug-ins, derived from abstract class ConfigurationPlugin are plugged into an object of type Configuration and are responsible for reading (and optionally writing) variables from dedicated sources.
Class Configuration offers an interface to retrieve and store configuration variables using the plug-ins. The plug-ins are attached to the Configuration instance along with a unique priority. Values are retrieved and stored by looping through the plug-ins sorted by priority. As soon as one plug-in confirms to have found (or stored) the variable, the loop ends. This way, plug-ins may "overrule" each other in respect to retrieving configuration data.
Class ALIB creates a static singleton of this class for public access and this singleton is usually all that is needed.
Naming Configuration Variables:
Configuration variables are addressed by two strings: The category and the name. In the case of INI files, the category is translated to the section and the name to variables within the section. Other plug-ins, for example CLIArgs or Environment, are prepending the category name to the variable name separated by an underscore character '_'
. For example, a variable in category "ALIB"
named "WAIT_FOR_KEY_PRESS"
, in an INI file would be stated like this:
[ALIB] WAIT_FOR_KEY_PRESS= yes
To define the same variable and value on the command-line, the parameter needs to be:
--ALIB_WAIT_FOR_KEY_PRESS=yes
The anonymous, empty category is allowed. For convenience, with variables of this category, no underscore is prepended by the plug-ins. The little drawback of this is, that variables in the anonymous category that contain an underscore character, for some plug-ins can get ambiguous. For example, variable MY_VARIABLE
in the anonymous category, on the command line would be uniquely addressed by:
--MY_VAR=my value
In an INI file, two ways of specifying the variable are possible (and therefore ambiguous). In the anonymous section:
MY_VAR = my value
or, in section MY:
[MY] VAR = my value
Three different standard plug-ins that collect external configuration variables are provided with ALib already:
CategoryName_VariableName=value
.The proposed priorities to be used when attaching the plug-ins to the Configuration object, are given in static fields:
With these default priorities set, whatever is stored in an INI file, can be overwritten by setting an environment variable. Both settings can in turn be overwritten by specifying a corresponding command line parameter when launching the process!
In addition to the three plug-ins described above, ALib implements a fourth one, class InMemoryPlugin. As the name indicates, this class keeps configuration variables in memory. The special thing about it is that it does not read any external data source! The reason for having it, is twofold. The first use case are Default variables.
An instance is plugged into class Configuration with a priority of
this plug-in serves as a storage for default values. The only way to set these default values is programatically, which means "with program code".
The advantages of having such default variables are:
Class InMemoryPlugin is by default used a second time by plugging an instance into class Configuration with a priority of
When setting a variable within this plug-in, no other plug-in can 'overrule' this value. This way, it is possible to protect values against external modification.
In normal use cases, there is no need to create an instance of class Configuration, as a default singleton is provided with ALIB.Config. The command line parameters (optionally) provided with ALIB.Init are passed to the command-line plug-in of this singleton.
Class Configuration in the constructor by default sets up four plug-ins automatically: CLIArgs for parsing command-line arguments as variables, Environment for environment variables and two plug-ins of type InMemoryPlugin used for default and protected values.
If an application wants to suppress the use of one of the plug-ins, the plug-ins can be removed using method RemovePlugin.
On the other hand, a plug-in of type IniFile may be attached on bootstrap of a process using Configuration.PrioStandard (20000).
In addition (or alternatively), custom plug-ins may be written and installed using arbitrary priorities.
Class IniFile is designed for simplicity and smaller applications. Instead of using it IniFile, it is recommended to use application/platform specific mechanisms for writing configuration data. In this case, write your own plug-in to grant ALib and other libraries which rely on ALib, access to your applications's configuration data. Again, ALib here follows its design principle to be non intrusive: The plug-in concept allows users of ALib (more important: users of ALib enabled libraries) to expose any external configuration source to these libraries. This way, the users can stick to his/her preferred way of implementation.
Method Configuration.Load by default substitutes references to other configuration variables found in the value of the requested variable.
For example, if two variables are defined as follows:
MYCAT_RESULT= 42 MYCAT_MYVARIABLE= The result is $MYCAT_RESULT
then, with the retrieval of variable MYCAT_MYVARIABLE
, variable MYCAT_RESULT
is read and the substring "$MYCAT_RESULT" is substituted by "42".
Substitutions are performed repeatedly until all variables are resolved. Therefore, nested substitutions may be defined as well. To avoid an endless loop in case of circular dependencies, a simple threshold applies: A maximum of 50 replacements are done.
The dollar sign '$'
used to recognize variables is the default and can be modified. It is also possible to specify a prefix and a suffix for the identification of substitutable variables in other variables' values. For example, the syntax can be adjusted to
MYCAT_MYVARIABLE= The result is %{MYCAT_RESULT}
See documentation of fields SubstitutionVariableStart, SubstitutionVariableEnd and SubstitutionVariableDelimiters for more information.
When parsing a variables' category and name, method Configuration.Load searches for an underscore character '_'
. The first underscore found serves as a delimiter of category from the name. If no underscore character is found, the category is left empty (anonymous category) and the name is set to what is given as a variable name.
TEXT= Welcome to $_HOME_LOCATION
HOME_LOCATION
in the anonymous category ""
.Values of variables are loaded and received using instances of class Variable. Instances of this class can be passed to the interface of class Configuration or directly to specific ConfigurationPlugin objects.
Simple access methods allow to read or set the values of a variable.
By consequently using optional class VariableDecl for declaring all variables of an application or library, all attributes of variables can be maintained in one place. This includes categories, names, comments, value delimiters and default values of variables. Class Variable accepts instances of VariableDecl in the constructor as well as in overloaded method Variable.Declare.
Variable values provided via command line parameters, environment variables or textual configuration files need to be converted when loading and storing them. This has two reasons:
'\n'
or '\t'
within stringsFor this task, class XTernalizer is used. Each ConfigurationPlugin owns an instance of this class (which is exchangeable). Conversion is done internally and there is no need to interface with this class directly when using variables. A huge benefit of this API design is that variable values look the same in an INI-file as when passed as a command line parameter.
But it is important to understand that value parameters provided with interface methods to store variables accept "externalized" strings only. In simple cases this is not relevant. But if a variable contains multiple values or special characters, it has to be understood that 'internalization' of the value takes place.
Normal, internal string values need to be added to the variable in code prior to invoking a store method. If an externalized string is provided with the store methods, then previously added variable values are cleared!
Classes | |
class | CLIArgs |
class | Configuration |
class | ConfigurationPlugin |
class | Environment |
class | IniFile |
class | InMemoryPlugin |
class | Variable |
struct | VariableDecl |
class | XTernalizer |