| Configuration Admin Service specification explained by Example |
|
|
| Written by Valery Abu-Eid | |
| Wednesday, 24 September 2008 18:11 | |
|
Confguration Admin Service specification of the OSGi Compendium Services defines a standard way for configuring Bundles in OSGi Environments. Like any other OSGi Compendium Service, Configuration Admin Service has a standard API and implementations provided by different vendors, in this article we will use the implementation provided by Apache Felix project. There are two kinds of bundles from Configuration perspective: Configurable Bundles and Configurator Bundles. As the names suggest, Configurable Bundles are bundles that configured by Configurator Bundles. A bundle can be a Configurable bundle and a Configurator bundle at the same time - Such bundles usually provide a User Interface. We will go through the Config Admin Service specification by observing these two kinds of bundles. Configuration Admin Service is also responsible for persisting configuration data. So if you restart your application (without specifying the clean start parameter of the OSGi Framework in use) your previous configuration data should be available. The example application and its source code + Implementations of the Configuration Admin Service specification are contained in config-admin-service-example.zip. The example application was tested in Equinox, Felix and Knopflerfish.Configurable BundlesThe way you choose to make your bundle configurable largely depends on whether the bundle provides a single instance of a service, e.g., HTTP Engines, System Monitoring services, etc. or multiple instances of the same service, a service instance per configuration, e.g., a directory watcher service whose instance is created for each watched directory. The sections below explain how to configure each of these two kinds of services. Providing a Managed Service (Single Instance)To configure a singleton service you need to:
The Configurable bundle of the example application contains one Managed Service that configures a servlet that shows a greetings message. Below is a simplified version of the example code.
import java.util.Dictionary;
import java.util.Hashtable;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.Constants;
import org.osgi.service.cm.ManagedService;
public class Activator implements BundleActivator {
public void start(BundleContext bundleContext) throws Exception {
bundleContext.registerService(ManagedService.class.getName(),
greetingsServletManager.getGreetingsManagedService(),
getManagedServiceProperties());
/// ...
}
protected Dictionary getManagedServiceProperties() {
Dictionary result = new Hashtable();
result.put(Constants.SERVICE_PID, "greetings_servlet_service");
return result;
}
private GreetingsServletManager greetingsServletManager =
new GreetingsServletManager();
// ...
}
public class GreetingsServletManager {
protected class GreetingsManagedService implements ManagedService {
public void updated(Dictionary properties) throws ConfigurationException {
System.out.println("Configuration Updated.");
setProperties(properties);
updateServletService();
}
}
private final GreetingsManagedService greetingsManagedService =
new GreetingsManagedService();
public GreetingsManagedService getGreetingsManagedService() {
return greetingsManagedService;
}
protected void updateServletService() {
// Update Logic
}
// ...
}
You can see from the code above that the Bundle Activator registered a Managed Service with a Service PID, and the method updated of the Managed Service is used to update the configuration of the Servlet. Providing Managed Services using a Factory (Multiple Instances)To configure a service of which you will have an instance per configuration you need to:
import java.util.Dictionary;
import java.util.Hashtable;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.Constants;
import org.osgi.service.cm.ManagedService;
public class Activator implements BundleActivator {
public void start(BundleContext bundleContext) throws Exception {
bundleContext.registerService(ManagedServiceFactory.class.getName(),
greetingsServletsManager.getGreetingsManagedServiceFactory(),
getManagedServiceFactoryProperties());
/// ...
}
protected Dictionary getManagedServiceFactoryProperties() {
Dictionary result = new Hashtable();
result.put(Constants.SERVICE_PID, "greetings_servlet_service_factory");
return result;
}
private GreetingsServletsManager greetingsServletsManager =
new GreetingsServletsManager();
// ...
}
public class GreetingsServletsManager {
class GreetingsManagedServiceFactory implements ManagedServiceFactory {
public void updated(String pid, Dictionary properties)
throws ConfigurationException {
// Depending on whether a Servlet exists with this pid or not:
// create a new servlet or update an existing one
}
public void deleted(String pid) {
// If a servlet has such pid, remove it.
}
// getName() method returns a descriptive name of the service factory.
public String getName() {
return "Greetings Servlet Service Factory";
}
}
private final GreetingsManagedServiceFactory managedServiceFactory =
new GreetingsManagedServiceFactory();
public GreetingsManagedServiceFactory getGreetingsManagedServiceFactory() {
return managedServiceFactory;
}
// ...
}
Configurator BundlesConfiguration Admin ServiceImplementations of the Configuration Service specification provides a Configuration Admin service which implements the org.osgi.service.cm.ConfigurationAdmin interface. ConfigurationAdmin interface provides methods to maintain configuration data in the OSGi Environment, below are its main methods:
Configuring a Managed ServiceTo configure a Managed Service you need to:
Below is a simplified version of the Configurator bundle.
import java.util.Dictionary;
import java.util.Hashtable;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleActivator;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
public class Activator implements BundleActivator {
public void start(BundleContext bundleContext) throws Exception {
ServiceReference configAdminServiceRef =
bundleContext.getServiceReference(ConfigurationAdmin.class.getName());
if (configAdminServiceRef != null) {
ConfigurationAdmin configAdmin = (ConfigurationAdmin)
bundleContext.getService(configAdminServiceRef);
Configuration config = configAdmin.getConfiguration(
"greetings_servlet_service", getConfigurableBundleLocation());
Dictionary properties = config.getProperties();
if (properties == null) {
properties = new Hashtable();
}
properties.put("servletAlias", "/greetings");
config.update(properties);
}
}
protected String getConfigurableBundleLocation() {
// Logic to acquire the Location Identifier of the Configurable bundle
}
// ...
}
Configuring Managed Services provided by a FactoryTo configure Managed Services provided by a Managed Service Factory you need to:
Below is a simplified version of the Configurator bundle.
import java.util.List;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleActivator;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
public class Activator implements BundleActivator {
public void start(BundleContext bundleContext) throws Exception {
ServiceReference configAdminServiceRef =
bundleContext.getServiceReference(ConfigurationAdmin.class.getName());
if (configAdminServiceRef != null) {
ConfigurationAdmin configAdmin = (ConfigurationAdmin)
bundleContext.getService(configAdminServiceRef);
Configuration config = configAdmin.createFactoryConfiguration(
"greetings_servlet_service_factory",
getConfigurableBundleLocation());
Dictionary properties = new Hashtable();
properties.put("servletAlias", "/greetings");
properties.put("friendName", "World");
config.update(properties);
configObjects.add(config);
}
}
protected String getConfigurableBundleLocation() {
// Logic to acquire the Location Identifier of the Configurable bundle
}
private List configObjects = new ArrayList();
// ...
}
Configuration Service ImplementationsEach project of the tree main OSGi Frameworks (Equinox, Felix and Knopflerfish) provides an implementation of the Configuration Service specification - In Equinox and Knopflerfish it's called "cm", in Felix it's "scr". The implementations provided by Felix and Knopflerfish are included in the example application - The implementation provided by Equinox wasn't included since it isn't compatible with Knopflerfish, at least using the default configuration. |