ZK OSGi - Developing plug-in based applications with OSGi

From Documentation
Revision as of 13:02, 30 December 2011 by Erko (talk | contribs)
DocumentationSmall Talks2011DecemberZK OSGi - Developing plug-in based applications with OSGi
ZK OSGi - Developing plug-in based applications with OSGi

Author
Erko Knoll, Java Developer
Date
December 30, 2011
Version
ZK 5.0.9

Introduction

This article shows how to use ZK in OSGi environment and example that comes with it demonstrates how to develop plug-in based applications using OSGi bundles as base for plug-ins.

OSGi

OSGi (Open Services Gateway initiative framework) allows Java application to be written in fully modular way. Something that is not present in standalone Java environments as of 2011. Basically OSGi allows to decouple each application concern into 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 it's own classpath. Manifest files are used to define bundle meta-data, which packages from other bundles this particular bundle should be able to use and which packages from this bundle should be exported for other bundles to use. OSGi keywords are: loose-coupling, hot deployment and versioning.

Example Bundles

This example comes with 3 bundles:

  • zk-osgi.blueprint - Contains interface which is shared with other 2 bundles.
  • 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 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.

Loose-Coupling

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. More bundles you have more modular your application is.

Hot Deployment

Host application is able to discover plug-in installs/uninstalls and modifications instantaneously.

Versioning

Not as in OSGi standards. When you deploy the same bundle under different version, host app will discover it and you will end up with duplicated resources. Example architecture is little bit different as OSGi standards dictate. Normally shared services are accessible via service registry. Plug-ins in this example don't use shared services in order to share their resources. Host application accesses directly plug-in resources when it needs via ApplicationContext.getBean() which is slightly discouraged because 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 in this way ensures that a bean only sees services with compatible versions of service types, 
and that OSGi platform dynamics are respected.

Example

Used Frameworks

  • ZK 5.0.9
  • Spring 3.0.5
  • Spring DM (Virgo provides)
  • Hibernate 3.3.2.GA (with Ehcache as second level cache)

Prerequisites

Running Example

  • Download example and unpack it.
  • Download and install Virgo and PostgreSQL.
  • Configure PostgreSQL:
    • Create database: osgi.
    • Grant an user access for that database. Username: postgres, Password: osgi.
  • Copy content of Required Bundles to Virgo/repository/usr directory.
  • Copy content of Example Bundles 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/ URL.

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 other 2 bundles back to pickup directory. This forces Virgo to redeploy other 2 bundles, which now should be resolved correctly. To avoid such manual intervention in the future Virgo supports PARs and Plans for more concrete deployment.

Building Projects

Projects can be built with Maven. There are 2 dependencies missing from the 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.

Modifications

zk-osgi.host bundle has 2 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.

OSGifying ZK

Standard ZK is not OSGi compatible. In order to use ZK in OSGi environment one has to OSGify ZK libraries. Process of OSGifying is to add 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:

  • BND
  • Bundlor
  • Or use Eclipse to create Plug-In Project

You can either convert each library separately or create one huge bundle for all ZK libraries you need. Creating one huge bundle you probably will save yourself from pain and misery caused by various bundles not finding resource from other bundles. I used Eclipse's Plug-In Project to create one huge bundle. 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), lets say to lib folder but the location shouldn't 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 (it may take some time).
  • Import packages 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 some what cumbersome. Also Eclipse manifest is generated with 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 (which are probably required anyway):
Import-Package: 
 javax.servlet;version="2.5.0",
 javax.servlet.http;version="2.5.0",
 org.reflections,
 javassist;version="3.12.1",
 javassist.bytecode;version="3.12.1",
 javassist.bytecode.annotation;version="3.12.1",
 com.google.common.collect;version="10.0.0",
 com.google.common.base;version="10.0.0",
 org.slf4j;version="1.6.1",
 org.springframework.beans.factory.annotation;version="3.0.5.RELEASE",
 org.springframework.beans.factory;version="3.0.5.RELEASE",
 org.springframework.context;version="3.0.5.RELEASE",
 org.springframework.web.context.support;version="3.0.5.RELEASE",
 org.springframework.beans.factory.xml;version="3.0.5.RELEASE",
 org.springframework.beans.factory.config;version="3.0.5.RELEASE",
 org.springframework.beans.factory.support;version="3.0.5.RELEASE",
 org.springframework.beans.propertyeditors;version="3.0.5.RELEASE",
 org.apache.commons.fileupload,
 javax.naming
  • Building bundle: navigate to Overview tab and use Export Wizard in bottom right corner to build the bundle.

Download Example

Download


Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.