Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Version numbers and JSR277

2008, jsr277, osgi

Although I’ve written recently that it looks like OSGi and JSR277 are coming together, there are still a number of things that are potential concrete blocks on the road to progress. This information is based on the public draft from 2006 so it’s possible that some detail has changed; but reading between the lines on the various JSR277 blogs, it doesn’t seem to be the case.

The first concerns the format of the version number. Why Sun, of all people, should be in charge of version formats is beyond me; they’ve invented a new versioning system for pretty much each version of Java that came out (JDK 1.0.2, JRE/JDK 1.1.8_010, J2RE/J2SDK 1.2.2_17, J2RE/J2SDK 1.3.1_21, J2RE/J2SDK 1.4.2_16, JDK/JRE 5.0 Update 14, JDK/JavaSE 6 Update 6 with NetBeans, and who could forget Java SE 6 Update 10 aka Update N aka 6uN). Oh, and of course they’ve changed all the URLs, so whilst you used to be able to browse for java.lang.Object, you now get redirected to a faceless JavaSE page which doesn’t have any references to what it used to point to. Way to go, Sun.

The second concerns the number of numbers. The version numbering format for a JSR277 module is major.minor.micro.update-qualifier. The first four are numeric (defaulting to zero if missing) and the qualifier is textual. According to the documentation of 2006, the qualifier must be used for beta releases, and must not be used for released versions. In fact, the empty string for qualifier is deemed greater than any other value. Quite aside from that, who uses four version numbers, anyway? Basically Oracle (hey, wow; they’re now on to five digits - Oracle Database 11g Release 1 (11.1.0.6.0) is the current version of Oracle 11g) and Sun (java -version gives java version "1.5.0_13"). Note how many of those digits are zero and basically unused; also note how many of them are still carrying around excess baggage of versions. All Java versions have started with a 1, so that’s one digit burnt up already; and the third digit is basically used occasionally to mark the number of builds. But get this - the Java builds have incremental feature, so that zero isn’t used anymore either. In a few passing versions of Java, they used it to reset the build count, but back in the really early days, they used the fourth number (e.g. 1.1.8_005, 1.1.8_006, 1.1.8_007, 1.1.8_008) to hide the fact that it was as buggy as hell, and they didn’t want to show to the outside world how many releases they had made. The same followed through into Java 1.4 (1.4.0_0 to 1.4.0_4, 1.4.1_0 to 1.4.1_07, 1.4.2_0 to 1.4.2_16). The whole rationale for the last number was purely a (failed) marketing exercise, much like the remainder of the Java versioning saga. Am I the only person who is reminded of the The Onion’s story on ever-increasing numbers of razor blades (which presaged this by two years, although it’s worth noting their incompetence extends to their home page … but I digress)

The third concern is the range specification for version numbers. Most modules will, at some point, want to depend on a specific version or range of versions. There’s a choice here; re-use well understood versioning or invent your own mechanism. But hey, if you’re re-inventing module systems, why not re-invent your own versioning format too? As a result, we’re left with an utterly bizarre notation for representing ranges. Thus is born:

Open range
An open range is defined as greater than or equal to a specified version, giving us:
  • 1+ anything 1.0.0.0 or above
  • 1.1+ anything 1.1.0.0 or above (c.f. other digits)
Family range
A family range is defined as greater than or equal to a specified version, but not going above the ceiling, giving us:
  • 1* anything 1.0.0.0 or above but below 2.0.0.0
  • 1.1* anything 1.1.0.0 or above but below 1.2.0.0 (c.f. other digits)
Open range within fammily
A combination of the two allowing for some utterly bizzare twists, giving us:
  • 1.[1.1.1+] anything 1.1.1.1 or above but below 2.0.0.0
  • 1.1.[1.1+] anything 1.1.1.1 or above but below 1.2.0.0 (c.f. other digits)
Union of open ranges within fammily
Seeing as it’s impossible to represent constraints of anything above +1, you need to be able to combine them:
  • 1.[2.3.4+];2*;3* anything 1.2.3.4 or above but below 4.0.0.0
  • 1.1.[1.1+];3* anything 1.1.1.1 or above but below 1.2.0.0, or those between 3.0.0.0 (inclusive) and 4.0.0.0 (exclusive)

Frankly, it will be amazing if anyone gets their version numbers right in their metadata. When to use * or +? When to have a different digit? Who knows. And how are they going to map onto a versioning system which uses less digits?

Now, compare that with OSGi’s version numbering scheme:

  • Three numeric and one string qualifier
  • Versions can be open “1.2.3” or a range “[1.2.3,4.5.6)”, technically allowing both inclusive and exclusive start/end points (but usually having an inclusive start and an exclusive end, defaulting to infinity)

That’s it. No other complications. Easy to define a version that must be greater than 1.2.3 and less than 4.5.6 (sub-versions are optional and default to zero). No restrictions on what you can use the qualifier for, or when to use it. No extra digits (OSGi went through the learning pain of getting it right the first time; learning from other people’s mistakes is the art of true genius).

True, it means that you can’t do things like five version numbers in OSGi, but that’s not a problem, that’s a feature. Look at most of the OSGi bundles around you - you can bet that at least one, possibly two of the version numbers are being consumed with some variant of the product number. Eclipse has started to move away from that somewhat, so in the recent 3.4 builds you’ll still find bundles that are prefixed with 3.1; but it’s still burning up two version numbers to get to that point (with the result that people are trying to cram in extra precision in the single last version number).

Module versioning is like playing the piano. The problem isn’t how many digits you’ve got, it’s using them effectively.