Question

In my current application, I've run into this pattern in a couple of places: I have two service interfaces in a single bundle which do different but related jobs.

interface Service1 { ... }

interface Service2 { ... }

and want to have singleton components implementing both, but find each needs a reference to the other:

public class Service1Impl implements Service1 { 

    private Service2 service2;
    ...

}

public class Service2Impl implements Service2 { 

    private Service1 service1;
    ...

}

Which of the three OSGi component models (DS, Blueprint, and iPOJO) allow this: 1) when Service1Impl and Service2Impl are in the same bundle; 2) when they are in different bundles?

Was it helpful?

Solution

Declarative Services Specification, version 1.1:

112.3.5 Circular References

It is possible for a set of component descriptions to create a circular dependency. For example, if component A references a service provided by component B and component B references a service provided by component A then a component configuration of one component cannot be satisfied without accessing a partially activated component instance of the other component. SCR must ensure that a component instance is never accessible to another component instance or as a service until it has been fully activated, that is it has returned from its activate method if it has one.

Circular references must be detected by SCR when it attempts to satisfy component configurations and SCR must fail to satisfy the references involved in the cycle and log an error message with the Log Service, if present. However, if one of the references in the cycle has optional cardinality SCR must break the cycle. The reference with the optional cardinality can be satisfied and bound to zero target services. Therefore the cycle is broken and the other references may be satisfied.

Blueprint specification explicitly allows this, provided at least one member of the dependency cycle takes others as properties and not arguments (121.2.6 Cyclic Dependencies):

When a member of a cycle is requested to provide a component instance, the Blueprint Container must break the cycle by finding one breaking member in the cycle’s members. A breaking member must use property injection for the dependency that causes the cycle. The Blueprint Container can pick any suitable member of the cycle for breaking member, if no such member can be found, then initialization fails or the getComponentInstance method must throw a Component Definition Exception.

A breaking member must return a partially initialized component instance when it is asked to provide an object. A partially initialized object has done all possible initialization but has not yet been called with the initMethod (if specified) nor has it been injected any of the properties that causes a cycle. The finalization of the partially initialized component instance must be delayed until the breaking member has been injected in all referring members of the cycles. Finalization means injecting any remaining unset properties and calling of the initMethod, if specified.

The consequence of partially initialized component instances is that they can be used before they have all properties set, applications must be aware of this.

All partially initialized component instances must be finalized before the Blueprint Container enters the Runtime phase and before a call to the getComponentInstance method returns a component instance. User code that causes a dynamic cycle by recursively calling the getComponentInstance method must be detected and cause a failure, these cycles cannot be broken.

All detected cycles should be logged.

For iPOJO

Your specific situation is supported. I can't talk for other situations without knowing further description though.

(answer received on the mailing list).

OTHER TIPS

Strictly speaking, what you are saying is impossible, because of the circular dependency.

Service1 can only function once Service2 is active and vice versa, so there is no order in which a framework can start your services.

As far as I can see you can make it work if you make one of the service references optional, so it can supply its service before it has it's injected service, so the other serviceimpl can supply its service back.

You can do this in all three frameworks. iPojo has optional references, DS has a cardinality setting to service requirements (use 0..1 for an optional reference instead of 1..1). Blueprint I don't know that well, but I'm sure it can be done.

Regards, Frank

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