--- layout: developersguide title: Configuration Admin --- {% include base.html %} # Configuration Admin Service As defined in the [OSGi Compendium Release 7][OSGi-cmpn] *configuration is the process of defining the configuration data of bundles and assuring that those bundles receive that data when they are active in the OSGi Service Platform.* ### Configuration Admin Service In OSGi, configurations are stored in a central database that is being managed by a special service - the *Configuration Admin Service*(`org.osgi.service.cm.ConfigurationAdmin`). This service monitors the service registry and **provides a configuration to the services** that are registered with a *service.pid* property. Configuration changes are first made persistent, and then are passed to the target service. It is important to understand that **the target bundle receives updates from the Configuration Admin service**. Implementations should be aware that the update reception could be delayed if the Configuration Admin service is missing. ### Configuration properties Each configuration is uniquely identified by a PID (Persistent IDentifier) and stores properties. The properties can be edited, or new properties could be added during runtime by other bundle that uses the Configuration Admin service. In OSGi, configurations properties are key-value pairs that are accessible via `Map`. Please note that the following types of objects are supported: - `String` - `Boolean` - `Byte` - `Short` - `Integer` - `Long` - `Float` - `Double` - `Character` If the Configuration Admin service detects an unsupported property type, it will throw an `IllegalArgumentException`. ## Configuring Declarative Services [Declarative Services](osgids.html) (DS) is highly integrated with the Configuration Admin service. Each DS component has a configuration object that is related with it. The configuration is injected in the bundle `activate`, `deactivate` and `modified` methods. The code below is an example, how to register a service and how to use the injected configuration. ```java package com.example; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Modified; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; @Component(service = { TimeEventHandler.class, EventHandler.class }, property = { "event.topics=some/topic" }) @NonNullByDefault public class TimeEventHandler implements EventHandler { // Use the default formatter private SimpleDateFormat dateFormatter = new SimpleDateFormat(); @Activate protected void activate(ComponentContext context, Map properties) { modified(properties); } /** * This method could be called by multiple threads */ @Modified public synchronized void modified(Map properties) { // note, that Config Admin may send an empty configuration if (properties != null) { String pattern = (String) properties.get("formatting"); dateFormatter = new SimpleDateFormat(pattern); } } @Deactivate protected void deactivate(ComponentContext context, Map properties) { modified(properties); } @Override public void handleEvent(@Nullable Event event) { Long timeInMillis = (Long) event.getProperty("time"); Date date = new Date(timeInMillis); System.out.println("The current time is: " + dateFormatter.format(date)); } } ``` ## Using the Configuration Admin to update the configuration As we have seen in the previous examples Configuration Admin service tracks the Service Registry and the internal configuration database for changes. It can be used to update the configuration (or create if it is missing) as well. The flow is the following: ```java package com.example; import java.io.IOException; import java.util.Dictionary; import java.util.Hashtable; import org.eclipse.jdt.annotation.NonNullByDefault; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @Component(service = TimeEventHandler.class) @NonNullByDefault public class TimeEventHandler { @Reference private @NonNullByDefault({}) ConfigurationAdmin configurationAdmin; // Here we perform a configuration update as soon as this service gets activated @Activate protected void activate() { try { Configuration config = configurationAdmin.getConfiguration("com.example.handler", null); Dictionary props = config.getProperties(); if (props == null) { // if null, the configuration is new props = new Hashtable<>(); } // set some properties props.put("formatting", "EEE, d MMM yyyy HH:mm:ss Z"); // update the configuration, the target bundle will be notified for the change config.update(props); } catch (IOException e) { // TODO: handle exception } } } ``` After the call to `update` the Configuration Admin service persists the new configuration data and sends an update to the ManagedService registered with the service PID asynchronously. ::: tip Hint! Configuration objects have a security feature called `Location` that prevents other bundles from modifying their configuration. In the example above we have created a configuration using the `Configuration config = configurationAdmin.getConfiguration("com.example.handler", null);`. The second parameter ('null') guarantees that the location for the configuration will be set when the service with this PID is registered for the first time. If the location is not set correctly the Config Admin may not send the update to the bundle. ::: ## Further Reading - [OSGi Compendium Release 7][OSGi-cmpn] - - - [OSGi-cmpn]: https://osgi.org/download/r7/osgi.cmpn-7.0.0.pdf