Get some Groov(y) to your OSGi-Bundles

Currently I’m fooling around with Groovy a little and since I’ve got some OSGi-Applications I was wandering if I could use Groovy to write some OSGi-Services. Here are my thoughts:

  • Start of with getting the Groovy-Plugin for your Eclipse-IDE: http://dist.codehaus.org/groovy/distributions/update/
  • Create Groovy-library-bundle: Download Groovy. Create a bundle: File | New | Project | Plug-in Development | Plug-in from existing JAR archives and select the Jar: groovy-all-1.0.jar from the embeddable directory from your Groovy distribution. A good name for this bundle would probably be org.codehaus.groovy.
  • Next create your bundle that leverages this Groovy bundle: Create a new OSGi-Bundle: File | New | Project | Plug-in Project, select that it’s supposed to be targeted on an OSGi-framework and give it a nice name (com.luebken.groovyservice). In this new Bundle add the dependency to our groovy-library-bundle in the manifest.mf:
    Require-Bundle: org.codehaus.groovy
  • Now right-click on the new project and select Groovy | Add Groovy-Nature. Since we import the Groovy classes from our library-bundle remove newly imported library from the Java-Build-Path: Project | Properties | Java Build-Path | Libraries (commons-io, commons-lang, groovy-all). Make sure that the Groovy-Scripts are compiled to some folder like “bin-groovy” (Project | Properties) and that the Groovy-compiler is enabled (Window Preferences).
  • Lets create our GroovyService (File | New | Groovy | Groovy Class) and some cool functionality like:
    class GroovyService {
    void sayHello(){
    println “A groovy hello to the world”
    }
    }
  • Next use this service in the start-method of the activator:
    public class Activator implements BundleActivator {
    public void start(BundleContext context) throws Exception {
    new GroovyService().sayHello();
    }
  • The last thing you have to do is adding bin-groovy/ to the classpath in the Manifest.mf
    Bundle-ClassPath: bin-groovy/,
    .
  • Now you can start the OSGi-Framewirk with the two bundles and you should see:
    osgi> A groovy hello to the world.
  • If you don’t want to code yourself see: a-groovyservice-part1.zip

If you know OSGi, than you are waiting for the real OSGi-Service. To all the others: OSGi has its own service mechanism to register and find services. But this shouldn’t be a problem:

  • First create a second bundle that uses the service like: com.luebken.groovyservice.client. Than export the package from the GroovyService in the original bundle and import it in the new client-bundle.
  • Now all you have to do is register the service in the activator class (com.luebken.groovyservice) :
    public void start(BundleContext context) throws Exception {
    groovyService = new GroovyService();
    context.registerService(GroovyService.class.getName(), groovyService, null);
    }
  • and get the service (com.luebken.groovyservice.client):
    public void start(BundleContext context) throws Exception {
    serviceReference = context.getServiceReference(GroovyService.class.getName());
    GroovyService service = (GroovyService) context.getService(serviceReference);
    service.sayHello();
    }
  • Again if you don’t want to code get the sources: a-groovyservice-part2.zip

So will we code our OSGi services in Groovy? What do you think?

screenshot.PNG
Update 27.01.:
As John Wilson pointed out there is no reason why the Activator shouldn’t be a Groovy-class. See the following source, where the Activator in the client is a real Groovy Class: a-groovyservice-part3.zip

7 thoughts on “Get some Groov(y) to your OSGi-Bundles

  1. Pretty cool!

    How about making all the code Groovy though?

    package com.luebken.groovyservice.client

    import org.osgi.framework.BundleActivator
    import org.osgi.framework.BundleContex
    import org.osgi.framework.ServiceReference

    import com.luebken.groovyservice.GroovyService

    public class Activator implements BundleActivator {

    private ServiceReference serviceReference

    public void start(BundleContext context) {
    serviceReference = context.serviceReference(GroovyService.name)
    def service = context.getService(serviceReference)
    service.sayHello()
    }

    public void stop(BundleContext context) {
    context.ungetService(serviceReference)
    }
    }

  2. I love it. This is an area to which I have devoted quite a bit of thought to. There are really only three minor issues I see in this scenario.

    1. Unfortunately the Groovy Eclipse plugin relies on the groovy embedded library that comes with the plugin, so even though at runtime your org.codehaus.groovy plugin (er bundle) is what is used by the OSGi container, your compiled bytecode is entirely dependent on the version contained in the plugin. So to upgrade or even use a previous version would require changing the plugin.

    2. Since Eclipse plugins are bundles, it can be very tempting to use the export feature to build the jars. This for the most part is not a huge problem, but in using the headless eclipse build, Eclipse wont know to use the groovyc ant task to compile the groovy code. This is something to be aware of, of course I loved using Groovy to perform my build of my OSGi bundles from with in the IDE seperate from the Eclipse export function. This is also something I have done in groovy using a Groovy Monkey script (I like being able to trigger it from a menu command).

    3. There can be trouble ( this is a known Groovy Eclipse issue/bug ) if you attempt to use both Groovy and Java within the same project. One way dependencies should be for the most part pretty safe, namely from Java to Groovy and vice versa. However, since the Groovy compiler is not hooked into the Eclipse compiler directly, be wary of writing Groovy code that depends on java code that depends on groovy code from within the same project. It could work out, particulary given Groovy’s dynamic nature, but it could leave one a bit perplexed especially after a full rebuild.

    Still it would be awesome to write bundles more with Groovy, maybe even leveraging some of Spring’s abilities (Spring-OSGi) to make writing bundles with groovy almost entirely an exercise in using POJO’s, kinda like what Grails is doing.

  3. >James E. Ervin wrote:
    Wow. Now I have real Groovy-Plugin experts on board. ;-)

    >1. Unfortunately the Groovy Eclipse plugin relies …

    Well there is a bug filled http://jira.codehaus.org/browse/GROOVY-690. So this might be fixed soon.

    >2. Since Eclipse plugins are bundles, it can be …

    Well I haven’t dicussed the building/exporting of the bundles and I am not familiar with the headless build. As far as I have thought through the build-process it should work like this:
    1. Let the Groovy-Plugin compile the Groovy classes to bin-groovy.
    2. Add bin-groovy to the bundles classpath in the manifest.
    3. Add bin-groovy to “bin.includes” in the build.properties.
    What is the problem with this approach?

    >3. There can be trouble ( this is a known Groovy …

    I haven’t found the bug entry. Do you have a pointer?

    My greatest concern right now is the typical OSGi-classloader issue. Is Groovy safe about this? Where does Groovy use specials classloaders, and how?

  4. >>James E. Ervin wrote:
    >Wow. Now I have real Groovy-Plugin experts on board.

    Flattery will get you everywhere :)

    >>1. Unfortunately the Groovy Eclipse plugin relies …

    >Well there is a bug filled http://jira.codehaus.org/browse/GROOVY-690. So this might be fixed soon.

    I know, in fact I played with trying to fix it a while back… There should be a refactoring of the plugin to at least separate out the groovy library into its own plugin, but I would love to add the ability of the plugin to be able to handle different versions of the GDK just like the JDT handles different JRE/JDKs.

    I just made the above point to tell everyone and that it is an issue to be aware of. This will become more apparent when you have apps that are Groovy 1.0 and Groovy 2.0 has incompatible changes, but you would still love to do new work in it.

    >>2. Since Eclipse plugins are bundles, it can be …

    >Well I haven’t dicussed the building/exporting of the bundles and I am not familiar with the headless build. As far as I have thought through the build-process it should work like this:
    >1. Let the Groovy-Plugin compile the Groovy classes to bin-groovy.
    >2. Add bin-groovy to the bundles classpath in the manifest.
    >3. Add bin-groovy to “bin.includes” in the build.properties.
    >What is the problem with this approach?

    Nothing per se, just that the classes must be compiled before using the export function and the headless build wont work since the PDE doesn’t know about the groovyc ant task. You could create a build.xml and manually add it in so that you can build your projects headless. Once again just another small point to keep in mind.

    >>3. There can be trouble ( this is a known Groovy …

    >I haven’t found the bug entry. Do you have a pointer?

    >My greatest concern right now is the typical OSGi-classloader issue. Is Groovy safe about this? Where does Groovy use specials classloaders, and how?

    There is not a bug entry, it is not a trivial issue. Perhaps someone with ecj (eclipse compiler) experience could help?

    I don’t see why there should be any issues with the classloader. When groovy compiles to bytecode it becomes Java bytecode and so it would behave, when deployed to a bundle and executed in an OSGi container, in just the exact same manner as if it were written in Java.

    Ah I see understand your question, but the Groovy class loader would be a class loader under the bundle’s classloader and therefore would work. I did have an issue when I was developing Groovy Monkey for the first time when I was using Groovy across bundles. In one bundle I had groovy code that relied on the groovy libraries that were included with that bundle. That groovy code invoked groovy code that was in another bundle that had its own copies of groovy libraries. In running that code the Groovy runtime did complain. If you export your groovy libraries from one library bundle for everyone, then I do not believe it should break. Also, I believe that it should have been repaired for Groovy 1.0, but I haven’t confirmed it.

    How is that for a short answer eh?

  5. Pingback: OSGi: Libraries in Bundles konvertieren at blog.gauner.org

  6. Hi,

    I have a strange problem when using Groovy under Equinox. Add runtime I add dynamic property to a Groovy class using ExpandoMetaClass, under Eclipse’s JUnit it works as expected, I mean the new property is recognized, but under JUnit Plug-in Test the new method is not recognized and MissingPropertyException keeps getting thrown. Pleaes see the complete story here http://www.nabble.com/Method-created-via-ExpandoMetaClass-is-not-recognized-td19108704.html

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>