Question

My Requirement: I have a service which takes care of persistence in my project. Let me call this service as PersistenceProvider service and lets assume it's residing in "my.persistenceservice" bundle.

Now, I have another bundle named "my.persitenceconsumer" bundle which referencing PersistenceProvider service using bind() unbind() method of one of the class named MyPersistenseConsumer. So when "my.persistenceconsumer" bundle starts, it will get reference of PersistenceProvider service using bind() method and MyPersistenceConsumer can use PersistenceProvider service

But, I also need to use this PersistenceProvider service from different classes in "my.persitenceconsumer" bundle.

My QUESTION is: What is the best way to use such shared service within different classes (in same bundle)

One of the solution: I can add Activator class in "my.persitenceconsumer" bundle .. having static getInstance() method. Which can be called by MyPersistenceConsumer.bind() and stores PersistenceProvider with Activator. Latter all classes in "my.persitenceconsumer" bundle can use PersistenceProvider using Activator class.

Here is the code:

public class MyPersistenceConsumer {
  public void bindPersistenceProvider(PersistenceProvider ppRef) {
    MyPersistenceConsumerActivator.getInstance().bindPersistenceProvider(ppRef);
  }
}

public class MyPersistenceConsumerActivator {
  static MyPersistenceConsumerActivator instance;
  PersistenceProvider ppRef;

  public static getInstance() {
    return instance;
  }

  public void bindPersistenceProvider(PersistenceProvider ppRef) {
    this.ppRef = ppRef;
  }
  public PersistenceProvider getPersistenceProvider() {
    return ppRef;
  }

  public void start(BundleContext context) throws Exception {
        instance = this;
  }
}

public class MyClass1 {

  public void usePersistenceProvider(){
    PersistenceProvider pp Ref =
      MyPersistenceConsumerActivator.getInstance().getPersistenceProvider();
  }

}

public class MyClass2 {

  public void usePersistenceProvider(){
    PersistenceProvider pp Ref =
      MyPersistenceConsumerActivator.getInstance().getPersistenceProvider();
  }

}

At Last: Does above is good way .. or is there a better way?

Was it helpful?

Solution

Singletons are an evilness that DS tries to eliminate. Singletons create brittle systems, they have the same problems as global vars.

The best solution is no-coupling. With DS I would use:

@Component
public class MyClass1 {
  @Reference
  void setPP( PersistenceProvider pp ) { ... }
}

And the same for MyClass2. If there is an instance relation between classes, pass the object around since you're already coupled then. As always, minimise coupling and maximise cohesion.

Factories and singletons are the exact evils OSGi tries to prevent for very good reasons.

OTHER TIPS

There are two possibilities I would recommend:

  • Make the objects that use the persistence-service declarative services. This the SCR will handle all the lifecycle-management and you will get very modular and testable classes.
  • Alternatively, you can pass a reference to the persistence-service in the constructor of these objects. The only problem here is that you have to make sure that these objects to not try to access the persistence-service after it has gone away.

Either of these approaches is to be preferred over the singleton-based solution you proposed.

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