Question

I'm currently converting a piece of code from plain Java code to OSGi Declarative Services.

Original plain Java code

new AggregateServiceImpl(
    new ChildServiceImpl1(),
    new ChildServiceImpl2(),
    new ChildServiceImpl3()
);

The classes are declared as so:

class AggregateServiceImpl implements Service
class ChildServiceImpl1 implements Service
class ChildServiceImpl2 implements Service
class ChildServiceImpl3 implements Service

So all classes implement Service, but the Aggregate implementation is capable of deferring to child Services when called upon.

AggregateServiceImpl itself does not know of the other implementations' existence. Its constructor is originally declared as:

public class AggregateServiceImpl(Service... children)

Clarification: the interface name 'Service' is intended generically and is not meant to represent an OSGi DS or Service concept.

Converting to OSGi

First I move each implementation into its own bundle. Then I declare my components (service implementations). I happen to be using bnd, so I use service annotations. For example:

@Component
class ChildServiceImpl1 implements Service

In the client class, we can look up the Service using the low level OSGi API or use DS in that bundle to create the object for us.

Problem

What's the best way of looking up a 'Service'? I want the AggregateServiceImpl but I might receive one of the ChildServiceImpls.

Is it best to use a separate service type or add a property to one of the components (e.g. "isRootService") to use as a filter when looking up ServiceReferences?

Was it helpful?

Solution

The best way is to use service registration properties

 @Component
 @Service
 @Property(name = "service.id", value = "<some service unique ID")
 class ChildServiceImpl1 implements Service{...}

When you look for some specific services you can use service filter:

bc.getServiceReferences(Service.class.getName(), "(service.id=<some value>)");

or if you like to use it in DS component as service reference:

@Reference(target = "(service.id=<some value>)", cardinality = ...)
private Service service;

OTHER TIPS

If the AggregateServiceImpl is the only Service being used by other bundles, then it should be the only one you register.

From the code you have currently shown, we cannot tell if the AggregateServiceImpl class has dependencies on Service or the actual implementations.

If it has dependencies directly on other implementations, not the Service interface (as you have currently described it) the aggregate bundle should create the other implementation classes it requires directly and then register the AggregateServiceImpl as a Service.

If the other implementations need to be used elsewhere as well, then you should use properties (as you suggested) so consumers can distinguish between them. In this case, you still cannot use DS to construct your aggregate, since it doesn't have a dependencies on Service

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top