Reputation: 62
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.
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.
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 😕.
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.
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();
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
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