Pierre De Rop created FELIX-4913:
------------------------------------

             Summary: DM Optional callbacks may sometimes be invoked twice
                 Key: FELIX-4913
                 URL: https://issues.apache.org/jira/browse/FELIX-4913
             Project: Felix
          Issue Type: Bug
          Components: Dependency Manager
    Affects Versions: org.apache.felix.dependencymanager-r3
            Reporter: Pierre De Rop
            Assignee: Pierre De Rop
             Fix For: org.apache.felix.dependencymanager-r4


The following use case is not currently supported by the DM state machine, 
which suffers from a bug where sometimes, when the use case happens, the same 
optional callback may be invoked twice.

The following case is supported by DS, so DM should support it, regardless of 
the fact that the design of this use case is arguable/questionable:

- there is a component B
- there is a component BFactory (registered in the OSGI registry). And 
BFactory.createB() creates a B instance and simply registers it in the OSGi 
registry.
- there is a A component that has two OPTIONAL dependencies:

{code}
  A.bind(BFactory)
  A.bind(B b)
{code}

- Then A is created and is starting. Since BFactory is available, the DM state 
machine for A transits from the INSTANTIATED_AND_WAITING_FOR_REQUIRED into the  
TRACKING_OPTIONAL state:

{code}
        if (oldState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED && 
newState == ComponentState.TRACKING_OPTIONAL) {
            invokeAutoConfigInstanceBoundDependencies();
            invokeAddRequiredInstanceBoundDependencies();
            invoke(m_callbackStart);
            invokeAddOptionalDependencies();
            registerService();
            notifyListeners(newState);
            return true;
        }
{code}

- then, when the invokeAddOptionalDependencies() is running, it is invoking 
A.bind(BFactory b). At this exact point, the A.bind(BFactory) method calls 
bf.createB():

{code}
A.bind(BFactory bf) {
    bf.createB();
}
{code}

- this has the following side effect: a B service is synchronously registered 
in the OSGI service registry. So ComponentImpl.handleAdded() is called, and 
since we are in the
TRACKING_OPTIONAL state (we are entering into this state), then the A.bindB(B 
b) callback is invoked.

- BUT ... we are still running in the invokeAddOptionalDependencies() method. 
So when that method is about to iterate on the available services of the B 
dependency, then it calls a
second time the "A.bind(B)" callback.

I have a patch for this use case, which I have extensively tested since two 
days.

To preserve my soul, the patch is simple and conservative: I use the same 
technique that was done in the ConfigurationDependencyImpl class: I'm using a 
cache of callbacks that ensures that the same callback won't be invoked more 
than one time. The advantage of this patch is that it does not make too much 
polutions in the state machine which is not altered too much.

I will also commit a test case which demonstrates the issue.




--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to