I've created these two components:

#1 FooImpl of IFoo service

@ObjectClassDefinition(name = "Foo Configuration")
@interface FooConfig {
  String message() default "Hi There";
}
@Designate(ocd = FooConfig.class, factory=true)
@Component(scope=ServiceScope.PROTOTYPE,configurationPolicy=ConfigurationPolicy.REQUIRE)
public class FooImpl implements IFoo {

    private FooConfig config;

    @Override
    public String getMessage() {
        return config.message();
    }

    @Activate
    void activate(FooConfig config) throws Exception {
System.out.println("activate instance="+this+" with config="+config);
        this.config = config;
    }

    @Deactivate
    void deactivate() {
        System.out.println("deactivate instance="+this);
    }

    @Modified
    void modified(FooConfig config) {
System.out.println("modified instance="+this+" with new config="+config);
    }
}


// #2 The FooConsumer that creates the prototype instances

@Component(immediate=true)
public class FooConsumer {

    private ComponentServiceObjects<IFoo> f;

    @Reference(scope=ReferenceScope.PROTOTYPE_REQUIRED)
    void setFooFactory(ComponentServiceObjects<IFoo> fact) {
        this.f = fact;
    }

    void unsetFooFactory(ComponentServiceObjects<IFoo> fact) {
        this.f = null;
    }

    private IFoo[] foos;

    @Activate
    void activate() {
        System.out.println("activate FooConsumer="+f);
        foos = new IFoo[5];
        for(int i=0; i < 5; i++) {
            foos[i] = f.getService();
System.out.println("foos["+i+"].getMessage() returns: "+foos[i].getMessage());
        }
    }

    @Deactivate
    void deactivate() {
        for(int i=0; i < 5; i++) {
            f.ungetService(foos[i]);
        }
    }
}

When the two bundles (IFoo API bundle and bundle containing above 2 components) are installed and started on Karaf 4.0.5 no output is produced, since there is no configuration created and the consumer ref to the ComponentServiceFactory is set to REQUIRE. When I go to the webconsole and create a Foo Configuration the following output is produced:

karaf@root()> activate FooConsumer=ComponentServiceObjectsImpl [instances=[], se
rviceObjects=org.apache.felix.framework.BundleContextImpl$ServiceObjectsImpl@b55
a5b0, deactivated=false, hashCode=2085697315]
activate instance=org.eclipse.ecf.test.foo.impl.FooImpl@6d86a6c2 with config=null
foos[0].getMessage() returns: Hi There Scott
activate instance=org.eclipse.ecf.test.foo.impl.FooImpl@68a1dfe8 with config=null
foos[1].getMessage() returns: Hi There Scott
activate instance=org.eclipse.ecf.test.foo.impl.FooImpl@215c5b23 with config=null
foos[2].getMessage() returns: Hi There Scott
activate instance=org.eclipse.ecf.test.foo.impl.FooImpl@7bba307e with config=null
foos[3].getMessage() returns: Hi There Scott
activate instance=org.eclipse.ecf.test.foo.impl.FooImpl@21f74969 with config=null
foos[4].getMessage() returns: Hi There Scott


I don't know why the config=null is reported...the config passed in is not null (via debugger), and you can see that the config.message() call returns Hi There Scott. It appears to me to be a small bug (e.g. in the toString() impl of the proxy that's passed in)?

This is fine for my use case WRT creating service instances on demand via the FooConsumer. However, I would like to be able to have a distinct/new configuration associated with each new FooImpl, rather than a single FooConfig instance assigned to all of them. Is this possible using the PROTOTYPE pattern, or is it necessary to use the ComponentFactory in the manner Tim describes to accomplish this:

The way that this is done is to pass the configuration using the newInstance 
method. Effectively your pattern would be to register a ConfigurationListener 
or ManagedServiceFactory, passing the configuration Dictionary to the Component 
Factory for each Factory Configuration.

Thanksinadvance,

Scott

_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to