Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OSGI Declarative Services (DS): What is a good way of using service component instances

I am just getting started with OSGI and Declarative Services (DS) using Equinox and Eclipse PDE.

I have 2 Bundles, A and B. Bundle A exposes a component which is consumed by Bundle B. Both bundles also expose this service to the OSGI Service registry again.

Everything works fine so far and Equinox is wireing the components together, which means the Bundle A and Bundle B are instanciated by Equinox (by calling the default constructor) and then the wireing happens using the bind / unbind methods.

Now, as Equinox is creating the instances of those components / services I would like to know what is the best way of getting this instance?

So assume there is third class class which is NOT instantiated by OSGI:

Class WantsToUseComponentB{
public void doSomethingWithComponentB(){
 // how do I get componentB??? Something like this maybe?
 ComponentB component = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName());
}

I see the following options right now:



1. Use a ServiceTracker in the Activator to get the Service of ComponentBundleA.class.getName() (I have tried that already and it works, but it seems to much overhead to me) and make it available via a static factory methods

 
public class Activator{

   private static ServiceTracker componentBServiceTracker;   

   public void start(BundleContext context){

     componentBServiceTracker = new ServiceTracker(context, ComponentB.class.getName(),null);
   }

   public static ComponentB getComponentB(){
     return (ComponentB)componentBServiceTracker.getService(); 
   };

}

2. Create some kind of Registry where each component registers as soon as the activate() method is called.

public ComponentB{

public void bind(ComponentA componentA){
   someRegistry.registerComponent(this);
}

or

public ComponentB{

   public void activate(ComponentContext context){
      someRegistry.registerComponent(this);
   }

}

}

3. Use an existing registry inside osgi / equinox which has those instances? I mean OSGI is already creating instances and wires them together, so it has the objects already somewhere. But where? How can I get them?

Conclusion Where does the class WantsToUseComponentB (which is NOT a Component and NOT instantiated by OSGI) get an instance of ComponentB from? Are there any patterns or best practises? As I said I managed to use a ServiceTracker in the Activator, but I thought that would be possible without it.

What I am looking for is actually something like the BeanContainer of Springframework, where I can just say something like Container.getBean(ComponentA.BEAN_NAME). But I don't want to use Spring DS.

I hope that was clear enough. Otherwise I can also post some source code to explain in more detail.

Thanks Christoph


UPDATED: Answer to Neil's comment:

Thanks for clarifying this question against the original version, but I think you still need to state why the third class cannot be created via something like DS.

Hmm don't know. Maybe there is a way but I would need to refactor my whole framework to be based on DS, so that there are no "new MyThirdClass(arg1, arg2)" statements anymore. Don't really know how to do that, but I read something about ComponentFactories in DS. So instead of doing a

MyThirdClass object = new MyThirdClass(arg1, arg2);

I might do a

ComponentFactory myThirdClassFactory = myThirdClassServiceTracker.getService(); // returns a 

if (myThirdClassFactory != null){
  MyThirdClass object = objectFactory.newInstance();

   object.setArg1("arg1");
  object.setArg2("arg2");
}
else{
 // here I can assume that some service of ComponentA or B went away so MyThirdClass Componenent cannot be created as there are missing dependencies?

}

At the time of writing I don't know exactly how to use the ComponentFactories but this is supposed to be some kind of pseudo code :)

Thanks Christoph

like image 459
Christoph Avatar asked Jul 09 '09 09:07

Christoph


People also ask

What are declarative services in OSGi?

Declarative Services (DS) are very common to define OSGi services. The DS bundle scans all bundles (extender pattern), parses the component definition xml-file and provides services based on that information. DS may also be used to define references to other services.

What capability does OSGi component @component provide?

The @Component annotation makes the class an OSGi component. Setting a service property to a particular service type in the annotation, allows other components to reference the service component by the specified service type.

How do you declare OSGi declarative services?

OSGi declarative services are the OSGi way to handle the instantiation problem: the fact that we want to code to interfaces, but we need some way to instantiate classes and some way to provide some concrete instance of an interface in order for the parts of our modular application to work together.

What is the difference between OSGi component and service?

"Components" are less formally defined than services. A service is any object that is registered in the OSGi Service Registry and can be looked up using its interface name(s). The only prerequisite is that a service should implement some interface... any interface.


1 Answers

Christoph,

Thanks for clarifying this question against the original version, but I think you still need to state why the third class cannot be created via something like DS.

DS causes components to be published as services, therefore the only way to "get" any component from DS is to access it via the service registry. Unfortunately the service registry can be hard to use correctly using the lower level APIs because it is dynamic, so you have to cope with the possibility of services going away or not being available at precisely the moment you want them to be available, and so on. This is why DS exists: it gives you an abstraction for depending on services and managing the lifecycle of your components based on the availability of services that they reference.

If you really need to access a service without using DS or something like it (and there is quite a choice of "things like it" e.g. Spring-DM, iPOJO, Guice/Peaberry, etc) then you should use ServiceTracker. I agree there is a lot of overhead -- again, this is why DS exists instead.

To answer your suggestion no (2), no you should not create your own registry of services because the service registry already exists. If you created a separate parallel registry then you would still have to handle all the dynamics, but you would have to handle it in two places instead of one. The same applies to suggestion (3).

I hope this helps.

Regards, Neil

UPDATED: Incidentally, although Spring has the Container.getBean() backdoor, you notice that in all Spring documentation it is strongly recommended not to use that backdoor: to get hold of a Spring bean, just create another bean that references it. The same applies to DS, i.e. the best way to get hold of a DS component is to create another DS component.

Also note that in the OSGi world, even if you're using Spring-DM there is no easy way to just call getBean() because you need to get hold of the Spring ApplicationContext first. That is itself an OSGi service, so how to you get that service?

like image 59
Neil Bartlett Avatar answered Oct 25 '22 23:10

Neil Bartlett