[ 
https://issues.apache.org/jira/browse/FELIX-5336?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15736700#comment-15736700
 ] 

Pierre De Rop edited comment on FELIX-5336 at 12/10/16 5:27 PM:
----------------------------------------------------------------

Hi Jan Willem,

I have something working. can you please try it ?
I have attached to this issue FELIX-5336.tgz (it's not a diff, but a tar.tgz of 
the modified/added files).

so, to install, first checkout dm from the trunk, then cd to dependencymanager 
, and tar zxvf FELIX-5336.tgz
(the tar.gz contains some more fix for other issues , I will create more JIRA 
issues soon about them).

there is a demo in 
org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/servicescope/api/.

I'm now describing the model used (a bit different from the one initially 
described in this issue).

So, to create a scoped service component, you can now invoke the 
createComponent(ComponentPolicy) method.
The policy is an enum allowing to define a strategy about how components are 
created.
you can also use the policy for all adapters, and for aspects.

this enum contains the following (it is actually only used when the component 
is a service provider):

- ComponentPolicy.SINGLETON: -> singleton component, as usual.
- ComponentPolicy.BUNDLE -> an instance of the component must be created for 
each bundle using the service. it actually corresponds to a ServiceFactory
- ComponentPolicy.BUNDLE_DYNAMIC: same as ComponentPolicy.BUNDLE, but allows to 
define a component which can add some dynamic dependencies from its init/start 
callback.
- ComponentPolicy.PROTOTYPE -> an instance of the component must be created for 
each distinct request for the service. it actually corresponds to a 
PrototypeServiceFactory
- ComponentPolicy.PROTOTYPE_DYNAMIC: same as ComponentPolicy.PROTOTYPE, but 
allows to define a component which can add some dynamic dependencies from its 
init/start callback.


So, for BUNDLE, and PROTOTYPE, a hidden component will track dependencies, and 
will register a ServiceFactory, or a PrototypeServiceFactory, respectively. 

when a component instance is created (because there is a requester for the 
service), then the component will be injected with the bundle / service 
registration (if it defines a Bundle or a ServiceRegistration field). This 
parameters correspond to the ones passed to the actual Service 
ServiceFactory.getService (or PrototypeServiceFactory.getService) methods.

So, if your scoped service provider component is dynamic (it may add some 
dynamic dependencies from the init or start callback), then you can use one of 
the two
constants from the enum:

BUNDLE_DYNAMIC, or PROTOTYPE_DYNAMIC.

In this case, a prototype instance component is always created (singleton), it 
will then be called as a regular DM component, and will add any dynamic 
dependencies it is necessary to add from the init or start callbacks. And once 
fully started (all required + instance bound dependencies injected), then the 
corresponding ServiceFactory or PrototypeServiceFactory will then be 
registered. And when a requester will define a dependency on the service, a 
copy of the prototype component instance will be created and returned by the 
ServiceFactory.getService (or PrototypeServiceFactory.getService) methods. 
Notice that the prototype component instance (singleton) won't be injected with 
the "Bundle" or "ServiceRegistration" parameters. This will allow you to detect 
if your component is the prototype instance or if it's a clone being created 
and returned to the requesting service.

Note: I did not have time to implement smart ServiceObjects injection. I may do 
this in a later release.

I'm now describing the demo:

So, in this demo, you will find two kind of prototype services:


- a Provider service which has a PROTOTYPE scope: The Provider service 
does not add some dynamic dependencies from its init/start callbacks (else it 
would has
a PROTOTYPE_DYNAMIC scope). Two Consumer components are depending on the 
Provider, and each Consumer will get injected with its own copy of the Provider 
service.

- a DynamicProvider service: this component has a PROTOTYPE_DYNAMIC scope 
because it adds some dynamic dependencies from its init/start callbacks. So, 
here a DynamicProvider component instance will be created but won't be injected 
to any service requesters; instead of that the service consumer will be 
injected with a copy of the prototype instance. 
Now, the ConsumerUsingServiceObjects component depends on the DynamicProvider 
service. Unlike in the Consumer example, the ConsumerUsingServiceObjects 
component will be injected with a ServiceReference to the DynamicProvider, and 
the ConsumerUsingServiceObjects will then obtain an OSGi "ServiceObjects" in 
order to manually instantiates two DynamicProvider component instances.

When you run the DM shell, you will see the first "Provider" component like 
this:

{code}
 [1] Prototype(#2) for 
org.apache.felix.dependencymanager.samples.servicescope.api.Provider registered
    org.osgi.service.cm.ConfigurationAdmin service required available
{code}

here, we see that the Provider component is a Prototype and has two instances 
(see "Prototype(#2)").
There are two instances because there are two Consumer component depending on 
it.

and the DynamicProvider will be displayed like this:

{code}
 [6] Prototype(#2) for 
org.apache.felix.dependencymanager.samples.servicescope.api.DynamicProvider 
registered
    org.osgi.service.cm.ConfigurationAdmin service required available
{code}

There are two instances because the ConsumerUsingServiceObjects has created two 
instances of the DynamicProvider
component using the OSGI ServiceObjects API.


One important remark: when you are using ServiceReference, by default the 
Component for the ConsumerUsingServiceObjects  will internally acquire an 
instance of the DynamicProvider.

it was implemented like this so far, and for the moment I don't have added some 
complexity in the state machine in order to avoid dereferencing (getService()) 
the service even if you actually only need to get injected with a 
ServiceReference (and not with the service itself). So, in order to avoid 
having a DynamicProvider automatically dereferenced by the 
ConsumerUsingServiceObjects Component (internally), you will see in the demo 
Activator that I have introduced  a new "dereference(boolean)" method in the 
ServiceDependency interface: it allows you to tell to DM that you don't want 
your component to automatically dereference the injected service internally, 
because all you want is the just the ServiceReference, not the actual service. 
So, please for now, use the dereference(boolean) method. (see the Activator in 
the demo).

Please tell me what you think about all this, and I can then possibly make a 
release soon.
thanks a lot.


was (Author: pderop):
Hi Jan Willem,

I have something working. can you please try it ?
I have attached to this issue FELIX-5336.tgz (it's not a diff, but a tar.tgz of 
the modified/added files).

so, to install, first checkout dm from the trunk, then cd to dependencymanager 
, and tar zxvf FELIX-5336.tgz
(the tar.gz contains some more fix for other issues , I will create more JIRA 
issues soon about them).

now, in the 
org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/servicescope/api/,
 there is a demo.

I'm now describing the model used (a bit different from the one initially 
described in this issue).

So, to create a scoped service component, you can now invoke the 
createComponent(ComponentPolicy) method.
The policy is an enum allowing to define a strategy about how components are 
created.
you can also use the policy for all adapters, and for aspects.

this enum contains the following (it is actually only used when the component 
is a service provider):

- ComponentPolicy.SINGLETON: -> singleton component, as usual.
- ComponentPolicy.BUNDLE -> an instance of the component must be created for 
each bundle using the service. it actually corresponds to a ServiceFactory
- ComponentPolicy.BUNDLE_DYNAMIC: same as ComponentPolicy.BUNDLE, but allows to 
define a component which can add some dynamic dependencies from its init/start 
callback.
- ComponentPolicy.PROTOTYPE -> an instance of the component must be created for 
each distinct request for the service. it actually corresponds to a 
PrototypeServiceFactory
- ComponentPolicy.PROTOTYPE_DYNAMIC: same as ComponentPolicy.BUNDLE, but allows 
to define a component which can add some dynamic dependencies from its 
init/start callback.


So, for BUNDLE, and PROTOTYPE, a hidden component will track dependencies, and 
will register a ServiceFactory, or a PrototypeServiceFactory, respectively. 

when a component instance is created (because there is a requester for the 
service), then the component will be injected with the bundle / service 
registration (if it defines a Bundle or a ServiceRegistration field). This 
parameters correspond to the ones passed to the actual Service 
ServiceFactory.getService (or PrototypeServiceFactory.getService) methods.

So, if your scoped service provider component is dynamic (it may add some 
dynamic dependencies from the init or start callback), then you can use one of 
the two
constants from the enum:

BUNDLE_DYNAMIC, or PROTOTYPE_DYNAMIC.

In this case, a prototype instance component is always created (singleton), it 
will then be called as a regular DM component, and will add any dynamic 
dependencies it is necessary to add from the init or start callbacks. And once 
fully started (all required + instance bound dependencies injected), then the 
corresponding ServiceFactory or PrototypeServiceFactory will then be 
registered. And when a requester will define a dependency on the service, a 
copy of the prototype component instance will be created and returned by the 
ServiceFactory.getService (or PrototypeServiceFactory.getService) methods. 
Notice that the prototype component instance (singleton) won't be injected with 
the "Bundle" or "ServiceRegistration" parameters. This will allow you to detect 
if your component is the prototype instance or if it's a clone being created 
and returned to the requesting service.

In the demo (see 
org.apache.felix.dependencymanager.samples/src/org/apache/felix/dependencymanager/samples/servicescope/api/),
 you have a Provider which is a prototype scope service: it does not add some 
dynamic dependencies from its init/start callbacks. So, there is now two Client 
instances which get injected with their own copy of the ProviderImpl.

You also have a DynamicProvider: it is a scoped service (PROTOTYPE_DYNAMIC), 
and the prototype instance is first created in order to add a dynamic 
dependency from the init method.
and once started, then the corresponding PrototypeServiceFactory will be 
registered.

At this point, a ConsumerUsingServiceObjects component will be started, and in 
this example, unlike from the Client example, A ServiceReference to the 
DynamicProvider is injected. I did not have time to inject a ServiceObjects 
directly. So for now, if you need to manually create some instances, you have 
to use the ref in order to get the ServiceObjects. Then from the 
ConsumerUsingServiceObjects.start() method, two instances of the 
DynamicProvider component  are created, and deleted from the stop() method.

one important remark: when you are using ServiceReference, by default the 
Component for the ConsumerUsingServiceObjects  will aquire an instance of the 
DynamicProvider.
for the moment, I don't have added some complexity in the state machine in 
order to detect that you actually only need to get injected with a 
ServiceReference (and not with the service itself). So, in order to avoid 
having a DynamicProvider automatically dereferenced by the 
ConsumerUsingServiceObjects Component (internally), you will see in the demo 
Activator that I have introduced  a new "dereference(boolean)" method in the 
ServiceDependency interface: it allows you to tell to DM that you don't want 
your component to automatically dereference the injected service internally, 
because all you want is the just the ServiceReference, not the actual service. 
So, please for now, use the dereference(boolean) method. (see the Activator in 
the demo).

Please tell me what you think about all this, and I can then possibly make a 
release soon.
thanks a lot.

> 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
>
>         Attachments: FELIX-5336.tgz
>
>
> 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