2

I have a java class, call it "Job", that implements an interface that I export as a service using blueprint. Although the class is defined as a bean with scope="prototype" in the blueprint xml file, and the service referen ces that bean, I can see from a System.out.println(this) statement in an instance method of the Job, that each time I access the service from a caller bundle, it reuses the same instance of the class Job that it created when I start the bundle; my caller bundle looks up the service references, calls context.getService(serviceReferences[0]) to get the reference to the Job service and then calls the method on that service (eg. Job.run()).

I thought making the scope of the service bean def prototype would give me a new instance of Job each time I called getService from the caller bundle, but my experiments are showing me that it's still using the same object instance.

So how do I call the service and have it create a new instance of Job each time, rather than reusing the same object?

I also need another service reference injected as a property into the bean Job since the bean interface doesn't have a set method to do this. So each new instance has to be created as the bean Job so that it can inject the property with a setX() method.

bmcdonald
  • 311
  • 6
  • 12

1 Answers1

1

If you use prototype scope for a bean, it means that a new instance will be created every time the bean is injected to another bean / service within the same blueprint container.

In your case a new instance of a bean is created as it is injected into the service component. However, the service component can provide only the same instance every time it is requested by another bundle.

For me it seems to me that you try to use blueprint and prototype scope for a task that should be done programmatically. You want to use a service that creates a new instance every time. That means that you should define a JobFactory interface and its implementation and register it as an OSGi service. On the other side, you should use JobFactory to instantiate as many Job instances as you want.

You could also use PrototypeServiceFactory but you have to register it programmatically as well. In my opinion, when someone wants to use PrototypeServiceFactory, it is time to extend the API with a Factory.

Balazs Zsoldos
  • 6,036
  • 2
  • 23
  • 31
  • After I asked my question, I thought someone might say something like, "if you want a new instance every time, then you have to design the service such that it does that instead." In other words, the decision on how to behave is up to the developer of the service to implement. Your answer seems to have some of that theme. – bmcdonald Feb 27 '15 at 19:20
  • I'm currently looking at having the bean that's being exported as a service be a proxy, or factory, that creates the new instance each time and calls the method on that instance on its behalf. Due to the need to inject something into the Job bean because its interface doesn't allow me to set a value, I'm looking at how to get the proxy object to create a new component. http://stackoverflow.com/questions/19384659/wiring-a-prototype-in-bleuprint looks interesting on how to go about that. – bmcdonald Feb 27 '15 at 19:23
  • " the decision on how to behave is up to the developer of the service to implement": Yes. Your solution will be much easier to understand if you define a clean API and not use tricks. Blueprint itself is full of tricks (timeout on reference proxies) and by doing that, it raises lots of issues that would not be there if there were no such tricks. – Balazs Zsoldos Feb 27 '15 at 19:36
  • The stackoverflow question you linked is about prototype bean scopes. That will not be a solution for you as it means prototype scope only within one blueprint container (injecting bean into bean within a container), but not via OSGi services. – Balazs Zsoldos Feb 27 '15 at 19:38
  • My solution (so far) is to create a JobProxy bean that injects the blueprint container and which the service references; like the link suggests. The JobProxy class implements the same interface as the Job class. The JobProxy creates a new Job bean instance via the blueprint container and runs the method on behalf of the Job. Class JobProxy implement Job { public int runJob(String[] args) { Job newJob = (Job)container.getComponentInstance("job"); return newJob.runJob(args); } } – bmcdonald Mar 01 '15 at 06:06
  • I'll try and update the question with real code example later. – bmcdonald Mar 01 '15 at 06:13