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

Reply via email to