For me, by far the most interesting new feature is the release tool. I hate versions with a vengeance, they are not very user friendly. In a large build it is so easy to get versions wrong and the resulting problems are not easy to detect, to say the least. Automating is the solution of course; the original reason behind bnd. However, bnd works on the bundle and class path level and therefore has no concept of change, and versions are all about change. Semantic versioning provides a language to express the nature of the change and thereby gives us the mechanism to describe a conditional dependency that accepts certain changes but rejects other changes. As the white paper argues, this dependency differs on the role the requirer plays. Consumers are loosely coupled to an API since we go out of our way to be backward compatible but Providers of that API have a much stronger connection, almost any change in the API is a responsibility of the provider. These different roles and their influence on imports is reflected in their import version policies.
The theory is fine but it requires very minute maintenance of versions. For a lot of developers the idea to maintain package versions sounds horrific because it is already so difficult to manage their artifact versions, just imagine that you have to do that 20x more! In reality, bnd has always provided support for minimizing that work. You rarely ever have to specify import versions since they're picked up from the classpath.
The story for exports is different. You have to specify the export versions by hand, and this is trickier because it requires a judgement of the changes that were made. For example, adding a method to an interface breaks all implementers of that interface. Depending if that interface was implemented by a Consumer or Provider, you have a major or minor change. Judging this change requires a comparison against a previous version and as I stated earlier, bnd had no concept of time. It had, however, a concept of (pluggable) repositories, and repositories can provide history. Though all parts were present, there was only rudimentary functionality that bound it all together before release 2.0.
There was a release tool in the previous release but it had some shortcomings. PK Søreide from CommActivity in Stockholm and I set out to improve this function for this release. I extended bndlib with an extensive API and resource diff tool and a baseline tool. The diff tool understands Java semantics and is capable of representing the changes between two JARs all the way up to the modifiers of a field or method. It also judges if a change is MAJOR, MINOR, or MICRO: the parts of our version. Since this judgement depends on the role that an interface or class plays, the diff tool supports the @ConsumerType and @ProviderType annotations. The diff tool also supports many other, sometimes subtle, rules about compatibility like adding methods to an interface or making a field protected.
$ bnd diff -am some-1.1.0.jar some-1.0.1.jar ADDED PACKAGE baeline CHANGED MANIFEST
REMOVED HEADER Bundle-Version:1.0.1 ADDED HEADER Bundle-Version:1.1.0 CHANGED HEADER Export-Package ADDED CLAUSE baeline ADDED HEADER Provide-Capability:x-jpm-plugin; x-jpm-plugin=apache.felix.webconsole
The baseline tool then takes the diff tool's output and calculates the minimum required version bump for the bundle and the packages. For example, from the command line:
$ bnd baseline some-2.0.0.jar some-1.1.0.jar Package Delta New Old Suggest If Prov. aQute.library.remote UNCHANGED 1.0.0 1.0.0 1.0.0 - aQute.service.library UNCHANGED 1.0.0 1.0.0 1.0.0 - aQute.struct UNCHANGED 1.0.0 1.0.0 1.0.0 - baseline MAJOR 2.0.0 1.0.0 2.0.0 -
Now, command lines are my favorite tool but, although they seem to be gaining in popularity, most developers want buttons and lists. So PK developed a GUI tool that displays the aggregates of the changes with the possibility to drill down to the most minute details. It also provides a suggestion for the bundle version and each modified package version. With one press of a button, the build is updated and the artifacts are pushed tot the release repository.
There is also a global command for releasing all the bundles in a workspace in one go. With one press, you can now release all your bundles to the Release repository. Since we also added a new File Repository that is easy to connect to ftp, git or some other deploy tool you can automatically make it available to team members or the world. However, that is for a next blog.