From the outside looking in it would seem trivial to implement a modular web application design in Java, but this is far from the current state of the industry. The Spring framework is a dominant feature of the Java web development industry but sometime in the recent past Spring abandoned OSGI support which is the industry standard when it comes to modular design in Java. It is so much of a standard that there are official JSR’s (Specification Requests) to include OSGi capabilities in Java 9, the next version of Java. The question is, can a bridge be built to re-connect these technologies in a meaningful way. As of now, the answer is YES.
It doesn’t take much research into the latest version of Spring, 4.1.6, to come to the invalid conclusion that it isn’t possible to implement the latest version of Spring in an OSGI modular environment. The SpringDM, Dynamic Modules, project was ended, and at some point it was forked off to the Gemini Blueprint project. The latest Official release of Gemini Blueprint didn’t include support for Spring 4.1 but thankfully the latest source code added to it on GIT does. The code on the master branch unfortunately won’t build on it’s own, but with a few minor changes I was able to get it to build. You can see my fork of the project at https://github.com/rritoch/gemini.blueprint/ . If you checkout and compile that forked code with maven it will produce bundles which support Spring 4.1.6 and includes an OsgiBundleXmlWebApplicationContext implementation thanks to an implementation I was able to find on Google which is almost identical to SpringDM’s implementation. A few small changes, copying and pasting old code, and it would compile, but getting it to function is another problem entirely!
I’m sure you have heard of the 800 pound gorilla, well that is exactly what OSGI becomes when you include spring and spring security into your project. It took me four days of hell to hunt down all of the OSGI dependencies needed just to get the system to boot up properly. My “Hello world” application currently consists of 3 bundles. A common API, A tomcat server, and the actual hello world web application. The remaining 103 bundles needed for the system to start are all spring, tomcat, and their dependencies. The process was painstaking, first you Build, than execute, finally review logs for missing dependencies, and repeat.
It would have been really nice if I could have just compiled these 104 bundles and have everything magically work, but that isn’t the case. When maven bundles dependencies it doesn’t always automatically produce the ideal bundle headers in the Manfiest file. In this case there were a few that I needed to manually alter, most notably was the tomcat-embed-core package which would publish the java.servlet package at the tomcat version so bundles relying on java.servlet 3.1.0 would fail to meet it’s dependencies since it had no way of resolving it to the tomcat provided version. To resolve that issue I changed the export to javax.servlet;version=”3.1.0″. I found that when running into cases where you know a dependency is provided, in most cases it will turn out that it’s being exported at the wrong version. In my application I was using an embedded felix implementation to provide the OSGI framework, and there were a few java dependencies that I also needed to export to get the system to work. I added the below as extra packages, and also needed to add “com.sun.*” as a bootdelegation. This combination made dependencies provided by Java 8 available to the bundles that needed them. Chances are there may be more needed in the future, but these are the ones I’m currently running with. (see next page)
Extra felix exports
This configuration is less than ideal, but it does work. There are some conflicts between Tomcat 7 and the felix framework but with this configuration I was still able to get the system to run even though there are still some problems being reported in the logs which don’t seem to effect the functionality of the platform.
The final battles are to get Taglibs and Expression language functional. This wasn’t as automatic as I hoped and wasn’t a simple matter of just adding new dependencies. For some reason the taglibs won’t fully function when provided from an OSGI bundle. I found that providing JSTL 1.2 as an OSGI bundle to meet bundle import requirements, AND providing it wrapping the classloader with a classloader which points to the JSTL jar (jar not bundle) and injecting that into the tomcat context was the only way I could get the tag libraries functional. I also needed to disable the external XML schema retrieval block in the context to allow it to load the schema’s from the web or else it wasn’t able to find the JSTL schema. The final issue, a problem with Expression Language, was more subtle, and simply required adding a ContextConfig LifecycleListener to the context.
It took nearly a week of my spare time to get the latest version of Spring running in a stand-alone OSGI application, but it is possible!!! The process is not easy and it does require making small adjustments to existing libraries, but it can be done. Java is an advanced technology that can play a vital role in the development of new web technologies, but only if the industry is willing to face the challenge of applying modular/OSGI technologies, instead of abandoning it as “too complicated”. There was a time when only scientists could use computers because they were too complicated, and then companies like Apple and Microsoft made it simpler. We can build on these technologies to make them simpler, but if the Java community throws these technologies away than companies will be forced to throw Java away in favor of platforms that DO support modular design, like Ruby and Python. I’ve proven that it can be done, so let’s “Just do it” and stop making excuses!!
Note: These issues were resolved on a Tomcat 7.0.61 embed implementation, after upgrading to Tomcat 8 there are additional issues with Tag libraries and Expression Language which need to be resolved.