Search code examples
javareferenceosgibundledeclarative-services

how to update OSGI @Reference List if my service starts earlier than half of referenced ones


That's one more attempt to make a dig at the theme "there is no order of OSGI bundles activation".

I have 4 services (bundles) which implement the same interface DataProvider meaning they implement it literally and also have it as service = { DataProvider.class } at their @Component annotations. This interface provides something like diagnostic data from these services. I want to collect this data from all 4 services and to print it on the GUI, which is also an OSGI bundle in my big framework. In order to do that I created such a reference in my GUI bundle:

@Reference
private volatile List<DataProvider> dataProvider;

and then I want to iterate over that list and append to the GUI's textframe everything I need.

The problem is that at the moment when GUI bundle starts, only two of four services are activated, so my list will contain only two service objects instead of all four and print only them. The last two services are loaded after my GUI Bundle has been already activated, because they also wait until their own references become fully satisfied (where some network operations are done, so it takes some time, around 10 seconds). Of course I want my GUI to show the diagnostic data from all 4 services. What could I do for that?

I tried to add policyOption = ReferencePolicyOption.GREEDY to the @Reference annotation, I expected it would force to reactivate GUI bundle each time this List<DataProvider> dataProvider receives a new member, but no, it didn't happen.

P.S. yes there is certainly a straightforward solution: just to add Thread.sleep() to the GUI Bundle with some appropriate value, so to the time of awakening the discussed above list will be full. But this is really bad thing, I don't want the user waits like 10 seconds before GUI appears, not to speak about the situations, when something goes wrong.


Solution

  • You can specify the minimum cardinality in the configuration. In your case, this is specified with the dataProvider.minimum.cardinality property in the configuration for your component. (See section 112.6.2.2 Minimum Cardinality Property.)

    package com.example;
    @Component
    public class Diagnostics {
        @Reference
        List<DataProvider> dataProvider;
    }
    

    So then you need to add a configuration record for PID com.example.Diagnostics:

    dataProvider.minimum.cardinality = 4
    

    This model of using configuration works very well with the Configurator Specification. With this specification, you can specify the configuration of an application in a bundle.

    Alternatively, you can create 4 references and distinguish the services by a property, using the target annotation method to specify a filter.