I took a look at OSGI DS and was curios about how to create a hello world bundle to run on Apache Felix. After a little search i decided that it would be a good opportunity to learn basics of maven 2. I checked out one of the projects at apache incubator svn and seeing pom.xml files I had no idea what they were used for. So for the sake of simplicity I will use Pax Construct and Pax Runner for building and running my bundle.
You should install the following software to continue this tutorial
- Eclipse Galileo (3.5.1)
- Maven 2.x
- m2eclipse
- Pax Runner plug-in for eclipse
Lets start by creating our project by typing
>mvn org.ops4j:maven-pax-plugin:create-project -DgroupId=org.example -DartifactId=ds_helloworld -Dversion=1.0-SNAPSHOT
It creates a folder named ds_helloworld and some sub directories like ds_helloworld/provisions and ds_helloworld/poms each containing a pom.xml. For what purpose these directories are used are explained here. Since we are only interested in making a hello world bundle we simply do not care.
Lets import the resulting maven projects into eclipse and see what they look like:
Lets move on and add a bundle to our project.
>cd ds_helloworld
>mvn org.ops4j:maven-pax-plugin:create-bundle -Dpackage=org.example.ds_helloworld -Dname=ds_helloworld -Dinternals=false -Dactivator=false
-Dinterface=false
>cd org.example.ds_helloworld
>mvn eclipse:eclipse (this will generate eclipse specific project files from pom.xml)
this will create a org.example.ds_helloworld bundle, again import it into workspace.
add org.apache.felix.scr and org.apache.felix.scr.annotations to dependencies of pom.xml of the newly created bundle
also add maven-scr-plugin to the plugins and define a goal like this:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.4.4</version>
<executions>
<execution>
<id>generate-scr-descriptions</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
then go to the projects pom.xml file (/ds_helloworld/pom.xml)
and add following plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
Now we need to add our source files to the org.example.ds_helloworld bundle. There are three .java files to add
org.example.ds_helloworld.HelloWorldService.java : This will define the interface that service implementation should implement. Each service is defined through an interface.
1 2 3 4 5 6 | package org.example.ds_helloworld; public interface HelloWorldService { public String helloWorld(); } |
org.example.ds_helloworld.HelloWorldServiceImp.java : This is the component that will provide implementation for our service. Only components can provide or consume services. Every component has a default constructor(public, takes no arguments).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package org.example.ds_helloworld; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; //This is a component so it can provide or consume services @Component // This component is providing the service that is defined through interface // org.example.ds_helloworld.HelloWorldService @Service public class HelloWorldServiceImp implements HelloWorldService { public String helloWorld() { return "helloWorld"; } } |
org.example.ds_helloworld.ServiceConsumer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package org.example.ds_helloworld; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.osgi.service.component.ComponentContext; //This is a component and it consumes a service @Component public class ServiceConsumer { // Service reference is preserved in a field @Reference private HelloWorldService service; // When needs of the component is statisfied the component will be activated // by calling this function @Activate public void activate(ComponentContext cc) { System.out.println(this.service.helloWorld()); } // When a HelloWorldService service is discovered it will be given to this // component through this method public void bindService(HelloWorldService service) { this.service = service; } } |
maven-scr-plugin is smart enough to generate serviceComponents.xml file and it is attached to the resulting jar file.
<?xml version=”1.0″ encoding=”UTF-8″?>
<components xmlns:scr=”http://www.osgi.org/xmlns/scr/v1.1.0″>
<scr:component enabled=”true” name=”org.example.ds_helloworld.HelloWorldServiceImp”>
<implementation class=”org.example.ds_helloworld.HelloWorldServiceImp”/>
<service servicefactory=”false”>
<provide interface=”org.example.ds_helloworld.HelloWorldService”/>
</service>
<property name=”service.pid” value=”org.example.ds_helloworld.HelloWorldServiceImp”/>
</scr:component>
<scr:component enabled=”true” name=”org.example.ds_helloworld.ServiceConsumer” activate=”activate”>
<implementation class=”org.example.ds_helloworld.ServiceConsumer”/>
<property name=”service.pid” value=”org.example.ds_helloworld.ServiceConsumer”/>
<reference name=”service” interface=”org.example.ds_helloworld.HelloWorldService” cardinality=”1..1″ policy=”static” bind=”bindService” unbind=”unbindService”/>
</scr:component>
</components>
then from the command line go to the root directory of the project and type:
>mvn clean install
after some console output eventually you will see something like that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [INFO] ------------------------------------------------------------------------ [INFO] Reactor Summary: [INFO] ------------------------------------------------------------------------ [INFO] org.example.ds_helloworld (OSGi project) .............. SUCCESS [5.407s] [INFO] ds_helloworld - plugin configuration .................. SUCCESS [0.032s] [INFO] ds_helloworld - wrapper instructions .................. SUCCESS [0.095s] [INFO] ds_helloworld - bundle instructions ................... SUCCESS [0.026s] [INFO] ds_helloworld - imported bundles ...................... SUCCESS [0.025s] [INFO] org.example.ds_helloworld ............................. SUCCESS [5.287s] [INFO] ------------------------------------------------------------------------ [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 14 seconds [INFO] Finished at: Tue Aug 10 20:43:41 EEST 2010 [INFO] Final Memory: 22M/53M [INFO] ------------------------------------------------------------------------ |
goto ds_helloworld/provision/pom.xml and add dependency (this is a dependency for Apache Felix SCR but not required in the org.example.sd_helloworld bundle so we put it into provisions module. This will be used when PAX runner constructs our launcher for felix platform).
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.configadmin</artifactId>
<version>1.2.4</version>
<type>bundle</type>
<scope>compile</scope>
</dependency>
Now we can create our launcher :
from command line go to the root of the project and type:
>mvn pax:provision
soon Apace Felix will start and output something like that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | __________ __________ \______ \_____ ___ ___ \______ \__ __ ____ ____ ___________ | ___/\__ \ \ \/ / | _/ | \/ \ / \_/ __ \_ __ \ | | / __ \_> < | | \ | / | \ | \ ___/| | \/ |____| (____ /__/\_ \ |____|_ /____/|___| /___| /\___ >__| \/ \/ \/ \/ \/ \/ Pax Runner (1.4.0) from OPS4J - <a href="http://www.ops4j.org">http://www.ops4j.org</a> ---------------------------------------------------- > Using config [classpath:META-INF/runner.properties] > Using only arguments from command line > Scan bundles from [C:\Users\Cihan\Documents\Blog\OSGI DS Intro\ds_helloworld\runner\deploy-pom.xml] > Scan bundles from [scan-pom:file:/C:/Users/Cihan/Documents/Blog/OSGI DS Intro/ds_helloworld/runner/deploy-pom.xml] > Provision bundle [mvn:org.apache.felix/org.apache.felix.configadmin/1.2.4, at default start level, bundle will be started, bundle will be loaded from the cache] > Provision bundle [mvn:org.example.ds_helloworld/org.example.ds_helloworld/1.0-SNAPSHOT, at default start level, bundle will be started, bundle will be loaded from the cache] > Provision bundle [mvn:org.apache.felix/org.apache.felix.scr/1.4.0, at default start level, bundle will be started, bundle will be loaded from the cache] > Preparing framework [Felix 2.0.2] > Downloading bundles... > mvn:org.apache.felix/org.apache.felix.configadmin/1.2.4 : 85016 bytes @ [ 14169kBps ] > mvn:org.example.ds_helloworld/org.example.ds_helloworld/1.0-SNAPSHOT : 5615 bytes @ [ 5615kBps ] > mvn:org.apache.felix/org.apache.felix.scr/1.4.0 : 185418 bytes @ [ 23177kBps ] > Using execution environment [J2SE-1.6] > Runner has successfully finished his job! Welcome to Felix ================ > helloWorld |
This shows us our HelloWorldService is created bound to the component that uses it and when this component activated it printed out the text.
-> shutdown
and stop Felix.
To start this launcher and debug it we need to define a run configuration in eclipse.
Run –> Run Configurations right click on OSGI Framework select new. A window will appear
goto Pax Runner tab and click Add POM and choose deploy-pom.xml from /ds_helloworld/runner
goto Bundles tab and choose Felix 2.0.1 via Pax runner as Framework and uncheck all bundles
Apply and Run then you will see helloWorld on Eclipse Console Tab.
Thats all for now next time we will be writing a Component Factory to create configured services at runtime.




