Resolving OSGi Bundle dependencies

In this tutorial, we will learn how one OSGi bundle A, which is dependent on another bundle B, can call methods of the bundle B.

Example Scenario :

We have two bundles. We have to call a method of one bundle from another bundle in its Activator class.


Project artifacts:

1. Technologies used –

a. Eclipse IDE for Java EE developer 4.5.0.20150621-1200 (Mars)
b. Preinstalled Maven with Eclipse Mars
c. Java 1.8
d. Eclipse Equinox comes preinstalled with Eclipse Mars

2. Eclipse project folder structure:

OSGiDependencyBundles

3. Bundle Project

Create a karaf bundle project in Eclipse by following the below link.

Create an OSGi Bundle

We will create two bundles. One is independent bundle and one dependent and make relevant changes to the source files and deploy the same, first independent followed by dependent bundle.

4. Maven Dependencies

1. Independent Bundle:

file:pom.xml. Paste the below content to pom.xml of the newly created Independent bundle project. It declares dependencies, uses maven bundle plugin to create OSGi bundles and sets values of important bundle headers of MANIFEST.MF file.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.javanbeyond</groupId>
    <artifactId>IndependentBundle</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>bundle</packaging>
    <name>IndependentBundle Bundle</name>
    <description>IndependentBundle OSGi bundle project.</description>
    <dependencies>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>5.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.5.0</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                        <Bundle-Version>${project.version}</Bundle-Version>
                        <Bundle-Activator>com.javanbeyond.independent_bundle.Activator</Bundle-Activator>
                        <!-- Check the export package declaration. We are exporting only the interface package. -->
                        <Export-Package>com.javanbeyond.independent_bundle.interf*;version=${project.version}</Export-Package>
                        <Import-Package>*</Import-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

2. Dependent Bundle:

file:pom.xml. Paste the below content to pom.xml in the newly created Dependent bundle project.It declares dependencies, uses maven bundle plugin to create OSGi bundles and sets values of important bundle headers of MANIFEST.MF file. Please note that it has declared Independent bundle as one of it’s dependencies and its interface package in “Import-Package” bundle header.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.javanbeyond</groupId>
    <artifactId>DependentBundle</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>bundle</packaging>
    <name>DependentBundle Bundle</name>
    <description>DependentBundle OSGi bundle project.</description>
    <dependencies>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>5.0.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- Dependency declaration -->
        <dependency>
            <groupId>com.javanbeyond</groupId>
            <artifactId>IndependentBundle</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.5.0</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                        <Bundle-Version>${project.version}</Bundle-Version>
                        <Bundle-Activator>com.javanbeyond.dependent_bundle.Activator</Bundle-Activator>
                        <Export-Package>com.javanbeyond.dependent_bundle*;version=${project.version}</Export-Package>
                        <!-- Check the import package decalaration -->
                        <Import-Package>com.javanbeyond.independent_bundle.interf*;version=${project.version},*</Import-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

5. Activator class

Class containing lifecycle methods of the bundle called during start and stop of bundle by OSGi framework.

1. Independent Bundle. file: com.javanbeyond.independent_bundle.Activator.java

In the start method of Activator class of Independent bundle, its interface and implementation object is registered with BundleContext to make it available for the dependent bundle to access its method. It can be unregistered by calling unregister method on ServiceRegistration in stop method.

package com.javanbeyond.independent_bundle;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

import com.javanbeyond.independent_bundle.impl.HelloWorldImpl;
import com.javanbeyond.independent_bundle.interf.IHelloWorld;

public class Activator implements BundleActivator {
    ServiceRegistration<IHelloWorld> helloWorldRegistration;

    public void start(BundleContext context) {
        System.out.println("Starting the bundle.Independent.");
        // Registering the implementation object so that it can be made
        // available by Framework when asked for by some other bundle and the
        // other bundle can call its methods. Please note that we are
        // registering
        // the object as Interface
        helloWorldRegistration = context.registerService(IHelloWorld.class, new HelloWorldImpl()null);
    }

    public void stop(BundleContext context) {
        System.out.println("Stopping the bundle.Independent.");
        // Cleaning up when bundle is stopping
        helloWorldRegistration.unregister();
    }

}

2. Dependent Bundle. file: com.javanbeyond.dependent_bundle.Activator.java

In the start method of Dependent bundle, the registered independent bundle object is referenced and fetched by calling BundleContext getService method. Once the reference is available, the hello world method is being called.

package com.javanbeyond.dependent_bundle;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import com.javanbeyond.independent_bundle.interf.IHelloWorld;

public class Activator implements BundleActivator {
    ServiceReference<IHelloWorld> helloWorldReference;

    public void start(BundleContext context) {
        System.out.println("Starting the bundle.Dependent.");
        // Getting the object from Framework by service reference
        // and calling it on the interface.
        helloWorldReference = context.getServiceReference(IHelloWorld.class);
        IHelloWorld helloService = context.getService(helloWorldReference);
        System.out.println(helloService.helloWorld());
    }

    public void stop(BundleContext context) {
        System.out.println("Stopping the bundle.Dependent.");
        // Cleaning up when bundle is stopping
        context.ungetService(helloWorldReference);
    }

}

 

6. Interface of Independent Bundle

file: IHelloWorld.java. This interface is used by the dependent bundle to call on the method of Independent bundle.

package com.javanbeyond.independent_bundle.interf;

public interface IHelloWorld {
    public String helloWorld();
}

7. Implementation of Independent Bundle

file: HelloWorldImpl.java. Implementation of the above interface of independent bundle.

package com.javanbeyond.independent_bundle.impl;

import com.javanbeyond.independent_bundle.interf.IHelloWorld;

public class HelloWorldImpl implements IHelloWorld {

    public String helloWorld() {
        return "Hello World";
    }
}

 


Example Execution:

  1. Execute Maven clean and install and build both the projects.
  2. Install and start the Independent bundle in an osgi framework.If you are new to installing bundles in Eclipse, please read Create a bundle and deploy tutorial.
osgi> install file:<PATH TO BUNDLE>/IndependentBundle-0.0.1-SNAPSHOT.jar
Bundle id is 5
Location             file:<PATH TO BUNDLE>/IndependentBundle-0.0.1-SNAPSHOT.jar
State                2
RegisteredServices   null
ServicesInUse        null
Module               osgi.identity; osgi.identity="IndependentBundle"; type="osgi.bundle"; version:Version="0.0.1.SNAPSHOT" [id=5]
Version              0.0.1.SNAPSHOT
Bundle                   5|Installed  |    1|IndependentBundle (0.0.1.SNAPSHOT)
BundleContext        null
BundleId             5
SymbolicName         IndependentBundle
LastModified         1443908223069
Headers               Bnd-LastModified = 1443908185010
 Build-Jdk = 1.8.0_25
 Built-By = <YOUR ID>
 Bundle-Activator = com.javanbeyond.independent_bundle.Activator
 Bundle-Description = IndependentBundle OSGi bundle project.
 Bundle-ManifestVersion = 2
 Bundle-Name = IndependentBundle Bundle
 Bundle-SymbolicName = IndependentBundle
 Bundle-Version = 0.0.1.SNAPSHOT
 Created-By = Apache Maven Bundle Plugin
 Export-Package = com.javanbeyond.independent_bundle.interf;version="0.0.1.SNAPSHOT"
 Import-Package = com.javanbeyond.independent_bundle.interf;version="[0.0,1)",org.osgi.framework;version="[1.7,2)"
 Manifest-Version = 1.0
 Require-Capability = osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.5))"
 Tool = Bnd-2.3.0.201405100607



osgi> start 5
Starting the bundle.Independent.

3.  Install and start the Dependent bundle in the OSGi framework. You should see it calling the Independent bundle method as shown in the console.

osgi> install file:<PATH TO BUNDLE>/DependentBundle-0.0.1-SNAPSHOT.jar
Bundle id is 6
Location             file:<PATH TO BUNDLE>/DependentBundle-0.0.1-SNAPSHOT.jar
State                2
RegisteredServices   null
ServicesInUse        null
Module               osgi.identity; osgi.identity="DependentBundle"; type="osgi.bundle"; version:Version="0.0.1.SNAPSHOT" [id=6]
Version              0.0.1.SNAPSHOT
Bundle                   6|Installed  |    1|DependentBundle (0.0.1.SNAPSHOT)
BundleContext        null
BundleId             6
SymbolicName         DependentBundle
LastModified         1443908296492
Headers               Bnd-LastModified = 1443908265166
 Build-Jdk = 1.8.0_25
 Built-By = <YOUR ID>
 Bundle-Activator = com.javanbeyond.dependent_bundle.Activator
 Bundle-Description = DependentBundle OSGi bundle project.
 Bundle-ManifestVersion = 2
 Bundle-Name = DependentBundle Bundle
 Bundle-SymbolicName = DependentBundle
 Bundle-Version = 0.0.1.SNAPSHOT
 Created-By = Apache Maven Bundle Plugin
 Export-Package = com.javanbeyond.dependent_bundle;version="0.0.1.SNAPSHOT";uses:="org.osgi.framework"
 Import-Package = com.javanbeyond.independent_bundle.interf;version="0.0.1.SNAPSHOT",org.osgi.framework;version="[1.7,2)"
 Manifest-Version = 1.0
 Require-Capability = osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.5))"
 Tool = Bnd-2.3.0.201405100607



osgi> start 6
Starting the bundle.Dependent.
Hello World
osgi>

 

Leave a Reply

Back to Top
%d bloggers like this: