fill0llif
fill0llif

Reputation: 1

OSGI Service visibility/DS annotation component injection

I have a service instantiated by Apache Felix Dependency Manager, because I need to use a factory method to return the implementation:

manager.add(
    manager.createComponent()
    .setInterface(aServiceName, new Properties())
    .setFactory(factory, "create"));

because I want this service to be injected into a service inside the same bundle, both aService and bService need to be in the same bundle:

@Component
public class BService {

    @Reference
    private AService aService;

    [...]
}

This is working perfectly fine, the thing is that I don't want aService to be visible outside the bundle, like a private service. If I remove:

.setInterface(aServiceName, new Properties())

the component seems to be created anyway is not created and it's not registered as a service and thus is not available to other bundles, but I can't use DS annotation to inject the component. Is really not possible to make the service only visible inside the bundle that originated it? Or is there a way to still inject the component with DS annotation?

I tried using Apache Felix Dependency Manager to inject the component:

import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ServiceDependency;

@Component
public class BService {

    @ServiceDependency
    private AService aService;

    [...]
}

but I found out the component is not injected:

[32] org.apache.felix.dependencymanager.runtime
 [0] org.apache.felix.dm.runtime.DependencyManagerRuntime registered
     active (DependencyManager-Component=*) bundle optional available
     org.osgi.service.packageadmin.PackageAdmin service required available
     org.osgi.service.log.LogService service optional available
[131] [...]
  [7] [...].BService unregistered
      org.osgi.service.log.LoggerFactory service required available
      [...].AService service required unavailable

Does this mean I can't inject simple component with @ServiceDependency because they have to be services and thus in the OSGI registry? How then can I inject simple components using annotation? It should there be one, right?

UPDATE

I've just realised that the aService implementation requires the package to be exported, therefore it was just a design flaw. Then I simply have found a way to separate the services in two different bundles (the OSGI way) and solved my issue.

Before doing that I tried removing the package from the exported bundle, but still didn't work, the service would still be available.

Export-Package: [...].services;version="0.0.1"
Provide-Capability: osgi.service;uses:="[...].services";o
 bjectClass="[...].services.BService",osgi.service;uses:=
 "[...].services.internal";objectClass="[...].services.internal.AService"
Require-Capability: osgi.extender;filter:="(&(osgi.extender=osgi.compo
nent)(version>=1.4.0)(!(version>=2.0.0)))",osgi.service;effective:=ac
tive;filter:="(objectClass=[...].services.internal.AServ
ice)"

Upvotes: 0

Views: 422

Answers (2)

Pierre De Rop
Pierre De Rop

Reputation: 61

Indeed, services injections will only work if services are published to the OSGi service registry. To work around, you could consider to make your "aService" package private to the bundle, and not export it. In this way, the aService will be only visible from the components declared inside your bundle.

Now, maybe you could also consider to wire your internal components (being part of your bundle) using the same old "new" keyword ? Please take a look at this interesting response from Peter Kriens regarding service components visibility:

https://www.mail-archive.com/[email protected]/msg16349.html

Hope this helps ?

kind regards Pierre

Upvotes: 1

Christian Schneider
Christian Schneider

Reputation: 19626

To create a service that is only visible inside the bundle simply make sure you do not export the package of the service interface. This way other bundles will not see or use the service.

Upvotes: 1

Related Questions