Kilimanjaro Configuration

How to configure an OsidManager: the XML file format, and the ways configuration files can be named, located, layered, and applied.

The Kilimanjaro Configuration OSID Provider

Kilimanjaro's built-in OSID Configuration Provider provides the runtime configuration for OSID Providers. The default OSID Configuration Provider is file-based to easily bundle configuration with a distribution artifact.

The purpose of the Kilimanjaro OSID Configuration Provider is to provide configuration services to OSID Providers. The Configuration OSID interfaces themselves can be used for all sorts of things but it does not mean that Kilimanjaro is the panacea of configuration services. In fact, nothing is. One-size fits all approaches create data swamps that don't serve anyone.

The principal audience for Kilimanjaro OSID Configuration is the person who is incorporating your OSID Provider into their application or system. The options described in more detail below give the integrator the flexibility of packaging, managing, operating, and tuning their application.

There may be top-level applications which can also use the Kilimanjaro OSID Configuration Service, especially for identifying which OSID Provider(s) it will load (keep in mind the Orchestration OSID to minimize the OSID Consumer touchpoint when needing many OSID Providers).

These are things to think about and not hard and fast rules. There's always grey area. The beauty of the OSID framework is that it allows the best fit to be applied rather than tossing everything into a single basket to get mediocrity which never quite gets there.

File Structure

<?xml version="1.0" encoding="utf-8" standalone="no"?> <configuration xmlns="urn:inet:osid.org:schemas:providers/configuration/base/1" lastmod="2010-01-29T16:25:00Z"> <displayName>Example Configuration</displayName> <description> <div>An example configuration to demonstrate the Base Configuration OSID Provider.</div> </description> <parameter id="shouldThisWork" syntax="boolean"> <displayName>Work</displayName> <description> <div>A parameter to specify whether or not this code should work.</div> </description> <value> <boolean>true</boolean> </value> </parameter> <parameter id="constant" syntax="float"> <displayName>The Constant</displayName> <description>Constant numbers used to make our program look smart.</description> <value> <float>3.14159</float> </value> <value> <float>42</float> </value> </parameter> <parameter id="serverName" syntax="string"> <displayName>Server Name</displayName> <description>The name of our database server.</description> <value priority="1"> <string>www1.company.com</string> </value> <value priority="1"> <string>www2.company.com</string> </value> <value priority="10"> <string>backup.company.com</string> </value> </parameter> <parameter id="language" syntax="type"> <displayName>Language</displayName> <description>The locale type for what language we will speak.</description> <value priority="1"> <type>urn:inet:osid.org:types:locale:language/English/US</type> </value> <value priority="2"> <type>urn:inet:osid.org:types:locale:language/French</type> </value> </parameter> </configuration>
Element / AttributeCardinalityDescription
configuration@lastmodrequireddate or dateTime the file was last modified
configuration@registryoptionalboolean - indicates if this Configuration exists to define Parameters only (a registry of parameters) or it also includes Values. Usually false (default).
configuration > displayNamerequiredinline text/markup - the name of this Configuration
configuration > descriptionrequiredblock text/markup - a description of this Configuration
configuration > parameter0 or morelist of Configuration Parameters
parameter@idrequiredstring - identifier of the Parameter Id. The namespace and authority of the OSID Id is managed by the Kilimanjaro Configuration OSID Provider.
parameter@syntaxrequiredone of boolean, byte, cardinal, coordinate, datetime, distance, float, id, integer, object, spatial, string, type
parameter@shuffleValuesoptionalboolean - if a Parameter has multiple Values, this flag indicates whether or not the Values will be shuffled on each retrieval (default false).
parameter > displayNamerequiredinline text/markup - the name of this Parameter
parameter > descriptionrequiredblock text/markup - a description of this Parameter
parameter > value0 or morelist of Values the Parameter
value@priorityoptionalinteger - rank of the Value, lowest to highest, if there are multiple. Values will be returned in the order or the rank unless they are shuffled.
value > path, ruleoptionalschema-legal but not read by providers.configuration.base.Value.parse() — path-based selection is a separate mechanism, see below
value > <syntax-typed element>exactly 1the actual value, e.g. <string>, <integer>, <type>. This must match parameter@syntax.

Parameter and Value Ids

The Kilimanjaro Configuration OSID Provider owns the namespace and authority of the Parameter Ids. Thus in the file, a simple string (the identifier component) is specified. The Value Id is implicitly the Parameter Id plus the position it sits in the Parameter group (serverName#1).

Configuration Validation

A configuration file can be checked against schemas/configuration.rnc using the validator wrapper checked in alongside the schemas:

schemas/validate.sh configuration.rnc myApplication.xml

validate.sh runs jing, to validate configuration files against the schema definitions.

Locating Configuration Files & Precedence

Every OsidRuntimeManager carries an application context string — the value passed to BootLoader.getRuntimeManager(context). Configuration Parameters specified in files whose name carries the context string are given the highest priority to give the application integrator the ability to override any setting in their integration project. These files are fetched from the classpath and if multiple files of the same name exist in the classpath, the Classloader will select whichever one it sees first (typically what is in your build before what is bundled in a dependency).

The runtime configuration is primarily geared toward configuring OSID Provider implementations. The name of implementation, such as net.tom.providers.TomRepositoryManager or edu.mit.providers.PersonnelProxyManager, may have configuration files specific to their implementation. These are given second priority. It may be that default configurations are shipped with the jar file or it may be desired to associate some or all of an OSID Provider's configuration with the implementation itself.

Finally, there is osid.xml. This is the catch-all behind the other tiers. It exists to centralize OSID Provider configurations at a lower priority to establish a baseline configuration. Perhaps useful for shared Parameter Ids.

PrecedenceSource
Highest<application context>.xml
 ↕<OsidManager class>.xml
Lowestosid.xml

Again, these files are fetched as resources from the Classloader.

Worked Example

An application boots with context "myApplication". It reads a parameter naming which implementation to load next, that implementation's own file names the next one down, and so on — a chain of managers, each with its own configuration file, each one layer lower in precedence than the one before it:

context "myApplication"
file: myApplication.xml — highest precedence
orchestrationPersonnelProvider = com.me.OrchestrationManager
↓ boots
com.me.OrchestrationManager
file: com.me.OrchestrationManager.xml
orchestrationPersonnelProvider = com.me.CachingPersonnelManager
↓ boots
com.me.CachingPersonnelManager
file: com.me.CachingPersonnelManager.xml
cachingPersonnelProvider = org.dxtera.DataPersonnelManager
cachingPersonnelCacheSize = 500
↓ boots
org.dxtera.DataPersonnelManager
file: org.dxtera.DataPersonnelManager.xml
dataPersonnelProvider = net.okapia.CloudFilingManager
↓ boots
net.okapia.CloudFilingManager
file: net.okapia.CloudFilingManager.xml — lowest of this stack
cloudFilingDirectory = /var/filing/personnel
↓ falls back to
osid.xml
the fallback — consulted last by every layer above, for any parameter none of them defined

Another setup, centralizing the adapter stack because you want to see them all in one place on an application by application basis.

context "myApplication"
file: myApplication.xml — highest precedence
orchestrationPersonnelProvider = com.me.OrchestrationManager
orchestrationPersonnelProvider = com.me.CachingPersonnelManager
cachingPersonnelProvider = org.dxtera.DataPersonnelManager
dataPersonnelProvider = net.okapia.CloudFilingManager
↓ boots
com.me.OrchestrationManager
file: com.me.OrchestrationManager.xml
↓ boots
com.me.CachingPersonnelManager
file: com.me.CachingPersonnelManager.xml
cachingPersonnelCacheSize = 500
↓ boots
org.dxtera.DataPersonnelManager
file: org.dxtera.DataPersonnelManager.xml
↓ boots
net.okapia.CloudFilingManager
file: net.okapia.CloudFilingManager.xml — lowest of this stack
cloudFilingDirectory = /var/filing/personnel
↓ falls back to
osid.xml
the fallback — consulted last by every layer above, for any parameter none of them defined

Another setup, not using any of the class-specific configuration files. Defaulting in osid.xml and allowing application config to override.

context "myApplication"
file: myApplication.xml — highest precedence
orchestrationPersonnelProvider = com.me.OrchestrationManager
orchestrationPersonnelProvider = com.me.CachingPersonnelManager
cachingPersonnelProvider = org.dxtera.DataPersonnelManager
dataPersonnelProvider = net.okapia.CloudFilingManager
cachingPersonnelCacheSize = 800
↓ boots
com.me.OrchestrationManager
file: com.me.OrchestrationManager.xml
↓ boots
com.me.CachingPersonnelManager
file: com.me.CachingPersonnelManager.xml
↓ boots
org.dxtera.DataPersonnelManager
file: org.dxtera.DataPersonnelManager.xml
↓ boots
net.okapia.CloudFilingManager
file: net.okapia.CloudFilingManager.xml — lowest of this stack
↓ falls back to
osid.xml
the fallback — consulted last by every layer above, for any parameter none of them defined
cachingPersonnelCacheSize = 500
cloudFilingDirectory = /var/filing/personnel

Ordering Multiple Values

When a Parameter carries more than one Value (like serverName in the example above), value@priority decides the order they come back in through getApplicableValueByParameter() (what is on top) and getApplicableValuesByParameter() (the entire list). Priorities are in ascending order with the lowest priorities (includes negative numbers) having the highest priority. Values with the same priority are always shuffled.

If (parameter@shuffleValues="true"), the Kilimanjaro OSID Configuration Provider will randomize across all priority levels using the priority level as a weight such that higher priorities (lower numbers) will appear more often than lower priorities. It uses an Efraimidis-Spirakis Reservoir Algorithm.

Worked example — priorities -10, 0, 0, 2, 3, 4, 999. Lowest present is -10, so the weights are shifted: 1 - (-10) = 11. Resulting exponents are 1, 11, 11, 13, 14, 15, 1010

priorityexponentweightP(sorts first)
-101171.5%
0111/116.5%
0111/116.5%
2131/135.5%
3141/145.1%
4151/154.8%
99910101/10100.07%

Qualified Parameter Identifiers

Two implementations that each ask for a Parameter of the same bare name will collide if that name is ever defined twice for different purposes — say, provider in myApplication.xml, once selecting com.me.OrchestrationManager for the application itself, and once meant only for com.me.CachingPersonnelManager's underlying provider. The integrator will need to qualify one or both of them.

A qualifier is the implementation class name of whichever OsidManager is doing the asking (which also happens to be the name of its own configuration file, the other means to help separate Parameter definitions). Qualify a Parameter identifier using the implementation class name and |:

<implementation class>|<parameter id>

This is done behind the OSID Providers' backs. Each OSID Provider will see the Parameter identifier it was expecting to see, unqualified.

context "myApplication"
file: myApplication.xml — highest precedence
provider = com.me.OrchestrationManager
com.me.OrchestrationManager|provider = com.me.CachingPersonnelManager
com.me.CachingPersonnelManager|provider = org.dxtera.DataPersonnelManager
org.dxtera.DataPersonnelManager|provider = net.okapia.CloudFilingManager
com.me.CachingPersonnelManager|cacheSize = 800

Value Application Rules

It seems someone had too much time on their hands.

Applying Rules to Values adds more files. The <identifier> in the filenames correspond to the filename prefix in the general configuration -- the application context, OsidManager class, or osid.xml.

FileSchemaRequiredHolds
<identifier>-rules.xmlrules-config.rncto enable any rule filtering at allmaps values to rule ids — only the time-rule mapping is actually read; path routing uses one fixed rule id and ignores this file's own path mapping entirely

The <identifier>-rules.xml file specifies which Values any Rule applies. Values not listed in this file go through the normal path (no special rules apply) as described above.

The gotcha is that due to the fact that the Rules OSID Provider is external to the OSID Configuration Provider, the Value identifiers need to be fully qualified OSID Ids. Id from the OSID Configuration Provider assigns each value (<parameterId>#<sequence>, authority local, namespace configuration). Note the Value Id below, referencing the third declared value of serverName from the earlier example (backup.company.com) — a single Value can also carry more than one Rule reference, unlike the single-Rule-per-Value shape in the time-rules example further down:

<?xml version="1.0" encoding="utf-8" standalone="no"?> <engine xmlns="urn:inet:osid.org:schemas:providers/rules/configuration/1"> <displayName>Server Name Rules</displayName> <description>Governs when the backup server value applies.</description> <value id="configuration:serverName#3@local"> <rule id="rule:net.okapia.CloudFilingManager#maintenanceWindow@localhost"/> <rule id="rule:net.okapia.CloudFilingManager#weekendOverflow@localhost"/> </value> </engine>

Check one against its schema the same way — schemas/rules-config.rnc against net.okapia.CloudFilingManager-rules.xml:

schemas/validate.sh rules-config.rnc net.okapia.CloudFilingManager-rules.xml

Now that a couple of Values are known to OSID Rules processing, we can define the Rules which go with them.

Time-Based Application Rules

FileSchemaRequiredHolds
<identifier>-time.xmlrules-time.rnconly if using time rulestime-of-day, date, and weekday rules

Time rules are used when Values may be applied at specific times relative to the date and time when it's evaluated. Three kinds of rules, each independently negatable:

ElementMatches when
<timeRange><start>/<end></timeRange>the current time of day (GMT) falls in [start, end), as HH:mm:ss
<dateRange><start>/<end></dateRange>the current date falls strictly between start and end
<dayOfWeek day="Monday"/>today (GMT) is that weekday — full name, three-letter abbreviation, or single-letter form all work

Check a file against the schema:

schemas/validate.sh rules-time.rnc net.okapia.CloudFilingManager-time.xml

Terms wrap in a <term op="and"|"or" negate="true"|"false">, which can nest other <term> elements arbitrarily; a <rule>'s own top-level terms are always AND'd together. Here's a deterministic pair — one term that's always true, one that's the same range negated, so the example doesn't depend on what day or time it's actually read:

<?xml version="1.0" encoding="utf-8" standalone="no"?> <engine xmlns="urn:inet:osid.org:schemas:providers/rules/time/1" lastmod="2026-07-11T00:00:00Z"> <displayName>Cloud Filing Manager Time Rules</displayName> <description>Deterministic always-true / always-false rules.</description> <rule id="alwaysOpen"> <displayName>Always Open</displayName> <description>A time range spanning the entire day.</description> <term op="or"> <timeRange> <start>00:00:00</start> <end>23:59:59</end> </timeRange> </term> </rule> <rule id="alwaysClosed"> <displayName>Always Closed</displayName> <description>The same all-day range, negated on the leaf term.</description> <term op="or"> <timeRange negate="true"> <start>00:00:00</start> <end>23:59:59</end> </timeRange> </term> </rule> <rule id="openBusinessHours"> <displayName>Open Business Hours</displayName> <description>Monday through Friday, 9am to 5pm.</description> <term op="and"> <timeRange> <start>09:00:00</start> <end>17:00:00</end> </timeRange> <term op="or"> <dayOfWeek day="Monday"/> <dayOfWeek day="Tuesday"/> <dayOfWeek day="Wednesday"/> <dayOfWeek day="Thursday"/> <dayOfWeek day="Friday"/> </term> </term> </rule> </engine>

openBusinessHours shows the two composition rules together: a <term> can hold more than one leaf directly (five dayOfWeek children under one op="or", rather than five nested single-child terms), and terms nest — the outer op="and" requires both the time range and the weekday in order to combine the weekday pattern with the time.

Different Rules may be applied to different Values in a set of Values. The example below illustrates two simple messages, each intended to be applied to whether or not our 9-5 business is open.

<parameter id="businessHoursMessage" syntax="string"> <displayName>Business Hours Message</displayName> <description>Two candidates, filtered by time.</description> <value> <string>Welcome</string> </value> <value> <string>Closed, come back when we are open.</string> </value> </parameter>

And how the message Values are applied to the defined Rules, using complete OSID Ids:

<?xml version="1.0" encoding="utf-8" standalone="no"?> <engine xmlns="urn:inet:osid.org:schemas:providers/rules/configuration/1"> <displayName>Cloud Filing Manager Rules</displayName> <description>Maps businessHoursMessage's two values to their time rules.</description> <value id="configuration:businessHoursMessage#1@local"> <rule id="rule:net.okapia.CloudFilingManager#alwaysOpen@localhost"/> </value> <value id="configuration:businessHoursMessage#2@local"> <rule id="rule:net.okapia.CloudFilingManager#alwaysClosed@localhost"/> </value> </engine>

Path-Based Rules

FileSchemaRequiredHolds
<identifier>-path.xmlrules-path.rnconly if using path rulespath patterns, one per named rule

Paths may be used to scope the application of a Value. A path is a set of components. Each component represents a layer (impl) in the OSID stack so the path is essentially the OSIDs in your stack from the application on down. These are specified in accompanying rules files.

Same requirement as the time example above: the -rules.xml enables the Path OSID Rule. However, for some inconsistent, unknown reason, the Path Rules are not named like the Time OSID Rules are. The consequence is that we need a simple enable Path Rules file and the paths are specified and applied in the path file directly.

<?xml version="1.0" encoding="utf-8" standalone="no"?> <engine xmlns="urn:inet:osid.org:schemas:providers/rules/configuration/1"> <displayName>Cloud Filing Manager Rules</displayName> <description>Required so the rules session for this file constructs at all.</description> </engine>

This is what a path specifier looks like:

<?xml version="1.0" encoding="utf-8" standalone="no"?> <engine xmlns="urn:inet:osid.org:schemas:providers/rules/path/1"> <displayName>Personnel Path Rules</displayName> <description>Picks a filing directory by caller path.</description> <rule id="cloudFilingDirectory-by-path"> <value id="configuration:cloudFilingDirectory#1@local"> <path> <component name="myApplication"/> <component name="com.me.OrchestrationManager"/> <component name="*"/> <component name="net.okapia.CloudFilingManager"/> </path> </value> </rule> </engine>

What the above example says is apply this Value to a net.okapia.CloudFilingManager used by any OSID Provider or set of OSID Providers which is/are used by the com.me.OrchestrationManager and in turn is used by myApplication.

Again, the Rule needs to reference the Value by its full Id, not just the bare <parameterId>#<sequence>.

Check a file against rules-path.rnc the same way as the others:

schemas/validate.sh rules-path.rnc net.okapia.CloudFilingManager-path.xml

I apologize for this.

Changing the Kilimanjaro Configuration OSID Provider

If you want to manage your runtime configuration in another data store, you can replace it.

Set the system property kilimanjaro.configuration.impl to the classname of an alternate org.osid.configuration.ConfigurationManager before the root runtime boots:

-Dkilimanjaro.configuration.impl=com.example.osid.MyConfigurationManager

It needs to support a ValueLookupSession. Specifically: supportsValueLookup(), getValueLookupSession(), and getValueLookupSessionForConfiguration(Id). The replacement doesn't need to be file-based at all; a database- or remote-backed ConfigurationManager works fine.

Your OSID Configuration Provider will be used for Parameter & Value persistence and Kilimanjaro will continue to handle the ValueRetrievalSession applying the Values to OsidManagers and other Rules.

You can also supply an OSID Configuration Federating Adapter to have the flexibility of pulling parts of configurations from more than one location.