Thursday, April 28, 2011

Hot Deploy OSGi CLI Commands in Apache Karaf with Eclipse PDE

Apache Felix GoGo is a really cool command line interface (CLI, aka shell aka console) framework that runs in an OSGi runtime.
Apache Karaf (based on Apache Felix OSGi runtime) just so happens to include Felix GoGo built-in, and the console is very extensible too, making it easy to add more commands at your will.

Karaf / Felix GoGo Features

A very nice feature of Apache Karaf is it has a built-in SSH server, so you can literally and practically just ssh to the Karaf server :

ceefour@annafi:/opt/apache-karaf-2.2.0$ ssh -p 8102 karaf@localhost
karaf@localhost's password: 
        __ __                  ____      
       / //_/____ __________ _/ __/      
      / ,<  / __ `/ ___/ __ `/ /_        
     / /| |/ /_/ / /  / /_/ / __/        
    /_/ |_|\__,_/_/   \__,_/_/         

  Apache Karaf (2.2.0)

Hit '<tab>' for a list of available commands
and '[cmd] --help' for help on a specific command.
Hit '<ctrl-d>' or 'osgi:shutdown' to shutdown Karaf.

karaf@bipposhell> erp:hello
Hello Ibrahim!

Default credentials is user=karaf, password=karaf .
And even (this I just found out!) the amazing thing is you can run a command directly from ssh :

$ ssh -p 8102 karaf@localhost erp:hello
karaf@localhost's password: 
Hello Ibrahim!

Isn't it amazing? What's more, the Karaf/Felix GoGo command line also supports POSIX/GNU-style option arguments, Tab completion, and UNIX-like pipes! (yes, pipes, where you can do 'grep' and stuff)

The other, and paramountly useful feature, is the ability to hot deploy exploded OSGi bundles! Now hot deploy in itself is really useful, the ability to deploy exploded bundles is even more fantastic. We'll see about that soon.

What About Virgo?

Some of you may (almost) cry that I didn't mention Eclipse Virgo Kernel. Which is, of course, a direct competitor to Apache Karaf.
I haven't used Virgo yet (but I should try it one day), so because I have used Karaf in the past so for now I'm using Karaf, and I know it has a cool built-in CLI ;-)
I think the steps below can be adapted to Virgo with little (or not so little?) work. Let me know if you have tips, ideas, etc. :-) I will appreciate it a lot.

Developing CLI on Felix GoGo

For my next Bippo Shell project I plan to use Felix GoGo as the CLI framework. I'll share my first steps experience on developing CLI Commands with Karaf and Felix GoGo with you.
To get started, I first download Apache Karaf OSGi runtime.

Felix GoGo looks for command services exposed by other OSGi bundles. To develop this OSGi bundle, my IDE of choice happens to be... (surprise!) Eclipse IDE. ;-)
Now there are several approaches to develop OSGi bundles in Eclipse IDE, but the path I want to take right now is using Eclipse PDE (Plug-in Development Environment). At least for developing the bundle (i.e. Eclipse plugin) itself, not for running/launching the runtime (yet...)

I assume you are already somewhat familiar with Eclipse IDE and Eclipse PDE. If not, it's not too late to reach enlightenment ;-) get Eclipse Rich Client Platform (2nd Edition) book.

Creating the Target Platform

The first thing I need to do before developing anything (for you guys familiar with Eclipse RCP would already know this: any Eclipse-based project for that matter) is prepare the target platform.
The target platform contains all the OSGi bundles (Eclipse plugins) that are already in the target runtime environment. In this case: Felix Karaf.

So, copy these files from Apache Karaf distribution (hint: look for lib/ and system/ folders) to another folder. These little commands may help you:

mkdir -vp ~/felix-karaf-target-platform/
cp -v lib/karaf-jaas-boot.jar ~/felix-karaf-target-platform
find system -iname '*.jar' -exec cp -v '{}' ~/felix-karaf-target-platform \;

Then I created a target platform in Eclipse PDE, and add content based on the directory that contains the Karaf JARs, then activate the target platform.

Creating the Eclipse Plugin Project

Although Karaf only needs an OSGi bundle, I decided to create an Eclipse plugin project. Why not, since an Eclipse plugin is always an OSGi bundle anyway! And it might be useful if I want to use my plugin projects in an Eclipse RCP project, for example.

First I create an Eclipse plugin project, then set the Import-Package in META-INF/MANIFEST.MF to:

Import-Package: org.apache.felix.gogo.commands;version="0.6.1",
 org.apache.karaf.shell.console;version="2.2.0",
 org.osgi.framework;version="1.3.0"

This allows me to refer to the Felix GoGo API classes and interfaces.

Writing the Command Implementation

Thanks to annotations in similar spirit of JAX-RS, writing the CLI command implementation class is simple:

package id.co.bippo.shell;

import org.apache.felix.gogo.commands.Command;
import org.apache.karaf.shell.console.OsgiCommandSupport;

@Command(scope="erp", name="hello", description="Says hello")
public class ErpCommand extends OsgiCommandSupport {

/* (non-Javadoc)
* @see org.apache.karaf.shell.console.AbstractAction#doExecute()
*/
@Override
protected Object doExecute() throws Exception {
System.out.println("Hello Ibrahim!");
return null;
}

}

I think the annotations and what this class does is pretty much self-explanatory.

Registering the Command Service using OSGi Blueprint

To register the command service implementation, OSGi Blueprint is used (although not mandatory, you can use manual OSGi wiring if you want, but why do it the hard way?)
Apache Karaf uses Apache Aries Blueprint as the OSGi Blueprint implementation, but I believe it should work with Eclipse Gemini Blueprint as well.

Put this in OSGI-INF/blueprint/myshell.xml (actual filename doesn't matter):

    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.0.0">
        <command name="erp/hello">
            <action class="id.co.bippo.shell.ErpCommand"/>
        </command>
    </command-bundle>

</blueprint>

This registers the command that can be executed by typing: erp:hello

I wondered why the command name is repeated again here. It turns out that the Blueprint declaration actually registers the command under the specified name, and the class annotations are only used for usage help, i.e. when typing: erp:hello --help

Deploying the Command Bundle/Plugin

I'm not yet using fancy launcher PDE feature here, just old-school style:
  1. Export the plugin as a binary JAR bundle to a folder
  2. Copy the plugin JAR to Karaf's deploy/ folder
Karaf will detect it and register the command:

karaf@bipposhell> la
START LEVEL 100 , List Threshold: 0
   ID   State         Blueprint      Level  Name
[   0] [Active     ] [            ] [    0] System Bundle (3.0.8)
[   1] [Active     ] [            ] [    5] OPS4J Pax Url - wrap: (1.2.5)
...
[  40] [Active     ] [Created     ] [   30] Apache Karaf :: Deployer :: Blueprint (2.2.0)
[  41] [Active     ] [Created     ] [   30] Apache Karaf :: Shell :: ConfigAdmin Commands (2.2.0)
[  42] [Active     ] [Created     ] [   60] Bippo Shell (1.0.0.qualifier)

karaf@bipposhell> erp:hello
Hello Ibrahim!

karaf@bipposhell> erp:hello --help
DESCRIPTION
        erp:hello

        Says hello

SYNTAX
        erp:hello [options]

OPTIONS
        --help
                Display this help message

Hot Deploying Eclipse Plugins

Karaf has very useful ability to do hot deploy of OSGi bundles during development. (actually, being OSGi, it can perform hot deployment anytime, not just "during development")
osgi:install and dev:watch Karaf commands will help you on this.

But I prefer the low-tech solution:

ceefour@annafi:~/project/bipponext/workspace/id.co.bippo.shell$ ln -s $PWD/bin /opt/apache-karaf-2.2.0/instances/bipposhell/deploy/id.co.bippo.shell

This creates a symlink to the ${project_loc}/bin folder inside the Karaf's deploy/ folder.
You may want to also copy the META-INF/MANIFEST.MF file. If not, it will still work in most cases, because Karaf is very smart to wrap non-OSGi "bundles" to be OSGi-friendly.
This magic works because Karaf supports "exploded bundles", i.e. OSGi bundles not packaged in a JAR, but exploded as a directory structure.

karaf@bipposhell> erp:hello
Hello Ibrahim!
(......edit the source in Eclipse, then Save...and......)
karaf@bipposhell> erp:hello
Hello Yudha!

No need to restart, nothing! You don't even need to build/package the JAR!
Pretty nifty, eh? :-)

Note: While doing this, I uncovered bug KARAF-602.
Karaf Tip: If something goes wrong, tail:log, log:set, and dev:show-tree Karaf commands are your friends. :-)

What's Next ?

As demonstrated, OSGi development can be easy and in some cases even easier than "plain" Java.

Actually I've managed to do a headless build using Eclipse Tycho (formerly Sonatype Tycho Maven plugin), so I hope to write about this in a later post.

To learn more about Eclipse plugins, I recommend the Eclipse Rich Client Platform (2nd Edition) book.
For a thorough explanation in developing OSGi applications, check out the recently released OSGi in Action, Creating Modular Applications in Java.