Let’s write and run your first OSGi service on WSO2 platform
As I promised last time, this post focuses on building OSGi services and their interaction. We are going to run over OSGi services in WSO2 carbon platform which is an OSGi based platform. Before heading to the implementation, make sure you have the basic idea of OSGi. You can get the background knowledge from here.
Let’s start with a very basic scenario.
Imagine there are two members; a producer (who produces a service) and a consumer (who consumes a service). For example, a greeting card maker(producer) to create greeting cards and a customer to buy a greeting card(consumer).
Let’s map this example to OSGi domain.
There is a module interaction in OSGi. Therefore, the producer and consumer 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, producer module should have a set of exposed services to the outside such as confirming order requests, sending orders, listing available cards, and etc. to use by consumers.
The consumer module can order a card, retrieve an ordered card, view available cards, and etc.
Hope now you have a good understanding of this practical example.
Let’s make our hands dirty.🤗
However, I hope you have the basic knowledge to make a maven project, add dependencies and plugins. If not, please have a quick glance at them, but I will explain in the lower level.
First, we will create the project structure to implement the modules(using Intellij IDEA editor in Ubuntu).
Create a maven project with the name greeting-card-manager. This is the main project and it contains both the producer and consumer component. (but it is not a must you can have a consumer and producer in separate two places)
groupId — org.wso2.carbon
artifactId — greeting-card-manager
version — 1.0-SNAPSHOT
packaging — pom
name — WSO2 Carbon-Greeting Card Manager
Note: <properties> and <modules> tags will add to this pom file later. Final pom is as follows.
Now let’s create 2 sub maven projects (producer and consumer).
(1) org.wso2.carbon.greeting.card.producer
artifactId — org.wso2.carbon.greeting.card.producer
packaging — bundle
name — WSO2 Carbon-Greeting Card Producer
plugin — maven-bundle-plugin
plugin — maven-scr-plugin
dependency — org.apache.felix.scr.ds-annotations
dependency — org.eclipse.osgi.services
dependency — org.eclipse.osgi
Note: When adding this project, the parent project should be updated accordingly with <modules> and the current project with <parent> tag. If you are using an IDE, it auto generates them.
Here is a brief explanation about the above pom file.
Writing the manifest.mf file is a most important task when building an OSGi bundle. However, writing that file correctly is not an easy task. Therefore, you need to use a tool to generate it. Maven bundle plugin an example to use for it.
Maven bundle plugin decides the classes and resources which need be copied to your bundle and the manifest headers and their values which should be placed in the bundle’s manifest.mf file. Let’s see the manifest file of this component after building it.
You can see,
<packaging>bundle</packaging>
Setting “bundle” as the packaging element is the place where you configure maven to build an OSGi bundle
Bundle-SymbolicName, Bundle-Name, Export-Package, Import-Package, Private-Package and some other values sets for OSGi manifest header under configuration instructions of the maven-bundle plugin.
Note: Export-Packages instruction has taken precedence.
If you use the following order, all classes in org.wso2.carbon.greeting.card.producer package will be exported except classes inside org.wso2.carbon.greeting.card.producer.internal.
<Export-Package>
!org.wso2.carbon.greeting.card.producer.internal,
org.wso2.carbon.greeting.card.producer.*
</Export-Package>
If the above order is changed, we can’t stop internal folder’s export.
Internal package contains the class which is used to register the OSGi service. We don’t expose it to outside. That’s why the above order is given in the Export-package. Further, we define that internal package is a private package.
<Private-Package>
org.wso2.carbon.greeting.card.producer.internal
</Private-Package>
Let’s write the greeting card service.
Create the following folder structure in org.wso2.carbon.greeting.card.producer project,and an interface named as GreetingCardProducer , a class named as GreetingCardProducerImpl (in src/main/java/org/wso2/carbon/greeting/card/producer/) , a java class named as GreetingCardProducerServiceComponent (in src/main/java/org/wso2/carbon/greeting/card/producer/internal) and a java class named as GreetingCard (in src/main/java/org/wso2/carbon/greeting/card/producer/model).
Let’s write the service as follows and create the data model.
Then register the created service of greeting card producer in a registry in order to use it from other components.
That registering is done in the GreetingCardProducerServiceComponent class.
bundleContext.registerService(GreetingCardProducer.class,
GreetingCardProducerImpl.getInstance(), null);
Service registration is done in this line under activate method. The above added dependencies are used in this class.
(2) org.wso2.carbon.greeting.card.consumer
artifactId — org.wso2.carbon.greeting.card.consumer
packaging — bundle
name — WSO2 Carbon-Greeting Card Consumer
plugin — maven-bundle-plugin
plugin — maven-scr-plugin
dependency — org.wso2.carbon.greeting.card.producer
dependency — org.apache.felix.scr.ds-annotations
dependency — org.eclipse.osgi.services
dependency — org.eclipse.osgi
Note: When adding this project, the parent project should be updated accordingly with <modules> and the current project with <parent> tag. If you are using an IDE, it auto generates them.
An important thing in this pom file is import-packages. Since we are going to use the greeting card producer in this consumer module, that producer need to be imported here.
<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.greeting.card.producer.*; version="${project.version}"
</Import-Package>
Create the following folder structure in org.wso2.carbon.greeting.card.consumer project, and a class named as GreetingCardConsumer (in src/main/java/org/wso2/carbon/greeting/card/consumer/), a class named as GreetingCardConsumerComponent (in src/main/java/org/wso2/carbon/greeting/card/consumer/internal/),and a class named as GreetingCardConsumerDataHolder (in src/main/java/org/wso2/carbon/greeting/card/consumer/internal/).
Now we are going to write the consumer, in such a way that the consumer requests to create a greeting card at its activation.
Now build your projects using mvn clean install
command. Navigate to the greeting-card-manager folder. Then open a terminal and print mvn clean install
.
If the build is succeeded, you could find
org.wso2.carbon.greeting.card.consumer-1.0-SNAPSHOT.jar inside greeting-card-manager/org.wso2.carbon.greeting.card.consumer/target
org.wso2.carbon.greeting.card.producer-1.0-SNAPSHOT.jar inside greeting-card-manager/org.wso2.carbon.greeting.card.producer/target
Open the jar files and check MANIFEST.MF file inside it, in order to understand how maven-bundle-plugin is made it.
Now we are done with creating OSGi bundles. Let’s deploy and test.
Deploy and Test
As I mentioned above, we are going to run these OSGi services in WSO2 platform.
- In your Web browser, go to http://wso2.com/products/carbon/.
- 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 then select the version that you want.
- Enter the required details in the form, and click Download.
- Extract the downloaded zip file. Hereafter I’ll use <PRODUCT_HOME> for that extracted folder.
- Navigate to
<PRODUCT_HOME>/repository/components/dropins
. - Copy org.wso2.carbon.greeting.card.consumer-1.0-SNAPSHOT.jar and org.wso2.carbon.greeting.card.producer-1.0-SNAPSHOT.jar to there.
- Then, go to
<PRODUCT-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 producer inside consumer when the consumer activates, That requested greeting card needs to be created before starts the server.
The below highlighted logs could be seen if your bundles are activated and working properly.
Okay we are done. 😎
If you got any issue when activating the bundles let’s do a quick debug.
Useful OSGi commands to debug
After the server starts up, enter few lines. Then you can get the OSGi console.
Then type osgi> ss greeting
.
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 bundles name and list out only relevant bundles.
In order to perform the bundles activities, they should in ACTIVE state. If it is not ACTIVE debug further.
Note : The bundle life cycle is explained in here.
Then type osgi>b <bundle id>
.
That command lists down the details of the selected bundle. Id, status, data root, registered services, services in use, exported packages, imported packages, and etc. So, you can check whether the services are registered and relevant packages are imported and exported.
Then type osgi>diag <bundle id>
.
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 unresolved constraints.
, it is good to proceed.
Here you can find the full code.
Happy Coding 😊