Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic target queries in OSGi with DS

Tags:

osgi

When I use a reference in DS I can specify a target that will allow me to narrow down which service instance I want. The problem is that all the examples show static queries that must be done at code time. Is there a way to do a dynamic query (maybe pull in a property from Configuration Admin)?

If DS does not support this is there another OSGi dependency injection framework (blueprint, iPojo, etc) that will support this?

like image 744
rancidfishbreath Avatar asked Apr 27 '12 18:04

rancidfishbreath


2 Answers

You can always use the target attribute of the reference to peform a first level filter. The if your bind method has the signature

void <method-name>(<parameter-type>, Map);

Then you can run any dynamic filter over the Map which contains the services properties. If the filter does not match, you can ignore that component (for the time being.)

In the alternate, since the component's configuration can contain the reference's target filter, you can modify the component's configuration to alter the target filter.

like image 145
BJ Hargrave Avatar answered Oct 20 '22 06:10

BJ Hargrave


I use the following trick. If you specify a "target" attribute on the service reference but leave its value as the empty string, then a component property with the same name but a ".target" suffix will be used at runtime.

In the example below, I select my JDBC source dynamically via a .cfg file in my Karaf container. The "datasourcefactory.target" property is injected automatically into the "target" attribute of the "datasourcefactory" reference.

Caveat: I don't actually know if this trick is officially supported or just a Felix SCR feature. I've been meaning to look this up in the spec to see if it's mentioned... +1 to any comment that clarifies its legality!

    @Component(
            name = "...",
            specVersion = "1.1",
            policy = ConfigurationPolicy.REQUIRE,
            metatype = true
    )
    @Property(name = "dataSourceFactory.target",
            value = "",
            label = "dataSourceFactory target",
            description = "An OSGi service filter to select the data source provider. "+
                    "For example: '(&(osgi.jdbc.driver.name=derby)(objectClass=org.osgi.service.jdbc.DataSourceFactory))' where 'derby' is the important bit and the rest is boilerplate. "+
                    "See DataSourceFactory.OSGI_JDBC_DRIVER_(NAME,CLASS,VERSION)."
    )
    @Reference(
            name = "dataSourceFactory",
            referenceInterface = org.osgi.service.jdbc.DataSourceFactory.class,
            cardinality = ReferenceCardinality.MANDATORY_UNARY,
            target = "", // must be overwritten by configuration property named "dataSourceFactory.target"
            bind = "bindDataSourceFactory",
            unbind = "unbindDataSourceFactory"
    )
like image 5
Chris Dolan Avatar answered Oct 20 '22 06:10

Chris Dolan