OSGi Declarative Services

For those of you who don’t know, the Eclipse SDK now ships an implementation of OSGi Declarative Services (DS). I love DS when working with OSGi services and recommend it to people over using the brittle ServiceTracker mechanism. I’m a big proponent of having people learn by example. To help people understand DS a bit more, PDE includes a DS template now. To access the template, simply create a new project and select the template:

ds11 266x300 OSGi Declarative Services

Since the template is based on a simple dictionary service, you can fill out some sample words to be in the dictionary:

ds21 266x300 OSGi Declarative Services

Once you click finish, PDE will generate a sample project for you. Inside that sample project, there will be a DictionaryService that allows you to register dictionaries (Dictionary):

package org.eclipse.equinox.ds.example;
 
public interface Dictionary {
 
    /**
     * Returns the language of the dictionary
     *
     * @return the language of the dictionary
     */
    public String getLanguage();
 
    /**
     * Check for the existence of a word in the dictionary
     * 
     * @param word the word to be checked.
     * @return true if the word is in the dictionary
     */
    public boolean check(String word);
 
}

You will also notice that the MANIFEST.MF has an entry of ‘OSGI-INF/*.xml’ for the Service-Component header that lists the required DS files. If we take a peak at the component that registers a sample dictionary, it looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Simple Dictionary">
   <implementation class="org.eclipse.equinox.ds.example.DictionaryImpl"/>
   <service>
      <provide interface="org.eclipse.equinox.ds.example.Dictionary"/>
   </service>
</scr:component>

The Java code equivalent of registering the sample dictionary without DS would look something like this:

...
service = new DictionaryImpl();
// register the service
context.registerService(DictionaryService.class.getName(), service, null);
...

Great, less code we have to write! Now let’s look at a more complicated example of declaring a component that both needs and registers a service:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="Command Provider for Dictionary Service">
   <implementation class="org.eclipse.equinox.ds.example.ServiceComponent"/>
   <service>
      <provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
   </service>
   <reference bind="setDictionary" cardinality="1..1" interface="org.eclipse.equinox.ds.example.DictionaryService" name="Dictionary" policy="static" unbind="unsetDictionary"/>
</scr:component>

If we had to write this in code, it would involve a ServiceTracker to track the dictionary service, registering our component’s CommandProvider service implementation and code to track dictionary implementations. All in all, it would be quite a chunk of code to keep track of everything. It would get more complicated if we allowed for different cardinality types.

As a reminder, you can also use the DS Tooling in PDE to help craft these component definitions:

ds3 300x298 OSGi Declarative Services

Let’s test this example now by launching a new self-hosted instance and checking out the console:

ds5 300x193 OSGi Declarative Services

Cool, we can now check for the existence of words in our dictionary using the Equinox console.

Here’s the code used in this example. To test, simply use the ‘Dictionary Example’ launch configuration included:

ds4 300x186 OSGi Declarative Services

For a bonus tip, there are console commands to help you debug DS:

---Service Component Runtime---
     list/ls [-c] [bundle id] - Lists all components; add -c to display the complete info for each component;
     use [bundle id] to list the components of the specified bundle
     component/comp <component id> - Prints all available information about the specified component;
     enable/en <component id> - Enables the specified component;
     disable/dis <component id> - Disables the specified component;

Also, I highly recommend using ‘-Dequinox.ds.print=true’ for extra debug information while debugging components that aren’t working like you expect them.

Good luck and I hope this helps! If you want more in depth knowledge of DS, I highly recommend checking out the new Equinox book which showcases an in depth chapter on DS.

7 Responses to “OSGi Declarative Services”

  1. Scott says:

    Cool Chris…I see you separated out the Dictionary from the provider…thanks. Now…should we add a Distributed Dictionary template? Also…could you point me at the new dictionary example template source?

  2. Sure, let’s do a ECF distributed OSGi example building on this one.

    Let’s save it for a blog post next week ;)

  3. Gary says:

    What version of Eclipse(DS) is the template available? I’m running 3.4 and I don’t see the template..

    Thanks!
    Gary

  4. Gary says:

    Ok.. So i did some digging and see the DS templates in 3.5.. I’ll have to get the latest 3.5 RC installed!

    One other question though related to the example above.. When I read the above it says to me that I don’t need the Activator code to register the service.. I can’t seem to get that to work.. If I include just the DS xml file (and it’s reference in the manifest) my service does not get registered (at least the other service which is listening for it doesn’t get notified).. But if I include code in the Activator to register the service my “listener” gets notified of thru it’s “bind” method.. So am I reading this wrong or do I still need the Activator code to register the service?

    Thanks!
    Gary

  5. Luke Patterson says:

    Had same problem as Gary, services not being registered, dropped to console and ran “services” (Equinox), the service in question doesn’t show up until I start the service-containing bundle. Any ideas?

  6. Luke, what’s the status of the org.eclipse.equinox.ds bundle?

    And, in the MANIFEST.MF of your bundle providing the component.xml, is it listed via the Service-Component header?

    You can start Equinox with -Dequinox.ds.print=true to hep with debugging DS issues

  7. Wolfgang Lux says:

    As I understand the example, the activator
    1. creates a DictionaryService instance
    2. registers the DictionaryService
    3. adds itself as service listener for Dictionary
    4. gets a reference to the DictionaryService instance using the service tracker it created before

    Is there a real need for the service tracker?
    If yes: why is there no need for the tracker methods addingService and removedService?
    My idea: Is this an example, to be split into several bundles, later?

7 responses so far

Written by . Published in Categories: Planet Eclipse