11 min read

(For more resources related to this topic, see here.)

In this article, we will cover the following topics:

  • What is OSGi and what are its key features?

  • The role of the OSGi framework

  • The OSGi base artifact—the OSGi bundle and the concept of dependencies between bundles

  • The Apache Karaf OSGi container and the provisioning of applications in the container

  • How to manage the provisioning on multiple Karaf instances?

What is OSGi?

Developers are always looking for very dynamic, flexible, and agile software components. The purposes to do so are as follows:

  • Reuse: This feature states that instead of duplicating the code, a component should be shared by other components, and multiple versions of the same component should be able to cohabit.

  • Visibility: This feature specifies that a component should not use the implementation from another component directly. The implementation should be hidden, and the client module should use the interface provided by another component.

  • Agility: This feature specifies that the deployment of a new version of a component should not require you to restart the platform. Moreover, a configuration change should not require a restart. For instance, it’s not acceptable to restart a production platform just to change a log level. A minor change such as a log level should be dynamic, and the platform should be agile enough to reload the components that should be reloaded.

  • Discovery: This feature states that a component should be able to discover other components. It’s a kind of Plug and Play system: as soon as a component needs another component, it just looks for it and uses it.

OSGi has been created to address the preceding points.

The core concept is to force developers to use a very modular architecture in order to reduce complexity. As this paradigm is applicable for most modern systems, OSGi is now used for small embedded devices as well as for very large systems.

Different applications and systems use OSGi, for example, desktop applications, application servers, frameworks, embedded devices, and so on.

The OSGi framework

OSGi is designed to run in Java. In order to provide these features and deploy OSGi applications, a core layer has to be deployed in the Java Virtual Machine (JVM): the OSGi framework.

This framework manages the life cycle and the relationship between the different OSGi components and artifacts.

The OSGi bundle

In OSGi, the components are packaged as OSGi bundles. An OSGi bundle is a simple Java JAR (Java ARchive) file that contains additional metadata used by the OSGi framework. These metadata are stored in the manifest file of the JAR file.

The following is the metadata:

Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Version: 2.1.6 Bundle-Name: My Logger Bundle-SymbolicName: my_logger Export-Package: org.my.osgi.logger;version=2.1 Import-Package: org.apache.log4j;version="[1.2,2)" Private-Package: org.my.osgi.logger.internal

We can see that OSGi is very descriptive and verbose. We explicitly describe all the OSGi metadata (headers), including the package that we export or import with a specified version or version range.

As the OSGi headers are defined in the META-INF/MANIFEST file contained in the JAR file, it means that an OSGi bundle is a regular JAR file that you can use outside of OSGi.

The life cycle layer of the OSGi framework is an API to install, start, stop, update, and uninstall OSGi bundles.

Dependency between bundles

An OSGi bundle can use other bundles from the OSGi framework in two ways.

The first way is static code sharing. When we say that this bundle exports packages, it means a bundle can expose some code for other bundles. On the other hand, when we say that this bundle imports packages, it means a bundle can use code from other bundles.

For instance, we have the bundle A (packaged as the bundleA.jar file) with the following META-INF/MANIFEST file:

Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Version: 1.0.0 Bundle-Name: Bundle A Bundle-SymbolicName: bundle_a Export-Package: com.bundle.a;version=1.0

We can see that the bundle A exposes (exports) the com.bundle.a package with Version 1.0. On the other hand, we have the bundle B (packaged as the bundleB.jar file) with the following META-INF/MANIIFEST file:

Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Version: 2.0.0 Bundle-Name: Bundle B Bundle-SymbolicName: bundle_b Import-Package: com.bundle.a;version="[1.0,2)"

We can see that the bundle B imports (so, it will use) the com.bundle.a package in any version between 1.0 and 2 (excluded). So, this means that the OSGi framework will wire the bundles, as the bundle A provides the package used by the bundle B (so, the constraint is resolved).

This mechanism is similar to regular Java applications, but instead of embedding the required JAR files in your application, you can just declare the expected code. The OSGi framework is responsible for the link between the different bundles; it’s done by the modules layer of the OSGi framework. This approach is interesting when you want to use code which is not natively designed for OSGi. It’s a step forward for the reuse of components. However, it provides a limited answer to the purposes seen earlier in the article, especially visibility and discovery.

The second way in which an OSGi bundle can use other bundles from the OSGi framework is more interesting. It uses Service-Oriented Architecture (SOA) for low-level components. Here, more than exposing the code, an OSGi bundle exposes a OSGi service. On the other hand, another bundle can use an OSGi service. The services layer of the OSGi framework provides a service registry and all the plumbing mechanisms to wire the services.

The OSGi services provide a very dynamic system, offering a Publish-Find-Bind model for the bundles.

The OSGi container

The OSGi container provides a set of additional features on top of the OSGi framework, as shown in the following diagram:

Apache Karaf provides the following features:

  • It provides the abstraction of the OSGi framework. If you write an OSGi application, you have to package your application tightly coupled with the OSGi framework (such as the Apache Felix framework or Eclipse Equinox). Most of the time, you have to prepare the scripts, configuration files, and so on in order to provide a complete, ready-to-use application. Apache Karaf allows you to focus only on your application. Karaf, by default, provides the packaging (including scripts and so on), and it also abstracts the OSGi framework. Thanks to Karaf, it’s very easy to switch from Apache Felix (the default framework in Karaf) to Eclipse Equinox.

  • Provides support for the OSGi Blueprint and Spring frameworks. Apache Karaf allows you to directly use Blueprint or Spring as the dependency framework in your bundles. In the new version of Karaf (starting from Karaf 3.0.1), it also supports new dependency frameworks (such as DS, CDI, and so on).

  • Apache Karaf provides a complete, Unix-like shell console where you have a lot of commands available to manage and monitor your running container. This shell console works on any system supporting Java and provides a complete Unix-like environment, including completion, contextual help, key bindings, and more. You can access the shell console using SSH. Apache Karaf also provides a complete management layer (using JMX) that is remotely accessible, which means you can perform the same actions as you do using the shell commands with several MBeans.

  • In addition to the default root Apache Karaf container, for convenience, Apache Karaf allows you to manage multiple container instances. Apache Karaf provides dedicated commands and MBeans to create the instances, control the instances, and so on.

  • Logging is a key layer for any kind of software container. Apache Karaf provides a powerful and very dynamic logging system powered by Pax Logging. In your OSGi application, you are not coupled to a specific logging framework; you can use the framework of your choice (slf4j, log4j, logback, commons-logging, and so on). Apache Karaf uses a central configuration file irrespective of the logging frameworks in use. All changes in this configuration file are made on the fly; no need to restart anything. Again, Apache Karaf provides commands and MBeans dedicated to log management (changing the log level, direct display of the log in the shell console, and so on).

  • Hot deployment is also an interesting feature provided by Apache Karaf. By default, the container monitors a deploy folder periodically. When a new file is dropped in the deploy folder, Apache Karaf checks the file type and delegates the deployment logic for this file to a deployer. Apache Karaf provides different deployers by default (spring, blueprint, features, war, and so on).

  • If Java Authentication and Authorization Service (JAAS) is the Java implementation of Pluggable Authentication Modules (PAM), it’s not very OSGi compliant by default. Apache Karaf leverages JAAS, exposing realm and login modules as OSGi services. Again, Apache Karaf provides dedicated JAAS shell commands and MBeans. The security framework is very flexible, allowing you to define the chain of login modules that you want for authentication. By default, Apache Karaf uses a PropertiesLoginModule using the etc/users.properties file for storage. The security framework also provides support for password encryption (you just have to enable encryption in the etc/org.apache.karaf.jaas.cfg configuration file). The new Apache Karaf version (3.0.0) also provides a complete Role Based Access Control (RBAC) system, allowing you to configure the users who can run commands, call MBeans, and so on.

  • Apache Karaf is an enterprise-ready container and provides features dedicated to enterprise. The following enterprise features are not installed by default (to minimize the size and footprint of the container by default), but a simple command allows you to extend the container with enterprise functionalities:

    • WebContainer allows you to deploy a Web Application Bundle (WAB) or WAR file. Apache Karaf is a complete HTTP server with JSP/servlet support, thanks to Pax Web.

    • Java Naming and Directory Interface (JNDI) adds naming context support in Apache Karaf. You can bind an OSGi service to a JNDI name and look up these services using the name, thanks to Aries and Xbean naming.

    • Java Transaction API (JTA) allows you to add a transaction engine (exposed as an OSGi service) in Apache Karaf, thanks to Aries JTA.

    • Java Persistence API (JPA) allows you to add a persistence adapter (exposed as an OSGi service) in Apache Karaf, thanks to Aries JPA. Ready-to-use persistence engines can also be installed very easily (especially Apache OpenJPA and Hibernate).

    • Java Database Connectivity (JDBC) or Java Message Service (JMS) are convenient features, allowing you to easily create JDBC DataSources or JMS ConnectionFactories and use them directly in the shell console.

  • If you can completely administrate Apache Karaf using the shell commands and the JMX MBeans, you can also install Web Console. This Web Console uses the Felix Web Console and allows you to manage Karaf with a simple browser.

Thanks to these features, Apache Karaf is a complete, rich, and enterprise-ready container. We can consider Apache Karaf as an OSGi application server.

Provisioning in Apache Karaf

In addition, Apache Karaf provides three core functionalities that can be used both internally in Apache Karaf or can be used by external applications deployed in the container:

  • OSGi bundle management

  • Configuration management

  • Provisioning using Karaf Features

As we learned earlier, the default artifact in OSGi is the bundle. Again, it’s a regular JAR file with additional OSGi metadata in the MANIFEST file. The bundles are directly managed by the OSGi framework, but for convenience, Apache Karaf wraps the usage of bundles in specific commands and MBeans.

A bundle has a specific life cycle. Especially when you install a bundle, the OSGi framework tries to resolve all the dependencies required by your bundle to promote it in a resolved state. The following is the life cycle of a bundle:

The OSGi framework checks whether other bundles provide the packages imported by your bundle. The equivalent action for the OSGi services is performed when you start your bundle. It means that a bundle may require a lot of other bundles to start and so on for the transitive bundles.

Moreover, a bundle may require configuration to work. Apache Karaf proposes a very convenient way to manage the configurations. The etc folder is periodically monitored to discover new configuration files and load the corresponding configurations. On the other hand, you have dedicated shell commands and MBeans to manage configurations (and configuration files). If a bundle requires a configuration to work, you first have to create a configuration file in the etc folder (with the expected filename) or use the config:* shell command or ConfigMBean to create the configuration.

Considering that an OSGi application is a set of bundles, the installation of an OSGi application can be long and painful by hand.

The deployment of an OSGi application is called provisioning as it gathers the following:

  • The installation of a set of bundles, including transitive bundles

  • The installation of a set of configurations required by these bundles

OBR

OSGi Bundle Repository (OBR) can be the first option to be considered in order to solve this problem. Apache Karaf can connect to the OBR server. The OBR server stores all the metadata for all the bundles, which includes the capabilities, packages, and services provided by a bundle and the requirements, packages, and services needed by a bundle. When you install a bundle via OBR, the OBR server checks the requirement of the installed bundle and finds the bundles that provide the capabilities matching the requirements. The OBR server can automatically install the bundles required for the first one.

LEAVE A REPLY

Please enter your comment!
Please enter your name here