Building OSGi Bundles with Scala and Gradle

There already some good blog posts about how to build OSGi bundles in Scala, among others “An OSGi Bundle… built in Scala” of Neil Bartlett and “OSGi, Maven and Scala” of Gavin Bong using pax-construct. Here is another alternative using Gradle. Gradle is an open-source build system providing the expressiveness of a Groovy based DSL together with build-by-convention support for the major build scenarios in the Java/Groovy world. Above that there is even support for Scala.

If you want to follow the example you need:
gradle 0.8
scala 2.7.7
apache felix framework 2.0.1 (or your favourite OSGi container)

Instead of a HelloWorld I’ll take Neill’s BundleActivator example that prints out a list of currently installed bundles when started.

package com.jayway.osgi.hello

import org.osgi.framework._

class Activator extends BundleActivator {

    def start( context: BundleContext ) {
          var bundleNames = context.getBundles()
                   .map   (b => b.getSymbolicName())
                   .filter(b => b != context.getBundle())
          println("Installed bundles: " + bundleNames.toString())
     }

     def stop( context: BundleContext )  {
     }
 }

Gradle comes with both Scala and OSGi plugins that make it quite easy to build the bundle. The Scala plugin assumes the same standard project layout as used in Maven, i.e java production code will reside in the ‘src/main/java’, scala production code in the ‘src/main/scala’ folder. So I put the Activator class in ‘src/main/scala’ and add the following build.gradle file in my project folder:

group = 'com.jayway'
version = '1.0.0'

usePlugin 'scala'
usePlugin 'osgi'

repositories {
  mavenCentral()  // http://repo1.maven.org/maven2/
  mavenRepo(urls: 'http://www.ibiblio.org/maven2/')
  mavenRepo(urls: 'http://scala-tools.org/repo-releases/')
}

dependencies {
    // Libraries needed to run the scala tools
    scalaTools 'org.scala-lang:scala-compiler:2.7.7'
    scalaTools 'org.scala-lang:scala-library:2.7.7'

    compile 'org.scala-lang:scala-library:2.7.7'
    // osgi framework
    compile 'org.apache.felix:org.apache.felix.framework:2.0.1'
}

configure(jar.osgi) {
    // generate the bundle manifest
    version = '1.0.0'
    name = 'scala osgi bundle built with gradle'
    symbolicName = 'com.jayway.osgi.hello'
    instruction 'Require-Bundle', 'scala.library'
    instruction 'Bundle-Activator', 'com.jayway.osgi.hello.Activator'
    instruction 'Import-Package', 'org.osgi.framework'
    instruction 'Export-Package', 'com.jayway.osgi.hello'
    instruction 'Bundle-Vendor', 'JAYWAY AB'
}

The Gradle OSGi plugin makes use of the BND tool to generate the bundle manifest. I added the scala library OSGi bundle as required and imported the package org.osgi.framework. Now I’m good to go and call gradle from the commandline:

C:ws-scala-testcom.jayway.osgi.hello>gradle build

Running on apache felix 2.0.1

Now start the osgi container and install the bundles starting with the scala library as OSGi bundle:

C:felix-framework-2.0.1>java -jar bin/felix.jar

Welcome to Felix
================

->install http://www.scala-lang.org/downloads/distrib/files/scala.library_2.7.7.final.jar
Bundle ID: 24

-> install file:C:ws-scala-testcom.jayway.osgi.hellobuildlibscom.jayway.osgi.hello-1.0.0.jar
Bundle ID: 25

-> ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (2.0.1)
[   1] [Active     ] [    1] Apache Felix Bundle Repository (1.4.2)
[   2] [Active     ] [    1] Apache Felix Shell Service (1.4.1)
[   3] [Active     ] [    1] Apache Felix Shell TUI (1.4.1)
[  24] [Resolved   ] [    1] Scala Library (2.7.7.final)
[  25] [Installed  ] [    1] scala osgi bundle built with gradle (1.0.0)

-> start 25
Installed bundles: Array(org.apache.felix.framework, org.apache.felix.bundlerepository, org.apache.felix.shell, org.apa
he.felix.shell.tui, scala.library, com.jayway.osgi.hello)

Running on eclipse equinox 3.5.1

If you want to use equinox instead of felix you could change the dependencies like this:

compile 'org.eclipse:osgi:3.5.1-R35x_v20090827'

I had some problems to find a maven repository containing the current equinox osgi bundles (3.5.1). If you are running maven you can publish the bundles from your eclipse installation to your local maven repository:

mvn eclipse:to-maven -DeclipseDir="[eclipse-installation-dir]"

Finally add your local repository to your build.gradle:

mavenRepo(urls: 'file://[path-to-user-home]/.m2/repository/')

This Post Has 7 Comments

  1. The plugin doesn’t package 3rd party classes into the bundle.jar…like the maven plugin does. I’m new to gradle, so how do I do this? Tried the following:
    instruction ‘Import-Package’, ‘*’
    instruction ‘Export-Package’, ‘*’
    But I still get unresolved dependencies because the bundle jar file doesn’t have the classes.
    Thanks!
    Erik

    1. #Erik:
      I’m new to Gradle myself, and not used to all features yet.

      First of all you should consider getting the 3rd party library as OSGi bundle and add it as required or import the packages. Have a look at Springsource Enterprise bundle repository (http://www.springsource.com/repository/app/) or eclipse orbit (http://www.eclipse.org/orbit/).

      If you still want to embed the 3rd party library you need to add the Bundle-ClassPath header to your manifest:

      instruction ‘Bundle-ClassPath’, ‘third-party.jar’

      But this will only tell OSGi to consult the bundle classpath when looking for classes. You still have to tell gradle that you want to embed the 3rd party jar. I think it should be possible to to this through configuring the jar task – but I haven’t done that myself. If that won’t work you still could add the 3rd party jar as resource – which feels a bit ‘hacky’:

      sourceSets {
      main {
      scala {
      srcDir ‘src/main/scala’
      }
      resources {
      srcDir ‘lib’
      }
      }
      }

      Assuming your 3rd party lib resides in the ‘lib’ folder.
      I hope this was helpful.

      /Mike

  2. Pingback: URL

Leave a Reply

Close Menu