Introspect Configuration Admin from Gogo Shell
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:
cm:createfactoryconfiguration
- create a factory configuration (maps to the Configuration Admin methodcreateFactoryConfiguration(String)
orcreateFactoryConfiguration(String,String)
)cm:getconfiguration
- create a single configuration (maps to the Configuration Admin methodgetConfiguration(String)
orgetConfiguration(String,String)
)cm:getfactoryconfiguration
- get or create a factory configuration (maps to the Configuration Admin methodgetFactoryConfiguration(String,String)
orgetFactoryConfiguration(String,String,String)
)cm:listconfigurations
- list configurations (maps to the Configuration Admin methodlistConfigurations(String)
)
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.