OSGi Getting Started

By Michael N. Lipp

Mastodon Follow

View GitHub Project

Introduction

Part 1: The container

Part 2: Simplest Bundle

Part 3: Simple Bundle

Part 4: Eclipse (OSGi) Plugin

Part 5: Bndtools

Part 6: Shift in Perspective

Part 7: Modules and Services

Part 8: Accessing a Service

Part 9: Tracking a Service

Part 10: Using a Service

Part 11: Providing a Service

Interlude: Cleaning up

Part 12: Configuration Admin

Part 13: Service Components

Part 14: Repositories

Part 15: Versions

Versions

“Success is relative. It is what we make of the mess we have made of things.” – T.S. Eliot

Maybe, for a start have a look at the Wikipedia article about Software Versioning. Nice topic, isn’t it? Well, luckily we can narrow the scope a bit.

What we have to provide versions for are bundles, packages and (assuming that we use Maven repositories) Maven artifacts. What we can build upon is that there seems to be a common consensus that, regarding libraries, “semantic versioning” is an acceptable approach1. In our context, we have to consider two specifications of semantic versioning: the respective OSGi Whitepaper and a more generally scoped specification2, often referred to as “SemVer”. An advantage of the former document is that it distinguishes between the provider and the consumer of an API. The big advantage of the latter is that it defines how to handle versions during development (pre-release versions).

What to Version

Let’s first get a clear idea about the kinds of versions that we have to provide. Regarding the API, the contract between components is essentially defined by the “Export-Package” and “Import-Package”. The versions declared in the “Export-Package” header are the really important versions, because they are used when wiring importers to exporters, i.e. when trying to find a match for an “Import-Package” requirement with a given name and version range.

The “Bundle-Version” header is, interesting enough, optional (with a default value of “0.0.0”). A bundle is an aggregate and therefore, if a bundle version is given, it “must move as fast as the fastest moving package [it contains]” (see the bnd documentation). However, although the bundle version can be used as a requirement at various places, the default is always “[0.0.0,∞)” (any version). Especially when providing “ordinary” libraries that include the required headers to be faithfully used in an OSGi context, you shouldn’t run into problems if the bundle version moves differently. Of course, the bundle version is used by tools to choose among available bundles with the same bundle name, so it isn’t completely insignificant.

Finally, we have the Maven artifact version. Wouldn’t it be nice if it matched the bundle version? It certainly would, and maybe could, if only OSGi had considered the pre-release versioning a bit more carefully.

Pre- vs. Post-Qualifiers

Let’s head straight at the core of the problem. OSGi defines a version number with a qualifier (“1.0.0.test”) to be higher than the version without the qualifier (“1.0.0”, the “release version”). So the qualifier is in fact a post-release qualifier. SemVer considers the release version “1.0.0” to be the final version with these major, minor and patch numbers. There is nothing “post” this release3. A version with a qualifier, such as “1.0.0-test”4, is therefore defined to be lower than “1.0.0”5.

This is important: OSGi: 1.0.0.test > 1.0.0, SemVer 1.0.0-test < 1.0.0. And Maven? Well, Maven effectively has qualifiers that mark a version as pre-release and qualifiers that mark it as post-release. The exact rules are decribed in the POM reference and are a bit complicated. What it boils down to from a practical point of view is, that qualifiers that start with a number (such as those used by maven tooling for snapshot versions) are pre-release versions.

Maven versioning’s support for qualifiers that indicate pre-release versions is one of the reasons that make working with such pre-releases rather simple. (The other is, of course, the special keyword “SNAPSHOT”. When used as the qualifier, it simply denotes the latest pre-release of a given release version6.)

The real fun starts when you think about version ranges. How do pre-release versions fit in? Obviously, a range “[1.0.0,1.1.0)” does not include the pre-release “1.0.0-test”, else the pre-release would have to provide all the features of the release version7. But what about “1.1.0-rc1”? It’s lower than “1.1.0”, so the version range formally includes it. But the intention of the range definition presumably was to exclude anything “related to” (includes “leading to”) version “1.1.0” (and beyond) because it was expected to introduce some incompatibility.

To be continued


  1. Trying to be very careful here. 

  2. This is “only” an individual’s (Tom Preston-Werner) project. But an influential one. The specification has been picked up by projects such as NPM, Racket, Ruby Gems, Angular (to just name a few of the top search results). 

  3. I admit that I like this approach. IMHO anything that causes an artifact to be rebuilt after its release (which establishes the release version) should result in an increase of the patch number. 

  4. Notice the different separator being used to separate the qualifier from the rest of the version number. Some have brought up the interpretation of a “minus”, so “1.0.0” is the release “minus” something, which clearly indicates that it is “less”. Of course, this interpretation becomes dubious when you consider the ordering of pre-releases: 1.0.0-2 < 1.0.0-3. Doesn’t really comply with mathematics. 

  5. At least there is no difference in the sort order of the qualifiers. SemVer defines it to be based on the ASCII values, OSGI refers to String.compareTo. Luckily, with respect to the characters allow in a qualifier, this boils down to the same result. 

  6. The OSGi Alliance has once considered to support pre-release versions as well, but discarded the proposal8

  7. Or maybe not so obvious. The “Semantic Versioning 2.0.0-rc.2” stated that “Pre-release versions satisfy but have a lower precedence than the associated normal version”. It was only in the final release 2.0.0 that this sentence was changed to the opposite statement “A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version”. The final version was published in June 2013. Keep this in mind when you come across old articles that refer to “SemVer”. 

  8. Maybe for the better, since it would have increased the mess. The attempt to define a version system that supports both pre- and post-release qualifiers (the use of “.” vs. “-” came in quite handy) made things rather complicated.