0

Here is snippet of intrested case:

We have some configuration class it can have multi instances. It suppose that we supply several configurations in one bundle. It's one scope.

@Service
@Component
public class SampleConfigurationImpl implements SampleConfiguration {
    // declaration of some properties, init method and etc...
}

Also we have a service which uses these configurations:

@Service
@Component
public class SampleServiceImpl implements SampleService {

    @Reference(
        referenceInterface = SampleConfiguration.class,
        cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
        policy = ReferencePolicy.DYNAMIC)
    private Map<String, SampleConfiguration> sampleConfigurations = new ConcurrentHashMap<>();

    private void bindSampleConfigurations(SampleConfiguration sampleConfiguration) {
        sampleConfigurations.put(sampleConfiguration.getName(), sampleConfiguration);
    }

    private void unbindSampleConfigurations(SampleConfiguration sampleConfiguration) {
        sampleConfigurations.remove(sampleConfiguration.getName());
    }

    @Activate
    private void init() {
        System.out.println(sampleConfigurations.size());
    }

}

So, can I get some guarantees that on invocation of init method all configurations are injected (at least of current bundle)? Maybe there is some alternative way to do this. I understand that another bundles can bring new configurations and it's unreal to get guarantees but it's intrested in case of only one bundle.

On practice it can be case when in init method there are only part of configurations. Especially if it's more difficalt case when you have several types of configuration or one service uses another one which has dynamic references and first service relies on fact that everything is injected.

The most unpleasant is that it can bind/unbind configurations both before and after init method. Maybe there is some way to guarantee that it bind always after init method...

I'm interested in any information. It will be great to get answer on two questions (guarantees before or after). Probably someone has experience how to resolve such problem and can share with me.

Thanks.

Alex
  • 139
  • 2
  • 8

1 Answers1

1

No, not that I know of. What I usually do in that case (depending on your use case, it depends on if your activation code is ok with running multiple times) is to create a 'reallyActivate' method I call both from the regular activate and from the bindSampleConfigurations (+ setting an isActivated flag in activate). Then I can perform some logic every time a new SampleConfiguration gets bound, even if it's after the activation. Does that help for your case?

Frank Lee
  • 2,728
  • 19
  • 30
  • 1
    Frank is correct. Dynamic references may be bound at any time before, after or *during* activation (yes, a service can be bound concurrently from another thread while your activate method is executing). This is simply the price of dynamic references... you may want to use a static reference with the greedy policy instead. By the way, it's suspicious that you are using services to inject configuration. Why not use the Config Admin binding for DS, where the configuration object is passed into the activate method? – Neil Bartlett Sep 04 '17 at 21:28
  • Thank you Frank. It can help me, but in this case I have to take into account that it has to bind configuration before and after init method differently (before init method I'm not sure that all static references are injected and I need to postpone it after init method). Also I have to create some queue of unprocessed configurations and after init method process it. It brings additional logic which synchronizes a state of such service to reflect binding of new configurations. I agree, it sounds strangely. – Alex Sep 05 '17 at 13:44
  • @NeilBartlett thank you too. Am I right that by Config Admin binding for DS you mean adding of configurationPid="com.sample.SampleConfigurationImpl" attribute for SampleServiceImpl? In this case it creates N servers where N is number of configurations. It does not suit when I need to inject this service to another component. Why not? I want to have some service which can process a request and which can decide what the configuration it needs to use for particular parameters. Sounds reasonable. So, even if I call a servlet of current bundle I'm not sure all configurations are bound. – Alex Sep 06 '17 at 04:56
  • 1
    The thing I don't quite understand is at what point do you know what dependencies are essential for your component? If you know that at compile time, perhaps it makes sense to make multiple dependencies and select a specific dependency using a 'target' setter. Then you can simple make those dependencies mandatory and then you can be certain that your activate method only gets called after those have been satisfied. – Frank Lee Sep 06 '17 at 11:57
  • @FrankLee It make sence but in such case my code looks like: @Reference(target="(&(objectclass=com.sample.SampleConfigurationImpl)(some.property=1))") private SampleConfiguration config1; @Reference(target="(&(objectclass=com.sample.SampleConfigurationImpl)(some.property=2))") private SampleConfiguration config2; @Reference(target="(&(objectclass=com.sample.SampleConfigurationImpl)(some.property=3))") private SampleConfiguration config3; etc... Especially I have to know how many configurations I keep. Of course I need some mapping but I can do this at runtime. No hardcode – Alex Sep 06 '17 at 12:06
  • @FrankLee For example: I have some service which converts data. It has single configuration. It's simple. In this configuration I can choose some strategy how to convert data. I want to switch strategy when I change this configuration. Sounds pretty simple. Let's imagine that there are N strategy implementations. I what to use felix DI for each strategy. At runtime I can get it and figure out what I need according to current configuration. It's not necessary to hardcode the mapping. – Alex Sep 06 '17 at 12:25
  • 1
    Yes, I understand, that case isn't supported, and I've missed it often, you can't base your dependencies on configuration, as configuration and activation are essentially the same step. The only thing you can do is listen for all services, and decide every time you activate or a dependency appears if you are 'really' active. It's a lot of ugly code, but it does work. – Frank Lee Sep 06 '17 at 21:51
  • @FrankLee Thank you. Unfortunately I have to live in such unbalance until I stop using this OSGi DI. – Alex Sep 07 '17 at 10:09