OSGI Concepts and Tutorial
OSGI is Open Service Gateway Initiative provides a modular architecture distributed systems and mostly widely used. This tutorial is intended of OSGI beginners and will drive you through OSGI components.
OSGI Building blocks:
- Bundles
- Components
- Services
1.OSGI Bundles
OSGI Bundle is one or more components/service are made as a jar file. In nutshell, its a plain jar file that contains components/services.
- Bundle is a JAR file packaging classes and resources.Each bundle is having metadata that is added in manifest file in META- INF/MANIFEST.MF.
- One OSGI bundle can not refer other OSGI bundle directly in the OSGI container.
- Each OSGI Bundle should have the activator that will be invoked when then bundle is starts. In this case, HelloWorldActivator is activator that implements BundleActivator interface will be called. (add org.eclipse.osgi.jar as dependency)
- Each bundle should also requires MANIFEST.MF file that defines meta data of bundle such – bundle activaor,policty, list of exported packages,services etc
- Bundles in OSGi can be installed,updated and uninstalled without taking down the entire application.
- One Bundle with differant versions can be installed in OSGI container.
- Each OSGI bundle has lifecycle in OSGI container with below six states:
- UNINSTALLED: The bundle is uninstalled and may not be used in the OSGI container
- INSTALLED :A bundle is installed in the Framework but is not resolved.
- RESOLVED: The bundle is resolved and is able to be started, which means bundle is not active. you can start the bundle at any time using start {bundle-id} command in OSGI console.
- STARTING: The bundle is in the process of starting.
- STOPPING: The bundle is in the process of stopping.
- ACTIVE:The bundle is now running.A bundle is in the
ACTIVE
state when it has been successfully started and activated.
Lets look into sample OSGI project.
- Create a java project
- add org.eclipse.osgi.jar as dependency
- create HelloWorldActivator.java file that implements BundleActivator interface
- create MANIFEST.MF file and add bundle activator entry and symbolic name in that
- that’s it.. the above two steps makes Java Project as OSGI Bundle
- Activator:
import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class HelloWorldActivator implements BundleActivator { @Override public void start(BundleContext arg0) throws Exception { System.out.println("_------ - Bundle is starting------"); } @Override public void stop(BundleContext arg0) throws Exception { System.out.println("---- Stopping Bundle -----"); } }
MANIFEST.MF file: Activator will be referred in MANIFESH.MF file
Manifest-Version: 1.0 Bundle-Name: Hello Service Bundle-SymbolicName: com.demo.osgi.bundle.helloworld Bundle-Version: 1.0.0 Bundle-Activator:com.demo.osgi.bundle.HelloWorldActivator Bundle-Vendor: jay Require-Bundle: org.eclipse.osgi Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Bundle-ActivationPolicy: lazy
What is MANIFEST.MF file in OSGI?
- MANIFEST.MF contains meta data about bundle and holds below information:
- bundle Name
- a symbolic name to determine bundle’s unique identity by OSGI Container
- bundle Name – decription of bundle
- bundle Version
- supported java version of the bundle
- bundle activation policy (lazy means bundle is installed but not active)
- import-packge
- export-Package
• Sample Manifest file
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Hellow Service Bundle-Version: 1.0.0 Bundle-SymbolicName: org.demo.osgi.bundle.hello-service Created-By: Jayaram Import-Package: com.liferay.portal.kernel.exception;version="[7.0,8)",com.liferay.portal.kernel.log;version="[7.0,8)", com.liferay.portal.kernel.service;version="[1.0,2)" Private-Package: org.demo.liferay.service Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" Bundle-ActivationPolicy: lazy;
How to Run OSGI applications?
OSGI bundles requires OSGI container to run the OSGI bundles. A bundle must be OSGI compliant which would be having BundleActivator to enable the bundle. The below are popular OSGI container Providers:
- Equinox – eclipse comes with equinox as default OSGI container
- Apache Felix
Its always recommended to use BndTools which provides OSGI workspace and runtime also. Just install the install the bnd eclipse plugin from : https://dl.bintray.com/bndtools/bndtools/latest/
2. OSGI Components:
The above example is native implementation of OSGI bundle where all things such as bundle activation,service registration,dependency injection are need to manage manually via BundleActivator.
How to make OSGI implementation easy? Answer Declarative Services
Declarative services are OSGI annotations are used to create OSGI components. Declarative Services provides annotations to create OSGI bundle, injects required dependencies, bundle activation and deactivation etc. All the annotations specifications are provided by org.osgi.compendium.jar file.
- OSGI Framework will have list of components and services.
- OSGI component can be exposed as service
- OSGI component can inject Other service from OSGI runtime
- OSGI component can not refer other OSGI components directly. OSGI component can only reuse services exposed by other OSGI component
@Component – Define Component
@Service – Defines Service I
@Reference – Injects external service
@Activate
@Deactivate
@Modified
@Property
In the below example:
- @Component need to at top level of each class difines this as a OSGI component
- @Activate method will be called when the bundle start
- @Deactivate method will be called when the bundle deactivated
- immediate = true means bundle will starts immediatly
- service/provide – This defines what service it is consuming. An OSGI component can be Service Provider or Consumer.
@Component( configurationPid={"org.javasavvy.demo.impl",Component.NAME}, enabled=true, immediate=true service = Portlet.class //(or Servlet.class or Listner.class) ) public class HelloWorldPortlet { @Activate protected void activate() { } @Deactivate protected void deactivate() { } }
3. OSGI Services
OSGI Services are follows Service Registry Modal to connects bundles in OSGI framework via Publish-Find-Bind Modal.
Lets take below use case:
1. org.demo.student.api – provides interface(StudentService.java) methods for entire project
2. org.demo.student.impl – provides implementation layer(StudentServiceImpl.java) of Interfaces
3. org.demo.student.web – this is client bundle that consumers student services
Service Registration:
-
-
public class StudentServiceActivator implements BundleActivator { private StudentService studentService; @Override public void start(BundleContext context) throws Exception { studentService = new StudentServiceImpl(); context.registerService(StudentService.class.getName(), studentService, null); } @Override public void stop(BundleContext context) throws Exception { System.out.println("[Student Activator] Stopping Module..."); } }
“org.demo.student.impl” bundle will register register StudentService as Service to OSGI framework with below code execution.
-
studentService = new StudentServiceImpl(); context.registerService(StudentService.class.getName(), studentService, null);
-
-
- “org.demo.student.web” bundle will get the StudentService at runtime via @Reference or ServiceTracker as per below:
How “org.demo.student.web” bundle got StudentService object?
- OSGI Framework looks up in Service Registry for implementation object for StudentService and returns the implementation object that “org.demo.student.impl” registered to the OSGI framework
What if there are multiple StudentService implementation providers are registered to the framework?
- OSGI framework offers filters such as bind,servcie,cardinality to identify the exact service.
public class StudentClient { private StudentService studentService; public void getName(){ System.out.println("Calling command getName:"+studentService.getStudentName()); } @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL) protected void setStudentService(StudentService studentService) { System.out.println("[Student Service Client]: setting student service"); this.studentService = studentService; } protected void unsetStudentService(StudentService studentService) { System.out.println("[Student Service Client]: remove student service"); this.studentService = null; }
Let looks into the tutorial : OSGI Bundle Tutorial