Cyclic references in two OSGI services | Community
Skip to main content
Level 2
January 6, 2021
Solved

Cyclic references in two OSGI services

  • January 6, 2021
  • 2 replies
  • 3475 views

Hi There,

 

We have a scenario in which we need to create an reference of class B in a class A and Class A in class B. We need to know whether there is any solution to this as we are getting "service unsatisfied"  and a sling exception is thrown by the service.

 

Example:

class A{​​​​​ @3214626 class B }​​​​​ and class B {​​​​​ @3214626 class A}​​​​​

 

Please provide your suggestions and let us know if our approach is correct or not. Thanks in advance.

 

Regards,

Ravi

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by Anudeep_Garnepudi

@ravi_shankerj14 

Add on to @joerghoh,

You can try inheriting the implementation class(ClassA or ClassB) along side implementing the interface. Check the below example.

ServiceOne

 

import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @Component(service=ServiceOne.class) public class ServiceOneImpl implements ServiceOne { @Reference ServiceTwo serviceTwo; @Override public String methodOne() { return "{\"ServiceOne\": \"methodOne\"}"; } @Override public String reuseMethodTwo() { return serviceTwo.methodTwo(); } }

 

ServiceTwo

 

import org.osgi.service.component.annotations.Component; @Component(service=ServiceTwo.class) public class ServiceTwoImpl extends ServiceOneImpl implements ServiceTwo { @Override public String methodTwo() { return "{\"ServiceTwo\": \"methodTwo\"}"; } @Override public String reuseMethodOne() { return super.methodOne(); } }

 

I am using a Servlet to invoke the ServiceTwo, which is internally calling ServiceOne method.

Servlet

 

import java.io.IOException; import javax.servlet.Servlet; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @Component(service=Servlet.class, property={ "sling.servlet.methods=" + "GET", "sling.servlet.paths="+ "/bin/test-servlet" }) public class TestServlet extends SlingAllMethodsServlet{ private static final long serialVersionUID = 1L; @Reference ServiceOne serviceOne; @Reference ServiceTwo serviceTwo; @Override public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) { response.setContentType("application/json"); try { response.getWriter().print(serviceOne.methodOne()); response.getWriter().print(serviceOne.reuseMethodTwo()); response.getWriter().print(serviceTwo.methodTwo()); response.getWriter().print(serviceTwo.reuseMethodOne()); } catch (IOException e) { e.printStackTrace(); } } }

 

Output

 

{"ServiceOne": "methodOne"}{"ServiceTwo": "methodTwo"}{"ServiceTwo": "methodTwo"}{"ServiceOne": "methodOne"}

 

2 replies

joerghoh
Adobe Employee
Adobe Employee
January 8, 2021

This is a conflict which the system cannot handle itself. But in many cases it is also a sign of a bad application design.

I see 2 options:

 

1) Make a reference optional and deal with this optionality in the application code. Just make sure that the optional reference is greedy, so it's getting satisfied as soon as the reference target is available.

 

2) Redesign your services so you don't have this circular dependency anymore. Most likely the creation of a third service C makes sense, which both A and B can depend on.

Level 8
July 18, 2021
Hi, how do you implement option 1?
Anudeep_Garnepudi
Community Advisor
Anudeep_GarnepudiCommunity AdvisorAccepted solution
Community Advisor
January 12, 2021

@ravi_shankerj14 

Add on to @joerghoh,

You can try inheriting the implementation class(ClassA or ClassB) along side implementing the interface. Check the below example.

ServiceOne

 

import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @Component(service=ServiceOne.class) public class ServiceOneImpl implements ServiceOne { @Reference ServiceTwo serviceTwo; @Override public String methodOne() { return "{\"ServiceOne\": \"methodOne\"}"; } @Override public String reuseMethodTwo() { return serviceTwo.methodTwo(); } }

 

ServiceTwo

 

import org.osgi.service.component.annotations.Component; @Component(service=ServiceTwo.class) public class ServiceTwoImpl extends ServiceOneImpl implements ServiceTwo { @Override public String methodTwo() { return "{\"ServiceTwo\": \"methodTwo\"}"; } @Override public String reuseMethodOne() { return super.methodOne(); } }

 

I am using a Servlet to invoke the ServiceTwo, which is internally calling ServiceOne method.

Servlet

 

import java.io.IOException; import javax.servlet.Servlet; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @Component(service=Servlet.class, property={ "sling.servlet.methods=" + "GET", "sling.servlet.paths="+ "/bin/test-servlet" }) public class TestServlet extends SlingAllMethodsServlet{ private static final long serialVersionUID = 1L; @Reference ServiceOne serviceOne; @Reference ServiceTwo serviceTwo; @Override public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) { response.setContentType("application/json"); try { response.getWriter().print(serviceOne.methodOne()); response.getWriter().print(serviceOne.reuseMethodTwo()); response.getWriter().print(serviceTwo.methodTwo()); response.getWriter().print(serviceTwo.reuseMethodOne()); } catch (IOException e) { e.printStackTrace(); } } }

 

Output

 

{"ServiceOne": "methodOne"}{"ServiceTwo": "methodTwo"}{"ServiceTwo": "methodTwo"}{"ServiceOne": "methodOne"}

 

AG