Dear Wiki user,

You have subscribed to a wiki page or wiki category on "James Wiki" for change 
notification.

The following page has been changed by JoachimDraeger:
http://wiki.apache.org/james/Development/ReplacePhoenix/OSGi/ConfigurationAdmin

New page:
= 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 ''Configuration``Admin'' 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 
''Managed``Service``Factory'' 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 ''Configuration``Admin''?

''Configuration``Admin'' service itself allows also the modification of 
configuration.

Here an example for a ''Managed``Service``Factory'': 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 ''Configuration``Admin'' are automatically made 
persistent. But the format used by the ''Configuration``Admin'' to save the 
data depends on its implementation. 
So there is a solution needed to get the data into the 
''Configuration``Admin''. 
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 ''Configuration``Admin''. 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 ''Configuration``Admin'' 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 ''Configuration``Admin'' just overhead?

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

 * When config is changed online the user may decide to discard his
changes by reloading the config files
 * If config is provided by an LDAP server the admin could decide to allow the 
server to start with the last known config values when the LDAP server is 
unavailable at startup.
 * there maybe situations where configuration is changed so fast that
an export to an external place (big config file/slow and overloaded ldap 
server) on every change is not appropriate. 

Reply via email to