Groovy 2.1.0-rc-2 is out!

Generally it is not a big deal when next RC is released. Generally not but that one is a big deal… at least for me. Why? This is the first Groovy release where my contribution can be spotted :)

Full release notes for RC2 are available here. Of course to get the release you can download it directly from Groovy site or use any other way you like. Personally I always use gvm to obtain new Groovy releases. If you haven’t tried gvm yet it is definitely a tool worth giving a try.

Working with legacy code is fun now!

From time to time we are all exposed to some amount of legacy code. First characteristic of legacy code is that it is hard to work with and even harder to change. Sometimes even a bit of refactoring is not an option. Fortunately there is a way to boost legacy code without really touching it. The option I am talking about is creating a custom Groovy extension module what has never been as simple as of version 2.0. Detailed instruction on creating Groovy extension module can be found here.
The question is how it can be used to easily fix the legacy code. The inspiration to write this blog post comes from my recent experience with Bouncy Castle support for OpenPGP (aka bcpg). I found working with the library really unpleasant due to its fossil API. I won’t go through whole bunch of cases but I will rather focus on one example to give the idea.
The thing I wanted to achieve was getting out proper PGPPublicKey from PGPPublicKeyRing based on the key usage. Since PGPPublicKeyRing is more or less just a set of PGPPublicKeys it sounds easy-peasy. But when it comes to reality it took me some time to find a way to get the correct key – below is the way I achieved it:

public final class PGPUtil {
    
    public static PGPPublicKey getByKeyUsage(PGPPublicKeyRing keyRing, int keyUsage) {
        final Iterator keys = keyRing.getPublicKeys();
        while (keys.hasNext()) {
            final PGPPublicKey key = keys.next();
            final Iterator signatures = key.getSignatures();
            while (signatures.hasNext()) {
                final PGPSignature signature = signatures.next();
                final KeyFlags keyFlags = KeyFlags.class.cast(signature.getHashedSubPackets().getSubpacket(SignatureSubpacketTags.KEY_FLAGS));
                if (keyFlags == null) {
                    continue;
                }
                
                if ((keyFlags.getFlags() & keyUsage) != 0) {
                    return key;
                }
            }
        }
        
        return null;
    }
    
    private PGPUtil() {
        // intentionally left blank
    }

}

As you can see the code is already written and extracted to utility class. Despite its ugliness probably it does what it is meant to. But does any guarantee come with it ensuring a developer will ever find a class and use it instead of reinventing the wheel? Won’t it be harder to look past if the PGPPublicKeyRing class simply has a method getByKeyUsage()?

public class PGPPublicKeyRing extends PGPKeyRing {

    ... // code omitted

    public PGPPublicKey getByKeyUsage(int keyUsage) { ... }

}

Unfortunately achieving this in pure Java will require modification existing Bouncy Castle codebase what is not even considered to be an option. But when it comes to Groovy we have a whole variety of tools to make it happen without making incursion into Bouncy Castle. We will modify Groovy metaclass of PGPPublicKeyRing but we will do it the smart way. And the smart way means here creating Groovy extension module.
Since we already have the util class there is not much left to do:

  1. assuming standard Maven-like structure of the project create org.codehaus.groovy.runtime.ExtensionModule file and put it under /src/main/resources/META-INF/services/
  2. the content of the file shall be as follows:
    moduleName = GroovyBouncyCastleExtension
    moduleVersion = 1.0
    extensionClasses = pl.helenium.showcase.groovy.extension.bc.PGPUtil

Voilà! That’s all. The additional method shall already be visible by the Groovy compiler and at least when it comes to IntelliJ IDEA 12 Ultimate the method is also available for code completion.
What is potentially left to be done?

  • build the project into the jar: every time the jar is added to the classpath PGPPublicKeyRing class will be enhanced with additional meta-method
  • add more easy to use meta-methods to this and other classes: static methods can be added in similar way but staticExtensionClasses property has to be used instead (in module descriptor)
  • make extension classes Groovier: currently PGPUtil is purely implemented in Java but nothing prevents it from being migrated to Groovy:
    final class PGPUtil {

    static PGPPublicKey getByKeyUsage(PGPPublicKeyRing keyRing, int keyUsage) {
    keyRing.publicKeys.toList().find { PGPPublicKey key ->
    key.signatures.toList().any { PGPSignature sig ->
    KeyFlags keyFlags = sig.hashedSubPackets.getSubpacket(SignatureSubpacketTags.KEY_FLAGS)
    keyFlags && (keyFlags.flags & keyUsage)
    }
    }
    }

    }

Benefits over runtime modification of metaclass:

  • elegance: instead of manually modifying the metaclasses let the Groovy engine enhance them for you (IoC)
  • reusability: extension module can be easily reused by simply adding it to the classpath
  • transparency: extension modules are treated as if they were a part of original GDK (support from your IDE like code completion shall be available out-of-the-box)
  • dependability: additional features provided by extension modules are available all the time through the application lifecycle

Main shortcomings of extension modules:

  • scope: there is no way of limiting the metaclass modification to particular block of code or class instances
  • control: it is not as powerful as local metaclass modifications (e.g. Expandos, Categories)

I wanted to show that a lot of legacy code can be improved with help of Groovy without even having to touch it. And additionally that it can be done in an elegant and easy way. However if you are looking for another more complete, yet simple example of Groovy extension module I have created and made one available at GitHub. It is Gradle-based Groovy extension module that adds some missing random functionality to GDK.
And don't ever forget - the best place to look for Groovy extension modules is Groovy GitHub ;)