[
https://issues.apache.org/jira/browse/FELIX-5336?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15664639#comment-15664639
]
Pierre De Rop commented on FELIX-5336:
--------------------------------------
So, I have a patch which I can commit soon for the support of prototype scopes
in DM4. I'm now describing here what it will look like:
So, using the patch, it will be possible to define DM components with a
"service scope" mode: SINGLETON (default), BUNDLE, or PROTOTYPE.
The new feature is available for all DM components, including all adapters and
aspects.
Here is description of the scopes:
- The SINGLETON scope is the default mode where a single service component
implementation object is injected to all service consumers. It is the same
behavior as before.
- the BUNDLE scope will register the component as a
org.osgi.framework.ServiceFactory; so when you declare a component with
scope=BUNDLE, then all service consumers from the same bundle will be injected
with the same service provider component instance, but other consumer
components from another bundle will get a separate copy instance.
- the PROTOTYPE scope will register the component as a
org.osgi.framework.PrototypeServiceFactory; so an instance of the component
will be created for each distinct request for the service.
Here is a description on how it will work:
- When a service S is using PROTOTYPE (or BUNDLE) scope, then an S1
implementation will first be created and started, as usual; so, you will see
the S component from the dm shell.
- Then, when a first consumer C1 is started, S1 will be delivered to the
consumer C1.
- When a second consumer C2 is started, then if the scope is PROTOTYPE (or
BUNDLE and the consumer C2 is not part of the C1 bundle), then at this point
the component instance will be internally cloned to S2. S2 will act as a
regular DM component: it will be injected with dependencies initially defined
in the Activator, the S2 init/start callbacks will be invoked, and S2 instance
will then be assigned to client C2. But you won't see the S2 instance from the
dm shell (you will only see the S service, as usual).
- Now, if the C2 consumer is stopped, then the S2 cloned component will be
stopped, as if it was a regular component: the dependencies will be unbound,
the stop/destroy callbacks will be invoked on the cloned component instance.
- Optionally, a component with scoped=PROTOTYPE or BUNDLE can as usual declare
a ServiceRegistration field, which will be injected with the original
ServiceRegistration of the prototype service.
Here are some example using the DM api (but DM-lambda or DM annotations could
also be used):
1) example for a simple Provider service component with prototype scope:
{code}
Component provider = m.createComponent()
.setImplementation(ServiceImpl.class)
.setInterface(Service.class.getName(), null)
.setScope(PROTOTYPE)
.add(createServiceDependency().setService(LogService.class,
null).setRequired(true);
public class ServiceImpl implements Service {
volatile LogService log; // injected
void start() {
log.log(LogService.INFO, "component started: this"
}
void stop() {
log.log(LogService.INFO, "component stopped: this"
}
}
{code}
So each consumer will then aquire a private copy of the cloned ServiceImpl.
(the cloned ServiceImpl will first be injected with dependencies, and will be
started as if it was a real component). The consumer can be a DM component
having a ServiceDepenency on the Service, or can be a code using the R6
ServiceObjects.getService() method.
When the consumer is stopped (or calls ServiceObjects.ungetService()), then the
cloned ServiceImpl will be stopped (will be invoked in its stop callback).
2) Example for a DM adapter, which adapts the "Service" service to
"AdapterService":
{code}
Component provider = m.createComponent()
.setImplementation(ServiceImpl.class)
.setInterface(Service.class.getName(), null);
Component adapter = m.createAdapterService(Service.class, null)
.setInterface(AdapterService.class.getName(), null)
.setImplementation(AdapterServiceImpl.class)
.setScope(PROTOTYPE);
{code}
So, here, it is the same: all clients depending on the AdapterService will get
their own instance (each adapter instance will be injected with dependencies,
and will be started before being assigned to one given adapter service
consumer).
Interestingly, in the example above, the Service provider could also have been
declared using a PROTOTYPE scope, so if you have multiple adapters for the same
service, then each adapter would get its private copy of the Service component
instance.
3) Example for a DM aspect:
{code}
Component provider = m.createComponent()
.setImplementation(ServiceImpl.class)
.setInterface(Service.class.getName(), null);
Component aspect = m.createAspectService(Service.class, null, 10)
.setImplementation(AspectServiceImpl.class)
.setScope(PROTOTYPE);
{code}
So, here it is the same: each client depending on the Service service will be
injected with a private copy of the AspectServiceImpl.
I will attach to this issue the not yet committed integration test so you can
check with more details if you want.
And May be some other DM committers want to give their opinion ?
thank you
> Add support for prototype scope services in DM4
> -----------------------------------------------
>
> Key: FELIX-5336
> URL: https://issues.apache.org/jira/browse/FELIX-5336
> Project: Felix
> Issue Type: New Feature
> Components: Dependency Manager
> Affects Versions: org.apache.felix.dependencymanager-r8
> Reporter: Pierre De Rop
> Assignee: Pierre De Rop
> Fix For: org.apache.felix.dependencymanager-r9
>
>
> In the users mailing list, there is a wish to add support in DM4 for OSGi
> prototype scope services, which allows any service consumer to get its own
> instance of a given service dependency.
> See http://www.mail-archive.com/[email protected]/msg17473.html
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)