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

Reply via email to