2 March 2017

Twelvemonkeys on OSGi

Using Java for working with images has never been first choice, especially if the requirement for advanced computer vision functionalities needs to be met. For these cases please study OpenCV and JavaCV.
For the more daily use cases there is of course the standard Java ImageIO, providing limited image format support. My project required extensive MTIFF with CCITT compression capabilities and the good old JAI-ImageIO seemed to be a good candidate. But MTIFF support requires some extra steps to be taken, and the 10 jear old code base is missing active development. I wanted something fresh and after some research i found myself staring at the github page of twelvemonkeys ImageIO.
TwelveMonkeys is a pure Java based collection of plugins and extensions for Java's ImageIO with few optional dependencies, and under active development. It provides all i need, with a flick of the service provider switch. But lets not make this too easy now. The library is not bundled like JAI, and since i am a heavy OSGi user i want to put it on Karaf.
The first thing to do is get the jars in a bundle, ready for Karaf deployment. The Apache-felix-maven-bundle-plugin tool brings the solution in the form of embedding dependencies, putting the twelvemonkeys jars inside of a single bundle. The registration of these plugins with ImageIO gets handled by the classloader through the javax.imageio.spi.ServiceRegistry. This is a type of Java service loader responseble for finding ImageIO extensions in the classpath under the META-INF/services folder, bringing us straight to the core of our problem. Every OSGi bundle has its own classloader, meaning any image plugin loaded in one bundle is not visible to ImageIO in others. This is also true for every other library on OSGi using the java service loader mechanism.
The OSGi Enterprise R5 ServiceLoader Mediator specs discribe a standard solution for this kind of integration problem, and the reference implementation is Apache Aries Spi Fly. Under the hood it uses some fancy runtime bytecode weaving, resulting in a short classloader switch as soon as the ImageIO Serviceregistry in a bundle starts to look for plugins on the classpath, loading the plugins from the bundle containing the twelvemonkeys embedded dependencies.
Getting the MTIFF utilities in the contrib package functional under OSGi is as simple as adding a  blueprint or declarative service to the bundle containing the twelvemonkeys jars.

Sample project on github.

Recommended reading:

OSGi Alliance javautilserviceloader in OSGi

4 comments:

  1. Hey,
    it is an interesting post. My goal is to create an osgi bundle from twelvemonkeys as you do, but not for karaf. I tried to clone your project, edit the export-package on the publisher project (so that all twelvemonkeys packages are exported) and build it with maven.
    after that i added the new bundle to my project, but no new reader and writer are registered within ImageIO.

    do you have an idea?

    regards
    rome

    ReplyDelete
  2. Hello Rome,

    there is no need to export the twelvemonkeys because they are 'bundle private'. Exposing the extensions is handled by OSGi, in my case through the Aries Spi Fly implementation (based on the OSGi Spec). You need this, or a equivalent implementation in your OSGi environment, and it has to be up and running before any other bundles call the ImageIO registry. To get a hang of the mechanics, try to debug my project on Karaf.

    Hope this helps,

    Maurice

    ReplyDelete
  3. Hi,
    I found you blog post a couple of weeks ago and used your sample project as a guide to getting twelvemonkeys working in our OSGi framework (Karaf within JBoss Fuse with blueprint). I have found that the twelvemonkeys plug-in is not being recognised/registered unless I call within the bundle activator of the consuming bundle:

    IIORegistry registry = IIORegistry.getDefaultInstance(); registry.registerServiceProviders(ServiceRegistry.lookupProviders(ImageReaderSpi.class)); registry.registerServiceProviders(ServiceRegistry.lookupProviders(ImageWriterSpi.class));

    I thought it was sufficient to have the following instruction for the maven-bundle-plugin in the consuming bundle's pom:

    javax.imageio.spi.ServiceRegistry#lookupProviders

    Have I missed something? I am not so familiar with the intracies of OSGi and normally only have to configure straight-forward inter-bundle dependencies.

    ReplyDelete
    Replies
    1. Hi oz_kath, be sure that your provider bundle including SPI-FLY are active before the consuming bundle. Take a look at the Aries SPI-FLY specs for reference: http://aries.apache.org/modules/spi-fly.html

      Delete