Tuesday, February 12, 2013

Bndtools 2.0 released

Yesterday Neil Bartlett released bndtools 2.0, a major piece of work by Neil and others. He worked so hard on it that he even stopped harassing me in the morning! Kidding aside, even though I am part of the time I am often surprised to find very useful functions that I was totally unaware of. Now, if you looked at bndtools some time ago, take another look since it really matured. I am convinced that it is by far the best tool to develop OSGi bundles in the market. This new release adds a lot of new features, some of them I'd like to point out in this blog. Today I am starting with release management.

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.

 Peter Kriens

2 comments:

  1. Hey Peter, this feature of Bnd alone is of huge benefit to all developers of Java APIs, whether or not they are using OSGi and semantic versioning.

    Thanks for putting in the effort, its much appreciated.

    ReplyDelete
  2. This blog is awesome for explaining some complex concepts and direction of Java language.Thanks a lot.

    ReplyDelete