The specification groups of the OSGi Alliance are currently in the process of finalizing the work for the upcoming OSGi R7 release. The major part of the specification work is done. This post explains some new functionality around OSGi configurations. Let’s start with a very brief introduction.
Configuration Admin
One of the most used but on the other hand barely noticed services from the OSGi compendium specification is the Configuration Admin. This service allows to create, update and delete configurations. It is up to the implementation where these configurations are stored. A configuration has a unique persistent identifier (PID) and a dictionary of properties.
Usually configurations are tied to an implementation of an OSGi service but configurations can be used for any purpose like database connections, current temperature or the set of available nodes in a cloud setup. While the Configuration Admin service has an API to find configurations or create them, it supports a more inversion of control like behavior by supporting a callback mechanism. The callback (known as the ManagedService interface) gets invoked for existing/created configurations of a certain PID and also if that configuration is deleted.
While this callback exists, its very often not used directly. The most common and easiest way to develop OSGi components and services is to use Declarative Services. Declarative Services (DS) provides build-in support for configurations. Simply by implementing an activation method the component can get it’s configuration. The implementor of that component does not have to worry whether such a configuration exists, gets deleted or is modified. DS takes care of all of this and invokes the right actions and the component.
In addition to single configurations, Configuration Admin provides support for factory configurations: multiple configurations of the same type, like for example different logger configurations for different categories or different database connection configurations. These factory configurations have a factory PID which is the same for all configurations of that type and a configuration PID to distinguish those configurations.
This should explain big picture, if you’re interested in more details, I refer you to the OSGi specifications. Especially the chapters about Configuration Admin and Declarative Services provide very valuable information. Let’s start talking about the new things.
Configurator Specification
R7 adds chapter 150, Configurator Specification. It basically consists of two parts. The first part describes a common textual representation of a set of configurations. Before this specification each and every tool was using its own format for provisioning configurations. For example, the famous Apache Felix File Install uses a properties like format. Other tools use slightly different formats. One problem is that you can’t simply switch from one tool to another and the other major problem is that some of the formats do not allow to specify the real type of a property value. For example, the value for the service ranking property must be of type Integer or your special implementation is expecting (for whatever reason) a value to be of type Byte. However some tools are simply always using a Long to represent numbers.
Therefore a common definition eliminates these problems and allows interchangeability of configurations between various tools. The format is JSON based and uses the PIDs of a configuration as the keys. The value is the configuration object with the properties:
{
"my.component.pid": {
"port:Integer" : 300,
"array:int[]" : [2, 3, 4],
"collection:Collection<Integer>" : [2,3,4],
"complex": {
"a" : 1,
"b" : "two"
}
}
}
As you can see in the example, it is possible to specify the runtime type of a configuration property by separating the property name from the type using a colon. For example, the “port” property value is of type Integer, the “array” property value is an array of ints and the “collection” property value is of type Collection<Integer>. You can specify all allowed types for a configuration and the configurator implementation uses converting rules as defined by the Converter Specification – another of the new specifications of R7.
In addition, a configuration property can hold structured JSON as a string value. In the example above “complex” contains at runtime a string value of the specified JSON.
Factory configurations can be specified by using the following syntax: FACTORY_PID~NAME. With the R7 Configuration Admin it is possible to use a meaningful name to address factory components, the name (see below). The tilde separates the factory PID from the name:
{
"my.factory.component~foo" : {
...
},
"my.factory.component~bar" : {
...
}
}
OSGi Bundle Configurations
The second part of the configurator specification describes a new extender based mechanism that picks up configurations from within a bundle and applies them. A bundle can contain one or more JSON files with configurations and once the bundle is started the configurations will be put into Configuration Admin by the Configurator. The configurator manages the state handling and ordering in a deterministic way. For example, if two bundles contain a configuration for the same PID, a ranking mechanism is used to specify which configuration is put into Configuration Admin, regardless of their installation or start order.
With this new feature, provisioning of bundles becomes part of the OSGi specifications. The specification of the Configurator has driven the update of the Configuration Admin specification. So let’s talk about the most important new features.
Improved Factory Configuration Handling
With the upcoming R7 specification handling factory configurations has been greatly improved. Before, when you create a factory configuration, the PID part is randomly generated which makes identifying a particular factory configuration later on much harder. In addition, as the PID is auto generated, it has no meaning. With R7 it is now possible to specify the PID of a factory configuration, removing those problems in the future.
New methods on the Configuration Admin allow to create and retrieve factory configurations based on the factory PID and a name. These methods behave the same as the already existing methods for plain configurations. The PID for those factory components is generated by appending the name to the factory PID separated by a tilde. The Configurator uses this syntax to specify factory configurations.
Improved Configuration Plugin Handling
When a configuration is delivered to a managed service, the configuration is passed through registered configuration plugin services. Such a service can manipulate the configuration. One common use case is to handle place holders in the configuration properties and replace them with real values when delivered. For example a property of a database connection configuration could just contain the value “${database.url}” which is replaced with the actual url when this configuration is passed to the component processing the configuration. Or if you have sensitive configuration data, you can store it encrypted in the configuration and just decrypt it in a configuration plugin before it is passed to the managed service.
While this mechanism sounds useful, it is only useful if you register a managed service. However, when you’re using Declarative Services for your components, the plugins are not called at all. Starting with R7 this gap is closed and the DS implementation uses a new functionality of the Configuration Admin service and calls the plugins before it is passing the configuration to components. This ensures, regardless how you get your configuration, plugins will be called making those use cases mentioned above possible.
Conclusion
The standard format for OSGi configurations is a great step forward for tooling and the Configurator implementation allows to deploy configurations through bundles in a standardized and well specified way. The update of the Configuration Admin resolves some long outstanding issues and allows for new use cases around configuration management. Of course, the final R7 specification will continue all the details.