knopflerfish / knopflerfish.org

Knopflerfish OSGi Service Platform. OSGi run-time container and SDK source code repo
http://www.knopflerfish.org
BSD 3-Clause "New" or "Revised" License
33 stars 11 forks source link

Multiple Declarative Services component instances are not created for multiple factory configurations #16

Closed magicmike2248 closed 7 years ago

magicmike2248 commented 7 years ago

This is concerning the Declarative Services SCR bundle (component_all-6.0.0.jar).

According to OSGi Compendium R6 Specification, item 112.7 (Declarative Services Specification / Deployment),

Factory Configuration - If one of the configuration PIDs matches a factory PID, with zero or more Configurations, then for each Configuration of the factory PID, a component configuration must be created that will obtain additional component properties from Configuration Admin.

If I have a component with configuration-policy="require", and multiple Configuration Objects in Configuration Admin with Factory PID matching my component's configuration-pid (which in my case is equal to component name), then for each Configuration Object I should have a Component Instance created and activated, but this is not happening.

Here's my component:

@org.osgi.service.component.annotations.Component(name = "Component", configurationPolicy = ConfigurationPolicy.REQUIRE, immediate = true)
public class Component {

    public Component( ) {
        println("=== Constructor ===");
    }

    @Activate
    public void activate(Map properties) {
        println("=== Activate " + properties.get("number") + " ===");
        println(properties);
    }

    @Deactivate
    public void deactivate(Map properties) {
        println("=== Deactivate " + properties.get("number") + " ===");
        println(properties);
    }

    private void println(Map properties) {
        if (properties != null) {
            Iterator it = properties.entrySet().iterator( );
            while (it.hasNext()) {
                println(it.next().toString());
            }
        }
    }

    private void println(String message) {
        System.out.println(message);
    }
}

And here's the console log of me creating three factory configurations and only the first component instance being created:

enter configuration
configuration> create -f Component
configuration> set number 1
configuration> save
configuration> [stdout] === Constructor ===
[stdout] === Activate 1 ===
[stdout] service.pid=Component._0
[stdout] service.factoryPid=Component
[stdout] component.name=Component
[stdout] number=1
[stdout] component.id=1
create -f Component
configuration> set number 2
configuration> save
configuration> create -f Component
configuration> set number 3
configuration> save
configuration> show
[-] Component._0
 factory PID: Component
 location: -
 change count: 1
 properties:
  number= 1
  service.factoryPid= Component
  service.pid= Component._0
[-] Component._1
 factory PID: Component
 location: -
 change count: 1
 properties:
  number= 2
  service.factoryPid= Component
  service.pid= Component._1
[-] Component._2
 factory PID: Component
 location: -
 change count: 1
 properties:
  number= 3
  service.factoryPid= Component
  service.pid= Component._2
configuration> 
magicmike2248 commented 7 years ago

If I then delete the first configuration object, component instances for two remaining configuration objects are activated:

list
Available configurations:
[0] Component._0
[1] Component._1
[2] Component._2
configuration> delete 0
Deleting Component._0
configuration> [stdout] === Deactivate null ===
[stdout] component.name=Component
[stdout] component.id=1
[stdout] === Constructor ===
[stdout] === Activate 2 ===
[stdout] service.pid=Component._1
[stdout] service.factoryPid=Component
[stdout] component.name=Component
[stdout] number=2
[stdout] component.id=1
[stdout] === Constructor ===
[stdout] === Activate 3 ===
[stdout] service.pid=Component._2
[stdout] service.factoryPid=Component
[stdout] component.name=Component
[stdout] number=3
[stdout] component.id=1

But only one of them is shown by the SCR command:

enter scr
scr> show -f Component
ID State        BID Name
 1 ACTIVE        28 Component
   > No services provided.
   > No referenced services
   > Property component.id = 1
   > Property component.name = Component
   > Property number = 2
   > Property service.factoryPid = Component
   > Property service.pid = Component._1
   > Immediate component, default enabled, config policy = require
scr> enter configuration
configuration> list
Available configurations:
[0] Component._1
[1] Component._2
configuration> delete 0
Deleting Component._1
configuration> [stdout] === Deactivate null ===
[stdout] component.name=Component
[stdout] component.id=1

I don't think "Deactivate null" is right, all component properties should be passed to deactivate method, including number=2, so it should be Deactivate 2.

Here, the last configuration object is deleted, but a Component Instance with configuration-policy="require" is still activated despite having no configurations available.

list
Available configurations:
[0] Component._2
configuration> delete 0
Deleting Component._2
configuration> [stdout] === Deactivate null ===
[stdout] component.name=Component
[stdout] component.id=1
[stdout] === Constructor ===
[stdout] === Activate null ===
[stdout] component.name=Component
[stdout] component.id=1
enter scr
scr> show -f Component
ID State        BID Name
 1 ACTIVE        28 Component
   > No services provided.
   > No referenced services
   > Property component.id = 1
   > Property component.name = Component
   > Immediate component, default enabled, config policy = require
scr> enter configuration
configuration> list
No configurations available
configuration> 
janste63 commented 7 years ago

I've tested test this and can confirm the bug. This bug was introduced in 6.0.0, in the previous version things worked correctly.

janste63 commented 7 years ago

Bug fixed in component(SCR) bundle version 6.0.2.