Get hands dirty with OSGi 🚀

Maneesha Indrachapa
9 min readJul 31, 2021

--

Photo by Jeremy Bishop in Unsplash

We learned the concepts of OSGi services last time, here we are trying to create new OSGI services and run them in the WSO2 Carbon platform, which is an OSGi platform. If you don’t have any idea regarding what is OSGI you can refer to this link

Let's look at a simple scenario and try to implement that scenario using these OSGi services. The scenario is like this, imagine there is a player who plays a game where there are multiple champions, the champion for the player is generated automatically when the player requests a champion from the game.

Now we have to map the above scenario to the OSGi services, There is a module interaction in OSGi. Therefore, the player and champion generation are two different modules. Each module in a system defines a logical boundary. Also, a module itself is in a control of the classes which are fully encapsulated (hidden) and which are exposed to external use.

So the player module will have functions like requesting a champion, view the champion details, view player stats, etc. when the Champion generation module will have functions like generate a champion, champion stats update, champions add to the champion pool, nerf champion abilities, etc.

Module Interaction of the above scenario

Okay now we need to code the two modules that need for the above scenario, but we need to write them as OSGi services. The most important task in building OSGi services is to write the manifest.mf file correctly. In most cases writing this file manually is not an easy task. So we need to use a tool to generate it, rather than writing it on our own. For this task, the Maven bundle plugin is a great choice.

Okay, let's create a maven project and start coding (Hope you have a basic understanding of the maven project management tool) Here we use Intellij IDEA as our IDE to create a maven project.

Create a maven project with the name game-manager. This is the main project and it contains both the player and champion pool components. we can create a player and champion pool in two different places, but doing this will make code less complex and easy to access.

groudId:org.wso2.carbon
artifactId:game-manager
version:1.0-SNAPSHOT
packaging:pom
name:WSO2 Carbon-Game Manager

After creating this parent module, in IntelliJ IDEA you can create sub-modules by right-clicking on the parent module and add new > module so like that you need to create two submodules org.wso2.carbon.game.producer and org.wso2.carbon.game.consumer so after creating those two submodules your project directory will look like this.

Note: When adding submodules to this project, the parent project pom should be updated accordingly with <modules> and the submodules pom will have a <parent> tag. If you are using an IDE, it auto-generates them.

as you can see under the wso2-game-manager parent project there are two submodules org.wso2.carbon.game.producer and org.wso2.carbon.game.consumer

the final parent pom file will look like below,

Game Producer

First, let’s look at how to create org.wso2.carbon.game.producer and we use the following stuff.

artifactId:org.wso2.carbon.game.producer
packaging:bundle
plugin:maven-bundle-plugin , maven-scr-plugin
dependency:org.apache.felix.scr.ds-annotations , org.eclipse.osgi.services ,org.eclipse.osgi
name:WSO2 Carbon-Game Producer

the final pom file looks like below.

As you can see in the pom file <packaging>bundle</packaging> so this module is packaging as an OSGi bundle. In an OSGI bundle hardest part is to write the manifest.mf file. So in the above pom, you can see we use the maven-bundle plugin.

In the maven-bundle-plugin, we identify the Bundle-Symbolic-Name, Bundle-Name, Export-Package, Import-Package, Private-Package, and some other values sets for OSGi manifest header under configuration instructions.

We described that the org.wso2.carbon.game.producer.internal the package needs to be private-package and also in the Export-package section we described that as below,

<Export-Package>
!org.wso2.carbon.game.producer.internal, org.wso2.carbon.game.producer.*
</
Export-Package>

So this means export all the packages in org.wso2.carbon.game.producer except the org.wso2.carbon.game.producer.internalpackage.

Let's start the coding game-producer💻

Project file order for game-producer

First, create your files like this, so you need to have 4 files inside 2 directories.

Inside internal directory create, GameProducerServiceComponent.java class

Inside model directory create, Player.java class and crate GameProducer.java interface and GameProducerImpl.java the class which implements the GameProducer.java interface

Champion.java
GameProducer.java interface
GameProducerImpl.java class implementing the GameProducer.java interface

Then register the created service of the game service producer in a registry to use it from other components.

That registering is done in the GameProducerServiceComponent.java class.

GameProducerServiceComponent.java
bundleContext.registerService(GameProducer.class, GameProducerImpl.getInstance(), null);

Service registration is done in this line under activate method. Also, you can see that service registering is done under a try-catch block, that is because there can be some errors or exceptions that can happen when service is registering in OSGi framework due to server errors or some other errors to catch that and throw error we register services inside a try-catch block.

Game Consumer

Now, let’s look at how to create org.wso2.carbon.game.consumer and we use the following stuff.

artifactId:org.wso2.carbon.game.consumer
packaging:bundle
plugin:maven-bundle-plugin , maven-scr-plugin
dependency:org.apache.felix.scr.ds-annotations , org.eclipse.osgi.services ,org.eclipse.osgi, org.wso2.carbon.game.producer
name:WSO2 Carbon-Game Consumer

the final pom file looks like below.

An important thing in this pom file is import packages. Since we are going to use the game producer in this consumer module, that producer needs to be imported as an imported package.

<Import-Package>
org.osgi.framework; version=”${osgi.framework.imp.pkg.version.range}”,
org.osgi.service.component; version=”${osgi.service.component.imp.pkg.version.range}”,
org.wso2.carbon.game.producer.*; version=”${project.version}”
</Import-Package>
Project file order for game-consumer

Create your files like this, there need to have a internal , the package consists of two java files. GameConsumerComponent.java and GameConsumerDataHolder.java and GameConsumer.java file outside the internal package.

Now we are going to write the GameConsumer.javain such a way that the consumer requests to run addPlayer() at its activation.

GameConsumer.java
GameConsumerComponent.java

We use a data-holder class to hold the services that need to be used in the component, As you can see

@Reference( name = “org.wso2.carbon.game.producer”, 
service = GameProducer.class,
cardinality = ReferenceCardinality.MANDATORY,
policy = ReferencePolicy.DYNAMIC, unbind = “unsetGameProducer” )

protected void setGameProducer(GameProducer gameProducer)
{
LOGGER.info(“Game producer is set to Game consumer bundle.”);
GameConsumerDataHolder.getInstance().
setGameProducer(gameProducer);
}

We are using GameProducer.class and we user GameProducer service and we are holding that service object inside the data holder class. So whenever we want it we can use that service by calling the data-holder class.

GameConsumerDataHolder.java

Now build your projects using the mvn clean install command. Navigate to the wso2-game-manager folder. Then open a terminal and execute mvn clean install .

If the build is succeeded, you could find,

org.wso2.carbon.game.producer-1.0-SNAPSHOT.jar inside wso2-game-manager/org.wso2.carbon.game.producer/target/

org.wso2.carbon.game.consumer-1.0-SNAPSHOT.jar inside wso2-game-manager/org.wso2.carbon.game.consumer/target/

to check the configurations that you added you can open the jar files and look at the manifest.mf file inside META-INF.

As an example, this is the org.wso2.carbon.game.consumer-1.0-SNAPSHOT.jar in the META-INF you can find the manifest.mf file.

manifest.mf

and inside OSGI-INF you can find OSGi metadata such as registered services and stuff. Below you can see the org.wso2.carbon.game.producer service that we added that we want to use as a service in the consumer is in the metadata.

<?xml version=”1.0" encoding=”UTF-8"?>
<scr:component xmlns:scr=”http://www.osgi.org/xmlns/scr/v1.1.0" immediate=”true” name=”org.wso2.carbon.game.consumer” activate=”activate”>
<reference name=”org.wso2.carbon.game.producer” interface=”org.wso2.carbon.game.producer.GameProducer” cardinality=”1..1" policy=”dynamic” bind=”setGameProducer” unbind=”unsetGameProducer”/>
<implementation class=”org.wso2.carbon.game.consumer.internal.GameConsumerComponent”/>
</scr:component>

Now we are done with creating OSGi bundles. Let’s deploy and test.

Deploy and Test

We are going to run these OSGi services on the WSO2 platform.

  1. In your Web browser, go to http://wso2.com/identity-server.
  2. Click the Download button in the upper right-hand corner of the page to download the latest version. To download an older version, click the Previous Releases link and select the version that you want.
  3. Enter the required details in the form, and click Download.
  4. Extract the downloaded zip file. Hereafter I’ll use <IS_HOME> for that extracted folder.
  5. Navigate to <IS_HOME>/repository/components/dropins .
  6. Copy org.wso2.carbon.game.producer-1.0-SNAPSHOT.jar and org.wso2.carbon.game.consumer-1.0-SNAPSHOT.jar to there.
  7. Then, go to the<IS_HOME>/bin folder and start the product as follows.

In Linux Environment

sh wso2server.sh -DosgiConsole

In Windows Environment

wso2server.bat -DosgiConsole

Since we have used the game-producer inside game-consumer when the consumer activates, That requested champion needs to be created before starts the server.
The below-highlighted logs could be seen if your bundles are activated and working properly.

Useful OSGi Commands

For you to know that the bundle is activated or if there are any issues OSGi console have few commands so by using those commands you can know bundle state, bundle details, etc.

ss → List down all bundles in the server with their bundle id, life cycle state and the name

ss <name> → Search the given name in the bundle's name and list out only relevant bundles.

To use this command press enter few times after the server is started then type the above command, As an example ss game will show me the bundles which have the “game” sub-string as their bundle name.

OSGi bundle summary

right now my server consists of two bundles that have a “game” sub-string in their bundle name. So I can see my two services, and you can see the state of the bundle, right now it is in an “Active” state. So bundles are active and running. If the bundle is not active can use the below commands for further debugging. (Bundle life-cycle is explained here)

b <bundle-id> →this will show bundle information

so you can see there is an “id” in the above screenshot of the terminal so “id” in there refers to the bundle.

Game-Consumer bundle info

So when using the b <bundle-id> the command you can get all the information of a particular bundle, it will lists down the details of the selected bundle. Id, status, data root, registered services, services in use, exported packages, imported packages, etc. So, you can check whether the services are registered and relevant packages are imported and exported.

diag <bundle id> →This shows any unsatisfied constraints of the bundle. So you can realize what are the reasons for not activating the bundle.

It shows any unsatisfied constraints of the bundle. So you can realize what are the reasons for not activating the bundle.
If it says,No resolution report for the bundleit is good to proceed.

Few Other OSGi Commands

p <package_name> → Shows the bundles that export and import the specified package.

ls -c → Lists down details of all OSGI components.

ls -c <bundle_id> or comp <component_id> → Lists down details all components of the specified bundle, or details specified OSGi components.

services <service_name> →Displays specified service details.

Below find the full code, 💻 🚀

--

--

Maneesha Indrachapa
Maneesha Indrachapa

Written by Maneesha Indrachapa

If you can dream it, you can do it.

No responses yet