Thursday, November 3, 2011

Creating your own Apache Karaf console command.

Have you ever wanted to create your own Apache Karaf console command but didn't know where to start? In this post I aim to show you how the critical code snippets required to create your own Apache Karaf console commands, complete with completer. Please note that the process for creating your own console command is well documented in the Apache Karaf documentation, however its nice to have a concrete example on hand.

The creation of a custom command can be boiled down to drafting a boiler plate pom file, extending OsgiCommandSupport, writing a command completer, and finally wiring it all together via blueprint. Don't worry about directory structure, or other boiler plate bits of code for now, a full source code demo will be included in Karaf starting on version 2.2.5.

The Pom File:

The critical bits you'll encounter in the pom file for making your own command will be the initial setup declarations:

  <groupId>org.apache.karaf.demos.command</groupId>
  <artifactId>shell-sample-commands</artifactId>
  <packaging>bundle</packaging>
  <version>2.2.5-SNAPSHOT</version>
  <name>your-commmand</name>

Adding in the dependency on the Karaf shell:


  <dependency>
    <groupId>org.apache.karaf.shell</groupId>
    <artifactId>org.apache.karaf.shell.console</artifactId>
  </dependency>

And finally configuring the maven bundle plugin to package the command:

  <plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <version>2.3.4</version>
      <configuration>
         <instructions>
            <Import-Package>
              org.apache.felix.service.command,
              org.apache.felix.gogo.commands,
              org.apache.karaf.shell.console,
              *
            </Import-Package>
         </instructions>
      </configuration>
  </plugin>

Extending OsgiCommandSupport:

The actual custom command logic is implemented in a class you write that extends OsgiCommandSupport. The annotations for 'command' and 'argument' is where you'll immediately need to pay attention. In the command annotation you setup your command scope and name (each scope can have several names associated via separate commands). In the argument annotation you describe the arguments that the command will expect. The doExecute() method is where you'll perform the action for the command, add any custom code you want to have performed here.

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


    @Argument(index = 0, name = "arg", 
              description = "The command argument", 
              required = false, multiValued = false)
    String arg = null;


    @Override
    protected Object doExecute() throws Exception {
        System.out.println("Executing your Command Demo");
        return null;
    }
}

Command Completer:

Although not strictly required, the command completer is generally a good idea to include. The completers' job is to allow the user to tab complete the command, possibly showing input possibilities.

public class YourCompleter implements Completer {
 /**
* @param buffer it's the beginning string typed by the user
* @param cursor it's the position of the cursor
* @param candidates the list of completions proposed to the user
*/
 public int complete(String buffer, int cursor, List candidates) {
  StringsCompleter delegate = new StringsCompleter();
  delegate.getStrings().add("one");
  delegate.getStrings().add("two");
  delegate.getStrings().add("three");
  return delegate.complete(buffer, cursor, candidates);
 }
}

Wiring it together with Blueprint:

Now to bring all these components together we use Blueprint. Blueprint is a dependency injection framework that we like to use with OSGi in Karaf. In short the below xml handles the instantiation of objects and wiring them together.

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.0.0">
        <command name="yourcommand/hello">
            <action class="org.apache.karaf.demos.command.YourCommand"/>
            <completers>
                <ref component-id="yourCompleter"/>
                <null/>
            </completers>
        </command>
    </command-bundle>
    <bean id="yourCompleter" class="org.apache.karaf.shell.samples.YourCompleter"/>
</blueprint>

Build and Deploy Time!

Now that we have composed the components of a custom command, lets build the code and test it out.

To build the command just invoke:

mvn install

This will build the command bundle and make it available in your local m2 repo.

To deploy the command bundle issue the following command in a running instance of Karaf:

karaf@root> osgi:install -s \ mvn:org.apache.karaf.demos/org.apache.karaf.demos.command/2.2.5-SNAPSHOT

After installing the bundle it will become available on the console command line. Your custom command will now act like the other commands already deployed inside of Karaf.

karaf@root> yourcommand:hello 
Executing your Command Demo
karaf@root>

This demo will start appearing in Apache Karaf 2.2.5, so don't worry about piecing together the boiler plate code. I hope you found this short tutorial useful.

3 comments:

TLCoder said...

Yay! Dyslexic porn file!

icbts said...

I told you that Apache development is exciting :)

Chintan said...

Hi,
A very nice blog.
I followed yours and was able to come up with one of my own CLIs.
How can we have a variable list of arguments for the CLI that we add.
Say, for my CLI, it can have 3/4/5 arguements (varaible length of arguments).
Any help will be greatly appreciated.