[
https://issues.apache.org/jira/browse/FELIX-5336?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16625275#comment-16625275
]
Pierre De Rop commented on FELIX-5336:
--------------------------------------
Some various enhancements was done for the dependency manager here
[https://github.com/pderop/dm.enhanced]., and this github project also contains
a simple support for service scopes (I plan to commit all this for the next r12
dm release soon).
So, here is a description of the what has been done in the github project:
>From the provider side, a new "scope" parameter has been added in the
>Component interface, allowing to define the scope of the registered service,
>and the parameter has three enum values: SINGLETON, BUNDLE, PROTOTYPE
* SINGLETON: it's as before: your registered service is a singleton
* BUNDLE: the service will be registered as a _ServiceFactory_
* PROTOTYPE: the service will be registered as a _PrototypeServiceFactory_
Scoped Services are supported by all kind of DM service components:
* Component
* Aspect Service
* Adapter Service
* Factory Pid Service
* Bundle Adapter service
When a consumer requests a service (using ServiceDependency), then DM will
automatically dereference the service like this:
* if the service has a SERVICE_SCOPE service property matching
SCOPE_PROTOTYPE, the DM will internally dereference the service using the
ServiceObject API: so, the consumer will get its own copy of the requested
service instance.
* else, DM will internally dereference the service, as before.
When defining scoped component implementation, you can optionally define two
special class fields in order to get injected with the client Bundle requesting
the service, and the ServiceRegisgtration Object. Using the DM API this is
enabled by default and you can turn off auto config using
Component.setAutoConfig(Bundle.class, boolean) method, or
Component.setAutoConfig(ServiceRegistration.class, boolean) methods. When using
annotation, just use @Inject annotations in order to get injected with the
client Bundle or the ServiceRegistration. You can also define a constructor
which takes as argument the client bundle as well as the service registration,
and in this case auto configuring Bundle/ServiceRegistration in class fields
will be disabled. (we will give concrete examples bellow using DM native API
and DM annotations).
*Example using annotations:*
here is a MyService component with PROTOTYPE scope, and each requester will get
its own copy of a MyService instance, and the MyServiceImpl.start() method will
be called for each instance:
{code:java}
import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ServiceScope;
@Component(scope=ServiceScope.PROTOTYPE)
public class MyServiceImpl implements MyService {
@Start
void start() {
// called on each MyService instance
}
}{code}
The above service will then automatically be instantiated for each of the
following service requesters:
{code:java}
import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ServiceScope;
@Component
public class Client1 {
@ServiceDependency
void bind(MyService service) {
// Client1 will be injected with its own MyService instance
}
@Component
public class Client2 {
@ServiceDependency
void bind(MyService service) {
// Client2 will be injected with its own MyService instance
}
}
{code}
The two Client1/Client2 above will be injected with two distinct component
instances for the MyService service (each MyServiceImpl instance will be
invoked in its start callback). Now, if you want to control the creation of the
MyService, you can then define a bind method which takes as argument a
ServiceObjects parameter like this:
{code:java}
import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ServiceScope;
@Component
public static class Client {
@ServiceDependency
void bind(ServiceObject<MyService> serviceObjects) {
MyService service;
try {
service = serviceObjects.getService();
} finally {
serviceObjects.ungetService(service);
}
}
}
{code}
Note that, unlink in DS, the ServiceObjects is not wrapped and won't
auto-unregister the created services when the bundle is stopping (I did not
have time to do this). Internally, DM will use the
PrototypeServiceFactory.getService(Bundle clientBundle, ServiceRegistration
reg) method in order to instantiate the MyServiceImpl component. So, the
MyServiceImpl component can optionally use the @Inject annotation in order to
get injected with the clientB undle and/or the service regisration, like this:
{code:java}
import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ServiceScope;
@Component(scope=ServiceScope.PROTOTYPE)
public static class MyServiceImpl implements MyService {
@Inject
Bundle m_clientBundle;
@Inject
ServiceRegisration m_registration;
@Start
void start() {
// called on each MyService instance.
}
}{code}
The Bundle and ServiceRegistration can also be injected in the component
Constructor:
{code:java}
import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ServiceScope;
@Component(scope=ServiceScope.PROTOTYPE)
public static class MyServiceImpl implements MyService {
public MyServiceImpl(Bundle clientBundle, ServiceRegistration registration)
{
...
}
@Start
void start() {
// called on each MyService instance.
}
}{code}
*Example using DM API:*
So, here is a MyService component with PROTOTYPE scope, and each requester will
get its own copy of MyService instance (the MyServiceImpl.start() method will
be called for each MyServiceImpl instance):
{code:java}
public class Activator extends DependencyActivatorBase {
@Override
public void init(BundleContext context, DependencyManager dm) throws
Exception {
dm.add(createComponent()
.setScope(ServiceScope.PROTOTYPE)
.setInterface(MyService.class.getName(), null)
.setImplementation(MyServiceImpl.class));
}
}
public class MyServiceImpl implements MyService {
void start() {
// called on each MyService instance
}
}
{code}
The MyServiceImpl, like with annotations, can define a constructor in order to
be injected with the client bundle invoking the service and also the service
Registration:
{code:java}
public class MyServiceImpl implements MyService {
public MyServiceImpl(Bundle clientBundle, ServiceRegistration reg) { ... }
void start() {
// called on each MyService instance
}
}
{code}
If you want to auto configure the client Bundle, and the ServiceRegistration,
then simply define class fields, they will be auto injected, unless you disable
auto configuraiton for Bundle/ServiceRegistration using
Component.setAutoConfig(Class, boolean) methods.
Now, here is a Client component which simply depends on the MyService service
using a basic DM activator (nothing special to do):
{code:java}
public class Activator extends DependencyActivatorBase {
@Override
public void init(BundleContext context, DependencyManager dm) throws
Exception {
dm.add(createComponent()
.setImplementation(Client.class)
.add(createServiceDependency()
.setService(MyService.class,
null).setRequired(true).setCallbacks("bind", "unbind"));
}
}
public class Client {
void bind(MyService service) {
// our client is injected with a specific instance of the MyService
component
// that is created for our Client.
// If another component defines a service dependency on MyService, then
the other
// component will get its own private copy of MyService component
instance
}
}
{code}
*Example using ServiceObjects API:*
If now you want to control the creation of the MyService using raw OSGI
ServiceObjects API, you can also do it like this:
{code:java}
public class Client {
void bind(ServiceObjects<MyService> so) {
MyService s1 = so.getService();
MyService s2 = so.getService();
...
so.ungetService(s1); // will deactivate the MyService s1 instance
so.ungetService(s2); // will deactivate the MyService s2 instance
}
}
{code}
h4.
h4.
> 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-r12
> Reporter: Pierre De Rop
> Assignee: Pierre De Rop
> Priority: Major
> 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
(v7.6.3#76005)