Embedding Apache Cassandra – The technical aspect.

This post is an add-on to the post I just recently did at codecentric AG. The scope of this additional post is to narrow down on some of the technical aspects that needed to be done to have the showcase running inside Karaf 4.0.0.

But first let’s take another quick look at the showcase, we have the following modules in the sources.

  1. Apache Cassandra embedded runtime
  2. Admin commands for controlling the embedded Apache Cassandra service
  3. Apache Client bundle for Connecting and issuing CQL commands to any Apache Cassandra node.
  4. A Feature descriptor for easy installation of all other modules plus bundles needed to run a Cassandra client.
  5. Integration tests for automatic testing of the embedded Cassandra and shell commands.

Additionally to the sources of this showcase some enhancements where made to the Apache Karaf shell implementation. This is because per default the shell is supposed to look and behave like a standard Unix shell. This behavior needed to be disabled by the command, or better by the environment the shell is running in.
You’ll find this enhanced Apache Karaf in my CustomKaraf Github project. For running the showcase make sure you have this Karaf build first. Without it some of the features won’t work.

Embedding Cassandra

Embedding Cassandra didn’t turn out to be as easy as hoped. If you use the CassandraDeamon it will cause an System.exit() if can’t find the configuration needed. So in the beginning I was looking for a solution of preventing this, but in the end I just discarded this. Instead a custom simple cassandra.yaml is placed inside the bundle which is found by the CassandraDeamon and therefore, the System.exit() issue has been resolved. Though beware if using a custom configuration which isn’t accessible by the CassandraDeamon you might end up with a broken Karaf container as the Cassandra Embedded bundle tries to startup and will fail with System.exit().

The Cassandra-Embedded bundle just contains two custom Classes to start the Cassandra instance as Service, but it also embeds a bunch of Bundles to just start the CassandraDeamon. This Bundle itself is quite big, it takes about 38MB. On the other hand, it does start a Apache Cassandra node, so that should be ok.

Creating shell commands

Creating the shell commands with the new syntax, which has been introduced with Karaf 4 is very easy. Just create the class for the Command implement the Action interface and add some annotations. Done with creating a simple command like the ones used for administration of the embedded Cassandra as a service.

@Command(scope = "cassandra-admin", name = "isRunning", description = "Connect to cassandra server")
@Service
public class IsServiceRunning implements Action {

	@Reference
	CassandraService cassandraServer;

	@Override
	public Object execute() throws Exception {
		if (cassandraServer.isRunning())
			System.out.println("Embedded Cassandra is available.");
		else
			System.out.println("Embedded Cassandra is stoped.");
		return null;
	}

}

Commands using completion are as simple to create, see also my other blog post at codecentric.de (TODO)

Installation and usage of the embedded Cassandra including the administrative commands can be seen with this screencast:

Special handling of variable characters in Karaf

The standard Karaf shell is supposed to behave like a standard Unix shell, so you are actually able to do some scripting in it. This also means that a echo „FOO“ will result in FOO. This will give you the power to work with a Karaf shell like with a unix shell:

karaf@root()> echo "FOO"
FOO
karaf@root()> echo $0
null
karaf@root()> x = "FOO"
FOO
karaf@root()> echo $x
FOO
karaf@root()>

But this feature causes trouble in case you actually want to use a quotation mark, or a bracket for your command and/or your completion. So some enhancements needed to be done to the shell of Karaf.

Thanks to help of Guillaume Nodet, it didn’t take to long to figure this part out. First of all parts of the Gogo Shell, used by Karaf, needed to be patched. As Karaf uses and inlines the Gogo shell this had been an easier task. I just needed to change the Closure Class and place it in the corresponding shell-core bundle of Karaf. The key of disabling is to disable the evaluation of a token if it contains such characters.

        for (Token t : statement)
        {
            Object v = isExpansionEnabled() ? eval(t) : t.toString();

            if ((Type.EXECUTION == t.type) && (statement.size() == 1))
            {
                return v;
            }

There is a convenience method in the Closure Class to check wether a certain flag is set to the session.

    private boolean isExpansionEnabled() {
        Object v = session.get("org.apache.felix.gogo.expansion");
        if (v != null) {
            return Boolean.parseBoolean(v.toString());
        }
        return true;
    }

So this did safe us the quotes and brackets for the variables that are send to the command. Now we need to make sure the completion also works for or at least with one of those special characters present.
For this a couple more classes need to be „embedded“ inside Karaf:

  • CommandSessionImpl
  • Parser
  • Tokenizer

All or some of these need to be informed also of the fact that those characters are supposed to be ignored.

In the end the completion now works successfully for any select like syntax:

SELECT * FROM system.schema_keyspaces WHERE keyspace_name = 'system'

Completion in Action can be seen in the following screencast:

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*