Pax Web Extender - War - OSGi-fy
This page explains what it takes to make a standard war file deployable into OSGi. For detailed information read OSGi Service Platform Core Specification section 3.2 — Module Layer — Bundles. The pages specified bellow refers to Release 4, Version 4.1 April 2007.
The quickest way is for your project to use Maven and utilize Maven Bundle Plugin to generate OSGi manifest for your WAR project. See: http://ops4j1.jira.com/wiki/confluence/display/ops4j/Getting+the+benefits+of+maven-bundle-plugin+in+other+project+types
If you opt for a lower level way, read on...
First of all the war has to be a valid OSGi bundle. As minimum the war file must contain the following manifest headers in META-INF/MANIFEST.MF
:
- Bundle-ManifestVersion: 2 — This header defines that the bundle follows the rules of R4 specification.
- Bundle-SymbolicName — This header specifies a unique, non-localizable name for this bundle. This name should be based on the reverse domain name convention. See Bundle-SymbolicName on page 35.
- (optional) Bundle-Version — This header specifies the version of this bundle. The default value is 0.0.0. See Version on page 28.
- (optional) Bundle-Name — This header defines a readable name for this bundle. This should be a short, human-readable name that can contain spaces.
- (optional) Bundle-Vendor — This header contains a human-readable description of the bundle vendor.
- (optional) Bundle-Copyright — This header contains the copyright specification for this bundle.
- (optional) Webapp-Context — servlet context path. If not specified Bundle-SymbolicName will be used. Note that this header is a War extender specific header not an OSGi header.
If you have this header, will suffice to deploy the war into OSGi. But this is not enough to have it working in most of the situations as OSGi has a very strict class loading policy. So next, you will have to specify how the classes you need in runtime will be found via the following headers:
- Bundle-ClassPath — This header defines a comma-separated list of JAR file path names or directories (inside the bundle) containing classes and resources. The period ('.') specifies the root directory of the bundle's JAR. The period is also the default. See Bundle Class Path on page 49.
- Import-Package — This header declares the imported packages for this bundle. See Import-Package Header on page 36.
- (not recommended) Require-Bundle — This header specifies the required exports from another bundle. See Require-Bundle on page 65.
Most likely the above headers will have to have the following values:
- Bundle-ClassPath :
WEB_INF/classes
— this will find any class / file in WEB-INF/classes.
— this will find any file from the root of the warlib/<dependency>.jar
— you should have an entry for each jar you have in your lib directory, where <dependency> is the name of jar
So, as an example the header can look like:
Bundle-ClassPath: .,WEB-INF/classes,lib/commons-logging.jar,lib/spring.jar
- Import-Package : should contain any package that your web application depends on but is not included into one of your dependencies that you listed in the Bundle-ClassPath header. Usually a war will not include J2EE apis:
javax.servlet
- servlet apijavax.servlet.http
- servlet api
So, as an example the header can look like:
Import-Package: javax.servlet,javax.servlet.http
Now you are ready to deploy your war. If you still get class loading exceptions then is most likely that you did not include all the jars you need in the Bundle-ClassPath or Import-Package.
Preprocess
If you find this process hard to grasp or if you cannot change the manifest of your war or maybe you simple want to automate it take a look at how you can automate it in a static or dynamic way. You may also use War Protocol.