It has been several months since I’ve started using OSGi to build Web Applications with Spring and Eclipse Virgo, and I thought it would be a good time to review the various learning’s to date and present my opinions, in particular on OSGi and Virgo.
It is a work in-progress, but I hope this works out to be a good resource for OSGi \ Virgo programmers and a starting point for some discussion around the below points – I invite comments…
In summary, Virgo (now Virgo Tomcat Server to differentiate between it’s sibling Virgo Jetty Server) is neat little Tomcat web server embedded as an OSGi module within Equinox. It uses the OSGi extender pattern to create a bridge between Equinox and Tomcat so that Web artifacts (WARs) inherit the same properties and lifecycle as a regular OSGi bundle – meaning they can be hot-deployed at runtime – with little effort from the developer.
It has some excellent features, including out-of-the-box declarative services support, the ability to specify dependencies on entire bundles or libraries (instead of tediously entering in billions of error prone Import-Package statements – use with caution) using Import-Bundle and Import-Library manifest headers, OSGi configuration artifacts and possibly the most import – the concept of a ‘plan'; an XML artifact that specifies the atomic installation order of various other OSGi modules, optionally limiting the scope the modules to other modules within the plan. In my view, the ‘plan’ artifact coupled with configuration artifacts provide a clean and dramatically simpler deployment packaging process across environments.
From a Web Application point-of-view, under the hood, it is still Tomcat. Clustering and most configuration is straightforward and is performed in the same manner as you would normally. In fact, your application doesn’t need to be an OSGi bundle, so if you want to migrate slowly to a complete OSGi system over time, Virgo supports this. As a bonus, the latest 3.0.0.M05 Milestone release contains Tomcat 7 meaning the Servlet 3.0 and EL 2 specifications is also now available and the default.
In general, the documentation is pretty good (http://www.eclipse.org/virgo/documentation) and in true Spring fashion there is a decent reference application that takes you through a fairly sophisticated Web Application.
Find out more here: http://www.eclipse.org/virgo/
Possibly the only downside is that I feel Virgo has a reasonably small community when compared to the likes of Glassfish, for example. It is probably explained by the fact that OSGi in the Web is still relatively new, and the fact that Virgo is the successor to Spring DM Server – a gift from SpringSource. I imagine there are many customers still on that platform and the Spring forums still have some value for OSGi issues.
Again, to be fair, whilst the Glassfish community is large I would say only a small percentage are actually using OSGi.
Virgo has an excellent, yet relatively undocumented feature. Glyn Normington hints at it, but I don’t think the post does it enough justice. One of the most difficult problems to solve are uses conflicts. Virgo has some nice features around making them clearer in the log files, but sometimes they are a little cryptic. However, Virgo is configured by default to take a snapshot of the current state of bundles during an installation failure. The snapshot alone is of little use on it’s own, however if you navigate to the admin console at http://localhost:8080/admin and choose ‘OSGi state’ there is an option to select live or the dump just created by Virgo – this allows you to see what Virgo sees when it’s trying to resolve your set of bundles. I won’t go into detail here on this, as I’ve dedicated a separate post to debugging in Virgo.
One of the best features of Virgo for Spring developers, is that it came out of Spring DM server and is therefore ‘Spring ready’. That means, it was designed to work with Spring applications – Web applications or otherwise. To get a basic Spring MVC application running in Virgo is not a big deal; it pretty much boils down to creating an appropriate OSGi manifest and modifying the context in web.xml to use the ServerOsgiBundleXmlWebApplicationContext context class instead of the default. From here on, the usual dependency injection and Spring goodness just works and behaves like Tomcat would. The only difference you need to worry about is breaking apart your application into logical chunks (vertically or horizontally, as described in the docs) and deploying them as separate modules to enable hot-deployment.
You don’t really appreciate this, until you try and install a Web Application into another container; such as Felix or Equinox alone. The magic that happens behind the scenes is completely transparent to you.
Why not Glassfish?
In the early investigation stage, it became immediately clear that there were two front-runners when it came to picking a ready-made, OSGi-enabled web server. Glassfish (3.1+) was the obvious competitor as it had a proven track record in the real world of being a fantastic Application Server, and was now OSGi capable (Apache Felix by default). The down side at the time was that it used CDI (JSR-299) heavily internally which conflicted with the Spring Library DI mechanisms. Theoretically it was possible, but it seemed like we were leading down a more difficult path; bending Glassfish and our application in a way that just didn’t feel like the right way to go. I’ll certainly keep my eyes on projects such as the Spring to CDI bridge which help to make these platforms more open.
The world is not OSGi ready – be prepared to Wrap Jars
Whilst Spring have provided the somewhat dated Enterprise Bundle Repository – a repository of ready made OSGi artifacts of common libraries – not all libraries you need exist there. In fact, I’m pretty sure some of the latest Spring releases don’t either i.e. Spring Security Core 3.0.5 (It’s not a huge deal though, all Spring bundles now how OSGi manifests created anyway). Not all is lost, however. Both the Maven Bundle Plugin and Bundlor are able to ‘wrap’ existing libraries and turn them into OSGi ready bundles. The catch is ensuring that you use the correct bundle version, package export and package import versions. Pax Construct provides some nice command line tools to get the job done, which uses the Maven Bundle Plugin.
Import-Bundle is evil
OK maybe not evil, but with one exception, and we’ll get to that, my personal belief is that Import-Bundle should be used with caution. I could pretty much say that all uses-conflict issues (see below) that I’ve encountered have been as a result of lazily importing an entire bundle, when only a few packages are actually required. Whether right or wrong, some 3rd party bundles are huge and contain many packages that you’re never going to use. In these cases, importing the entire bundle is like inviting all of Iran and Iraq to a party without telling them – it’s going to end badly. Conversely, inviting a few like-minded Iranians & Iraqi’s will be a pleasant experience.
What I mean by this, is that all of those extra packages not used in the imported bundle still bring along their baggage – transitive dependencies that need to be resolved – the bigger the bundle, the more baggage. This is because Import-Bundle is a shorthand for ‘import all packages in the bundle’. It is an illusion, and at some point, you’ll have several bloated 3rd party JARs that have been poorly packaged with conflicting dependencies all over the shop.
This article would have you believe otherwise, however my view is that Import-Bundle regresses OSGi development to the old-school ‘throw the JAR in WEB-INF/lib’ view of the world. Whilst we get the benefit of re-use, we lose out on precision. True, the tooling to get the job done is still in progress, and configuration files that result in package dependencies are the main cause of this. Bundlor is a great Spring tool that can not only parse byte-code dependencies, but also look in Spring configuration files to determine what needs to be imported.
Declarative Services is your friend
Simply put, don’t do things the hard way – use Spring DM’s or Blueprint’s declarative services model to implement OSGi services and avoid boilerplate code. Take the time to understand how they work, and then never think about it again. Not only will it simplify things, it will make your code more modular and loosely coupled. Think of it as Dependency Injection for OSGi. Read more on Spring DM \ Blueprint here.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <osgi:service ref="myExposedObject" interface="com.melbourneit.foo.bar.AwesomeService"/> <osgi:reference id="someOtherPotentiallyRemoteObject" interface="com.somebody.something.Useful"/> </beans>
The above Spring DM XML declaration located by convention in META-INF/spring/*.xml (I used the recommended osgi-context.xml naming scheme) is all that is required to trigger Virgo to expose an object of type com.melbourneit.foo.bar.AwesomeService with name ‘myExposedObject’ which is now available to any other bundle within the OSGi container. Similarly, it will also search for an object of type com.somebody.something.Useful and wait until it can be found. Once found, it is injected as per any other object injected in Spring.
Notice how we don’t care about searching for services, checking for states, runtime exceptions or anything – the DS library takes care of that for us.
Build API and Implementation Bundles
You want to be able to hot swap code at runtime? Then make sure you create API bundles separate from your implementation bundles, and expose the implementation bundle as an OSGi Service (as above). Here’s why:
- It encourages contract-first development, forcing you to think about the design & features you are implementing up front
- It will decouple your application from implementation specifics, meaning they are more modular in nature
- It allows you to create many different providers of that API which, importantly, allows you to hot-swap them at runtime.
- It (interface first) is a basic principle of Dependency Injection and it will mean many Spring things, like AOP, will work out-of-the-box
So, let’s say for example you decide you want to move from an XML SOAP/RPC based web service to a RESTful one using JSON. For whatever reason, if the WS API objects changed significantly due to the service protocol change your application using it need not worry about it. The implementation bundle can take on that burden to ensure the API interface (contract) is kept consistent. The application simply expresses a dependency on a particular interface which is satisfied at run time by a provider of that interface (service). Turn on this bundle, turn off the old bundle provider and you application should swap over automagically. It need not be as big a change as this, it could be a matter of fine tuning an existing bundle. OSGi and Declarative Services will take care of the wiring for you.
Get to know the console
The Virgo OSGi console contains pretty much all of the information and tools you need to fix bugs, introspect state etc. The Admin application provided with Virgo contains a really nice feature to debug uses-constraints, but apart from that in my opinion the console is much faster and easier to use. Read more about it in my debugging post or at the official documentation.
We had a need to use Terracotta for HA session and caching replication, which required a specific Valve customisation to Tomcat’s context.xml configuration file. This is normally really easy – simply add the Valve and put the relevant JAR’s into the shared /lib folder. However, in OSGi this process is not possible. As Tomcat is now an OSGi bundle, it explicitly states the packages that it depends on so dumping a JAR in a directory will do nothing. What you need to do is add the Terracotta packages into the Tomcat classpath when Virgo starts it up.
To achieve this, the most elegant way is to not fiddle with the OSGied Tomcat bundle, nor the boot classpath to make available to all bundles, but to extend it’s classpath using a Bundle-Fragment. Learn more about them on Glyn Normington’s post or at the Spring Documentation.
In practice, you create a bundle for Terracotta (or bundle X) and create a separate bundle consisting only of a manifest file, with the usual headers and a Fragment-Host header specifying the bundle it should latch on to.
Fragment-Host: org.eclipse.gemini.web.tomcat;bundle-version="[2.0.0.,3.0.0)" Manifest-Version: 1.0 Built-By: Matt Fellows ... Bundle-Version: 1.0.0 Bundle-ManifestVersion: 2 Bundle-Description: OSGi Web Self-Service Application Reference Implem entation Bundle-SymbolicName: com.melbourneit.web.eclipse.virgo.web.tomcat.terr acotta Import-Package: ...
You may need to get used to these sorts of solutions, especially if enhancing Virgo internals is required.
Tools for the trade
There are at least 3 tools that I use daily to get the job done
- Pax Construct – Logically organises your OSGi project into Maven modules, useful tools to wrap 3rd party JARs to make OSGi compliant, sets reasonable defaults, completely transparent if you want it to be.
- Maven Bundle Plugin – Used by Pax Construct by default, I prefer this tool over bundlor for simple bundles
- Bundlor – Integrates in Eclipse, STS and Maven and can really simplify your Manifest management. Alternative to Maven Bundle Plugin.
The Virgo Team are awesome
In my experience so far, the Virgo team have been extremely helpful with responding to queries and solving issues and are really working toward building a quality product that meets the needs of their customers. You’ll find the forums quite active and a good resource for troubleshooting, and the guys are all over Twitter so you can keep up with the latest news.
Read the following – you’re parallel dimension self with thank you for it.
- http://njbartlett.name/osgibook.html – This should get you started on all of the main concepts, problems etc.
- http://njbartlett.name/2011/02/09/uses-constraints.html – A well explained article on debugging uses-constraints.
- http://www.osgi.org/blog/2006/04/misconceptions-about-osgi-headers.html – OSGi headers explained.
- http://www.ibm.com/developerworks/websphere/techjournal/1007_charters/1007_charters.html?ca=drs- – OSGi Best Practices.
- http://www.eclipse.org/virgo/documentation/ – The Virgo Documentation is pretty good, make sure that you read them in detail
You can find all of my OSGi bookmarks here: http://www.delicious.com/mefellows/osgi
Overall, I’m quite happy with what Virgo provides in the way of support for Spring and OSGi. I’m not 100% convinced at this stage, that OSGi is the fastest means of development – there is most definitely an overhead – however I believe in the long term this is the direction that the industry is moving in, especially with the upcoming Java Modularity requirements for Java 8 I believe OSGi developers will be well prepared for the change.
I don’t believe that Virgo has really pushed the envelope with respect to Hot deployments – one of the main selling points of OSGi. Automating deployments these days is a key activity in Agile project management, indeed it is a best practice full stop. With the current toolset, it is hard to see an elegant solution to automating deployments that allows for hot deployment of modules whilst the Web Application is still running. Plan files significantly reduce the complexity of a deployment, however an artifact within the plan cannot be hot deployed – the entire plan needs to be redeployed. Doing this by hand is possible and Virgo deals with this as expected; if a service dependency is removed at runtime, the application flow requiring it simply pauses until it comes back online. Better still, if the bundle is an implementation provider of an API, you can hot swap out the service at runtime without the Web Application even knowing. However, the cost is that this is a very manual process and that means it’s error-prone.
I’d like to see the features, like the ability to hot-deploy artifacts within a plan or command-line (aka Glassfish asadmin) tools to perform deployments in an atomic and controlled fashion from deployment scripts, for example.
For me, coming up with a best-practice and elegant solution to this problem would really ensure Virgo is the stand-out choice as a Web-enabled OSGi server for the community.