I would like to present a tutorial in which I show 4 ways how to activate/start code inside your OSGi bundle. All those ways are part of OSGi 4.2 specifications. The goal of the tutorial is to explain in a short form some OSGi specifications chapters with samples. I do not like to make any deep comparison of activation ways, just overview with workable examples. All sources you can find here.
Contents:
- Requirements
- Use Case details
- Bundle Activator
- Declarative Services
- Blueprint Services
- Web Application Bundle
- How to run examples
- References
- Requirements. There are minimum requirements:
- Apache Maven 2.x or 3.0.x
- Your IDE with Maven support.
- Basic knowledge of OSGi specification
- Basic knowledge of PAX tools (Pax Runner). You can get some brief information also here
- Use Case details.
The tutorial use case is very simple:
- There is interface org.knowhowlab.osgi.tips.activation.core.Echo
public interface Echo { String ECHO_TYPE_PROP = "echo_type"; String echo(String str); }This interface exported by core bundle. - This interface should be implemented
- Implementation should be registered as OSGi service only when org.osgi.service.prefs.PreferencesService service is available in OSGi registry
- There is interface org.knowhowlab.osgi.tips.activation.core.Echo
- Bundle Activator.
This is the simplest and oldest way to activate code in your bundle.
There are some details of this activation way:- There is only one BundleActivator per bundle
- Any class could implement org.osgi.framework.BundleActivator interface
- This class should have empty constructor
- This class should be provided with MANIFEST OSGi header Bundle-Activator to be called on OSGi bundle STARTING stage
- The best way to use it (from my own experience) in low-level bundles (e.g. implementation of any OSGi API) or when you like to control everything yourself
- This way could be also used when your code does not have a lot of dependencies to external services. org.osgi.util.tracker.ServiceTracker could be used to track external services. As many external services you track as more logic code you have to write to cover all cases.
Here is code of my BundleActivator that implements required tutorial use case:public class Activator implements BundleActivator, Echo { // ServiceTracker for PreferencesServices private ServiceTracker serviceTracker; // BundleContext private BundleContext bc; // Registration of Echo service private ServiceRegistration registration; // activation public void start(BundleContext context) throws Exception { bc = context; // init and start ServiceTracker to track PreferencesService serviceTracker = new ServiceTracker(context, PreferencesService.class.getName(), new Customizer()); serviceTracker.open(); } // deactivation public void stop(BundleContext context) throws Exception { // stop ServiceTracker to track PreferencesService serviceTracker.close(); serviceTracker = null; } public String echo(String str) { return str; } // customizer that handles tracked service registration/modification/unregistration events private class Customizer implements ServiceTrackerCustomizer { public Object addingService(ServiceReference reference) { System.out.println("PreferencesService is linked"); // register Echo service Dictionary<String, String> props = new Hashtable<String, String>(); props.put(ECHO_TYPE_PROP, "BundleActivator"); registration = bc.registerService(Echo.class.getName(), Activator.this, props); return bc.getService(reference); } public void modifiedService(ServiceReference reference, Object service) { } public void removedService(ServiceReference reference, Object service) { // unregister Echo service registration.unregister(); System.out.println("PreferencesService is unlinked"); } } }
Bundle MANIFEST.MF:Manifest-Version: 1.0 Bundle-Name: KnowHowLab Tips&Tricks: Bundle Activation - Activator Bundle-Version: 1.0.0.SNAPSHOT Bundle-ManifestVersion: 2 Bundle-Activator: org.knowhowlab.osgi.tips.activation.activator.Activa tor Bundle-Description: KnowHowLab Tips and Tricks: Bundle Activation - Ac tivator Import-Package: org.knowhowlab.osgi.tips.activation.core,org.osgi.fram ework;version="1.5",org.osgi.service.prefs;version="1.1",org.osgi.uti l.tracker;version="1.4" Bundle-SymbolicName: org.knowhowlab.osgi.tips.activation.activator
- Declarative Services.
Declarative Services specification is the next higher-level way of activation your code in bundle.
It helps developer to concentate on application logic and takes responsibility for almost all OSGi aspects
of tracking and registering services.
There are some details of this activation way:- Declarative Services do not work with bundle as atomic item (as in BundleActivator way). Service Component model is used instead of Bundle model
- OSGi bundle can contain any count of Service Components
- Every component should have Component Description - XML file with declaration of component
- Every Component Description should be listed in MANIFEST OSGi header Service-Component to be available for Service Component Runtime, that manages components and their life cycle
Here is code of my EchoComponent:public class EchoComponent implements Echo { // Reference to PreferencesService private PreferencesService preferencesService; public String echo(String str) { return str; } // Called to bind PreferencesService public void bindPreferencesService(PreferencesService preferencesService) { System.out.println("PreferencesService is linked"); this.preferencesService = preferencesService; } // Called to unbind PreferencesService public void unbindPreferencesService(PreferencesService preferencesService) { this.preferencesService = null; System.out.println("PreferencesService is unlinked"); } }
Here is Component Description:<?xml version="1.0" encoding="UTF-8"?> <components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0"> <!-- Echo Component --> <scr:component enabled="true" immediate="true" name="Echo"> <!--Component Class name--> <implementation class="org.knowhowlab.osgi.tips.activation.ds.EchoComponent"/> <!-- Echo Service description --> <service servicefactory="false"> <provide interface="org.knowhowlab.osgi.tips.activation.core.Echo"/> </service> <!-- Service registration properties --> <property name="echo_type" type="String" value="Declarative Services"/> <property name="service.pid" value="Echo"/> <!-- PreferencesService dependency description --> <reference name="preferencesService" interface="org.osgi.service.prefs.PreferencesService" cardinality="1..1" policy="static" bind="bindPreferencesService" unbind="unbindPreferencesService"/> </scr:component> </components>
Bundle MANIFEST.MF:Manifest-Version: 1.0 Service-Component: OSGI-INF/serviceComponents.xml Export-Package: org.knowhowlab.osgi.tips.activation.ds;uses:="org.know howlab.osgi.tips.activation.core,org.osgi.service.prefs" Bundle-Name: KnowHowLab Tips&Tricks: Bundle Activation - DS Bundle-Version: 1.0.0.SNAPSHOT Bundle-ManifestVersion: 2 Import-Package: org.knowhowlab.osgi.tips.activation.core,org.osgi.serv ice.prefs;version="1.1" Bundle-SymbolicName: org.knowhowlab.osgi.tips.activation.ds
There is Component Descrition annotations library that generate Component Description during OSGi bundle build and makes development of Service Components easier. Here is code with annotations:// Component description @Component(name = "Echo", immediate = true) // Service description @Service(value = Echo.class) // Service properties @Property(name = Echo.ECHO_TYPE_PROP, value = "Declarative Services") public class EchoComponent implements Echo { // Reference to PreferencesService @Reference(name = "preferencesService", referenceInterface = PreferencesService.class, cardinality = ReferenceCardinality.MANDATORY_UNARY, policy = ReferencePolicy.STATIC) private PreferencesService preferencesService; public String echo(String str) { return str; } // Called to bind PreferencesService public void bindPreferencesService(PreferencesService preferencesService) { System.out.println("PreferencesService is linked"); this.preferencesService = preferencesService; } // Called to unbind PreferencesService public void unbindPreferencesService(PreferencesService preferencesService) { this.preferencesService = null; System.out.println("PreferencesService is unlinked"); } }
- Blueprint Services.
Blueprint Services specification is derived from Spint Dynamic Modules specification and very similar to
Declarative Services specification (developer concentrates more on application-specific code).
There are some details of this activation way:- Blueprint Services do not work with bundle as atomic item (as in BundleActivator way). Component/Bean model is used instead of Bundle model
- OSGi bundle can contain any count of Components/Beans
- Every component/bean should have Component Definition - XML file with definition
- All Component/Bean Definitions should be stored in OSGI-INF/blueprint directory
Here is code of my EchoBean:public class EchoBean implements Echo { // Reference to PreferencesService private PreferencesService preferencesService; public String echo(String str) { return str; } // Called to bind PreferencesService public void bindPreferencesService(PreferencesService preferencesService, Map props) { this.preferencesService = preferencesService; System.out.println("PreferencesService is linked"); } // Called to unbind PreferencesService public void unbindPreferencesService(PreferencesService preferencesService, Map props) { this.preferencesService = null; System.out.println("PreferencesService is unlinked"); } }
Here is Bean Definition (OSGI-INF/blueprint/echo.xml):<?xml version="1.0" encoding="UTF-8" standalone="no"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <!-- Bean definition --> <bean id="echoservice" class="org.knowhowlab.osgi.tips.activation.blueprint.EchoBean"/> <!-- Service definition --> <service ref="echoservice" interface="org.knowhowlab.osgi.tips.activation.core.Echo" depends-on="preferencesService"> <service-properties> <entry key="ECHO_TYPE_PROP" value="Blueprint"/> </service-properties> </service> <!-- PreferencesService reference definition --> <reference id="preferencesService" interface="org.osgi.service.prefs.PreferencesService" availability="mandatory"> <reference-listener bind-method="bindPreferencesService" unbind-method="unbindPreferencesService"> <ref component-id="echoservice"/> </reference-listener> </reference> </blueprint>
I found very nice project BlueprintAnnotation under Apache Aries project. It provides runtime annotations for Blueprint beans that replaces Component/Bean Definition files. Here is EchoBean with Blueprint Annotations:// Bean definition @Bean(id = "echoservice") // Service definition @Service(interfaces = Echo.class, serviceProperties = @ServiceProperty(key = Echo.ECHO_TYPE_PROP, value = "Blueprint-Annotations")) @ReferenceListener public class EchoBean implements Echo { // Reference definition @Reference(availability = "mandatory", referenceListeners = @ReferenceListener(ref = "echoservice")) private PreferencesService preferencesService; public String echo(String str) { return str; } @Bind public void bindPreferencesService(PreferencesService preferencesService, Map props) { this.preferencesService = preferencesService; System.out.println("PreferencesService is linked"); } @Unbind public void unbindPreferencesService(PreferencesService preferencesService, Map props) { this.preferencesService = null; System.out.println("PreferencesService is unlinked"); } }
- Web Application Bundle.
Web Application Bundle (WAB) was introduced in OSGi Enterprise 4.2 Specification.
WAB is a combination of JEE Web Application and OSGi bundle.
There are some details of this activation way:- WAB has the same structure as standard WAR + OSGi MANIFEST.MF
- WAB uses the same life cycle and class/resource loading rules as standard OSGi bundle
- WAB context path should be described in MANIFEST OSGi header Web-ContextPath
- /classes and all JARs/ZIPs in /lib folder should be listed in MANIFEST OSGi header Bundle-Classpath
- OSGi BundleContext is provided to WAB as ServletContext attribute "osgi-bundlecontext". It is available for Servlets/JSPs/Listeners/Filters.
Here is code of my ContextListener:public class ContextListener implements ServletContextListener, Echo { private ServiceTracker serviceTracker; private BundleContext bc; private ServiceRegistration registration; public void contextInitialized(ServletContextEvent sce) { bc = (BundleContext) sce.getServletContext().getAttribute("osgi-bundlecontext"); serviceTracker = new ServiceTracker(bc, PreferencesService.class.getName(), new Customizer()); serviceTracker.open(); } public void contextDestroyed(ServletContextEvent sce) { serviceTracker.close(); serviceTracker = null; } public String echo(String str) { return str; } private class Customizer implements ServiceTrackerCustomizer { public Object addingService(ServiceReference reference) { System.out.println("PreferencesService is linked"); Dictionary<String, String> props = new Hashtable<String, String>(); props.put(ECHO_TYPE_PROP, "WAB"); registration = bc.registerService(Echo.class.getName(), ContextListener.this, props); return bc.getService(reference); } public void modifiedService(ServiceReference reference, Object service) { } public void removedService(ServiceReference reference, Object service) { registration.unregister(); System.out.println("PreferencesService is unlinked"); } } }
Here is web.xml:<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" metadata-complete="true" version="2.5"> <listener> <listener-class>org.knowhowlab.osgi.tips.activation.wab.ContextListener</listener-class> </listener> <!-- welcome file mapping --> <welcome-file-list> <welcome-file>index.htm</welcome-file> </welcome-file-list> </web-app>
Here is MANIFEST.MF:Manifest-Version: 1.0 Export-Package: org.knowhowlab.osgi.tips.activation.wab;uses:="org.kno whowlab.osgi.tips.activation.core,org.osgi.util.tracker,org.osgi.fram ework,javax.servlet,org.osgi.service.prefs";version="1.0.0.SNAPSHOT" Bundle-Classpath: WEB-INF/classes Bundle-Name: KnowHowLab Tips&Tricks: Bundle Activation - WAB Web-ContextPath: / Bundle-Version: 1.0.0.SNAPSHOT Bundle-ManifestVersion: 2 Import-Package: javax.servlet,org.knowhowlab.osgi.tips.activation.core ,org.osgi.framework;version="1.5",org.osgi.service.prefs;version="1.1 ",org.osgi.util.tracker;version="1.4" Bundle-SymbolicName: org.knowhowlab.osgi.tips.activation.wab
-
How to run examples
- Download samples from here
-
Compile with Maven command
mvn clean install
-
Run BundleActivator sample
mvn -f run.xml -P activator
-
Run Declarative Services sample
mvn -f run.xml -P ds
-
Run Blueprint Services sample
mvn -f run.xml -P blueprint
-
Run Blueprint Annotations sample
mvn -f run.xml -P blueprint-annotations
Note: It does not work for me (even Aries BlueprintAnnotation sample). I'll try with the next version. -
Run WAB sample
mvn -f run.xml -P wab
-
Run All sample
mvn -f run.xml -P all
Framework started:id State Bundle 0 ACTIVE org.eclipse.osgi_3.6.0.v20100517 1 ACTIVE org.eclipse.osgi.services_3.2.100.v20100503 2 ACTIVE org.eclipse.equinox.common_3.6.0.v20100503 3 ACTIVE org.eclipse.equinox.preferences_3.3.0.v20100503 4 ACTIVE org.eclipse.equinox.cm_1.0.200.v20100520 5 ACTIVE org.eclipse.equinox.util_1.0.200.v20100503 6 ACTIVE org.eclipse.equinox.ds_1.2.0.v20100507 7 ACTIVE org.apache.geronimo.specs.geronimo-servlet_2.5_spec_1.2.0 8 ACTIVE org.apache.geronimo.specs.geronimo-jaspic_1.0_spec_1.1.0 9 ACTIVE org.eclipse.jetty.aggregate.jetty-all-server_7.2.0.v20101020 10 ACTIVE org.eclipse.jetty.osgi.boot_7.2.0.v20101020 11 ACTIVE slf4j.api_1.6.1 Fragments=12 12 RESOLVED slf4j.jdk14_1.6.1 Master=11 13 ACTIVE org.apache.aries.blueprint_0.2.0.incubating 14 ACTIVE org.knowhowlab.osgi.tips.activation.core_1.0.0.SNAPSHOT 15 ACTIVE org.knowhowlab.osgi.tips.activation.activator_1.0.0.SNAPSHOT 16 ACTIVE org.knowhowlab.osgi.tips.activation.ds_1.0.0.SNAPSHOT 17 ACTIVE org.knowhowlab.osgi.tips.activation.blueprint_1.0.0.SNAPSHOT 18 ACTIVE org.knowhowlab.osgi.tips.activation.wab_1.0.0.SNAPSHOTAll Echo services registered:osgi> services (objectClass=org.knowhowlab.osgi.tips.activation.core.Echo) {org.knowhowlab.osgi.tips.activation.core.Echo}={echo_type=BundleActivator, service.id=41} Registered by bundle: org.knowhowlab.osgi.tips.activation.activator_1.0.0.SNAPSHOT [15] No bundles using service. {org.knowhowlab.osgi.tips.activation.core.Echo}={service.pid=Echo, echo_type=Declarative Services, component.name=Echo, component.id=0, service.id=42} Registered by bundle: org.knowhowlab.osgi.tips.activation.ds_1.0.0.SNAPSHOT [16] No bundles using service. {org.knowhowlab.osgi.tips.activation.core.Echo}={osgi.service.blueprint.compname=echoservice, ECHO_TYPE_PROP=Blueprint, service.id=46} Registered by bundle: org.knowhowlab.osgi.tips.activation.blueprint_1.0.0.SNAPSHOT [17] No bundles using service. {org.knowhowlab.osgi.tips.activation.core.Echo}={echo_type=WAB, service.id=49} Registered by bundle: org.knowhowlab.osgi.tips.activation.wab_1.0.0.SNAPSHOT [18] No bundles using service.Stop PersistenceService bundle, all Echo services are unregistered:osgi> stop 3 PreferencesService is unlinked PreferencesService is unlinked PreferencesService is unlinked PreferencesService is unlinked osgi> services (objectClass=org.knowhowlab.osgi.tips.activation.core.Echo) No registered services.
-
References:
- OSGi specifications
- OSGi API
- Bnd tool - tool to help you diagnose and create OSGi bundles
- maven-bundle-plugin - Maven plugin for Bnd tool
- maven-scr-plugin - Maven plugin to ease the development of OSGi component and services
- SCR annotations - How to use annotations for OSGi components
- Aries Blueprint - Blueprint "Hello World" tutorial
- Aries BlueprintAnnotations - BlueprintAnnotation tutorial
- Pax Runner - tool to provision OSGi bundles in all major open source OSGi framework implementations (Felix, Equinox, Knopflerfish, Concierge)
Thank you.
Dmytro

Hello,
ReplyDeleteNot sure if you should care (you've done a lot of good to the community with this posting), I just noticed that reference #7, the 'Blueprint Hello World' tutorial is broken. It should take you here http://aries.apache.org/documentation/tutorials/blueprinthelloworldtutorial.html
Thank you for the post,
Ytsejammer
Very nice blogpost, complete and concise.
ReplyDeleteThx
cool post thx Dmytro
ReplyDeleteChristian
Hey! No iPojo?
ReplyDeleteCovered ways are from OSGi Specs. iPojo is a custom solution.
DeleteHello Dmitro,
ReplyDeletefirst, thanks for the nice tutorial.
I am currently fighting with the WAB part. When I compile and run it, it works as described - visiting http://localhost:8080/ shows "Hello World!".
But if I go to the OSGi console, and stop the wab bundle with "stop 9", I expect that the service is no longer available. But it still returns the same page...
Besides that, if I remove the listener from src and web.xml, then do clean rebuild and run again, I get the same behavior - "Hellow World!" is printed no matter if the bundle is active or not.
Am I doing something wrong ?
TIA, Petr
Hello Petr,
Deletethank you for your comment.
it's an error in jetty version.
replace lines 167-168 in run.xml with:
<param>mvn:org.apache.geronimo.specs/geronimo-annotation_1.1_spec/1.0.1</param>
<param>mvn:org.eclipse.jetty.aggregate/jetty-all-server/7.5.1.v20110908</param>
<param>mvn:org.eclipse.jetty.osgi/jetty-osgi-boot/7.5.1.v20110908</param>
Regards,
Dmytro
11:28:22,702 ERROR [org.apache.aries.blueprint.container.BlueprintContainerImpl]
ReplyDelete(Blueprint Extender: 2) Unable to start blueprint container for bundle org.knowhowlab.osgi.tips.activation.blueprint due to unresolved dependencies [(objectClass=org.osgi.service.prefs.PreferencesService)]: java.util.concurrent.TimeoutException
at org.apache.aries.blueprint.container.BlueprintContainerImpl$1.run(BlueprintContainerImpl.java:288)
any ideas on this? I don't know why it's able to find the preferences service on deploy, but then not get a reference to it?
Using JBoss 7.1/7.2. Guess it doesn't implement Preferences Service API.
DeleteYou can use Preferences API implementation from Felix. Check that OSGi compendium is installed as well
Delete