0

I have created an Osgi service. I want to create a new instance of my service each time the service request comes. Code look likes this -

    @Component(immediate=true)
    @Service(serviceFactory = true)
    @Property(name = EventConstants.EVENT_TOPIC, value = {DEPLOY, UNDEPLOY })
    public class XyzHandler implements EventHandler {
         private Consumer consumer;
         public static setConsumer(Consumer consumer) {
          this.consumer = consumer;
          }
     @Override
        public void handleEvent(final Event event) {
                consumer.notify();          
     }
 }

public class Consumer {

private DataSourceCache cache;
public void notify() {
  updateCache(cache);
  System.out.println("cache updated");
 }
public void updateCache(DataSourceCache cache) {
   cache = null;
  }
}

In my Consumer class, I want to access the service instance of XyzHandler & set the attribute consumer. Also I would like to have a new service instance of XyzHandler created every time for each request. I found few articles where it is mentioned that using osgi declarative service annotations this can be achieved. OSGi how to run mutliple instances of one service

But I want to achieve this without using DS 1.3.

How can I do this without using annotations or how can it be done using DS 1.2?

James Z
  • 12,209
  • 10
  • 24
  • 44

2 Answers2

1

To me this looks like a case of having asked a question based on what you think the answer is rather than describing what you're trying to achieve. If we take a few steps back then a more elegant solution exists.

In general injecting objects into stateful services is a bad pattern in OSGi. It forces you to be really careful about the lifecycle, and risks memory leaks. From the example code it appears as though what you really want is for your Consumer to get notified when an event occurs on an Event Admin topic. The easiest way to do this would be to remove the XyzHandler from the equation and make the Consumer an Event Handler like this:

@Component(property= { EventConstants.EVENT_TOPIC + "=" + DEPLOY,
                       EventConstants.EVENT_TOPIC + "=" + UNDEPLOY})
public class Consumer implements EventHandler {

  private DataSourceCache cache;

  @Override
  public void handleEvent(final Event event) {
    notify();          
  }

  public void notify() {
    updateCache(cache);
    System.out.println("cache updated");
  }

  public void updateCache(DataSourceCache cache) {
       cache = null;
  }
}

If you really don't want to make your Consumer an EventHandler then it would still be easier to register the Consumer as a service and use the whiteboard pattern to get it picked up by a single XyzHandler:

@Component(service=Consumer.class)
public class Consumer {

  private DataSourceCache cache;

  public void notify() {
    updateCache(cache);
    System.out.println("cache updated");
  }

  public void updateCache(DataSourceCache cache) {
       cache = null;
  }
}

@Component(property= { EventConstants.EVENT_TOPIC + "=" + DEPLOY,
                       EventConstants.EVENT_TOPIC + "=" + UNDEPLOY})
public class XyzHandler implements EventHandler {

  // Use a thread safe list for dynamic references!
  private List<Consumer> consumers = new CopyOnWriteArrayList<>();

  @Reference(cardinality=MULTIPLE, policy=DYNAMIC)
  void addConsumer(Consumer consumer) {
    consumers.add(consumer);
  }

  void removeConsumer(Consumer consumer) {
    consumers.remove(consumer);
  }

  @Override
  public void handleEvent(final Event event) {
    consumers.forEach(this::notify);          
  }

  private void notify(Consumer consumer) {
    try {
      consumer.notify();
    } catch (Exception e) {
      // TODO log this?
    }
  }
}

Using the whiteboard pattern in this way avoids you needing to track which XyzHandler needs to be created/destroyed when a bundle is started or stopped, and will keep your code much cleaner.

Tim Ward
  • 1,169
  • 8
  • 9
0

It sounds like your service needs to be a prototype scope service. This was introduced in Core R6. DS 1.3, from Compendium R6, includes support for components to be prototype scope services.

But DS 1.2 predates Core R6 and thus has no knowledge or support for prototype scope services.

BJ Hargrave
  • 9,324
  • 1
  • 19
  • 27