ntoll.org

(Everything I say is false...)
home | about | articles | presentations | cv | contact

JFluidDB

Monday 12 October 2009 (04:09PM)

FluidEiffle If you read this blog regularly you'll already know about FluidDB from FluidInfo. Well, I've written a Java based client library for it (I started from the excellent work by Ross Jones).

"FluidDB..?"

In a nutshell, FluidDB is a wonderfully simple yet powerful web based database that lives "in the cloud". Objects exist in the database (there is only one instance of FluidDB), users tag objects and (optionally) associate values with the tags. A tag's "value" can be anything: a number, a string of characters or even something more exotic like a picture, document or sound recording. Tags are organised with "namespaces" – hierarchies for organizing names – and can be searched using a minimalist query language.

"So far, so simple…"

Now here's the interesting bit: all objects are public and never get deleted; it's the namespaces, tags and their associated values that are covered by an elegantly simple permission system. FluidDB is open to write but powerful enough to enforce privacy.

"So what?"

I'd like to draw your attention to the adjectives I use in relation to FluidDB: "Simple", "Elegant", "Powerful", "Minimalist", "Open".

If you're a developer you'll know that one of the most difficult aspects of software development is getting the abstraction and conceptual framework right. For example, you might think you're reading a "document" in a "browser" on your "desktop" but these are just convenient names we use to make sense of our interactions with the computer. Such abstractions are layered from the lowest (1s and 0s) to the highest level that everyday users mostly see ("document", "browser", "desktop" etc). Abstractions in these layers of code are often (although not exclusively) expressed through an API ("Application Programming Interface" for you non-programmers, the public face a piece of software shows in order to interact with the outside world).

It is FluidDB's API to which I refer when using the adjectives listed above. Any developer can create a badly designed API with lots of "features" and confusing terminology but it takes a rare discerning discipline to keep things as simple as possible but not too simple to be useless (to paraphrase Albert Einstein).

It is upon this API that I have written a Java library to allow developers to easily interact with FluidDB. JFluidDB is an evening and weekend project and my first stab at working with Java so all feedback is most welcome – especially if you find un-idiomatic Java. Below is an example that encapsulates all you need to know in order to work with it and FluidDB:


import java.io.IOException;

import com.fluidinfo.*;

import com.fluidinfo.fom.*;

import com.fluidinfo.fom.Object;

import org.json.*;

public class fluidTest {

    /**

     * Some example code for using the Fluid Object Model (FOM) classes with 

     * FluidDB

     * @throws JSONException 

     * @throws IOException 

     * @throws FluidException 

     * @throws FOMException 

     */

    public static void main(String[] args) throws FOMException, FluidException, IOException, JSONException {

        // The FluidDB class represents the instance of FluidDB you're connecting to.

        // The default constructor is set to use http://fluiddb.fluidinfo.com/ but we're

        // passing the URI to the sandbox here.

        FluidDB fdb = new FluidDB(FluidConnector.SandboxURL);

        // Login to FluidDB with your credentials

        String username = "username";

        String password = "password";

        fdb.Login(username, password);

        // Get the User object representing me

        User u = fdb.getLoggedInUser();

        // My root namespace

        Namespace root = u.RootNamespace();

        // Create a new namespace underneath my root namespace (name, description)

        Namespace books = root.createNamespace("books", "For storing tags about books I might be reading.");

        // Add some tags to the new namespace (name, description, indexed)

        Tag title = books.createTag("Title", "The title of a book I've read", true);

        Tag authors = books.createTag("Authors", "The author list", true);

        Tag hasRead = books.createTag("HasRead", "Indicates I've read this book", true);

        Tag rating = books.createTag("Rating", "Marks out of ten", true);

        Tag comment = books.createTag("Comment", "Some notes and commentary", false);

        // Create a new object in FluidDB (the argument is the "fluiddb/about" tag)

        // An object can represent ANYTHING

        Object seven_pillars = fdb.createObject("ISBN:0954641809");

        // Associate some tag/values with it

        // The first tag is only associating a tag but NOT a value

        seven_pillars.tag(hasRead);

        // We're associating values with these tags

        seven_pillars.tag(title, "Seven Pillars of Wisdom");

        seven_pillars.tag(authors, new String[]{"T.E.Lawrence"});

        seven_pillars.tag(rating, 8);

        seven_pillars.tag(comment, "The dreamers of the day are dangerous men, for they may act out their dreams with open eyes, to make it possible.");

        // A search of all objects that I have read (returns matching object's unique IDs)

        String[] result = fdb.searchObjects("has "+username+"/books/HasRead");

        // result will contain only one result... the id for the seven_pillars Object

        // Lets instantiate it and get a list of the available tags I have permission to see

        Object newObj = fdb.getObject(result[0]);

        String[] tagPaths = newObj.getTagPaths();

        // tagPaths will include my tags I created above...

        // Lets get the first tag and find out what is in it...

        Tag newTag = fdb.getTag(tagPaths[0]);

        FluidResponse r = newObj.getTagValue(newTag);

        // Assuming all is well the result is returned by calling r.getResponseContent(); 

        // Lets set / get some permissions

        // This will only give the current user and the fluiddb "superuser" account the ability

        // to CREATE namespaces underneath the namespace "book".

        // Permissions can have either OPEN or CLOSED policy and a list of exceptions, so this

        // Permission is CLOSED to everyone but fluiddb and username

        Permission p = new Permission(Policy.CLOSED, new String[]{"fluidDB", username});

        books.setPermission(Namespace.Actions.CREATE, p);

        // Lets get the permission policy for our user for updating the "books/rating"

        // tag

        Permission updateTag = rating.getTagPermission(Tag.TagActions.UPDATE);

        // Calling GetPolicy() and GetExceptions() on an instance of the Permission class will

        // tell you what the permissions are (as described in the FluidDB docs)

        // Lets do some cleanup...

        // Remove the tags from the object that we created to represent the seven pillars

        newObj.deleteTag(title);

        newObj.deleteTag(authors);

        newObj.deleteTag(hasRead);

        newObj.deleteTag(rating);

        newObj.deleteTag(comment);

        // Now delete the tags

        title.delete();

        authors.delete();

        hasRead.delete();

        rating.delete();

        comment.delete();

        // and finally the namespace

        books.delete();

    }

}

"But Nicholas, you're a Python/.NET guy! Why Java?"

Good question! I have helped out with one of the early Python libraries and have written a functional .NET library (which will be brought up-to-date with JFluidDB), but I went for Java because of Android (Java is the development language for such mobile devices).

It strikes me that FluidDB would be an excellent database for lots of mobile applications and a good excuse to get into this field.

For example:

So, my next evening and weekend project is to create some simple Android applications as described above.

I'll let you know when there's something to show…