felix-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Pierre De Rop (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (FELIX-5336) Add support for prototype scope services in DM4
Date Mon, 14 Nov 2016 18:35:58 GMT

    [ 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:
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:

Component provider = m.createComponent()
     .setInterface(Service.class.getName(), null)
     .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"

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":

        Component provider = m.createComponent()
            .setInterface(Service.class.getName(), null);

        Component adapter = m.createAdapterService(Service.class, null)
            .setInterface(AdapterService.class.getName(), null)

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:

        Component provider = m.createComponent()
            .setInterface(Service.class.getName(), null);

        Component aspect = m.createAspectService(Service.class, null, 10)

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/users@felix.apache.org/msg17473.html

This message was sent by Atlassian JIRA

View raw message