Sunday, 7 February 2010

Objectify; an easy way to use Google Datastore

If you had watched Larry Ellison on Oracle-Sun Strategy Update webcast, he was making fun with the word "cloud", telling thats just a new name for something they had been doing a long time. However same time Oracle's web site was announcing Oracle Cloud Computing Forum.

Whatever name you call it, clouds are popular and when it comes to clouds Google App Engine is an exciting one. Google's approach to clouds is not much different from Apple to computers, end users should not be involved to administration and internals, things should be simple,  easy to use but yet still trendy. Google App Engine supports Java, has an eclipse plugin, built on Google's famous database approach the BigTable, comes with GWT which offers easy web development and a simple, easy to use database supporting JPA/JDO. Still datastore might become a little confusing since it is not a full relational database and also the low level API might become confusing.

This is where objectify takes stage, its The simplest possible *typed* abstraction to the Google App Engine datastore. Objectify comes with a nice wiki, which includes examples, and documentation.

To try objectify first you need to install GAE plugin to eclipse, next you need to download one single jar file. The following would not be adding much to original wiki, but can be used as a summary and shows what i tried on objectify.

I assume you have GAE plugin running on eclipse, if you don't, visit http://code.google.com/appengine/downloads.html#Download_the_Google_Plugin_for_Eclipse to install the plugin, and while you are there don't forget to register an account.

Lets start with creating some entities;


@Entity
public class Course {
@Id //id fields can be long, Long or String. Only Long automatically generates keys when it s null
Long id;
String name;
String branch;
//add getters and setters
}


Now lets create another entity within relation to first one;


@Entity
public class Student {
@Id
Long id;
String name;
OKey course;
//add getters and setters
}


Since our entities are ready, lets start playing with them. To use our entities on datastore via Objectify, first thing we need to do is to register them. Lets create a service class to perform data operations.


public class SchoolService{
public SchoolService(){
ObjectifyService.register(Course.class);
ObjectifyService.register(Student.class);
}
//...


Now lets write some code to test the datastore.


//...
public boolean createCourseWithSomeStudents()[
Objectify objectify=ObjectifyService.begin();

//create a course
Course course=new Course();
course.setName("Beginning GAE Programming");
course.setBranch("Cloud Platforms");
objectify.put(course); //persists our entity and sets a generated id

//Lets create some students for our class
Student student=new Student();
student.setName("Murat");
student.setCourse(new OKey(Course.class, course.getId());
objectify.put(student);

//just add as many to same course...
return true;
}


Entities with null assigned Long ids will automatically assigned autogenerated values. If you set this id to your object same put operation would work as an update. Since out datastore has some data, now it is time to query.

First lets write a method to list all our available courses.


public List getCourses(){
Objectify objectify=ObjectifyService.begin();
//Create a OQuery for Course class without setting any filter
OQuery q = ObjectifyService.createQuery(Course.class);
List courses = ofy.prepare(q).asList();
return courses;
}


This should return all persisted courses (which should be one if you had just followed the example) as type safe list. Since the course is retrieved we can query for the data related to it. Too add a method which queries the student objects which have relations with the course we retrieved, OQuery provides filter methods.


public List getStudentsFromCourse(Course course){
Objectify objectify=ObjectifyService.begin();
//get the OKey of the object
OKey courseKey = new OKey(Course.class, course.getId());
//prepare a query for student
OQuery q = ObjectifyService.createQuery(Student.class);
//add our course key as a search criteria
q.filter("course", courseKey);
List students = objectify.prepare(q).asList();
return students;
}


Instead of using asList method there are several other methods such as, asIterable and asSingle (nice if you are sure to hit a single result).

Objectify may not be perfect on all aspects but its quite nice and easy, to use the Google App Engine Datastore which may not be very friendly with JPA/JDO all the time. The current documentation is not bad and quite complete and honestly I find it much clear than GAE's JPA/JDO documentation.

Also do not forget to check best practices which has nice tips and can save you from pitfalls like not using static initializers for the entites to register themselves to objectifyService.

By the way, for a quick test just extend HttpServlet in our service class and add a doPost method calling the methods you want to test.