ConfigurationAdmin

Motivation

Although OSGi doesn't force us, we should consider to do configuration the OSGi-way. If we would not find an appropriate solution, it would be possible to implement an own or use another configuration service if there is one. Doing it the OSGi-way would enable other bundles to interact with james configuration and give us more interoperability.

How The ConfigurationAdmin works

In OSGi configuration is handled by the ConfigurationAdmin service. Every component that needs to be configured does subscribe to a configuration by using a service.pid. The service.pid is a system-wide unique identifier that is e.g. constructed by using the full qualified class name. The configuration for a component consists of a java-style properties like dictionary of key/value pairs.

When the component first subscribes to the configuration or every time the configuration is changed ConfigurationAdmin calls the components that implements ManagedService update method.

public void updated(java.util.Dictionary properties)
             throws ConfigurationException

Note: Spring OSGi will even support direct injection of values into setters. But maybe this is even not appropriate at all, in some cases.

And what about fancy nested XML configuration? For updating a single bean or a static hierarchy of beans the flat approach should be sufficient and actually the most handy:

component.option1=test
component.bean1.option1=test
component.bean1.option2=test
component.bean2.option1=test
component.bean2.bean1.option1=test

For components that have 0..n child beans OSGi provides a ManagedServiceFactory interface. For each child that is added/modified the update method gets called together with a new unique pid.

public void updated(java.lang.String pid,
                    java.util.Dictionary properties)
             throws ConfigurationException

This pid could be usually combined with the full class name and an incrementing number for each child.

If the child gets deleted, deleted is called

public void deleted(java.lang.String pid)

The component should hold an own map pid -> child to manage update/delete properly.

As an example from the James world, you could think of multiple mailets that get attached to a spoolmanager processor.

ConfigurationAdmin And Persistence

Although some people dislike overloaded nested xml file configuration a long pseudo-nested properties-file could be really unhandy, too. So how comes the configuration into the ConfigurationAdmin?

ConfigurationAdmin service itself allows also the modification of configuration.

Here an example for a ManagedServiceFactory: add a new child to Component1

Configuration conf = getConfigurationAdmin().createFactoryConfiguration(
                                                "org.apache.james.Component1");
String newPid=conf.getPid());
Dictionary newOptions = new Hashtable();
newOptions.put("key", "value");
conf.update(newOptions);

And now we modify it using the pid newPid

Configuration conf = getConfigurationAdmin().getConfiguration(newPid);
Dictionary options = conf.getOptions();
options.put("key2","value2");
conf.update(options);

In both cases Component1.updated(pid,dictionary) gets called.

To delete the child named newPid:

Configuration conf = getConfigurationAdmin().getConfiguration(newPid);
conf.delete();

The changes made to the ConfigurationAdmin are automatically made persistent. But the format used by the ConfigurationAdmin to save the data depends on its implementation. So there is a solution needed to get the data into the ConfigurationAdmin. Because the possibilities to make configuration are not limited this approach makes sense. (UI/files/Ldap...) At the moment the only existing solution I know is a console offered by knopflerfish. This is great for making small quick only changes but not an option for bigger reconfiguration.

The idea I have in mind is a custom import/export service. This would allow the use of configuration files. At startup and every time a change in the files is signaled (manually or automatically) the custom configuration gets imported into the ConfigurationAdmin. If desired it is imaginable to even allow an export of online changed options.

As input file we could choose xml/properties as appropriately. We have to find a way how the input data could be mapped to ConfigurationAdmin properties without the need of (too much) depended code. An ideal way would be to do it by convention or e.g. a xml-description file.

But isn't that much more complicated as what we are doing now?

At the moment our components deal directly with the structure of the config.xml which makes them very dependent. By only passing a key/value map we are avoiding the dependence but the actual work of mapping human-readable config file to attributes has to be done somewhere.

Outlook

So isn't the persistence done by the ConfigurationAdmin just overhead?

If configuration is done only via external config files, yes. But there are examples where it becomes useful:

changes by reloading the config files

an export to an external place (big config file/slow and overloaded ldap server) on every change is not appropriate.

Development/ReplacePhoenix/OSGi/ConfigurationAdmin (last edited 2009-09-20 22:58:39 by localhost)