ZK OSGi - Developing plug-in based applications with OSGi
Erko Knoll, Java Developer
December 30, 2011
This article shows how to use ZK in OSGi environment and the example that comes with it demonstrates how to develop plug-in based applications using OSGi bundles as base for plug-ins.
OSGi (Open Services Gateway initiative framework) allows Java applications to be written in a fully modular way. Something that is not present in standalone Java environments as of 2011. Basically OSGi allows decoupling each application concern into a separate bundle. Bundles run concurrently in different kernels and by default are unaware of other bundles, their kernels and their classpaths. Bundle services can be shared with other bundles via service registry - that's how bundles interact with each other. Each bundle has its own classpath. Manifest files are used to define bundle imports and exports. OSGi keywords are: loose-coupling, hot deployment and versioning.
This example comes with 3 bundles:
- zk-osgi.blueprint - Contains interfaces for inter-bundle communication.
- zk-osgi.host - Host web application bundle.
- zk-osgi.test-plugin - Test plug-in bundle.
Example vs. OSGi Dynamics
When you start going through example projects you probably start noticing that not every OSGi rule is respected. This example's goal is to demonstrate the capability of seamless plug-in integration with the host application without the need to define plug-in dependencies. Host application is capable of discovering changes in real time as they happen.
Example is not as loose-coupled as it should be in OSGi standards. For the sake of simplicity I kept it to 3 bundles. There are no restrictions if you want to fragment your application to smaller bundles. The more bundles you have, the more modular your application is.
Host application is able to discover plug-in installs/uninstalls and modifications instantaneously.
Not exactly as OSGi versining is meant to be used. When you deploy the same bundle under different versions, host app will discover it and you will end up with duplicated resources. Example architecture is little bit different as to how OSGi standards dictate. Normally, shared services are accessible via service registry. Plug-ins in this example don't use shared services for communication. Host application accesses plug-in resources directly when it needs via ApplicationContext.getBean() which is slightly discouraged because by doing so host application bypasses service registry which guarantees that it only sees services it is supposed to see. Excerpt from Spring DM documentation.
- Note: the application context is published as a service primarily to facilitate testing, administration, and management. Accessing this context object at runtime and invoking getBean() or similar operations is discouraged. The preferred way to access a bean defined in another application context is to export that bean as an OSGi service from the defining context, and then to import a reference to that service in the context that needs access to the service. Going via the service registry ensures that a bean only sees services with compatible versions of service types, and that OSGi platform dynamics are respected.
- ZK 5.0.9
- Spring 3.0.5
- Spring DM (Virgo provides)
- Hibernate 3.3.2.GA (with Ehcache as second level cache)
- Fair understanding of ZK, OSGi, Virgo and frameworks used if you choose to modify examples.
- EclipseRT Virgo (Example is designed for version 3.0.2)
- Download example and unpack it.
- Download and install Virgo and PostgreSQL.
- Configure PostgreSQL:
- Create database: osgi.
- Grant user access for that database. Username: postgres, Password: osgi.
- Copy Required Bundles content to Virgo/repository/usr directory.
- Copy Example Bundles content to Virgo/pickup directory.
- Launch Virgo/bin/startup.bat.
If Virgo manages to deploy bundles in correct order you should be able to access it from http://localhost:8080/zk-osgi/.
Virgo Constraint Errors
If Virgo fails to deploy example bundles in correct order you most likely will be prompted with a constraint error informing that some package is missing. As zk-osgi.blueprint bundle is needed for the other 2 bundles this bundle should be first to be installed. To enforce correct order, delete other 2 bundles, and leave zk-osgi.blueprint in pickup directory. When deleted, copy the other two bundles back to pickup directory. This forces Virgo to redeploy the other two bundles which should now be resolved correctly. To avoid such manual intervention in the future Virgo supports PARs and Plans for more concrete deployment.
Projects can be built with Maven. There are two dependencies missing from public repositories. You have to install them manually to your local repository.
- zk-osgi.blueprint - Comes with the example.
- org.eclipse.virgo.kernel.deployer - Resides in Virgo/repository/ext folder.
zk-osgi.host bundle has two classes which are modified in order to accommodate plug-in architecture:
- zk.osgi.host.hibernate.PluginAwareOpenSessionInViewFilter - Modified version of OpenSessionInViewFilter which compared to the original also opens sessions for Hibernate SessionFactories found from plug-ins.
- zk.osgi.spring.scope.PluginAwareSessionScope - Modified version of SessionScope for the use in plug-ins so that plug-in beans can be scoped as sessions.
Standard ZK is not OSGi compatible. In order to use ZK in OSGi environment one has to "OSGify" ZK libraries. Process of "OSGifying" is adding meta-data information to META-INF/MANIFEST.MF file, import packages that might be needed and export packages that other bundles might need (including versioning).
There are various tools to help you achieve this:
You can either convert each library separately or create a huge single bundle for all ZK libraries you need. Creating a single bundle you probably will save yourself from pain and misery caused by various bundles not being able to find resources they need. I used Eclipse's Plug-In Project for that purpose. Steps to follow:
- Create Plug-In Project.
- Import all the libraries you need (I also added reflections-0.9.5.jar and zkspring-core.jar and excluded ones I don’t use), let's say to lib folder but location does not really matter.
- If you are using zkspring-core.jar then unpack it and copy spring.handlers and spring.schemas files under META-INF to your plug-in project's META-INF folder.
- Open plug-in project's MANIFEST.MF under META-INF folder and navigate to Runtime tab.
- In Runtime tab add all imported jars to your classpath.
- Then add all export packages.
- Hit Calculate Uses (may take some time).
- Import packages that are missing from the project, there are 2 approaches you could take:
- Use Dependencies tab to add imports. Eclipse requires all the plug-ins to be present where you want to import from. This can be somewhat cumbersome. Also, Eclipse manifest is generated with a slightly different import directive and may cause problems later on.
- Import packages manually (which I did). Build the bundle (next step). Unpack the bundle and modify META-INF/MANIFEST.MF manually for packages you need. I added following packages:
1 Import-Package: 2 javax.servlet;version="2.5.0", 3 javax.servlet.http;version="2.5.0", 4 org.reflections, 5 javassist;version="3.12.1", 6 javassist.bytecode;version="3.12.1", 7 javassist.bytecode.annotation;version="3.12.1", 8 com.google.common.collect;version="10.0.0", 9 com.google.common.base;version="10.0.0", 10 org.slf4j;version="1.6.1", 11 org.springframework.beans.factory.annotation;version="3.0.5.RELEASE", 12 org.springframework.beans.factory;version="3.0.5.RELEASE", 13 org.springframework.context;version="3.0.5.RELEASE", 14 org.springframework.web.context.support;version="3.0.5.RELEASE", 15 org.springframework.beans.factory.xml;version="3.0.5.RELEASE", 16 org.springframework.beans.factory.config;version="3.0.5.RELEASE", 17 org.springframework.beans.factory.support;version="3.0.5.RELEASE", 18 org.springframework.beans.propertyeditors;version="3.0.5.RELEASE", 19 org.apache.commons.fileupload, 20 javax.naming
- Building bundle: navigate to Overview tab and use Export Wizard in bottom right corner to build the bundle.
|Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.|