0

I have multiple Impl classes which implements the same service. I need to write a single factory class in osgi where I should write getter method to return appropriate Impl Object. Below is the code I tried. I am struck in factory class. Any ideas to proceed ?

public interface ServiceA {
   public void display();
}

@Component (description = "Test1 service", ds = true, immediate = true)
@Service (value = {ServiceA.class})
class Test1 implements ServiceA{

      public void display(){
        Log.debug("Test1");
      }
}

@Component (description = "Test2 service", ds = true, immediate = true)
@Service (value = {ServiceA.class})
class Test2 implements ServiceA{

      public void display(){
        Log.debug("Test2");
      }
}

//How to write factory ?
class Factory{

    public ServiceA getObject(String testType){
         if(testType.equals("Test1")){
             return Test1;
         }
         else{
             return Test2;
         }
    }
}
Neil Bartlett
  • 23,743
  • 4
  • 44
  • 77
keyanwb
  • 63
  • 1
  • 7
  • Can you explain in more detail why you want to do this. Usually you would inject the service object directly into the class that actually needs to use it. – Neil Bartlett Feb 20 '19 at 09:56
  • I need to create factory for serviceA . That's my intention. Since I am new to OSGi I imagine everything with classic way. So if any other way is there as per OSGi pls guide me. – keyanwb Feb 20 '19 at 11:05
  • I'm sure the user of your application doesn't care that you are using a factory. As I suggested in my previous comment, you can just inject the instance of the service directly into the place where it is actually needed. – Neil Bartlett Feb 21 '19 at 08:44

1 Answers1

1

Although it's not clear how your application intends to make use of these different service implementations, one way to do it is using service properties and then require that property when actually referencing these services at the service consumer, e.g.:

@Component (description = "Test1 service", ds = true, immediate = true)
@Service (value = {ServiceA.class})
@Property (name = "type", value = "test1")
class Test1 implements ServiceA{
    // ...
}

@Component (description = "Test2 service", ds = true, immediate = true)
@Service (value = {ServiceA.class})
@Property (name = "type", value = "test2")
class Test2 implements ServiceA{
    // ...
}

...and at the consumer side, you just add service selection criteria for the reference, e.g.:

@Component (...)
class MyConsumer {
    // ...

    @Reference(target="(type=test2)")
    ServiceA testService2;

    // ...
}

No factories needed! :)

For more information, have a look at this little article.

If you need to dynamically route to a specific service implementation based on runtime service request attributes, you can also hold a reference to all service implementations and map them using the desired property for fast selection, e.g.:

@Component (...)
class MyConsumer {
    // ...
    private final Map<String, ServiceA> services = // ...

    @Reference(
            cardinality = ReferenceCardinality.MULTIPLE,
            policy = ReferencePolicy.DYNAMIC,
            service = ServiceA.class,
            target = "(type=*)"
    )
    public void addServiceA(ServiceA instance, Map properties) {
        service.put(String.valueOf(properties.get("type")), instance);
    }

    public void removeServiceA(Map properties) {
        service.remove(String.valueOf(properties.get("type")));
    }

    // ...
}
Ancoron
  • 2,447
  • 1
  • 9
  • 21