How to use OSGi getServiceReference ()

I am new to OSGi and came across several examples of OSGi services.

For instance:

import org.osgi.framework.*;
import org.osgi.service.log.*;

public class MyActivator implements BundleActivator {
  public void start(BundleContext context) throws Exception {
    ServiceReference logRef = 
      context.getServiceReference(LogService.class.getName());
  }
}

      

My question is why are you using

getServiceReference(LogService.class.getName())

      

instead

getServiceReference("LogService")

      

If you are using LogService.class.getName () you need to import the interface. This also means that you need to import the org.osgi.services.log package into your MANIFEST.MF file.

Isn't it counterproductive if you want to reduce the dependency to push the loose coupling? As far as I know, one of the benefits of services is that the consumer of the service does not need to know the publisher of the service. But if you need to import one specific interface, you clearly need to know who provides it. Just by using a string like "LogService" you don't need to know that the interface is provided by org.osgi.services.log.LogService.

What am I missing here?

+2


a source to share


4 answers


It looks like you have confused the implementation and interface

By using the actual interface for the name (and importing the interface you will end up doing anyway) re-extends the contract for the interface that the services are developing. You don't care about the LogService injection, but you do care about the interface. Each LogService needs to implement the same interface, hence you are using the interface to receive the service. As far as you know, LogService is indeed a SLF4J wrapper provided by some other package. All you see is the interface. This is the torso you are looking for. You don't need to ship an interface with every implementation. Leave the interface as its own package, and implement multiple implementations of that interface.

Side note: ServiceTracker is usually easier to use, give it a try!



Additional advantages: Using an interface allows you to get the class name, which avoids spelling errors, excessive string literals, and greatly simplifies refactoring.

After you have received the ServiceReference, your next pair of lines will most likely be related to this:

Object logSvc = content.getService(logRef)

// What can you do with logSvc now?!? It an object, mostly useless

// Cast to the interface ... YES! Now you need to import it!
LogSerivce logger = (LogService)logSvc;

logger.log(LogService.LOG_INFO, "Interfaces are a contract between implementation and consumer/user");

      

+6


a source


If you are using a LogService, you are associated with it anyway. If you are writing middleware you will probably get the name parameterized via some XML file or via an API. And yes, "LogService" will fail, you need to use the fully qualified name: "org.osgi.service.log.LogService". The main reason for using the LogService.class.getName () pattern is for correct renaming while refactoring your code and minimizing spelling errors. The following OSGi API is likely to have:

ServiceReference<S> getServiceReference(Class<S> type)

      

to improve type safety.



Anyway, I would never use this low-level API unless you are developing middleware. If you really depend on a specific DS class, it is infinitely easier and even more when you use it with bnd annotations ( http://enroute.osgi.org/doc/217-ds.html ).

@Component
class Xyz implements SomeService {
  LogService log;

  @Reference
  void setLog( LogService log) { this.log = log; }

  public void foo() { ... someservice ... }

}

      

If you are developing middleware, you usually get service classes without knowing the actual class through a string or class object. In these cases, the OSGi string based API is used because it allows us to be more lazy without creating a classloader until recently. I think the biggest mistake we made in OSGi 12 years ago is not to incorporate DS concepts into the core ...: --(

+3


a source


You cannot use a value "LogService"

as the class name to get the ServiceReference because you must use the fully qualified class name "org.osgi.services.log.LogService"

.

If you are importing a package this way org.osgi.services.log;resolution:=optional

and you are using ServiceTracker to track services in the BundleActivator.start () method, I suggest using the initializazion "org.osgi.services.log.LogService"

instead LogService.class.getName()

in ServiceTracker. In this case, you will not receive NoClassDefFoundError/ClassNotFountException

when you start the beam.

+1


a source


As basszero mentioned, you should consider using ServiceTracker. It's pretty easy to use and also supports a much better programming pattern. You should never assume that the ServiceReference you received in the past is still valid. The service pointed to by ServiceReference may have disappeared. ServiceTracker will automatically inform you when a service is registered or unregistered.

0


a source







All Articles