Introspect Configuration Admin from Gogo Shell

5 minute read

Apache Felix Gogo is by far one of the most potent tools in any OSGi development toolkit. And if you are fortunate enough to have access to a very modern version of Apache Felix Configuration Admin you can already benefit from the fact that you can interact with Configuration Admin through the Gogo shell with the commands:

Note: You may find that when using help the commands come up in camel case. Luckily commands are case insensitive so you can use all lower case to simplify execution if you choose.

listconfigurations

The most useful function right off the bat is to list any existing configurations that might already exist in the framework using the listconfigurations:

g! listconfigurations "(service.pid=*)"
Configuration PID=foo.bar, factoryPID=null, bundleLocation=?
Configuration PID=foo.baz, factoryPID=null, bundleLocation=?

To get all configurations:

g! listconfigurations null
...
Configuration PID=foo.bar, factoryPID=null, bundleLocation=?
Configuration PID=foo.baz, factoryPID=null, bundleLocation=?
...

To get an individual configuration from the list you can use the array syntax:

g! c = (listconfigurations "(service.pid=?)") 0
Properties           [foo=bar, service.pid=foo.bar]
Attributes           []
FactoryPid           null
Pid                  foo.bar
ChangeCount          2
BundleLocation       ?

To list the properties of a configuration in tabular form you can use:

g! $c properties
foo                 bar
service.pid         foo.bar

getconfiguration: Get or create single configurations

You can get a configuration using:

g! c = getconfiguration "foo.biz"
Properties           null
Attributes           []
FactoryPid           null
Pid                  foo.biz
ChangeCount          1
BundleLocation       reference:file:???????/org.apache.felix.gogo.runtime-1.1.4.jar

However, you’ll note that if the configuration doesn’t exist a new instance is returned. The problem is that if you use the single argument getconfiguration AND the configuration does not already exist what you will get is an instance that is only visible to the bundle that triggered the creation (notice the BundleLocation above), which is not usually what you want. In that case you should use:

g! c = getconfiguration "foo.bom" "?"
Properties           null
Attributes           []
FactoryPid           null
Pid                  foo.bom
ChangeCount          1
BundleLocation       ?

Note that now you have a BundleLocation of ? which means it is visible to any bundles that want to read it.

If you don’t want the or create behaviour it’s best to use listconfigurations when searching for configurations (it’s more powerful anyway since you can filter on any properties of the configurations).

Configuration Plugins & Processed Properties

If you happen to have a Configuration Admin that implements the 1.6 version of the spec you might also have Configuration Plugins that are able to alter or interpolate configurations (e.g. Felix ConfigAdmin Interpolation Plugin.)

Suppose you have this FileInstall config called game.pid.config which uses Felix Interpolation Plugin interpolation:

player.initial.lives="$[env:player_initial_lives]"
player.maximum-lives="5"

You’d want to call the getProcessedProperties method of Configuration to cause plugins to execute over the properties. This method does have one argument, a ServiceReference to a service that can contextualize the processing (i.e. to find properties/files for instance.)

In the case of the Felix Interpolation Plugin all you need is a ServiceReference to the ConfigurationAdmin service itself:

g! sr = servicereference org.osgi.service.cm.ConfigurationAdmin

With that you can call the getProcessedProperties method to see the properties fully resolved:

g! (getconfiguration "game.pid") processedproperties $sr
player.initial.lives 3
player.maximum-lives 5

Create configurations from scratch

So let’s say that no configuration exist for the PID and you also want to configure it with properties. First you need a way to create a Dictionary object since that is the argument required by the Configuration.update(Dictionary) method.

You can use the following to create a dictionary object:

g! d = (((bundle 0) loadclass java.util.Hashtable) newInstance)

Add some properties:

g! $d put "Foo" "bar"

Print the result:

g! $d
Foo                 bar

Now you can pass this dictionary to the configuration you have stored in the var c:

g! $c update $d
g! $c
Properties           [Foo=bar, service.pid=foo.bom]
Attributes           []
FactoryPid           null
Pid                  foo.bom
ChangeCount          2
BundleLocation       ?

createfactoryconfiguration: Create factory configurations

The basic incarnation of createfactoryconfiguration has the same gotchas as getconfiguration where it will create a configuration with a BundleLocation limited to the caller bundle. So you should prefer the two argument version as follows:

g! c = createfactoryconfiguration "foo.biz" "?"
Properties           null
Attributes           []
FactoryPid           foo.biz
Pid                  foo.biz.54bf0c1f-a7bd-4bfd-a80f-fedf58793442
ChangeCount          1
BundleLocation       ?

Notice that now the PID contains a generated part, e.g. foo.biz.54bf0c1f-a7bd-4bfd-a80f-fedf58793442.

Setting configuration properties is exactly the same as above.

getfactoryconfiguration: Named factory configurations

Recent versions of Configuration Admin specification make it possible to create named configurations. The command getfactoryconfiguration follows the pattern getConfiguration with it’s get or create paradigm. However, the difference between this and the createfactoryconfiguration is the name argument which allows passing a human readable string to uniquely disambiguate factory configurations beyond the opaque generated suffix normally used for factory configurations which make them hard to identify. Here we also prefer adding the third argument so that we make the configuration readable by any bundle.

g! c = getfactoryconfiguration "foo.biz" "one" "?"
Properties           null
Attributes           []
FactoryPid           foo.biz
Pid                  foo.biz~one
ChangeCount          1
BundleLocation       ?

Notice that in this case the PID is suffixed with a tilde (~) followed by the human readable string argument we passed (one).

What about older versions of Felix Configuration Admin

Earlier I mentioned:

if you are fortunate enough to have access to a very modern version of Apache Felix Configuration Admin you can already benefit from the fact that you can interact with Configuration Admin through the Gogo shell with the commands

Well, it turns out that even if you are using an older version you can still do most of the above provided you create a command from the Configuration Admin service (if the service is available).

First you may need to setup the command context so that you have a few basic commands:

g! addcommand context ${.context}

(This gives you access to commands like servicereference <fqcn|filter>.)

Now you can add the config admin service commands with:

g! addcommand cm (service (servicereference "org.osgi.service.cm.ConfigurationAdmin"))

That’s it! Now everything above should work exactly as documented.

Updated: