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