You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@felix.apache.org by Pierre De Rop <pi...@gmail.com> on 2012/02/16 16:10:46 UTC

a question of Declarative Service specification

Hi everyone,

This post is about a question regarding SCR and especially about SCR
Component Factory:

When a component A is defined with a factory attribute, then SCR is
intended to register an org.osgi.service.component.ComponentFactory inside
the registry, in order to allow another component to be injected with that
ComponentFactory. This way, some other components may programatically
instantiate one (or several instances) of the component A.

The question is: should the ComponentFactory be registered only once the A
component is satisfied
(that is: after all A required dependencies are available) ?

I guess yes, because in DS spec, (112.2.4), it is stated the following:

"... SCR must register a Component Factory service on behalf of the
component
as soon as the component factory is satisfied."

I ask this question because I'm facing the following issue:

I have a component A, which depends on B1(property=b2) like this:

public interface B {
}

@Component(factory = "A")
public class A /* implements something which required B2 */ {
    @Reference(target = "(property=b2)")
    void bind(B b, Map<?, ?> properties) {
        System.out.println("A.bind(b=" + b + ", properties=" + properties +
")");
    }

    @Activate
    void start() {
        System.out.println("A.start");
    }
}

And here is the component which is in charge of instantiating A:

@Component
public class AFactory {
    @Reference(target = "(component.factory=A)")
    void bind(ComponentFactory aFactory) {
        System.out.println("AFactory: bound aFactory=" + aFactory);
        try {
            ComponentInstance ci = aFactory.newInstance(null);
            A a = (A) ci.getInstance();
            System.out.println("AFactory: created instance of a: " + a);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

Now, I have B1, defined like this:

@Component(properties = { "property=b1" })
public class B1 implements B {
}

and I then have B2 (which is the one required by A):

@Component(enabled=false, properties = { "property=b2" })
public class B2 implements B {
}

Here, B2 is declared with "enabled=false", meaning that the component B2 is
not activated by default, at startup time.
So, B2 is meant to be manually enabled from web console.

So, what I expect is the following:

1) When B2 is enabled from web console (using the "Component" menu), then
B2 is registered in the registry.
2) At this point, I expect A to become satisfied, because A is depending of
service B2 (with property=b2).
3) Then I expect the ComponentFactory of A to be registered in the OSGi
registry.
4) Finally, AFactory is activated, and then instantiates A (using the
injected A ComponentFactory).

The problem is that when I start the framework, it seems that the AFactory
component is immediately registered
with the ComponentFactory of A, while at this point A is not yet satisfied
(because at startup, only B1 is available, and
B2 is not yet available). So when AFactory instantiates A (using
ComponentFactory.newInstance), I then get the exception:

g! AFactory: bound aFactory=Component: test.scr.factory.A (1)
org.osgi.service.component.ComponentException: Failed activating component
        at
org.apache.felix.scr.impl.manager.ComponentFactoryImpl.newInstance(ComponentFactoryImpl.java:120)
        at test.scr.factory.AFactory.bind(AFactory.java:15)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at
org.apache.felix.scr.impl.helper.BaseMethod.invokeMethod(BaseMethod.java:227)
        at
org.apache.felix.scr.impl.helper.BaseMethod.access$500(BaseMethod.java:38)
        at
org.apache.felix.scr.impl.helper.BaseMethod$Resolved.invoke(BaseMethod.java:595)
        at
org.apache.felix.scr.impl.helper.BaseMethod$NotResolved.invoke(BaseMethod.java:552)
        at
org.apache.felix.scr.impl.helper.BaseMethod.invoke(BaseMethod.java:476)
        at
org.apache.felix.scr.impl.manager.DependencyManager.invokeBindMethod(DependencyManager.java:1028)
        at
org.apache.felix.scr.impl.manager.DependencyManager.bind(DependencyManager.java:944)
        at
org.apache.felix.scr.impl.manager.DependencyManager.open(DependencyManager.java:868)
        at
org.apache.felix.scr.impl.manager.ImmediateComponentManager.createImplementationObject(ImmediateComponentManager.java:200)
        at
org.apache.felix.scr.impl.manager.ImmediateComponentManager.createComponent(ImmediateComponentManager.java:118)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1140)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
        at
org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
        at
org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
        at
org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
        at
org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
        at
org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
        at
org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
        at org.apache.felix.framework.Felix.registerService(Felix.java:3275)
        at
org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
        at
org.apache.felix.scr.impl.manager.ComponentFactoryImpl.registerService(ComponentFactoryImpl.java:173)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
        at
org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
        at
org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
        at
org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
        at
org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
        at
org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
        at
org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
        at org.apache.felix.framework.Felix.registerService(Felix.java:3275)
        at
org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager.registerService(AbstractComponentManager.java:456)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
        at
org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:158)
        at
org.apache.felix.scr.impl.config.ImmediateComponentHolder.enableComponents(ImmediateComponentHolder.java:313)
        at
org.apache.felix.scr.impl.BundleComponentActivator.loadDescriptor(BundleComponentActivator.java:241)
        at
org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:147)
        at
org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:111)
        at
org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:274)
        at
org.apache.felix.scr.impl.Activator.bundleChanged(Activator.java:192)
        at
org.apache.felix.framework.util.EventDispatcher.invokeBundleListenerCallback(EventDispatcher.java:868)
        at
org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:789)
        at
org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:514)
        at org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:4244)
        at org.apache.felix.framework.Felix.startBundle(Felix.java:1923)
        at
org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1191)
        at
org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:295)
        at java.lang.Thread.run(Thread.java:662)

And after I enable B2 from webconsole, then nothing happens, and AFactory
is not injected with the A Component Factory anymore.

Am I making sense with all this ? Is there really an issue in SCR to be
reported in jira ?
(I reported this in an old issue FELIX-3090 which is currently closed, but
I still feel there is something to it).

thanks for your help;

/pierre

Re: a question of Declarative Service specification

Posted by Felix Meschberger <fm...@adobe.com>.
Hi,

Am 17.02.2012 um 15:25 schrieb Pierre De Rop:

> Thank you Felix, I tested the fix and it's working fine.

Cool. Thanks for the feedback,

> 
> PS: will you close the issue, or should I ?

I will close it once I cut the release.

Regards
Felix

> 
> regards;
> /Pierre
> 
> On Fri, Feb 17, 2012 at 2:31 PM, Felix Meschberger <fm...@adobe.com>wrote:
> 
>> Hi Pierre
>> 
>> I committed a fix, if you like to check. Thanks.
>> 
>> Regards
>> Felix
>> 
>> Am 17.02.2012 um 12:40 schrieb Pierre De Rop:
>> 
>>> Hi Felix,
>>> 
>>> Thanks a lot for reopening this issue.
>>> 
>>> kind regards;
>>> /Pierre
>>> 
>>> On Fri, Feb 17, 2012 at 12:26 PM, Felix Meschberger <fmeschbe@adobe.com
>>> wrote:
>>> 
>>>> Hi Pierre,
>>>> 
>>>> Thanks for insisting ...
>>>> 
>>>> I revert my earlier opinion and now think you are right: The
>> satisfaction
>>>> of the ComponentFactory service must include the target properties.
>>>> 
>>>> The newInstance method may be provided with different target property
>>>> values and cause the desired instance to not be satisfiable and thus
>> fail.
>>>> 
>>>> I have reopened the issue and will reconsider your patch.
>>>> 
>>>> Regards
>>>> Felix
>>>> 
>>>> Am 16.02.2012 um 16:10 schrieb Pierre De Rop:
>>>> 
>>>>> Hi everyone,
>>>>> 
>>>>> This post is about a question regarding SCR and especially about SCR
>>>>> Component Factory:
>>>>> 
>>>>> When a component A is defined with a factory attribute, then SCR is
>>>>> intended to register an org.osgi.service.component.ComponentFactory
>>>> inside
>>>>> the registry, in order to allow another component to be injected with
>>>> that
>>>>> ComponentFactory. This way, some other components may programatically
>>>>> instantiate one (or several instances) of the component A.
>>>>> 
>>>>> The question is: should the ComponentFactory be registered only once
>> the
>>>> A
>>>>> component is satisfied
>>>>> (that is: after all A required dependencies are available) ?
>>>>> 
>>>>> I guess yes, because in DS spec, (112.2.4), it is stated the following:
>>>>> 
>>>>> "... SCR must register a Component Factory service on behalf of the
>>>>> component
>>>>> as soon as the component factory is satisfied."
>>>>> 
>>>>> I ask this question because I'm facing the following issue:
>>>>> 
>>>>> I have a component A, which depends on B1(property=b2) like this:
>>>>> 
>>>>> public interface B {
>>>>> }
>>>>> 
>>>>> @Component(factory = "A")
>>>>> public class A /* implements something which required B2 */ {
>>>>>  @Reference(target = "(property=b2)")
>>>>>  void bind(B b, Map<?, ?> properties) {
>>>>>      System.out.println("A.bind(b=" + b + ", properties=" + properties
>>>> +
>>>>> ")");
>>>>>  }
>>>>> 
>>>>>  @Activate
>>>>>  void start() {
>>>>>      System.out.println("A.start");
>>>>>  }
>>>>> }
>>>>> 
>>>>> And here is the component which is in charge of instantiating A:
>>>>> 
>>>>> @Component
>>>>> public class AFactory {
>>>>>  @Reference(target = "(component.factory=A)")
>>>>>  void bind(ComponentFactory aFactory) {
>>>>>      System.out.println("AFactory: bound aFactory=" + aFactory);
>>>>>      try {
>>>>>          ComponentInstance ci = aFactory.newInstance(null);
>>>>>          A a = (A) ci.getInstance();
>>>>>          System.out.println("AFactory: created instance of a: " + a);
>>>>>      }
>>>>>      catch (Throwable t) {
>>>>>          t.printStackTrace();
>>>>>      }
>>>>>  }
>>>>> }
>>>>> 
>>>>> Now, I have B1, defined like this:
>>>>> 
>>>>> @Component(properties = { "property=b1" })
>>>>> public class B1 implements B {
>>>>> }
>>>>> 
>>>>> and I then have B2 (which is the one required by A):
>>>>> 
>>>>> @Component(enabled=false, properties = { "property=b2" })
>>>>> public class B2 implements B {
>>>>> }
>>>>> 
>>>>> Here, B2 is declared with "enabled=false", meaning that the component
>> B2
>>>> is
>>>>> not activated by default, at startup time.
>>>>> So, B2 is meant to be manually enabled from web console.
>>>>> 
>>>>> So, what I expect is the following:
>>>>> 
>>>>> 1) When B2 is enabled from web console (using the "Component" menu),
>> then
>>>>> B2 is registered in the registry.
>>>>> 2) At this point, I expect A to become satisfied, because A is
>> depending
>>>> of
>>>>> service B2 (with property=b2).
>>>>> 3) Then I expect the ComponentFactory of A to be registered in the OSGi
>>>>> registry.
>>>>> 4) Finally, AFactory is activated, and then instantiates A (using the
>>>>> injected A ComponentFactory).
>>>>> 
>>>>> The problem is that when I start the framework, it seems that the
>>>> AFactory
>>>>> component is immediately registered
>>>>> with the ComponentFactory of A, while at this point A is not yet
>>>> satisfied
>>>>> (because at startup, only B1 is available, and
>>>>> B2 is not yet available). So when AFactory instantiates A (using
>>>>> ComponentFactory.newInstance), I then get the exception:
>>>>> 
>>>>> g! AFactory: bound aFactory=Component: test.scr.factory.A (1)
>>>>> org.osgi.service.component.ComponentException: Failed activating
>>>> component
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.newInstance(ComponentFactoryImpl.java:120)
>>>>>      at test.scr.factory.AFactory.bind(AFactory.java:15)
>>>>>      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>>>      at
>>>>> 
>>>> 
>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>>>>>      at
>>>>> 
>>>> 
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>>>>>      at java.lang.reflect.Method.invoke(Method.java:597)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.helper.BaseMethod.invokeMethod(BaseMethod.java:227)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.helper.BaseMethod.access$500(BaseMethod.java:38)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.helper.BaseMethod$Resolved.invoke(BaseMethod.java:595)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.helper.BaseMethod$NotResolved.invoke(BaseMethod.java:552)
>>>>>      at
>>>>> org.apache.felix.scr.impl.helper.BaseMethod.invoke(BaseMethod.java:476)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.invokeBindMethod(DependencyManager.java:1028)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.bind(DependencyManager.java:944)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.open(DependencyManager.java:868)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createImplementationObject(ImmediateComponentManager.java:200)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createComponent(ImmediateComponentManager.java:118)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1140)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
>>>>>      at
>>>>> org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
>>>>>      at
>>>> org.apache.felix.framework.Felix.registerService(Felix.java:3275)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.registerService(ComponentFactoryImpl.java:173)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
>>>>>      at
>>>>> org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
>>>>>      at
>>>> org.apache.felix.framework.Felix.registerService(Felix.java:3275)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerService(AbstractComponentManager.java:456)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:158)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.config.ImmediateComponentHolder.enableComponents(ImmediateComponentHolder.java:313)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.BundleComponentActivator.loadDescriptor(BundleComponentActivator.java:241)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:147)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:111)
>>>>>      at
>>>>> org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:274)
>>>>>      at
>>>>> org.apache.felix.scr.impl.Activator.bundleChanged(Activator.java:192)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.util.EventDispatcher.invokeBundleListenerCallback(EventDispatcher.java:868)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:789)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:514)
>>>>>      at
>>>> org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:4244)
>>>>>      at org.apache.felix.framework.Felix.startBundle(Felix.java:1923)
>>>>>      at
>>>>> org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1191)
>>>>>      at
>>>>> 
>>>> 
>> org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:295)
>>>>>      at java.lang.Thread.run(Thread.java:662)
>>>>> 
>>>>> And after I enable B2 from webconsole, then nothing happens, and
>> AFactory
>>>>> is not injected with the A Component Factory anymore.
>>>>> 
>>>>> Am I making sense with all this ? Is there really an issue in SCR to be
>>>>> reported in jira ?
>>>>> (I reported this in an old issue FELIX-3090 which is currently closed,
>>>> but
>>>>> I still feel there is something to it).
>>>>> 
>>>>> thanks for your help;
>>>>> 
>>>>> /pierre
>>>> 
>>>> 
>> 
>> 


Re: a question of Declarative Service specification

Posted by Pierre De Rop <pi...@gmail.com>.
Thank you Felix, I tested the fix and it's working fine.

PS: will you close the issue, or should I ?

regards;
/Pierre

On Fri, Feb 17, 2012 at 2:31 PM, Felix Meschberger <fm...@adobe.com>wrote:

> Hi Pierre
>
> I committed a fix, if you like to check. Thanks.
>
> Regards
> Felix
>
> Am 17.02.2012 um 12:40 schrieb Pierre De Rop:
>
> > Hi Felix,
> >
> > Thanks a lot for reopening this issue.
> >
> > kind regards;
> > /Pierre
> >
> > On Fri, Feb 17, 2012 at 12:26 PM, Felix Meschberger <fmeschbe@adobe.com
> >wrote:
> >
> >> Hi Pierre,
> >>
> >> Thanks for insisting ...
> >>
> >> I revert my earlier opinion and now think you are right: The
> satisfaction
> >> of the ComponentFactory service must include the target properties.
> >>
> >> The newInstance method may be provided with different target property
> >> values and cause the desired instance to not be satisfiable and thus
> fail.
> >>
> >> I have reopened the issue and will reconsider your patch.
> >>
> >> Regards
> >> Felix
> >>
> >> Am 16.02.2012 um 16:10 schrieb Pierre De Rop:
> >>
> >>> Hi everyone,
> >>>
> >>> This post is about a question regarding SCR and especially about SCR
> >>> Component Factory:
> >>>
> >>> When a component A is defined with a factory attribute, then SCR is
> >>> intended to register an org.osgi.service.component.ComponentFactory
> >> inside
> >>> the registry, in order to allow another component to be injected with
> >> that
> >>> ComponentFactory. This way, some other components may programatically
> >>> instantiate one (or several instances) of the component A.
> >>>
> >>> The question is: should the ComponentFactory be registered only once
> the
> >> A
> >>> component is satisfied
> >>> (that is: after all A required dependencies are available) ?
> >>>
> >>> I guess yes, because in DS spec, (112.2.4), it is stated the following:
> >>>
> >>> "... SCR must register a Component Factory service on behalf of the
> >>> component
> >>> as soon as the component factory is satisfied."
> >>>
> >>> I ask this question because I'm facing the following issue:
> >>>
> >>> I have a component A, which depends on B1(property=b2) like this:
> >>>
> >>> public interface B {
> >>> }
> >>>
> >>> @Component(factory = "A")
> >>> public class A /* implements something which required B2 */ {
> >>>   @Reference(target = "(property=b2)")
> >>>   void bind(B b, Map<?, ?> properties) {
> >>>       System.out.println("A.bind(b=" + b + ", properties=" + properties
> >> +
> >>> ")");
> >>>   }
> >>>
> >>>   @Activate
> >>>   void start() {
> >>>       System.out.println("A.start");
> >>>   }
> >>> }
> >>>
> >>> And here is the component which is in charge of instantiating A:
> >>>
> >>> @Component
> >>> public class AFactory {
> >>>   @Reference(target = "(component.factory=A)")
> >>>   void bind(ComponentFactory aFactory) {
> >>>       System.out.println("AFactory: bound aFactory=" + aFactory);
> >>>       try {
> >>>           ComponentInstance ci = aFactory.newInstance(null);
> >>>           A a = (A) ci.getInstance();
> >>>           System.out.println("AFactory: created instance of a: " + a);
> >>>       }
> >>>       catch (Throwable t) {
> >>>           t.printStackTrace();
> >>>       }
> >>>   }
> >>> }
> >>>
> >>> Now, I have B1, defined like this:
> >>>
> >>> @Component(properties = { "property=b1" })
> >>> public class B1 implements B {
> >>> }
> >>>
> >>> and I then have B2 (which is the one required by A):
> >>>
> >>> @Component(enabled=false, properties = { "property=b2" })
> >>> public class B2 implements B {
> >>> }
> >>>
> >>> Here, B2 is declared with "enabled=false", meaning that the component
> B2
> >> is
> >>> not activated by default, at startup time.
> >>> So, B2 is meant to be manually enabled from web console.
> >>>
> >>> So, what I expect is the following:
> >>>
> >>> 1) When B2 is enabled from web console (using the "Component" menu),
> then
> >>> B2 is registered in the registry.
> >>> 2) At this point, I expect A to become satisfied, because A is
> depending
> >> of
> >>> service B2 (with property=b2).
> >>> 3) Then I expect the ComponentFactory of A to be registered in the OSGi
> >>> registry.
> >>> 4) Finally, AFactory is activated, and then instantiates A (using the
> >>> injected A ComponentFactory).
> >>>
> >>> The problem is that when I start the framework, it seems that the
> >> AFactory
> >>> component is immediately registered
> >>> with the ComponentFactory of A, while at this point A is not yet
> >> satisfied
> >>> (because at startup, only B1 is available, and
> >>> B2 is not yet available). So when AFactory instantiates A (using
> >>> ComponentFactory.newInstance), I then get the exception:
> >>>
> >>> g! AFactory: bound aFactory=Component: test.scr.factory.A (1)
> >>> org.osgi.service.component.ComponentException: Failed activating
> >> component
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.newInstance(ComponentFactoryImpl.java:120)
> >>>       at test.scr.factory.AFactory.bind(AFactory.java:15)
> >>>       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> >>>       at
> >>>
> >>
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> >>>       at
> >>>
> >>
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> >>>       at java.lang.reflect.Method.invoke(Method.java:597)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.helper.BaseMethod.invokeMethod(BaseMethod.java:227)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.helper.BaseMethod.access$500(BaseMethod.java:38)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.helper.BaseMethod$Resolved.invoke(BaseMethod.java:595)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.helper.BaseMethod$NotResolved.invoke(BaseMethod.java:552)
> >>>       at
> >>> org.apache.felix.scr.impl.helper.BaseMethod.invoke(BaseMethod.java:476)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.DependencyManager.invokeBindMethod(DependencyManager.java:1028)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.DependencyManager.bind(DependencyManager.java:944)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.DependencyManager.open(DependencyManager.java:868)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createImplementationObject(ImmediateComponentManager.java:200)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createComponent(ImmediateComponentManager.java:118)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1140)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
> >>>       at
> >>> org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
> >>>       at
> >> org.apache.felix.framework.Felix.registerService(Felix.java:3275)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.registerService(ComponentFactoryImpl.java:173)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
> >>>       at
> >>> org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
> >>>       at
> >> org.apache.felix.framework.Felix.registerService(Felix.java:3275)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerService(AbstractComponentManager.java:456)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:158)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.config.ImmediateComponentHolder.enableComponents(ImmediateComponentHolder.java:313)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.BundleComponentActivator.loadDescriptor(BundleComponentActivator.java:241)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:147)
> >>>       at
> >>>
> >>
> org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:111)
> >>>       at
> >>> org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:274)
> >>>       at
> >>> org.apache.felix.scr.impl.Activator.bundleChanged(Activator.java:192)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.util.EventDispatcher.invokeBundleListenerCallback(EventDispatcher.java:868)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:789)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:514)
> >>>       at
> >> org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:4244)
> >>>       at org.apache.felix.framework.Felix.startBundle(Felix.java:1923)
> >>>       at
> >>> org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1191)
> >>>       at
> >>>
> >>
> org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:295)
> >>>       at java.lang.Thread.run(Thread.java:662)
> >>>
> >>> And after I enable B2 from webconsole, then nothing happens, and
> AFactory
> >>> is not injected with the A Component Factory anymore.
> >>>
> >>> Am I making sense with all this ? Is there really an issue in SCR to be
> >>> reported in jira ?
> >>> (I reported this in an old issue FELIX-3090 which is currently closed,
> >> but
> >>> I still feel there is something to it).
> >>>
> >>> thanks for your help;
> >>>
> >>> /pierre
> >>
> >>
>
>

Re: a question of Declarative Service specification

Posted by Felix Meschberger <fm...@adobe.com>.
Hi Pierre

I committed a fix, if you like to check. Thanks.

Regards
Felix

Am 17.02.2012 um 12:40 schrieb Pierre De Rop:

> Hi Felix,
> 
> Thanks a lot for reopening this issue.
> 
> kind regards;
> /Pierre
> 
> On Fri, Feb 17, 2012 at 12:26 PM, Felix Meschberger <fm...@adobe.com>wrote:
> 
>> Hi Pierre,
>> 
>> Thanks for insisting ...
>> 
>> I revert my earlier opinion and now think you are right: The satisfaction
>> of the ComponentFactory service must include the target properties.
>> 
>> The newInstance method may be provided with different target property
>> values and cause the desired instance to not be satisfiable and thus fail.
>> 
>> I have reopened the issue and will reconsider your patch.
>> 
>> Regards
>> Felix
>> 
>> Am 16.02.2012 um 16:10 schrieb Pierre De Rop:
>> 
>>> Hi everyone,
>>> 
>>> This post is about a question regarding SCR and especially about SCR
>>> Component Factory:
>>> 
>>> When a component A is defined with a factory attribute, then SCR is
>>> intended to register an org.osgi.service.component.ComponentFactory
>> inside
>>> the registry, in order to allow another component to be injected with
>> that
>>> ComponentFactory. This way, some other components may programatically
>>> instantiate one (or several instances) of the component A.
>>> 
>>> The question is: should the ComponentFactory be registered only once the
>> A
>>> component is satisfied
>>> (that is: after all A required dependencies are available) ?
>>> 
>>> I guess yes, because in DS spec, (112.2.4), it is stated the following:
>>> 
>>> "... SCR must register a Component Factory service on behalf of the
>>> component
>>> as soon as the component factory is satisfied."
>>> 
>>> I ask this question because I'm facing the following issue:
>>> 
>>> I have a component A, which depends on B1(property=b2) like this:
>>> 
>>> public interface B {
>>> }
>>> 
>>> @Component(factory = "A")
>>> public class A /* implements something which required B2 */ {
>>>   @Reference(target = "(property=b2)")
>>>   void bind(B b, Map<?, ?> properties) {
>>>       System.out.println("A.bind(b=" + b + ", properties=" + properties
>> +
>>> ")");
>>>   }
>>> 
>>>   @Activate
>>>   void start() {
>>>       System.out.println("A.start");
>>>   }
>>> }
>>> 
>>> And here is the component which is in charge of instantiating A:
>>> 
>>> @Component
>>> public class AFactory {
>>>   @Reference(target = "(component.factory=A)")
>>>   void bind(ComponentFactory aFactory) {
>>>       System.out.println("AFactory: bound aFactory=" + aFactory);
>>>       try {
>>>           ComponentInstance ci = aFactory.newInstance(null);
>>>           A a = (A) ci.getInstance();
>>>           System.out.println("AFactory: created instance of a: " + a);
>>>       }
>>>       catch (Throwable t) {
>>>           t.printStackTrace();
>>>       }
>>>   }
>>> }
>>> 
>>> Now, I have B1, defined like this:
>>> 
>>> @Component(properties = { "property=b1" })
>>> public class B1 implements B {
>>> }
>>> 
>>> and I then have B2 (which is the one required by A):
>>> 
>>> @Component(enabled=false, properties = { "property=b2" })
>>> public class B2 implements B {
>>> }
>>> 
>>> Here, B2 is declared with "enabled=false", meaning that the component B2
>> is
>>> not activated by default, at startup time.
>>> So, B2 is meant to be manually enabled from web console.
>>> 
>>> So, what I expect is the following:
>>> 
>>> 1) When B2 is enabled from web console (using the "Component" menu), then
>>> B2 is registered in the registry.
>>> 2) At this point, I expect A to become satisfied, because A is depending
>> of
>>> service B2 (with property=b2).
>>> 3) Then I expect the ComponentFactory of A to be registered in the OSGi
>>> registry.
>>> 4) Finally, AFactory is activated, and then instantiates A (using the
>>> injected A ComponentFactory).
>>> 
>>> The problem is that when I start the framework, it seems that the
>> AFactory
>>> component is immediately registered
>>> with the ComponentFactory of A, while at this point A is not yet
>> satisfied
>>> (because at startup, only B1 is available, and
>>> B2 is not yet available). So when AFactory instantiates A (using
>>> ComponentFactory.newInstance), I then get the exception:
>>> 
>>> g! AFactory: bound aFactory=Component: test.scr.factory.A (1)
>>> org.osgi.service.component.ComponentException: Failed activating
>> component
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.newInstance(ComponentFactoryImpl.java:120)
>>>       at test.scr.factory.AFactory.bind(AFactory.java:15)
>>>       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>       at
>>> 
>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>>>       at
>>> 
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>>>       at java.lang.reflect.Method.invoke(Method.java:597)
>>>       at
>>> 
>> org.apache.felix.scr.impl.helper.BaseMethod.invokeMethod(BaseMethod.java:227)
>>>       at
>>> 
>> org.apache.felix.scr.impl.helper.BaseMethod.access$500(BaseMethod.java:38)
>>>       at
>>> 
>> org.apache.felix.scr.impl.helper.BaseMethod$Resolved.invoke(BaseMethod.java:595)
>>>       at
>>> 
>> org.apache.felix.scr.impl.helper.BaseMethod$NotResolved.invoke(BaseMethod.java:552)
>>>       at
>>> org.apache.felix.scr.impl.helper.BaseMethod.invoke(BaseMethod.java:476)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.invokeBindMethod(DependencyManager.java:1028)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.bind(DependencyManager.java:944)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.open(DependencyManager.java:868)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createImplementationObject(ImmediateComponentManager.java:200)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createComponent(ImmediateComponentManager.java:118)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1140)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
>>>       at
>>> 
>> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
>>>       at
>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
>>>       at
>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
>>>       at
>>> org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
>>>       at
>> org.apache.felix.framework.Felix.registerService(Felix.java:3275)
>>>       at
>>> 
>> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.registerService(ComponentFactoryImpl.java:173)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
>>>       at
>>> 
>> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
>>>       at
>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
>>>       at
>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
>>>       at
>>> org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
>>>       at
>> org.apache.felix.framework.Felix.registerService(Felix.java:3275)
>>>       at
>>> 
>> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerService(AbstractComponentManager.java:456)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
>>>       at
>>> 
>> org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:158)
>>>       at
>>> 
>> org.apache.felix.scr.impl.config.ImmediateComponentHolder.enableComponents(ImmediateComponentHolder.java:313)
>>>       at
>>> 
>> org.apache.felix.scr.impl.BundleComponentActivator.loadDescriptor(BundleComponentActivator.java:241)
>>>       at
>>> 
>> org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:147)
>>>       at
>>> 
>> org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:111)
>>>       at
>>> org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:274)
>>>       at
>>> org.apache.felix.scr.impl.Activator.bundleChanged(Activator.java:192)
>>>       at
>>> 
>> org.apache.felix.framework.util.EventDispatcher.invokeBundleListenerCallback(EventDispatcher.java:868)
>>>       at
>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:789)
>>>       at
>>> 
>> org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:514)
>>>       at
>> org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:4244)
>>>       at org.apache.felix.framework.Felix.startBundle(Felix.java:1923)
>>>       at
>>> org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1191)
>>>       at
>>> 
>> org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:295)
>>>       at java.lang.Thread.run(Thread.java:662)
>>> 
>>> And after I enable B2 from webconsole, then nothing happens, and AFactory
>>> is not injected with the A Component Factory anymore.
>>> 
>>> Am I making sense with all this ? Is there really an issue in SCR to be
>>> reported in jira ?
>>> (I reported this in an old issue FELIX-3090 which is currently closed,
>> but
>>> I still feel there is something to it).
>>> 
>>> thanks for your help;
>>> 
>>> /pierre
>> 
>> 


Re: a question of Declarative Service specification

Posted by Pierre De Rop <pi...@gmail.com>.
Hi Felix,

Thanks a lot for reopening this issue.

kind regards;
/Pierre

On Fri, Feb 17, 2012 at 12:26 PM, Felix Meschberger <fm...@adobe.com>wrote:

> Hi Pierre,
>
> Thanks for insisting ...
>
> I revert my earlier opinion and now think you are right: The satisfaction
> of the ComponentFactory service must include the target properties.
>
> The newInstance method may be provided with different target property
> values and cause the desired instance to not be satisfiable and thus fail.
>
> I have reopened the issue and will reconsider your patch.
>
> Regards
> Felix
>
> Am 16.02.2012 um 16:10 schrieb Pierre De Rop:
>
> > Hi everyone,
> >
> > This post is about a question regarding SCR and especially about SCR
> > Component Factory:
> >
> > When a component A is defined with a factory attribute, then SCR is
> > intended to register an org.osgi.service.component.ComponentFactory
> inside
> > the registry, in order to allow another component to be injected with
> that
> > ComponentFactory. This way, some other components may programatically
> > instantiate one (or several instances) of the component A.
> >
> > The question is: should the ComponentFactory be registered only once the
> A
> > component is satisfied
> > (that is: after all A required dependencies are available) ?
> >
> > I guess yes, because in DS spec, (112.2.4), it is stated the following:
> >
> > "... SCR must register a Component Factory service on behalf of the
> > component
> > as soon as the component factory is satisfied."
> >
> > I ask this question because I'm facing the following issue:
> >
> > I have a component A, which depends on B1(property=b2) like this:
> >
> > public interface B {
> > }
> >
> > @Component(factory = "A")
> > public class A /* implements something which required B2 */ {
> >    @Reference(target = "(property=b2)")
> >    void bind(B b, Map<?, ?> properties) {
> >        System.out.println("A.bind(b=" + b + ", properties=" + properties
> +
> > ")");
> >    }
> >
> >    @Activate
> >    void start() {
> >        System.out.println("A.start");
> >    }
> > }
> >
> > And here is the component which is in charge of instantiating A:
> >
> > @Component
> > public class AFactory {
> >    @Reference(target = "(component.factory=A)")
> >    void bind(ComponentFactory aFactory) {
> >        System.out.println("AFactory: bound aFactory=" + aFactory);
> >        try {
> >            ComponentInstance ci = aFactory.newInstance(null);
> >            A a = (A) ci.getInstance();
> >            System.out.println("AFactory: created instance of a: " + a);
> >        }
> >        catch (Throwable t) {
> >            t.printStackTrace();
> >        }
> >    }
> > }
> >
> > Now, I have B1, defined like this:
> >
> > @Component(properties = { "property=b1" })
> > public class B1 implements B {
> > }
> >
> > and I then have B2 (which is the one required by A):
> >
> > @Component(enabled=false, properties = { "property=b2" })
> > public class B2 implements B {
> > }
> >
> > Here, B2 is declared with "enabled=false", meaning that the component B2
> is
> > not activated by default, at startup time.
> > So, B2 is meant to be manually enabled from web console.
> >
> > So, what I expect is the following:
> >
> > 1) When B2 is enabled from web console (using the "Component" menu), then
> > B2 is registered in the registry.
> > 2) At this point, I expect A to become satisfied, because A is depending
> of
> > service B2 (with property=b2).
> > 3) Then I expect the ComponentFactory of A to be registered in the OSGi
> > registry.
> > 4) Finally, AFactory is activated, and then instantiates A (using the
> > injected A ComponentFactory).
> >
> > The problem is that when I start the framework, it seems that the
> AFactory
> > component is immediately registered
> > with the ComponentFactory of A, while at this point A is not yet
> satisfied
> > (because at startup, only B1 is available, and
> > B2 is not yet available). So when AFactory instantiates A (using
> > ComponentFactory.newInstance), I then get the exception:
> >
> > g! AFactory: bound aFactory=Component: test.scr.factory.A (1)
> > org.osgi.service.component.ComponentException: Failed activating
> component
> >        at
> >
> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.newInstance(ComponentFactoryImpl.java:120)
> >        at test.scr.factory.AFactory.bind(AFactory.java:15)
> >        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> >        at
> >
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> >        at
> >
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> >        at java.lang.reflect.Method.invoke(Method.java:597)
> >        at
> >
> org.apache.felix.scr.impl.helper.BaseMethod.invokeMethod(BaseMethod.java:227)
> >        at
> >
> org.apache.felix.scr.impl.helper.BaseMethod.access$500(BaseMethod.java:38)
> >        at
> >
> org.apache.felix.scr.impl.helper.BaseMethod$Resolved.invoke(BaseMethod.java:595)
> >        at
> >
> org.apache.felix.scr.impl.helper.BaseMethod$NotResolved.invoke(BaseMethod.java:552)
> >        at
> > org.apache.felix.scr.impl.helper.BaseMethod.invoke(BaseMethod.java:476)
> >        at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.invokeBindMethod(DependencyManager.java:1028)
> >        at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.bind(DependencyManager.java:944)
> >        at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.open(DependencyManager.java:868)
> >        at
> >
> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createImplementationObject(ImmediateComponentManager.java:200)
> >        at
> >
> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createComponent(ImmediateComponentManager.java:118)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1140)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
> >        at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
> >        at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
> >        at
> >
> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
> >        at
> >
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
> >        at
> >
> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
> >        at
> > org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
> >        at
> org.apache.felix.framework.Felix.registerService(Felix.java:3275)
> >        at
> >
> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
> >        at
> >
> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.registerService(ComponentFactoryImpl.java:173)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
> >        at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
> >        at
> >
> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
> >        at
> >
> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
> >        at
> >
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
> >        at
> >
> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
> >        at
> > org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
> >        at
> org.apache.felix.framework.Felix.registerService(Felix.java:3275)
> >        at
> >
> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerService(AbstractComponentManager.java:456)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
> >        at
> >
> org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:158)
> >        at
> >
> org.apache.felix.scr.impl.config.ImmediateComponentHolder.enableComponents(ImmediateComponentHolder.java:313)
> >        at
> >
> org.apache.felix.scr.impl.BundleComponentActivator.loadDescriptor(BundleComponentActivator.java:241)
> >        at
> >
> org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:147)
> >        at
> >
> org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:111)
> >        at
> > org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:274)
> >        at
> > org.apache.felix.scr.impl.Activator.bundleChanged(Activator.java:192)
> >        at
> >
> org.apache.felix.framework.util.EventDispatcher.invokeBundleListenerCallback(EventDispatcher.java:868)
> >        at
> >
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:789)
> >        at
> >
> org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:514)
> >        at
> org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:4244)
> >        at org.apache.felix.framework.Felix.startBundle(Felix.java:1923)
> >        at
> > org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1191)
> >        at
> >
> org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:295)
> >        at java.lang.Thread.run(Thread.java:662)
> >
> > And after I enable B2 from webconsole, then nothing happens, and AFactory
> > is not injected with the A Component Factory anymore.
> >
> > Am I making sense with all this ? Is there really an issue in SCR to be
> > reported in jira ?
> > (I reported this in an old issue FELIX-3090 which is currently closed,
> but
> > I still feel there is something to it).
> >
> > thanks for your help;
> >
> > /pierre
>
>

Re: a question of Declarative Service specification

Posted by Felix Meschberger <fm...@adobe.com>.
Hi Pierre,

Thanks for insisting ...

I revert my earlier opinion and now think you are right: The satisfaction of the ComponentFactory service must include the target properties.

The newInstance method may be provided with different target property values and cause the desired instance to not be satisfiable and thus fail.

I have reopened the issue and will reconsider your patch.

Regards
Felix

Am 16.02.2012 um 16:10 schrieb Pierre De Rop:

> Hi everyone,
> 
> This post is about a question regarding SCR and especially about SCR
> Component Factory:
> 
> When a component A is defined with a factory attribute, then SCR is
> intended to register an org.osgi.service.component.ComponentFactory inside
> the registry, in order to allow another component to be injected with that
> ComponentFactory. This way, some other components may programatically
> instantiate one (or several instances) of the component A.
> 
> The question is: should the ComponentFactory be registered only once the A
> component is satisfied
> (that is: after all A required dependencies are available) ?
> 
> I guess yes, because in DS spec, (112.2.4), it is stated the following:
> 
> "... SCR must register a Component Factory service on behalf of the
> component
> as soon as the component factory is satisfied."
> 
> I ask this question because I'm facing the following issue:
> 
> I have a component A, which depends on B1(property=b2) like this:
> 
> public interface B {
> }
> 
> @Component(factory = "A")
> public class A /* implements something which required B2 */ {
>    @Reference(target = "(property=b2)")
>    void bind(B b, Map<?, ?> properties) {
>        System.out.println("A.bind(b=" + b + ", properties=" + properties +
> ")");
>    }
> 
>    @Activate
>    void start() {
>        System.out.println("A.start");
>    }
> }
> 
> And here is the component which is in charge of instantiating A:
> 
> @Component
> public class AFactory {
>    @Reference(target = "(component.factory=A)")
>    void bind(ComponentFactory aFactory) {
>        System.out.println("AFactory: bound aFactory=" + aFactory);
>        try {
>            ComponentInstance ci = aFactory.newInstance(null);
>            A a = (A) ci.getInstance();
>            System.out.println("AFactory: created instance of a: " + a);
>        }
>        catch (Throwable t) {
>            t.printStackTrace();
>        }
>    }
> }
> 
> Now, I have B1, defined like this:
> 
> @Component(properties = { "property=b1" })
> public class B1 implements B {
> }
> 
> and I then have B2 (which is the one required by A):
> 
> @Component(enabled=false, properties = { "property=b2" })
> public class B2 implements B {
> }
> 
> Here, B2 is declared with "enabled=false", meaning that the component B2 is
> not activated by default, at startup time.
> So, B2 is meant to be manually enabled from web console.
> 
> So, what I expect is the following:
> 
> 1) When B2 is enabled from web console (using the "Component" menu), then
> B2 is registered in the registry.
> 2) At this point, I expect A to become satisfied, because A is depending of
> service B2 (with property=b2).
> 3) Then I expect the ComponentFactory of A to be registered in the OSGi
> registry.
> 4) Finally, AFactory is activated, and then instantiates A (using the
> injected A ComponentFactory).
> 
> The problem is that when I start the framework, it seems that the AFactory
> component is immediately registered
> with the ComponentFactory of A, while at this point A is not yet satisfied
> (because at startup, only B1 is available, and
> B2 is not yet available). So when AFactory instantiates A (using
> ComponentFactory.newInstance), I then get the exception:
> 
> g! AFactory: bound aFactory=Component: test.scr.factory.A (1)
> org.osgi.service.component.ComponentException: Failed activating component
>        at
> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.newInstance(ComponentFactoryImpl.java:120)
>        at test.scr.factory.AFactory.bind(AFactory.java:15)
>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>        at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>        at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>        at java.lang.reflect.Method.invoke(Method.java:597)
>        at
> org.apache.felix.scr.impl.helper.BaseMethod.invokeMethod(BaseMethod.java:227)
>        at
> org.apache.felix.scr.impl.helper.BaseMethod.access$500(BaseMethod.java:38)
>        at
> org.apache.felix.scr.impl.helper.BaseMethod$Resolved.invoke(BaseMethod.java:595)
>        at
> org.apache.felix.scr.impl.helper.BaseMethod$NotResolved.invoke(BaseMethod.java:552)
>        at
> org.apache.felix.scr.impl.helper.BaseMethod.invoke(BaseMethod.java:476)
>        at
> org.apache.felix.scr.impl.manager.DependencyManager.invokeBindMethod(DependencyManager.java:1028)
>        at
> org.apache.felix.scr.impl.manager.DependencyManager.bind(DependencyManager.java:944)
>        at
> org.apache.felix.scr.impl.manager.DependencyManager.open(DependencyManager.java:868)
>        at
> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createImplementationObject(ImmediateComponentManager.java:200)
>        at
> org.apache.felix.scr.impl.manager.ImmediateComponentManager.createComponent(ImmediateComponentManager.java:118)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1140)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
>        at
> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
>        at
> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
>        at
> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
>        at
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
>        at
> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
>        at
> org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
>        at org.apache.felix.framework.Felix.registerService(Felix.java:3275)
>        at
> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
>        at
> org.apache.felix.scr.impl.manager.ComponentFactoryImpl.registerService(ComponentFactoryImpl.java:173)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
>        at
> org.apache.felix.scr.impl.manager.DependencyManager.serviceAdded(DependencyManager.java:283)
>        at
> org.apache.felix.scr.impl.manager.DependencyManager.serviceChanged(DependencyManager.java:170)
>        at
> org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:932)
>        at
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:793)
>        at
> org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:543)
>        at
> org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4260)
>        at org.apache.felix.framework.Felix.registerService(Felix.java:3275)
>        at
> org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:346)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerService(AbstractComponentManager.java:456)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager.registerComponentService(AbstractComponentManager.java:508)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager$Unsatisfied.activate(AbstractComponentManager.java:1157)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:334)
>        at
> org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:158)
>        at
> org.apache.felix.scr.impl.config.ImmediateComponentHolder.enableComponents(ImmediateComponentHolder.java:313)
>        at
> org.apache.felix.scr.impl.BundleComponentActivator.loadDescriptor(BundleComponentActivator.java:241)
>        at
> org.apache.felix.scr.impl.BundleComponentActivator.initialize(BundleComponentActivator.java:147)
>        at
> org.apache.felix.scr.impl.BundleComponentActivator.<init>(BundleComponentActivator.java:111)
>        at
> org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:274)
>        at
> org.apache.felix.scr.impl.Activator.bundleChanged(Activator.java:192)
>        at
> org.apache.felix.framework.util.EventDispatcher.invokeBundleListenerCallback(EventDispatcher.java:868)
>        at
> org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:789)
>        at
> org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:514)
>        at org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:4244)
>        at org.apache.felix.framework.Felix.startBundle(Felix.java:1923)
>        at
> org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1191)
>        at
> org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:295)
>        at java.lang.Thread.run(Thread.java:662)
> 
> And after I enable B2 from webconsole, then nothing happens, and AFactory
> is not injected with the A Component Factory anymore.
> 
> Am I making sense with all this ? Is there really an issue in SCR to be
> reported in jira ?
> (I reported this in an old issue FELIX-3090 which is currently closed, but
> I still feel there is something to it).
> 
> thanks for your help;
> 
> /pierre