Documentation for easyconf

The purpose of easyconf is to provide an easy to use and centralized library to configure software components from XML and properties configuration files. Easyconf simplifies the management of different configuration of an application in different environments (preproduction, production, etc. or for different deployments). The purpose of easyconf is to provide an easy to use and centralized library to access documentation. Its main features are:

1. Support for both properties and XML files (or a mix of both)
2. Support for changing the configuration for different environments and subprojects
3. Support for accessing properties from JSP files
4. Support for several configuration modules (called components) to allow different software components running in the same JVM to use separate configuration files.

# Quick start

Easyconf consist of a central component (ConfReader) that returns the configuration of a given component. This class has a static method called `getConfiguration` which must be given the name of a component. The name of the component can be any String which can be used to identify it within easyconf.

## Reading the configuration from Java

Following is an example of how to use this class:

    ComponentConfiguration conf = ConfReader.getConfiguration("my-component");

The result is an object with the configuration of the given component. The component configuration contains a properties based configuration and a XML based configuration. Let's start with the first one. Note that we'll asume from now on that we'll be working with the configuration of a component called my-component.
The properties are read from a file named after the component name. In our example the properties would be read from the file `my-component.properties` (later you'll see that other files will also be read to allow a property value to be overridden in different environments). This simple convention hides the name of the file from the program code.
Once you have the `ComponentConfiguration` you can just read the property values which are automatically converted to integers, booleans, lists, etc. Following are two examples of how to read typed properties:

      List portlets = conf.getProperties().getList("static.portlets");
      boolean disable = conf.getProperties().getBoolean("registration.disable");

On the other hand the XML configuration can be converted to any object by filling a digester rules file. The XML configuration of the previous example will be read from a file named `my-component.xml` and its digester rules from `my-component.digesterRules.xml`. The XML parsing converts the configuration to a set of user defined object classes. For example imagine that we want to configure some databases specifying it's tables and types of tables. We define two classes: `DatabaseConf` and `Table`. Then we write the XML configuration in `my-component.xml`, for example:

    <database>
      <tables>
        <table tableType="type1"/>
      </tables>
    </database>

Next we write the Digester rules in `my-component.digesterRules.xml`:

    <!DOCTYPE digester-rules PUBLIC
       "-//Jakarta Apache //DTD digester-rules XML V1.0//EN"
       "digester-rules.dtd">
    <digester-rules>
      <pattern value="database">
        <object-create-rule classname="com.foo.bar.DatabaseConf"/>
        <pattern value="tables/table">
          <object-create-rule classname="com.foo.bar.Table"/>
          <set-properties-rule/>
          <set-next-rule methodname="addTable" paramtype="com.foo.bar.Table"/>
        </pattern>
      </pattern>
    </digester-rules>

Finally, just one line of code is necesary to obtain the objects which have resulted from parsing the configuration. Easyconf calls the result an object graph because it returns one object which can contain other objects inside, which can contain even more objects, etc. Here is an example of code of retrieving and using the object graph of the previous XML configuration:

        DatabaseConf dbconf = (DatabaseConf) conf.getConfigurationObject();
        Table firstTable = dbconf.getTables().get(0);
        String tableType = firstTable.getTableType();

For more information about how to write the rules files check the digester xml rules documentation A variant of this example is using properties from the properties based configuration in the XML file. For example:

    <database>
      <tables>
        <table tableType="${table.type1}"/>
      </tables>
    </database>

Where table.type1 is defined in a properties file as:

    table.type1=type1

This allows to change this value for different environments.

In a next section is a more detailed description of a component configurations.

## Reading the configuration from a JSP page

EasyConf provides a taglib to make it very easy to read the configuration of a component from a JSP. It is limited to properties because that's what is most commonly needed in this situations. Herea is a self explaining example:

        <%@ taglib uri="/WEB-INF/tld/easyconf.tld" prefix="easyconf" %>

            <easyconf:property id="static_portlets"
                       component="xpression-ui"
                       property="static.portlets"
                       type="java.util.List"/>
            <logic:iterate id="item" name="static_portlets">
               <bean:write name="item"/>
            </logic:iterate>

            <easyconf:property id="registration_disabled"
                       component="my-component"
                       property="registration.disabled"/>
            <logic:equal name="registration_disabled" value="true">
               <bean:message key="registration.disabled"/>
            </logic:equal>

Los valores soportados en el parametro type son: java.util.List, java.lang.Integer , java.lang.String java.lang.Double, java.lang.Float, java.lang.Byte java.math.BigDecimal, java.lang.BigInteger, java.lang.Boolean java.lang.Short y java.lang.Long.

# Structure of a component configuration

The configuration is an instance of `ComponentConfiguration` which is composed of:

- XML based configuration: An object graph obtained from an XML file
- Properties based configuration: A `ComponentProperties` object from serveral 'properties' files.

## XML based configuration

The XML configuration of a component is read using Digester from Jakarta and is converted to objects using the information of two files:

- `${componentName}.xml`: Contains the specific XML with the configuration of the component.
- `${componentName}.digesterRules.xml`: Contains the rules which the parser should use to convert the XML file to objects

The result of reading this configuration is a graph of regular Java objects (POJOs) which can be used without limitations by the software component. A nice additional feature of the XML based configuration is that the values of any of its elements or attributes can contain variables whose values are defined in the properties based configuration. The variable should be of the form `${variableName}`. For example, the following XML fragment can be used:

`<welcome-msg> Bienvenido a ${server.name} </welcome-msg>`

As long as there is a property named `server.name` as explained next.

## Properties based configuration

The properties configuration of a module is obtained from a composition of the following files:

1. ${componentName}.properties
2. global-configuration.properties

In case of collision the values of global-configuration.properties will override the ones in the specific properties file. Furthermore, any of this files can include other files which contain overridden values for any of its properties. This is done with a special property whose key is `include-and-override`. This property is multivaluated so that several files can be included. In case of collision of values among the included files the ones specified last will override the previous ones. A usual pattern is to include the following properties in `global-configuration.properties`:

`include-and-override=global-configuration-env.properties include-and-override=global-configuration-prj.properties`

Which allows any property in any component to be redefined for a especific environment and for a specific project. Note that if the specified file does not exist it will be ignored silently.

### Access to system properties

EasyConf makes available all system properties as variables that can be used in the values of the properties files. For example, if the application is run using the following command:

`java ......... -Dinstallation-dir=/opt/application`

You can use the variable ${installation-dir} in a properties file. For example:

`readme.file.path=${installation-dir}/README`

### Support for environment configuration

The support for environment configuration is based on the access to system properties and the special `include-and-override` property. Using a system property you can set the name of the current environment. For example:

`java ......... -Dconfiguration-environment=production`

Then in `global-configuration.properties` you can set the following property:

`include-and-override=global-configuration-${configuration-environment}.properties`

Which in the previous example will cause EasyConf to load the file `global-configuration-production.properties`. Using this pattern you can have an application EAR, WAR or JAR which contains the configuration for all the environments and then set a system property when running the application to select which configuration should be used. As usual, the referenced files that do not exist they will be silently ignored. If the JVM property is not defined no file will be loaded.

### Properties format

The format of the properties files is the same as the standard Java properties with the following additions:

- The properties are typed so if the value is a number it can be retrieved as an int or long. If the value is 'true' or 'false' it can be retrieved as a boolean, etc. For example:

            long-property=5
            boolean-poroperty=true

- Multivalued properties are supported: if the same key is used or several values are specified separated with commas they will be automaticaly converted to a `List`. For example:

            valid-values=one,two,three,four

  Important: if the value of a property contains a comma but you do not want it converted to a list the comma should be scaped with a double slash. For example:

             a-property=Once upon a time\\, there was a princess...

- The value of some variables can contain others using variables. For example:

             database-type=oracle
             sql-file=insert-${database-type}.sql

For more information about the format of the properties read:

- The Jakarta Commons Configuration Website
- Javadoc for the class which reads the properties

Note that not all the funcionalities of Commons Configuration are available in easyconf, particularly the way to read XML as EasyConf provides a more powerful mechanism.