Frank Büttner
Frank Büttner

Reputation: 62

osgi service: reference on active service not satisfied

I have an unsatisfied osgi service:

ls 142
Components in bundle A: 
ID  State           Component Name          Located in bundle
90  Unsatisfied     ServiceA            A(bid=142)

The reference to ServiceB is unsatisfied:

comp 90
    Component[
    name = ServiceA
    activate = activate
    deactivate = deactivate
    modified = 
    configuration-policy = optional
    factory = null
    autoenable = true
    immediate = false
    implementation = ServiceA
    state = Unsatisfied
    properties = 
    serviceFactory = false
    serviceInterface = [ServiceA]
    references = {
        Reference[name = ServiceB, interface = ServiceB, policy = static, cardinality = 1..1, target = null, bind = setServiceB, unbind = unsetServiceB]
    }
    located in bundle = B_2.12.0.qualifier [142]
]
Dynamic information :
  *The component is NOT satisfied
  The following references are not satisfied:
    Reference[name = ServiceB, interface = ServiceB, policy = static, cardinality = 1..1, target = null, bind = setServiceB, unbind = unsetServiceB]
  Component configurations :
    Configuration properties:
      component.name = ServiceA
      component.id = 136
      objectClass = String[ServiceA]
    Instances:

Nevertheless, ServiceB is active:

ls 52
Components in bundle B: 
ID  State           Component Name          Located in bundle
14  Active      ServiceB            B(bid=52)

So why is the reference from ServiceA to ServiceB unsatisfied? A restart of bundle A (stop and start) doesn't help. Configuring the reference on a working ServiceC in bundle C makes ServiceC unsatisfied.

Update: ServiceB has been registered

The result of the "services" command in the osgi console contains the following nipped:

{ServiceB}={service.id=180}
  Registered by bundle: Z_2.12.0.qualifier [123]
  No bundles using service.

Additional information: configuration, initialization and registration of ServiceA and ServiceB

ServiceB is basically an apache cxf web service, that's implementing an interface. This interface has been generated out of a wsdl. The ServiceB is registered programmatically. ServiceA has a reference to the generated interface. This pattern works perfectly with another web service (lets say ServiceC and ServiceD).
And if it helps: This pattern even worked between ServiceA and ServiceB until we upgraded apache cxf. I didn't provide this information before because I feared it would make this problem too complicated 😕.

Update: configuration of the component ServiceB

There are two parts considering the configuration: The xml file and the registration. The xml file contains the implementation class "WebServiceConfigImpl", a provided interface "WebServiceConfig" and some properties. One of the properties is the webservice "ServiceB" - the name under that the service is registered programmatically later in the start procedure.

xml file:

<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" deactivate="deactivate" name="ServiceB">
   <implementation class="WebServiceConfigImpl"/>
   <service>
      <provide interface="WebServiceConfig"/>
   </service>
   <property name="webservice" type="String" value="ServiceB"/>
   <property name="address" type="String" value="${adresse}"/>
   <property name="username" type="String" value="${benutzer}"/>
   <property name="password" type="String" value="${passwort}"/>
   (...)
   two references to other osgi services for resolving the web service configuration
</scr:component>

registration: We are using our own org.osgi.util.tracker.ServiceTracker for this. This ServiceTracker is opened in the Activator of bundle Z. It calls the constructor of ServiceTracker with "WebServiceConfig" as parameter, so this ServiceTracker is notified if a Service providing the interface "WebServiceConfig" has been registered. Our implementation of the SeriveTracker now reads the property "webservice" and publishs the osgi service under this name:

context.registerService(serviceName, service, null);

After that, the service is available and activated in the osgi console.

Update: accessing ServiceB

After the registration through our ServiceTracker, ServiceB is available through the osgi console AND by source code:

ServiceTracker st = new ServiceTracker(bundleContext, "ServiceB", null);
st.open();
st.getService();

Update: accessing ServiceB 2

ServiceB is accessible via source code in bundle Z. But it cannot be accessed via source code from bundle A. Then the service object is null.

Upvotes: 1

Views: 1227

Answers (1)

Frank B&#252;ttner
Frank B&#252;ttner

Reputation: 62

I found a workaround to get programmatically access to ServiceB:

ServiceTracker st = new ServiceTracker(context, ServiceB.class.getName(), null);
st.open(true);
st.getService()

The boolean parameter in the open method makes the difference.

Unfortunatelly I wasn't able to answer the question why some bundles have "direct" access to the ServiceB (no parameter in the open method needed) and some need the "true" parameter.

Upvotes: 2

Related Questions