Cassandra Hector Wrapper – Hector Simplified


This a simple wrapper I wrote for Hector.
—————————————–
Available at :
https://github.com/zcourts/cassandra-hector-wrapper

It doesn’t support all the features of Hector…that’s sort of the point but not. The main point was to get something quick and simple.
I did this on the train over 3/4 mornings while heading to work. I wanted it to not have anything too complex or low level.
In effect I hope that even a new Cassandra user could just download a copy and start using it without the need to
fully understand all of Cassandra’s concepts. 
I’ll review it and make some needed changes however it does currently work fine. I noticed after pushing to github that
I’m not check if Hector returns null, which generally means whatever was requested couldn’t be found or an error occured
or something or the other.

Usage is similar to Hector’s see
https://github.com/rantav/hector
if you want to use Hector directly.
See the file
https://github.com/zcourts/cassandra-hector-wrapper/blob/master/src/main/java/com/scriptandscroll/adt/UsageExamples.java

for a decent set of usage examples.

You start by creating a Keyspace object.

Keyspace ks=new Keyspace("clusterName", "keyspaceName", "localhost:9160") ;

//then a column or super column family object
ColumnFamily cf= new ColumnFamily(ks,"columnFamilyName);

//now the magic happens, you simple do cf.get[column|columns|row,rows]
Row row= cf.Row getRow("rowKey", "startColumn", "endColumn");

//you can now do
Column col = row.getColumn("columnName");
//then
String val= col.getValue();
//  OR .....
String val2=row.getColumnValue("columnName");
//OR
Iterator<Column> it=row.iterator();
while(it.hasNext()){
  Column c = it.next();
  //do whatever
}

Thats it!

Its important to note that I didn’t write this because the Hector client was lacking in anyway at all.
Quite the opposite in fact. The guys working on hector have done an awesome job and myself and I’m sure others
appreciate it. However when I was working on updating a project recently it was taking me far too much time to sift
through the hector docs and get familiar with all the changes etc. I started with a single file but that quickly got too nasty
and I just stopped, drew out some ideas and it turned out into all the classes currently in the project.


https://github.com/zcourts/cassandra-hector-wrapper/blob/master/src/main/java/com/scriptandscroll/adt/UsageExamples.java

package com.scriptandscroll.adt;

import java.util.ArrayList;
import java.util.List;

/**
 *Shows basic usage of the classes.
 * It firstly makes no provision to allow you to create keyspaces or column families, YET!
 * But once those are created from the CLI or some other way it provides a way to deal with
 * just about everything
 * @author Courtney Robinson <courtney@crlog.info>
 */
public class UsageExamples {

	public static void main(String[] args) {
		Keyspace ks = new Keyspace("clusterName", "keyspaceName", "localhost:9160");
		//Standard column family examples
		//create a column family object - THIS DOES NOT CREATE A COLUMN FAMILY IN CASSANDRA but assumes one with the given name already exists!
		ColumnFamily cf = new ColumnFamily(ks, "cfName");
		//now we can perform actions on this column family.
		//
		//first lets get a single column
		Column col = cf.getColumn("rowkey1", "columnName");
		//now we can use its value or name using
		col.getName();//returns a string
		//or
		col.getValue();//returns a string
		//
		//
		//we can get a set of columns from a row in three ways, by giving a startand end column name
		List<Column> cols = cf.getColumns("rowkey2", "startCol", "endCol");
		//by giving start and end col names and specifying a max amount of cols to get
		List<Column> cols2 = cf.getColumns("rowke2", "startCol", "endCol", false, 5);
		//or by giving an array of all columns to get
		//in this case it will only return the given columns
		List<Column> cols3 = cf.getColumns("rowkey2", new String[]{"col1", "col2", "col3", "col4"});
		//
		//We can also get rows within a CF
		//by setting start and end column names to an empty string and not setting a max value
		//we can get all the columns within the given row
		//the same options as getColumns apply, you specify columns by start and end key with an optional max amount or an array of columns
		Row row = cf.getRow("rowkey", "", "");
		//you can now do cool stuff with this row object like add and remove columns.
		//if you later pass this object to a column family it will apply those changes in Cassandra e.g.
		row.putColumn("newColName", "newColValue");
		//or
		row.putColumn(new Column("newerColName", "newerColValue"));
		//while we're at it we can remove columns from this row
		row.removeColumn(col);
		//or
		row.removeColumn("colName");
		//if we now write this row back to the column family all those changes are applied
		cf.putRow(row);//that's it! two new columns will be added, and two removed
		//we coould do
		//setting false stops it removing columns from cassandra that were removed from the object
		//columns that were added are still added obviously...
		cf.putRow(row, false);
		//we can also get multiple rows like this
		//setting start and end row keys and column names to empty gets everything
		//but we set the max rows to return as 20 and the max columns per row to 5
		//so up to 20 rows are returned which will contain up to 5 columns
		//there are multiple variations on these methods that allows various operations
		List<Row> rows = cf.getRows("", "", "", "", false, 20, 5);
		//Simple? Good! That is the aim!

		//Lukily Super column family operations work in a similar manner
		SuperColumnFamily scf = new SuperColumnFamily(ks, "superCFName");
		//now go through the same thing again...
		SuperColumn scol = scf.getSuperColumn("rowkey", "supercolName");
		//get sub columns of this super column
		List<Column> subCols = scol.getAllColumns();
		//or get multiple super columns
		List<SuperColumn> scol2 = scf.getSuperColumns("rowkey", new String[]{"superCol1", "superCol2", "superCol3"});

		//get a single sub column
		Column subCol = scf.getSubColumn("rowket", "superColname", "subcolname");
		List<Column> subCols2 = scf.getSubColumns("rowkey", "superCol", "startSubcol", "endSubCol");

		//we can get sub columns from multiple rows
		List<String> keys = new ArrayList<String>();
		keys.add("key1");
		keys.add("key2");
		keys.add("key3");
		keys.add("key4");
		keys.add("key5");
		//gets a list of rows with the sub columns requested
		List<Row> rowSubCols = scf.getSubColumnsFromMultipleRows(keys, "superColumn", "startSubCol", "endSubCol", false, 20);
		//get an entire super row
		SuperRow srow = scf.getSuperRow("rowkey", "startColumn", "endCol");
		SuperColumn sc = srow.getSuperColumn("superCol");//now do what we want
		List<SuperRow> lsuperRows = scf.getSuperRows(keys, "startCol", "endCol");
		//get up to 20 rows
		List<SuperRow> srows2 = scf.getSuperRows("startKey", "endKey", new String[]{}, 20);

		//we can also add and remove from a super row just as we did with a normal row
		ArrayList<Column> cols5 = new ArrayList();
		cols5.add(new Column("subname", "subval"));

		srow.putSuperColumn(new SuperColumn("colname", cols5));
		//and now
		scf.putSuperRow(srow);
		//all done...
		//still simple?
	}
}

On its own this would all mean nothing so again, a big thank you to the Hector guys.

If you can think of a better name then by all means, please say. Any comments, suggestions or general thoughts on it are most welcomed.

Algorithm to swap the values of two variables without using a temporary variable


In a recent interview, I was asked whether or not it would be possible to swap the contents of two variables without using a temporary variable of any sort.

The scenario, given two variables X,Y where X=5 and Y=3; Swap the contents of the variables such that,
outputting X produces the value 3 and outputting Y produces the value 5. Your algorithm must only use the two variables
X and Y and you’re allowed to perform any Mathematical operation on them to achieve the desired results.

What I came up with worked…sort of (that was on the fly without much time/thought). After thinking about the algorithm I came up with below achieves this using only the two variables by using addition and subtraction. (The below solution is an extension of what my original answer was).

The Java program (works in any language,easily translated)


/**
 *
 * @author Courtney
 */
public class Test {

    public static void main(String... args) {
        int y = 3;
        int x = 5;
        System.out.println(&quot;Original X and Y Value&quot;);
        System.out.println(&quot;Y : &quot; + y);
        System.out.println(&quot;X : &quot; + x);
        //add X on to Y so that we can take it off again later
        x = x + y;
        /**
         * We want to get the original X value into Y
         *we now know that sum(x)=x+y
         *therefore remove y =&gt; (x-y)
         */
        y = x - y;
        /**
         * At this point we know that the original X value is stored in Y,
         * we also know that X's value is x+y i.e. sum(x)=x+y
         * and we want X to get Y's original value so remove X's original
         * value and we're left with Y's original value
         */
        x = x - y;
        System.out.println(&quot;Swaped X and Y Value&quot;);
        System.out.println(&quot;Y : &quot; + y);
        System.out.println(&quot;X : &quot; + x);
    }
}

The output from the program should be:

Original X and Y Value
Y : 3
X : 5
Swaped X and Y Value
Y : 5
X : 3

Never thought about doing this before so I was caught completely off guard when asked…didn’t even know it was
possible until I was asked… Hope it helps

Building a simple Java none-blocking server


O’reily NIO tutorial(1)

I found myself in need of a way to connect to Cassandra 0.7
Existing clients are either unreliable or none existent. Being a fan of the
Java hector client (which is undoubtedly the best I’ve found) I decided to write a language independent
“wrapper” around the hector API.

I’ll cover the client a different blog post, but I wanted to write a socket server that’ll handle multiple users at the same time.
I t turns out using the raw Java NIO package would end taking the attention away from writing the Cassandra “client” so in the end
I used the server library, Netty… Below is the code I had up to the point I moved to Netty.
It allows multiple connections on the same socket but the requests are still processed sequentially which means, if a single request
hangs then all subsequent requests will hang until the connections start to timeout or the server is overloaded and turns over.

package info.crlog.server;

import info.crlog.interfaces.Constants;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *based on http://tim.oreilly.com/pub/a/onjava/2002/09/04/nio.html?page=2
 * @author Courtney
 */
public class Server implements Constants {

    private int port = 9969;
    private String host = "127.0.0.1";

    public static void main(String[] args) {
        Server serv = new Server();
        serv.init();
    }

    private void init() {
        try {
            // Create the server socket channel
            ServerSocketChannel server = ServerSocketChannel.open();
            // nonblocking I/O
            server.configureBlocking(false);
            // host-port
            server.socket().bind(new InetSocketAddress(host, port));
            System.out.println("Server connected on " + host + ":" + port);
            // Create the selector
            Selector selector = Selector.open();
            // Recording server to selector (type OP_ACCEPT)
            server.register(selector, SelectionKey.OP_ACCEPT);
            // Infinite server loop
            for (;;) {
                // Waiting for events
                selector.select();
                // Get keys
                Set keys = selector.selectedKeys();
                Iterator i = keys.iterator();
                // For each keys...
                while (i.hasNext()) {
                    SelectionKey key = (SelectionKey) i.next();
                    // Remove the current key
                    i.remove();
                    //see if client is requesting connection
                    if (acceptConn(key, server, selector)) {
                        continue;
                    }

                    // then the server is ready to read
                    if (performIO(key)) {
                        continue;
                    }
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private boolean performIO(SelectionKey key) throws IOException {
        if (key.isReadable()) {
            SocketChannel client = (SocketChannel) key.channel();
            // Read byte coming from the client
            int BUFFER_SIZE = 32;
            ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
            try {
                client.read(buffer);
            } catch (Exception e) {
                // client is no longer active
                e.printStackTrace();
                return true;
            }
            buffer.flip();
            Charset charset = Charset.forName("ISO-8859-1");
            CharsetDecoder decoder = charset.newDecoder();
            CharBuffer charBuffer = decoder.decode(buffer);
            Handler dataHandler = new Handler();
            client.write(ByteBuffer.wrap(dataHandler.processInput(charBuffer.toString()).getBytes()));
            client.socket().close();
            return true;
        }
        return false;
    }

    private boolean acceptConn(SelectionKey key, ServerSocketChannel server, Selector selector) throws IOException {
        // if isAccetable = true
        // then a client required a connection
        if (key.isAcceptable()) {
            // get client socket channel
            SocketChannel client = server.accept();
            // Non Blocking I/O
            client.configureBlocking(false);
            // recording to the selector (reading)
            client.register(selector, SelectionKey.OP_READ);
            return true;
        }
        return false;
    }
}

There are comments included to help you follow, the page cited below has an excellent tutorial and indept description of how
to get this all done so if you’re having problems making it work, ask in the comments or have a read through the tutorial linked
below.
Further reading:
[1]Introducing Nonblocking Sockets by Giuseppe Naccarato

Java MultiMap or MultiValue Map


In my recent course work I found the need for wanting to have a key value type object which maps one key to multiple values.

This could be easily accomplished in Java using a HashMap and a list or set. Doing HashMap would be very nice if you knew all the values you wanted to have mapped to the same key. Unfortunately, my use case wasn’t that simple. And it wouldn’t be very practical to manually maintain a reference to a list for each key.

I had to build a plugin framework in Java which allowed plugins to “register” for events. Multiple plugins could register for the same event and once that event had been queued for processing, all the handlers registered to listen for that event had to be notified.

A plugin could register and unregister which means the list of items to map an event to had to be dynamic, i.e must be able to add and remove items that a key points to. I came up with a solution as shown below, which worked out very nicely.

package utils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

/**
*
* @author Courtney
*/
public class MultiValue implements Cloneable, Serializable {


/**
* Keys stored as key:valueID
*/
private HashMap keys = new HashMap();
private HashMap> values = new HashMap>();


/**
* Adds a new value for the specified key
* @param key the key for the current value
* @param value the value to associate with this key
*/
public void put(K key, V value) {
ArrayList vals = new ArrayList();

//if the key already exist get the current list and add to it
if (this.containsKey(key)) {
int id = keys.get(key);
//get the existing items
vals = values.get(id);
//add the new item
vals.add(value);
//put the list back
values.put(id, vals);
} else {
//add the new item
vals.add(value);
int id = keys.size();
//if there is more than one item then add this item as size+1
// if(id==0)
id++;
values.put(id, vals);
keys.put(key, id);
}
}

/**
* @param key they key to get the values of
* @return a list of all values associated with the key
*/
public ArrayList get(K key) {
if (this.containsKey(key)) {
int id = keys.get(key);
return values.get(id);
}
return null;
}

/**
*
* @return the set of keys available
*/
public Set getKeySet() {
return keys.keySet();
}

/**
*
* @param key the key to check for
* @return true if the key exists and false otherwise
*/
public boolean containsKey(K key) {
return keys.containsKey(key);
}

public int size() {
return keys.size();
}

public Set keySet() {
return keys.keySet();
}
}

Using MultiValue is pretty simple,

//using the magic of generics can be any combination of valid types
MultiValue registeredEvents = new MultiValue();
//this can be called multiple times, if the same key is used then all the items with the same key can
//be retrieved later
registeredEvents.put(key, value);
//if multiple values are stored then you simply iterate as normal
ArrayList handlers = registeredEvents.get(cmd);

Follow

Get every new post delivered to your Inbox.

Join 360 other followers

%d bloggers like this: