Question

I'm experiencing what I believe it's an strange behaviour from Osgi services and their tracking.

I've got two bundles: Provider and Client. Provider offers the "comm service" which Client receives and uses.

At the beginning, Client retrieved the service via the OSGi TrackerService thanks to this method on the ClientActivator class:

private CommService retrieveCommService(BundleContext bc) 
                              throws InterruptedException {

        //create the tracker
        ServiceTracker tracker = new ServiceTracker(bc, CommService.class.
                                                   getName(), null);
        tracker.open();

        //timeout of 5 seconds to find the service
        CommService service = (CommService) tracker.waitForService(5000);
        tracker.close();

        return service;
    }

This way, the tracker found the service when the activator of the Client bundle was executed.

If the ServiceTracker works properly, this is what I see when I type services on the OSGi console:

{some.project.folder.imaComms.CommService}={service.id=46}
  Registered by bundle: MA_Provider [2062]
  Bundles using service:
    MA_Client [2565]

Anyway, after reading several documentation about OSGi services, I decided to use DS instead of ServiceTrackers.

So, I created the components (provider and client xml files) and implemented the bind and unbind methods:

 public void setComms(CommService comm){        
        this.comm = comm;
        System.out.println("got comms!");
    }

    public void unsetComms(CommService comm){           
        this.comm=null;
        System.out.println("lost comms..");
    }

And, this time, this is what I see when I type services on the Console:

{some.project.folder.imaComms.CommService}={component.name=
 MA_Comm_Provider, component.id=18, service.id=47}
  Registered by bundle: MA_Provider [2062]
  Bundles using service:
        MA_Client [2565]

So, whenever I stopped the Provider bundle, the message lost comms... appeared on console. When I started it again, got comms! was the message.


Everything perfect so far. But I wanted to make a last test. I implemented the bind and unbind methods, the component definition, but I also let the ServiceTracker find the service on the ClientActivator.

The result is somehow strange.

When I start the OSGi framework, got comms! appears on console, as if the DS bind method was working and offering the service to my Client. But if I type services, this is what I got:

 {some.project.folder.imaComms.CommService}={service.id=46}
      Registered by bundle: MA_Provider [2062]
      Bundles using service:
        MA_Client [2565]


 {some.project.folder.imaComms.CommService}={component.name=
  MA_Comm_Provider, component.id=18, service.id=47}
      Registered by bundle: MA_Provider [2062]
      No Bundles using this service.

The Client is using the service via ServiceTracker. If I stop the ProviderService, I got this message from the unbind method: *lost comms...*

What happens if I start the bundle again? Yeah, "got comms!" appears on console...but then again, if I take a look at services, the service id 47 (DS service) is not being used by anyone. What? O_o

Any clue of what's going on? Thanks in advance!

Also, forgot to mention: Whenever I restart the Provider bundle, Osgi takes about 2-3 minutes starting the bundle, and it completely stops any other bundles' work.


UPDATE 28/03/14

XML files for provider and client DS

Provider

  <?xml version="1.0" encoding="UTF-8"?>
    <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"  name="MA_Comms_Provider">
       <implementation class="some.project.folder.maComms.CommServiceImpl"/>
       <service>
          <provide interface="some.project.folder.imaComms.CommService"/>
       </service>
    </scr:component>

Client

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="MA_Comms_consumer">
   <implementation class="some.project.folder.maClient.MyClientImpl"/>
   <reference bind="setComms" cardinality="1..1" interface="some.project.folder.imaComms.CommService" name="CommService" policy="static" unbind="unsetComms"/>
</scr:component>

Manifest files for Provider and Client

Provider

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: MA_Provider
Bundle-SymbolicName: MA_Provider
Bundle-Version: 1.0.0
Bundle-ClassPath: src/,
 .
Bundle-Activator: myActivator
Export-Package: ...
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: ...,
 org.osgi.framework;version="1.5.0",
 org.osgi.util.tracker;version="1.4.2"
Service-Component: OSGI-INF/CommsProvider.xml

Client

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: MaClient
Bundle-SymbolicName: MA_Client
Bundle-Version: 1.0.0
Bundle-ClassPath: src/,
 .
Bundle-Activator: ...
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: ...,
 org.osgi.framework;version="1.3.0",
 org.osgi.util.tracker;version="1.4.2"
Export-Package: es.techabout.meetabout.macomms
Service-Component: OSGI-INF/CommsConsumer.xml, ...

It should be noted that I omitted the real names of folders, classes and services, so even if my text has any error regarding names of classes, folders ..., I assure you that the real project is build with no errors whatsoever.

Was it helpful?

Solution

So if I understand you correctly, you have installed the following bundles:

  1. Provider using DS
  2. Provider registering service directly
  3. Client using DS
  4. Client using ServiceTracker

If you start all those bundles, you see the DS Client found one of the Provider services. You also see that if you stop the bundle that provides that service, the DS Client does not find the other Provider service. That might sound odd, but could be explained if you have managed to partition your class space. For a definitive answer about that, we'd need all 4 bundle's manifests, but my guess is that the DS Client is wired to the export of one of the providers and that the other provider has a different export.

The fact that you don't see the Client using ServiceTracker show up can be explained because you open and close that tracker in your code. After closing it, OSGi no longer regards the service as "in use". Yes you still keep a reference around, but you don't know if the service is still there.

So let us see the manifests (and maybe also the DS XML) so we can see if my theory is correct.

OTHER TIPS

I don't understand your problem. Your DS version appeared to be working fine, so you decide to mess with it and then it doesn't work any more? Perhaps go back to what was working.

service.id=46 seems to be a "raw" service registration by your provider bundle. service.id=47 is a registration by DS on behalf of your provider bundles. See the component.name service property. So you have the provider bundle registering 2 services.

You don't show the component description for your client bundles, so we can assume it would be fine with either service, so one of the two is picked.

Finally, you original use of ServiceTracker is wrong. The tracker must remain open while you use the service. When you use a tracker, you never hold the service object directly in a long term variable. You hold the tracker in a long term variable and consult it for the service object each time you need the service. Otherwise, you are assuming that once you get the service object that it is valid forever.

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