Extending the console
This chapter will guide you through the steps needed to extend the console and create a new shell.
We will leverage Maven, Blueprint and OSGi, so you will need some knowledge of those products.
You may also find some information about the console at http://felix.apache.org/site/rfc-147-overview.html.
Create the project using maven
We first need to create a project using Maven. Let's leverage Maven archetypes for that.
Command line
Using the command line, we can create our project:
mvn archetype:create \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DgroupId=org.apache.karaf.shell.samples \ -DartifactId=shell-sample-commands \ -Dversion=1.0-SNAPSHOT
This generate the main pom.xml and some additional packages.
Interactive shell
You can also use the interactive mode for creating the skeleton project:
mvn archetype:generate
Use the following values when prompted:
Choose a number: (1/2/3/4/5/6/7/.../32/33/34/35/36) 15: : 15 Define value for groupId: : org.apache.karaf.shell.samples Define value for artifactId: : shell-sample-commands Define value for version: 1.0-SNAPSHOT: : Define value for package: : org.apache.karaf.shell.samples
Manual creation
Alternatively, you can simply create the directory shell-sample-commands and create the pom.xml file inside it:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.karaf.shell.samples</groupId>
<artifactId>shell-sample-commands<artifactId>
<packaging>bundle</packaging>
<version>1.0-SNAPSHOT</version>
<name>shell-sample-commmands</name>
<dependencies>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.console</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</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>
</plugins>
</build>
</project>
Configuring for Java 5
We are using annotations to define commands, so we need to ensure Maven will actually use JDK 1.5 to compile the jar.
Just add the following snippet after the dependencies section.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<target>1.5</target>
<source>1.5</source>
</configuration>
</plugin>
</plugins>
</build>
Loading the project in your IDE
We can use Maven to generate the needed files for your IDE:
Inside the project, run the following command
mvn eclipse:eclipse
or
mvn idea:idea
The project files for your IDE should now be created. Just open the IDE and load the project.
Creating a basic command class
We can now create the command class HelloShellCommand.java
package org.apache.karaf.shell.samples;
import org.apache.felix.gogo.commands.Command;
import org.apache.karaf.shell.console.OsgiCommandSupport;
@Command(scope = "test", name = "hello", description="Says hello")
public class HelloShellCommand extends OsgiCommandSupport {
@Override
protected Object doExecute() throws Exception {
System.out.println("Executing Hello command");
return null;
}
}
Creating the associated blueprint configuration files
The blueprint configuration file will be used to create the command and register it in the OSGi registry, which is the way to make the command available to Karaf console. This blueprint file must be located in the OSGI-INF/blueprint/ directory inside the bundle.
If you don't have the src/main/resources directory yet, create it.
mkdir src/main/resources
Then, re-generate the IDE project files and reload it so that this folder is now recognized as a source folder.
Inside this directory, create the OSGI-INF/blueprint/ directory and put the following file inside (the name of this file has no impact at all):
<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="test/hello">
<action class="org.apache.karaf.shell.samples.HelloShellCommand"/>
</command>
</command-bundle>
</blueprint>
Compiling the jar
Let's try to build the jar. Remove the test classes and sample classes if you used the artifact, then from the command line, run:
mvn install
The end of the maven output should look like:
[INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------
Test in Karaf
Launch a Karaf instance and run the following command to install the newly created bundle:
karaf@root> osgi:install -s mvn:org.apache.karaf.shell.samples/shell-sample-commands/1.0-SNAPSHOT
Let's try running the command:
karaf@root> test:hello Executing Hello command
Command completer
A completer allows you to automatically complete a command argument using <tab>. A completer is simply a bean which is injected to a command.
Of course to be able to complete it, the command should require an argument.
Command argument
We add an argument to the HelloCommand:
package org.apache.karaf.shell.samples; import org.apache.felix.gogo.commands.Command; import org.apache.felix.gogo.commands.Argument; import org.apache.karaf.shell.console.OsgiCommandSupport; @Command(scope = "test", name = "hello", description="Says hello") public class HelloShellCommand 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 Hello command"); return null; } }
The Blueprint configuration file is the same as previously.
Completer bean
A completer is a bean which implements the Completer interface:
package org.apache.karaf.shell.samples; import org.apache.karaf.shell.console.completer.StringsCompleter; import org.apache.karaf.shell.console.Completer; /** * <p> * A very simple completer. * </p> */ public class SimpleCompleter implements Completer { /** * @param buffer the beginning string typed by the user * @param cursor 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); } }
Blueprint configuration file
Using Blueprint, you can "inject" the completer linked to your command. The same completer could be used for several commands and a command can have several completers:
<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="test/hello"> <action class="org.apache.karaf.shell.samples.HelloShellCommand"/> <completers> <ref component-id="simpleCompleter"/> <null/> </completers> </command> </command-bundle> <bean id="simpleCompleter" class="org.apache.karaf.shell.samples.SimpleCompleter"/> </blueprint>
Test in Karaf
Launch a Karaf instance and run the following command to install the newly created bundle:
karaf@root> osgi:install -s mvn:org.apache.karaf.shell.samples/shell-sample-commands/1.0-SNAPSHOT
Let's try running the command:
karaf@root> test:hello <tab> one two three