Creating a plugin system with Karaf and OSGi µServices
When we started to design calvaDrive, it became clear that we can only achieve true feature flexibility if we implement a plugin system. Of course we could have created it from scratch, but why? If you implement a plugin system you have to think about dynamics, class loaders, interfaces and a couple of other things you do not even have in mind until they ruin your schedule. On the other hand we already had begun to use OSGi to split our monolithic application into small modules.
OSGi and µServices
If you have never heard of OSGi before, it may be worth to have a look at it. In short it is a Java-based framework which supports modularization by encapsulating JAR files (called OSGi bundles). The OSGi Alliance provides a nice overview as well as all specifications.
One of the key features of OSGi is the service registry which allows to implement µServices. The concept of µServices was created by Peter Kriens and described in a blog post back in 2010. Though they sound like Microservices, they are in fact older and much more light-weight. Microservices are designed to split monolithic business applications into smaller parts, which are distributed across several nodes in a network. OSGi and µServices also help you to break up your monoliths, while still running on a single JVM. Therefore, µServices do not require all that network communication overhead but still give you the ability to design clean interfaces and to separate them from their implementations.
OSGi enables dynamism, class loaders and interfaces. It introduces a component model and services. And it also allows you to install, update and remove code bundles at runtime – everything you need to build a plugin system. But before you can start, you need to choose an OSGi server implementation which runs your application and the plugin code. For calvaDrive, we have decided to use Apache Karaf. It offers all the aspects you need to build an OSGi application and can easily be extended to a full-featured web server using a concept called features. A feature is essentially a group of bundles with optional dependencies and configuration data. Karaf already provides features to install, e.g. a Jetty web server or JPA support.
Karaf provides base functionality for plugin system
Karaf enables us to build calvaDrive as modern modular web application consisting of one hundred OSGi bundles at the moment (not counting third-party dependencies like Apache Commons). The core application defines extension points for plugins as Java interfaces. A plugin implements the extension point interface and provides its implementation as µService. But a plugin might not only consist of one bundle – it might integrate several bundles, configuration data and dependencies. Sounds familiar? Karaf not only provides for us OSGi support, it also helps us to install plugins. In fact, our plugins are just Karaf features. They become installed using the Karaf Feature Service – which is provided as OSGi service, itself.
One of our first plugins we created was the Watch System plugin. The plugin can be installed on-the-fly without a restart of calvaDrive. After activation, it provides new options in the menus for observing a file or folder. If an observed file is downloaded, the system sends an e-mail to the observer. For this purpose, we have implemented an extension point in the context menu. The core application detects registered extensions and delegates all rendering and execution tasks to that extension. If the plugin becomes uninstalled, the menu options disappear and no e-mails will be send in the future.
OSGi µServices provide you with the architectural power of Microservices but without network overhead. They are perfect if you want to break up a monolithic application into small manageable pieces of code. And they help you to comply with principles like SOLID. Apache Karaf is an extendible OSGi server offering many useful features with it. Together, µServices and Karaf helped us to build a flexible plugin system for calvaDrive.