OSGi and servlets can work together
Join the DZone community and get the full member experience.
Join For FreeOSGi is the emerging Java platform, and a surefire architectural solution to avoid the infamous Jar hell during the development of Java applications.
Web interfaces are another rather important feature today, and OSGi lacks as far as I know a native solution for implementing web applications inside of bundles (like instead it does with the ConfigurationAdmin specification, which many OSGi frameworks implement.)
It seems reasonable that OSGi frameworks can take advantage of existing, well-working solutions like servlet containers, and integrate in the architecture of web applications realized with servlets, JSP and WAR files.
That said, integration with servlet containers is fairly experimental in the OSGi environment (although I hope some reader will refute me), and there are essentially two ways to achieve the same thing: serving HTTP requests from an OSGi bundle.
Embed an OSGi framework into a servlet container
Equinox is the open source OSGi framework provided by the Eclipse Foundation. Equinox provides a Bridge.war web application that can be used to link together Tomcat (as an example of popular servlet container) and Equinox itself, by providing the functionalities needed to embed the framework inside a web application and tunnel the requests to it.
There is already a very good article explaining the mechanisms of this type of integration, so I won't discuss it here. However, I see OSGi web applications only as a front end for the overall applications constituted by the whole set of bundles - if I wanted to embed all my code into a web application I would have chosen a PHP platform. A key advantage of Java is its natural ability to run asynchronously from HTTP requests.
I will explain another solution, which is adopted by the Eclipse SMILA framework for search applications, which is built on top of OSGi.
Embed a servlet container into an OSGi framework
Let's imagine that you have an OSGi application, possibly with different interfaces, that run some processes in response to external events from any kind of user interface - local or remote. It will be nice to add a web interface to this application to easily handle remote use cases, and leaving the application running as the main thread in the JVM.
This is exactly SMILA's approach. SMILA indexes records asynchronously, for instance by running crawlers on web sites or disk folders. The web user interface is a simple mean to perform a search, but SMILA applications does not depend on it.
In SMILA, Tomcat's (and Catalina's) Jars are embedded in a single org.apache.tomcat bundle, which put them on the Bundle-ClassPath and exports the various Java packages contained, such as org.apache.tomcat.util.
Another bundle is in charge of wrapping Tomcat's functionalities with a Facade, which is started as an OSGi service. In SMILA's case this bundle is org.eclipse.smila.tomcat, and contains a TomcatServiceImpl class which activate() and deactivate() method manage the lifecycle of Tomcat infrastructure. TomcatService is an interface created by SMILA and not Tomcat-specific code, so you're free to wrap Tomcat in your implementations in the way you feel more appropriate.
The point of connection between servlets and OSGi services is crucial in this setup. Bundles expose their functionalities via services, whose lifecycles and dependency resolution are managed by the OSGi framework. On the other hand, servlets must satisfy HTTP requests and they need a way to access the services, which represent the model of the web application used as front end.
This connection is provided by an Activator class local to the servlets bundle, independent from the two bundles cited before (and listed in the manifest with the Bundle-Activator header). This Activator creates ServiceTracker for the bundles needed by its servlets, and exposes static getters that the servlets may use to get a reference to the service. There is no guarantee that the services will be available if you do not start them via their OSGi configuration, but the gap is easily bridged.
The configurable folders for Tomcat (the webapps/ one for example) are defined by the OSGi service that acts as a Facade, and I invite you to refer to SMILA source code linked at the end of this article if you're hungry for more information. An important part of the setup, however, is to put a WAR-like folder to represent the web application in the chosen webapps/ folder. You won't strictly need any file in this folder but WEB-INF/web.xml, which will contain the servlet mappings with their fully qualified name (as the standard preaches).
A last important point is making sure that the bundles containing Tomcat's Jars and their wrappers can see the servlet packages exported by other bundle. The simplest way to achieve this is with Equinox-specific manifest headers that tell the classloader of the Tomcat's bundle to demand classes also to other specific bundles. These headers are
Eclipse-BuddyPolicy: registered
in Tomcat's and Facade's bundles manifests, and
Eclipse-RegisterBuddy: org.apache.tomcat, org.eclipse.smila.tomcat
in the servlets bundles (remember also to export the packages containing them.) Here's how these headers work.
A final note: JSP support is much more difficult to setup and currently I haven't had the time to look into it. With this simple wrapping, they won't be executed as the generated code will fail to resolve its dependencies. If you have found any easy solution to integrate also JSP in an OSGi application, feel free to add your thoughts in the comments.
Resources
Opinions expressed by DZone contributors are their own.
Comments