Hi David,

Thanks, I just created the FELIX-4984
<https://issues.apache.org/jira/browse/FELIX-4984> issue and described
everything in it.

I have not yet modified the SCR core. I only ported SCR project to bndtools
and integrated it in the DM project. what I did so far is that I reworked
the SCR tests in order to not use anymore pax-exam and simply rely on
BndTools integration tests.

So unless I did a mistake while reworking the tests, I think it's worth
that you take a look in case there is really a pending bug somewhere that
is sometimes reproduced by the CircularReferenceTest.
(I can't reproduce it using maven from the current felix-trunk/scr/).

In the meantime, I will also continue to investigate.

thank you.
/Pierre



On Thu, Jul 30, 2015 at 6:49 AM, David Jencks <[email protected]>
wrote:

> Hi Pierre,
>
> Please open a jira.  I will try to look into this soon.
>
> I haven’t had much time lately but I would like to move the existing
> feliix DS to bndtools no matter whether your idea of making DM support DS
> works or not :-).  Is your current work available somewhere?
>
> thanks
> david jencks
>
> > On Jul 29, 2015, at 6:53 PM, Pierre De Rop <[email protected]>
> wrote:
> >
> > Hello all;
> >
> > While working on FELIX-4955
> > <https://issues.apache.org/jira/browse/FELIX-4955> I think I'm facing an
> > issue with the CircularReferenceTest in the SCR integration tests.
> >
> > Unfortunately, I can not currently reproduces this problem in the scr
> > maven/pax-exam environment. I can only (sometimes, not always) reproduce
> it
> > under bndtools in the context of FELIX-4955.
> > <https://issues.apache.org/jira/browse/FELIX-4955>
> >
> > The problem comes from the
> > CircularReferenceTest.test_A11_B01_delayed_B_first() method: sometimes,
> > this test fails because A component has been bound with two B instances
> and
> > the following assertion fails:
> >
> >        assertEquals( 1, a.getBs().size());
> >
> > I'm showing now the original code from the scr integration test:
> >
> >    @Test
> >    public void test_A11_B01_delayed_B_first() throws Exception
> >    {
> >        String componentNameA = "7.A.1.1.dynamic";
> >        ComponentConfigurationDTO componentA =
> > findComponentConfigurationByName( componentNameA,
> > ComponentConfigurationDTO.SATISFIED );
> >
> >        String componentNameB = "7.B.0.1.dynamic";
> >        final ComponentConfigurationDTO componentB =
> > findComponentConfigurationByName( componentNameB,
> > ComponentConfigurationDTO.SATISFIED );
> >
> >        ServiceReference[] serviceReferencesB =
> > bundleContext.getServiceReferences( B.class.getName(), "(service.pid=" +
> > componentNameB + ")" );
> >        TestCase.assertEquals( 1, serviceReferencesB.length );
> >        ServiceReference serviceReferenceB = serviceReferencesB[0];
> >        Object serviceB = bundleContext.getService( serviceReferenceB );
> >        assertNotNull( serviceB );
> >
> >        ServiceReference[] serviceReferencesA =
> > bundleContext.getServiceReferences( A.class.getName(), "(service.pid=" +
> > componentNameA + ")" );
> >        TestCase.assertEquals( 1, serviceReferencesA.length );
> >        ServiceReference serviceReferenceA = serviceReferencesA[0];
> >        Object serviceA = bundleContext.getService( serviceReferenceA );
> >        assertNotNull( serviceA );
> >
> >
> >        delay();
> >        A a = getServiceFromConfiguration(componentA, A.class);
> >
> ------------------------------------------------------------------------------------------------------------
> > ->         assertEquals( 1, a.getBs().size()); // this assert sometimes
> > fails and a.getBs().size() returns 2
> >
> ------------------------------------------------------------------------------------------------------------
> >        B b = getServiceFromConfiguration(componentB, B.class);
> >        assertEquals( 1, b.getAs().size() );
> >
> >
> >        //disabling (removing the A service registration) and re-enabling
> > will
> >        //result in a service event to B, so B will bind A.
> >        disableAndCheck(componentA);
> >        delay();
> >        enableAndCheck(componentA.description);
> >        delay();
> >
> >        //new component.id, refetch configuration.
> >        componentA = findComponentConfigurationByName( componentNameA,
> > ComponentConfigurationDTO.ACTIVE );
> >        a = getServiceFromConfiguration(componentA, A.class);
> >        assertEquals( 1, a.getBs().size());
> >        b = getServiceFromConfiguration(componentB, B.class);
> >        assertEquals( 1, b.getAs().size() );
> >
> >    }
> >
> > Sometimes, the a.getBs().size() method returns 2 and this test fails.
> >
> > I have tried to make a diagnostic and here is my current understanding of
> > the problem:
> >
> > - I have added some logs in the A component like this: (a log is done
> when
> > A.setB(B b) is called, and the stacktrace call is stored in
> "bsStackTraces"
> > list:
> >
> > public class A
> > {
> >    private List<B> bs = new ArrayList<B>();
> >    private List<Exception> bsStackTraces = new ArrayList<>();
> >
> >    private boolean activated;
> >
> >    private void activate(ComponentContext cc)
> >    {
> >        activated = true;
> >    }
> >
> >    private void setB(B b)
> >    {
> >        System.out.println(Thread.currentThread().getName() + ":" +
> > "A.setB(" + b + ")");
> >        bs.add( b );
> >        bsStackTraces.add(new Exception());
> >    }
> >
> >    private void unsetB(B b)
> >    {
> >        System.out.println(Thread.currentThread().getName() + ":" +
> > "A.unsetB(" + b + ")");
> >        bs.remove( b );
> >        bsStackTraces.remove(bsStackTraces.size()-1);
> >    }
> >
> >    public List<B> getBs()
> >    {
> >        return bs;
> >    }
> >
> >    public void dumpStackTracesWhenBWasBound() {
> >        System.out.println("stack traces when B was bound:");
> >        for (Exception e : bsStackTraces) {
> >            e.printStackTrace();
> >        }
> >    }
> > }
> >
> > - so, under bndtools (in the context of FELIX-4955
> > <https://issues.apache.org/jira/browse/FELIX-4955>), I see that
> A.setB(B b)
> > is called twice:
> >
> >
> main:A.setB(org.apache.felix.scr.integration.components.circular.B@192d43ce
> )
> > SCR Component
> >
> Actor:A.setB(org.apache.felix.scr.integration.components.circular.B@192d43ce
> > )
> >
> > here, a.setB(B b) is first called from the main thread, and called a
> second
> > time from the component actor thread.
> >
> > - now, from the test method, I have added this debug statement:
> >
> >    @Test
> >    public void test_A11_B01_delayed_B_first() throws Exception
> >    {
> >        String componentNameA = "7.2.A.1.1.dynamic";
> >        ComponentConfigurationDTO componentA =
> > findComponentConfigurationByName( componentNameA,
> > ComponentConfigurationDTO.SATISFIED );
> >
> >        String componentNameB = "7.2.B.0.1.dynamic";
> >        final ComponentConfigurationDTO componentB =
> > findComponentConfigurationByName( componentNameB,
> > ComponentConfigurationDTO.SATISFIED );
> >
> >        ServiceReference[] serviceReferencesB =
> > bundleContext.getServiceReferences( B.class.getName(), "(service.pid=" +
> > componentNameB + ")" );
> >        TestCase.assertEquals( 1, serviceReferencesB.length );
> >        ServiceReference serviceReferenceB = serviceReferencesB[0];
> >        Object serviceB = bundleContext.getService( serviceReferenceB );
> >        assertNotNull( serviceB );
> >
> >        ServiceReference[] serviceReferencesA =
> > bundleContext.getServiceReferences( A.class.getName(), "(service.pid=" +
> > componentNameA + ")" );
> >        TestCase.assertEquals( 1, serviceReferencesA.length );
> >        ServiceReference serviceReferenceA = serviceReferencesA[0];
> >        Object serviceA = bundleContext.getService( serviceReferenceA );
> >        assertNotNull( serviceA );
> >
> >
> >        delay();
> >        A a = getServiceFromConfiguration(componentA, A.class);
> >        // TODO remove
> >        if (a.getBs().size() != 1) {
> >            System.err.println("detected problem ...");
> >            a.dumpStackTracesWhenBWasBound();
> >        }
> >        assertEquals( 1, a.getBs().size());
> >        ...
> >
> > so, when a.getBs().size() does not return 1, we call
> > "a.dumpStackTracesWhenBWasBound()" and here are those stacktraces:
> >
> > stack traces when B was bound:
> > java.lang.Exception
> >    at
> > org.apache.felix.scr.integration.components.circular.A.setB(A.java:48)
> >    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
> >    at
> >
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> >    at java.lang.reflect.Method.invoke(Method.java:497)
> >    at
> >
> org.apache.felix.scr.impl.helper.BaseMethod.invokeMethod(BaseMethod.java:222)
> >    at
> >
> org.apache.felix.scr.impl.helper.BaseMethod.access$500(BaseMethod.java:37)
> >    at
> >
> org.apache.felix.scr.impl.helper.BaseMethod$Resolved.invoke(BaseMethod.java:615)
> >    at
> > org.apache.felix.scr.impl.helper.BaseMethod.invoke(BaseMethod.java:499)
> >    at
> > org.apache.felix.scr.impl.helper.BindMethod.invoke(BindMethod.java:41)
> >    at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.doInvokeBindMethod(DependencyManager.java:1653)
> >    at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.open(DependencyManager.java:1491)
> >    at
> >
> org.apache.felix.scr.impl.manager.SingleComponentManager.createImplementationObject(SingleComponentManager.java:265)
> >    at
> >
> org.apache.felix.scr.impl.manager.SingleComponentManager.createComponent(SingleComponentManager.java:113)
> >    at
> >
> org.apache.felix.scr.impl.manager.SingleComponentManager.getService(SingleComponentManager.java:847)
> >    at
> >
> org.apache.felix.scr.impl.manager.SingleComponentManager.getServiceInternal(SingleComponentManager.java:814)
> >    at
> >
> org.apache.felix.scr.impl.manager.SingleComponentManager.getService(SingleComponentManager.java:763)
> >    at
> >
> org.apache.felix.framework.ServiceRegistrationImpl.getFactoryUnchecked(ServiceRegistrationImpl.java:347)
> >    at
> >
> org.apache.felix.framework.ServiceRegistrationImpl.getService(ServiceRegistrationImpl.java:247)
> >    at
> >
> org.apache.felix.framework.ServiceRegistry.getService(ServiceRegistry.java:343)
> >    at org.apache.felix.framework.Felix.getService(Felix.java:3692)
> >    at
> >
> org.apache.felix.framework.BundleContextImpl.getService(BundleContextImpl.java:470)
> >    at
> >
> org.apache.felix.scr.integration.CircularReferenceTest.test_A11_B01_delayed_B_first(CircularReferenceTest.java:255)
> >    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> >    at
> >
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> >    at
> >
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> >    at java.lang.reflect.Method.invoke(Method.java:497)
> >    at junit.framework.TestCase.runTest(TestCase.java:176)
> >    at junit.framework.TestCase.runBare(TestCase.java:141)
> >    at junit.framework.TestResult$1.protect(TestResult.java:122)
> >    at junit.framework.TestResult.runProtected(TestResult.java:142)
> >    at junit.framework.TestResult.run(TestResult.java:125)
> >    at junit.framework.TestCase.run(TestCase.java:129)
> >    at junit.framework.TestSuite.runTest(TestSuite.java:255)
> >    at junit.framework.TestSuite.run(TestSuite.java:250)
> >    at junit.framework.TestSuite.runTest(TestSuite.java:255)
> >    at junit.framework.TestSuite.run(TestSuite.java:250)
> >    at aQute.junit.Activator.test(Activator.java:303)
> >    at aQute.junit.Activator.run(Activator.java:128)
> >    at aQute.launcher.Launcher$5.call(Launcher.java:1175)
> >    at aQute.launcher.Launcher$5.call(Launcher.java:1173)
> >    at aQute.launcher.Launcher.run(Launcher.java:278)
> >    at aQute.launcher.Launcher.main(Launcher.java:87)
> >
> > java.lang.Exception
> >    at
> > org.apache.felix.scr.integration.components.circular.A.setB(A.java:48)
> >    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
> >    at
> >
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> >    at java.lang.reflect.Method.invoke(Method.java:497)
> >    at
> >
> org.apache.felix.scr.impl.helper.BaseMethod.invokeMethod(BaseMethod.java:222)
> >    at
> >
> org.apache.felix.scr.impl.helper.BaseMethod.access$500(BaseMethod.java:37)
> >    at
> >
> org.apache.felix.scr.impl.helper.BaseMethod$Resolved.invoke(BaseMethod.java:615)
> >    at
> > org.apache.felix.scr.impl.helper.BaseMethod.invoke(BaseMethod.java:499)
> >    at
> > org.apache.felix.scr.impl.helper.BindMethod.invoke(BindMethod.java:41)
> >    at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.doInvokeBindMethod(DependencyManager.java:1653)
> >    at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.invokeBindMethod(DependencyManager.java:1629)
> >    at
> >
> org.apache.felix.scr.impl.manager.SingleComponentManager.invokeBindMethod(SingleComponentManager.java:370)
> >    at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.invokeBindMethodLate(DependencyManager.java:1573)
> >    at
> >
> org.apache.felix.scr.impl.ComponentRegistry$1.run(ComponentRegistry.java:570)
> >    at
> >
> org.apache.felix.scr.impl.ComponentActorThread.run(ComponentActorThread.java:99)
> >    at java.lang.Thread.run(Thread.java:745)
> >
> > So, in the first stacktrace, a.setB(B b) is called when the
> > test_A11_B01_delayed_B_first method calls
> > "Object serviceA = bundleContext.getService( serviceReferenceA );" which
> > then calls SingleComponentManager.createComponent() method. And that
> method
> > then calls createImplementationObject which then opens the
> > DependencyManager, which then calls A.bind(A b).
> >
> > But now in the second stacktrace (which comes from the componen actor
> > thread), "A.setB(B b)" is called a second time because in the first
> > stacktrace, the SingleComponentManager.createComponent() method has
> > schedule a task in the actor thread like this:
> >
> >
> >            if ( activator != null )
> >            {
> >                activator.missingServicePresent( getServiceReference() );
> >            }
> >
> > and the missingServicePresent schedules in the ComponentActor thread a
> task
> > which then calls invokeBindLate, which then finally calls a second time
> the
> > A.bind(B b) method.
> >
> > Am I correct with this diagnostic ? Should I open a jira issue ?
> >
> > thank you;
> > /Pierre
>
>

Reply via email to