5
votes

I am building some modules which I want to expose as OSGi bundles without any actual dependencies to OSGi libraries. It would seem that this is possible using the declarative services option.

However because I'm rather new to OSGi (at least on the bundle-creating side) I want to test if it all works as it should, to this end I want to set up a small embedded OSGi environment.

Currently I have a single bundle which exports an API and also provides a stub implementation of a single interface.

I have followed the following tutorials to set up an environment:

And the embedded felix implementation seems to work properly however there are two problems:

Bundle bundle = felix.getBundleContext().installBundle("/path/to/bundle.jar")
bundle.start();
System.out.println(bundle.getRegisteredServices());

This prints out null so while the bundle is seemingly started ok, it does not seem to expose any services.

Secondly I'm wondering whether I have to do anything special to get the declarative services bit up and running. My maven dependencies are:

<dependencies>
    <dependency>
        <groupId>org.apache.felix</groupId>
        <artifactId>org.apache.felix.framework</artifactId>
        <version>4.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.felix</groupId>
        <artifactId>org.apache.felix.scr</artifactId>
        <version>1.6.2</version>
    </dependency>
</dependencies>

Based on the email thread found here: http://mail-archives.apache.org/mod_mbox/felix-users/201111.mbox/%[email protected]%3E

I tried to add the bundle to the felix startup properties:

map.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "org.apache.felix.scr; version=1.6.2");

However this seems a bit optimistic at first glance. How do I enable the declarative services for an embedded felix engine?

2

2 Answers

6
votes

The solution to both problems was to load the "scr" jar (used to parse declarative services) as a bundle before loading my own bundles.

Because the jar is located in my maven repository and it should work cross system, the following bit of code loads the scr jar from wherever it resides:

    URL url = getClass().getClassLoader().getResource("org/apache/felix/scr/ScrService.class");
    String jarPath = url.toURI().getSchemeSpecificPart().replaceAll("!.*", "");
    framework.getBundleContext().installBundle(jarPath).start();

After this bit I load my own bundle and the services in it were detected properly.

On a sidenote, you can enable logging by adding some properties to the initial map:

    map.put("ds.showtrace", "true");
    map.put("ds.showerrors", "true");

More properties can be found at http://felix.apache.org/documentation/subprojects/apache-felix-service-component-runtime.html

For future reference, here is all the code I used to get it up and running

private void initialize() throws BundleException, URISyntaxException {
    Map<String, String> map = new HashMap<String, String>();

    // make sure the cache is cleaned
    map.put(Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);

    // more properties available at: http://felix.apache.org/documentation/subprojects/apache-felix-service-component-runtime.html
    map.put("ds.showtrace", "true");
    map.put("ds.showerrors", "true");

    System.out.println("Building OSGi Framework");
    FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next();
    Framework framework = frameworkFactory.newFramework(map);

    System.out.println("Starting OSGi Framework");
    framework.start();

    // declarative services dependency is necessary, otherwise they won't be picked up!
    loadScrBundle(framework);

    framework.getBundleContext().installBundle("file:/path/to/myBundle.jar").start();

    ServiceReference reference = framework.getBundleContext().getServiceReference("my.Interface");
    System.out.println(framework.getBundleContext().getService(reference));

    for (Bundle bundle : framework.getBundleContext().getBundles()) {
        System.out.println("Bundle: " + bundle.getSymbolicName());
        if (bundle.getRegisteredServices() != null) {
            for (ServiceReference serviceReference : bundle.getRegisteredServices())
                System.out.println("\tRegistered service: " + serviceReference);
        }
    }
}

private void loadScrBundle(Framework framework) throws URISyntaxException, BundleException {
    URL url = getClass().getClassLoader().getResource("org/apache/felix/scr/ScrService.class");
    if (url == null)
        throw new RuntimeException("Could not find the class org.apache.felix.scr.ScrService");
    String jarPath = url.toURI().getSchemeSpecificPart().replaceAll("!.*", "");
    System.out.println("Found declarative services implementation: " + jarPath);
    framework.getBundleContext().installBundle(jarPath).start();
}
1
votes

I suggest to take a look at pax exam. It allows to test your bundle in an OSGi container. The nice thing is that it integrates with junit so your test look very similar to normal tests.For some examples see the Apache Karaf Tests.