OSGi dependency management explain, how components or bundles share code between bundles. OSGi is dynamic component development so each application composed of components. Dependency Management define how code can be shared between bundles or we can say how we can access one bundle classes/interfaces in other bundles.
When we develop OSGi bundles any class or interfaces which we developed in the bundles accessible to within the bundle and not outside the bundle. Dependency management will explain how we can access one bundle resources in other bundles.
The following articles will give the introduction about OSGi dependency management
Usually to understand example we have two bundles and one bundles will have interface with set of service and its implementation. Other bundle will access the services which are developed by other bundle
The following are the steps
Bundle A Creation
- Create New Bundle A
- Define Service in the Interface
- Implements Service defined in the Interface
- Export Service Package
- Register Service Implementation Object with Bundle Context
Bundle B Creation
- Create New Bundle B
- Import Service Provider Bundle Services Package
- Access Service Provider Bundle Service Implementation Object in Consumer Bundle
Prerequisites
Install Java 8
Latest Eclipse IDE (Oxygen Release (4.7.0))
Create New Bundle A
Create New Bundle A
Create new bundle using eclipse with activator class. This bundle will have one interface and its service implementation.
Start Eclipse
File à New Project à New Plugin Project
Bundle Name: com.ls.de.LSServiceProvider Target Platform à OSGi Framework à standard |
Click on next
Click on Check Box Generate Activator Class and provide name
Example: com.ls.de.lsserviceprovider.ServiceActivator |
Click on Finish then new bundle will be created. Bundle can be visible in the project explorer with generated activator class and MANIFEST file
Define Services in the Interface
We already created bundle and now create Service Interface and define the service.
Create new package and create new java interface
Right Click on Project Src à New Interface à Provide Details à Click On Finish
Package : com.ls.de.lsserviceprovider.services Interface Name: HelloService |
Now define service method in the Interface finally it looks like as follows
HelloService.java
package com.ls.de.lsserviceprovider.services; public interface HelloService { public String greetHello(); } |
Implements Service defined in the Interface
We already define the service interface with method. Now we have to implements the service method in the implementation class. Create new package and new implementation class.
Right Click on Project Src à New Class à Provide Details à Click on Finish
Package : com.ls.de.lsserviceprovider.services.impl Interface Name: HelloServiceImpl |
Implement interface method in the implementation class, finally implementations class as follows.
HelloServiceImpl.java
package com.ls.de.lsserviceprovider.services.impl; import com.ls.de.lsserviceprovider.services.HelloService; public class HelloServiceImpl implements HelloService { @Override public String greetHello() { System.out.println("=====Inside HelloServiceImpl.greetHello()====="); return "Hello Greeting from Liferay Savvy World.."; } } |
Export Services Package
Now we have to Export Services package from services bundles so that these interfaces or resources can be accessible in the other bundles. Remember here only we are exporting services package not implementation package.
MANIFEST have OSGi header called “Export-Package” and we need to add package names with comma separate value, so that we can access these resources in other bundles.
Add “com.ls.de.lsserviceprovider.services” package name under “Export-Package” in the Bundle MANIFEST file
Finally MANIFEST looks as follows
MANIFEST.MF
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: LSServiceProvider Bundle-SymbolicName: com.ls.de.LSServiceProvider Bundle-Version: 1.0.0.qualifier Bundle-Activator: com.ls.de.lsserviceprovider.ServiceActivator Bundle-Vendor: LS Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Export-Package: com.ls.de.lsserviceprovider.services Import-Package: org.osgi.framework;version="1.3.0" |
Register Service Implementation Object with Bundle Context
Now we need to register service implantation in OSGi Bundle Context so that it will be accessible to other bundles.
The services registration and unregister information will managed by Service Registration object. When we register Service Implementation object with Bundle Context it will return Service Registration Object.
Usually when bundle is started then we register the services with bundle context. We will use Bundle Activator start (--) method to register service objects
Bundle Context have methods registerService(--) and unregister(--) methods to register and unregister service objects.
registerService(--) method will take three arguments
Argument: 1
Service object unique identification to identify the service, usually we will use fully qualified service interface class name
Argument: 2
Service Implementation Object to register with bundle context
Argument: 3
Its Java MAP object to filter the service objects. Sometime same interface have multiple implementation then we will use some filter properties to identify the service implementation object. Service Identification is same for all implementation so we will additional properties to get service objects. In this example we have only one implementation so we have passed null.
unregister(--) method will unregister service object from Bundle Context. Usually we unregister service when bundle is removed from the container then it will call stop(--) lifecycle method. We will unregister service when it execute stop(--) method.
Now go to Bundle Activator class add following code parts in the start (--) and stop (--) methods.
ServiceActivator.java
package com.ls.de.lsserviceprovider; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import com.ls.de.lsserviceprovider.services.HelloService; import com.ls.de.lsserviceprovider.services.impl.HelloServiceImpl; public class ServiceActivator implements BundleActivator { private static BundleContext context; ServiceRegistration serviceRegistration; static BundleContext getContext() { return context; } /* * (non-Javadoc) * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */ public void start(BundleContext bundleContext) throws Exception { ServiceActivator.context = bundleContext; System.out.println("Liferay Savvy Hello World Service Provider Bundle Activator Start"); HelloService helloService = new HelloServiceImpl(); serviceRegistration =context.registerService(HelloService.class.getName(), helloService, null); } /* * (non-Javadoc) * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext bundleContext) throws Exception { ServiceActivator.context = null; System.out.println("Liferay Savvy Hello World Service Provider Bundle Activator Stop"); serviceRegistration.unregister(); } } |
Create New Bundle B
Create new bundle using eclipse with activator class.
Start Eclipse
File à New Project à New Plugin Project
Bundle Name: com.ls.de.LSServiceConsumer Target Platform à OSGi Framework à standard |
Click on next
Click on Check Box Generate Activator Class and provide name
Example: com.ls.de.serviceconsumer.ServiceConsumerActivator |
Click on Finish then new bundle will be created. Bundle can be visible in the project explorer with generated activator class and MANIFEST file
Import Service Provider Bundle Services Package
We have to Import Services package from services bundle so that these interfaces or resources can be accessible in the consumer bundle.
MANIFEST have OSGi header called “Import-Package” and we need to add package names with comma separate value, so that we can access these resources in current bundle.
Add “com.ls.de.lsserviceprovider.services” package name under “Import-Package” in the Bundle MANIFEST file
Finally MANIFEST looks as follows
MANIFEST.MF
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: LSServiceConsumer Bundle-SymbolicName: com.ls.de.LSServiceConsumer Bundle-Version: 1.0.0.qualifier Bundle-Activator: com.ls.de.serviceconsumer.ServiceConsumerActivator Bundle-Vendor: LS Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.ls.de.lsserviceprovider.services, org.osgi.framework;version="1.3.0" |
When we use import header then the listed java classes and interfaces are available in the current working bundles.
Access Service Provider Bundle Service Implementation Object in Consumer Bundle
We already register services object and exported package in the consumer bundle. Now we can user service implementation in the consumer bundle. Now we can access service implementation object from consumer bundle context.
We have Bundle Context getService(--) method and it will return the service implementation object. We need to pass service reference object for this method.
We will identify the Service Implementation Object by service interface name. We already register the service with same name. So we will use same name to identify the service implementation Object.
We will use consumer Activator Class to get implementation object and call the required services.
Go to Consumer Bundle Activator class add the following code part in the Start (--) method and invoke service method using service implementation object.
ServiceConsumerActivator.java
package com.ls.de.serviceconsumer; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import com.ls.de.lsserviceprovider.services.HelloService; public class ServiceConsumerActivator implements BundleActivator { private static BundleContext context; ServiceReference helloServiceReference; static BundleContext getContext() { return context; } /* * (non-Javadoc) * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */ public void start(BundleContext bundleContext) throws Exception { ServiceConsumerActivator.context = bundleContext; System.out.println("Hello World Consumer Bundle Activator Start"); helloServiceReference= context.getServiceReference(HelloService.class.getName()); HelloService helloService =(HelloService)context.getService(helloServiceReference); System.out.println(helloService.greetHello()); } /* * (non-Javadoc) * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext bundleContext) throws Exception { ServiceConsumerActivator.context = null; System.out.println("Hello World Consumer Bundle Activator Stop"); context.ungetService(helloServiceReference); } } |
Execute Bundles
We have two bundles Service Provider Bundle and Service Consumer bundle.
Service Consumer bundle dependence on Service Provider Bundle. So we have to activate Service Provider bundler before access services in the consumer bundle.
Service Provider Bundle Name: com.ls.de.LSServiceProvider Service Consumer Bundle Name: com.ls.de.LSServiceConsumer |
Start com.ls.de.LSServiceProvider
Go to com.ls.de.LSServiceProvider Activator Class and Right click on class you can see Run
Right Click à Run à Run Configuration
Run configuration window check the required bundles then click on run
Basically we need OSGi implementation bundles that equinox and we can also use other implementation as well like apache Felix. Other two bundles are that we developed. Select only service provider bundle so that only provider bundle will be executed.
Once you run then bundle will activated you can see messages in the console.
In the console just type OSGi gogo shell command to list the bundles then you can see Service Provider Bundle in the list and we can see status that is activated.
Type following command in the gogo shell then we can see all bundles list
lb |
Now you can see Service Provider bundle in the list with active state and bundle number.
Now use following stop and start commands then you can see console messages. It will invoke Bundle Activator class
osgi> stop 1003 Liferay Savvy Hello World Service Provider Bundle Activator Stop osgi> start 1003 Liferay Savvy Hello World Service Provider Bundle Activator Start osgi> |
Note:
We will use bundle number to start or stop bundle in the OSGi container.
The following console shows Invoking Service Provider Bundle Life cycle methods.
Start com.ls.de.LSServiceConsumer
Service Provide Bundle is activated and Now execute Service Consumer bundles so that it will invoke the greetHello(--) method which is implemented in the Service Provider bundle.
Go to com.ls.de.LSServiceConsumerActivator Class and Right click on class you can see Run
Right Click à Run à Run Configuration
Run configuration window check the required bundles then click on run
Basically we need OSGi implementation bundles that equinox and we can also use other implementation as well like apache Felix. Other two bundles are that we developed. Select both bundle and click on run.
Go to Console and list bundles using lb command then you can see both bundles are in active state
Now use stop and start shell commands for service consumer bundle then we can see the console message that make sure that is invoking greetHell(--) method from service provider bundle from consumer bundle
osgi> stop 1003 Liferay Savvy Hello World Service Provider Bundle Activator Stop osgi> stop 1004 osgi> start 1003 Liferay Savvy Hello World Service Provider Bundle Activator Start osgi> start 1004 Liferay Savvy Hello World Consumer Bundle Activator Start =====Inside HelloServiceImpl.greetHello()===== Hello Greeting from Liferay Savvy World.. osgi> |
The following is console which shows its invoked greetHello(--) method
Download Source
Author
0 comments:
Post a Comment