Showing posts with label OSGi. Show all posts
Showing posts with label OSGi. Show all posts

Sunday, 11 September 2011

OSGi, Scala, Maven and Netbeans

So, I finally got around to trying the combo in the title out. Was it hard? Did it require alot of work? Does it slice bread? No.

Actually, I had "allocated" a few hours to get this working but, to my surprise, found out that it requires less than half an our to get started. So, don't get discouraged by the number of steps needed!

First of all, here is what you will need:
  • Netbeans 7.0
  • The zipped scala-plugin for Netbeans found here
  • An OSGi container, like Apache Felix
  • The osgi-fied version of scala libraries found here
First, unzip the netbeans plugin and place them somewhere on your disk. Then start Netbeans and go to Tools->Plugins and choose the tab Downloaded. Click the button "Add Plugins..." and browse to where you just unziped. Select all the unziped files and install. These files aren't signed so Netbeans might ask you if you want to continue anyway. You want that.

Now we have our environment set up. That's actually the real beauty of this. No need to download scala, set environment variables or anything like that. Just, install plugin and we're ready to go. Next, create a new project in Netbeans and choose a maven project. Choose the standard Java Application option and click ok. See, we don't want a standard Java Application but I couldn't find a maven archetype for scala at the maven central repository so, this will do for now.

Browse to the pom.xml file in your newly created project and cut and paste the following xml over the current build tag. Note that you want to edit some of the rows, most notably the Private-Package and Bundle-Activator tags.


   
      
      org.apache.felix
      maven-bundle-plugin
      1.4.3
      true
      
         
            
            *
            org.acme.impl*
            ${project.artifactId}
            org.acme.impl.Main
         
      
   
   
      org.scala-tools
      maven-scala-plugin
      2.15.2
         
            
               process-resources
               
                  add-source
                  compile
               
            
            
               scala-test-compile
               process-test-resources
               
                  testCompile
               
            
         
         
            ${scala.version}
            true
            
               -g:vars
               -deprecation
               -dependencyfile
               ${project.build.directory}/.scala_dependencies
            
         
      
   


Still in the pom file, change

jar

to

bundle

Finally, make sure you have the dependencies set to (at least)


   org.osgi
   org.osgi.core
   4.0.0


   org.scala-lang
   scala-library
   2.9.0


Enough with the xml (and if you know your way around netbeans, some of the xml can be fixed from the GUI, such as dependencies). At this point you want to create a bundle activator. So, create a new scala class and name it anything you want (just make sure that the pom has the fully qualified class name in the Bundle-Activator tag). As you see in the pom above, I chose Main. Now, let that class extend BundleActivator (or implement if you're still caught up in Java-not-Scala lingu) and implement the start and stop methods. You'll end up with something similar to this:

package org.acme.impl

import org.osgi.framework.BundleActivator
import org.osgi.framework.BundleContext

class Main extends BundleActivator {
  def start(context : BundleContext) : Unit = {
    println("Hello, OSGi container")
  }
  
  def stop(context : BundleContext) : Unit = {
    println("Goodbye container")
  }
}

If your netbeans scala plugin was installed successfully, this should now be able to compile. Give it a shot!

Wow, lots of code and xml! But at least we now have our OSGI-bundle. It is written in "pure" scala (wich of course gets compiled into even more pure java byte code). Time then to deploy this into the felix OSGi container (or any other OSGi container). But wait! We still need those scala libraries, otherwise we will not be able to run our scala code! Fine. Remember the osgi-fied version of scala libraries? The link above takes you to a site where the Eclipse scala plugin resides. From there you should be able to download a zip-file containing (including a heap of other things) a file named org.scala-ide.scala.library_2.9.1.final.jar. Deploy that first, then your module (or the other way around, just make sure to deploy both) and start both of them. Done! Simple and sweet. At least simple as compared to what I had hoped for. Basically, this is exactly what I do for any OSGi-bundle (of course I have archetypes creating the pom-file), and nothing really out of the ordinary. That surprised me alot!

A final disclaimer though is that the osgi-fied scala libraries file seem to be a draft and it also includes some other libraries not in the official scala-library file. This, in my eyes, breaks modularity, but it seems that you could just bundle up the official scala-library file yourself. Also, the file contain sources, so it is a heckofalot bigger than necessary. So, remember to NOT Require-Bundle but rather Import-Package, and you're bundles should be fine!

For once, maven will help modularization of OSGi related code rather than the other way around, since your pom only states a dependency on scala-library, your code will not compile if you try to use things from the deployed version that is not in the official one.

Now, off to scala and felix!

Sunday, 19 December 2010

OSGi and service binding

If you, like me, are trying to "embed" some OSGi framework inside your own application, you might have encountered a few problems. One of the biggest hurdles when dealing with OSGi is the dynamism, listening to services and of course listing them. The OSGi community have a multitude of solutions to these problems such as ServiceTrackers, Service Activator Toolkit, iPOJO and of course Declarative Services.

All these have their respective pros and cons. Service tracking with only ServiceTrackers is not only hard (with more than a few services), it also requires alot of boilerplate code. First you need to list all the currently available services, and then you need to start a tracker to stay informed about new services being added, removed or modified. With only a few services, this will quickly build up and become a whole bunch of seemingly unnecessary classes, taking up a fair amount of lines.

As for the others, they are either somewhat big or they have performance impacts when the number of bundles and services rises. Declarative Services is a great tool and I use it alot in my bundles but... As I said, I've embedded OSGi (Felix) inside my own application which means that some (most) of my classes are not OSGi aware, meaning that they don't come from a bundle. I can't use DS to bind with these classes (not in an easy way at least).

So, what do we do? The good news is DynamicJava.org's ServiceBinding framework. Just put a jar on your classpath and use the (very trimmed down) binding framework as in

    OsgiServiceBinder serviceBinder = new OsgiServiceBinder(context);
    serviceBinder.bind(this, "addActionListeners",
        ServiceFilter.forInterface(ActionListener.class.getName()));

This will
  1. Search for all available services that has registered in to OSGi that they provide the service ActionListener. 
  2. Call addActionListeners with the services it found.
  3. Continue to call addActionListeners every time a service is added or removed.
Note that if addActionListeners is a method that takes an array of ActionListener as its argument, the OsgiServiceBinder will, on each call, give you all the registered services. If addActionListeners takes only a single ActionListener, OsgiServiceBinder will give you the one with the highest ranking. So, if you want to be notified when a service is unregistered, you will still need to do some "store previous value, compare with previous value". For simple service binding though, where you do not want to type in the 50 or so lines of code needed to work with a ServiceTracker - this is a great, simple API.

As a final comment: Do not use OSGi to register ActionListeners. At least, think hard before doing so. First of all, the framework will not care much for event dispatch thread rules and secondly, the service registry is a very hectic place. Don't make it more so with unnecessary service registrations.