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