Sunday, October 12, 2008

FemtORM of Opera (part 1)

I posted on this blog some messages about OODBMS, but also PureMVC, and some readers spoke about DataNucleus. This morning I was thinking on a subject for the blog, and I said to myself : " why not a kind of PureMVC for ORM?" Instead of new frameworks, why not proposing a very small library and patterns to describe the communication between Object and relational world?
So, because it is very tiny, and because it is just a try, we could call this Femto ORM, shortuted as FemtORM :-)

How in fine FemtORM could work? We distinguish two main parts :
  1. storing/updating : we define in each persistent class two methods, ie store and update
  2. retrieving data : this is done by interrogating a DBAcess class singleton which offers some retrieving methods according the needs
What we have to say is that the developper has to write all the code for storing or getting data, ie he has to decide himself the transformation scheme.

So start with an exemple in this part 1. We will show another exemple in the upcoming part2.

Let define three persistent classes Class1, Class2, Class3 ( we focus for the moment only on the store method) where instance relationships are the following :
c1=>c3, c2=>c3
public class Class1 implements IDBAccess{
public Class1(Class3 class3, int anInteger, String str) {
super();
aClass3 = class3;
aStr = str;
this.anInteger = anInteger;
}

protected int id;
protected int anInteger;
protected String aStr;

protected Class3 aClass3;

public void store(DBProxy aDBProxy){
if(aDBProxy.isMarked(this))return;
aDBProxy.store(this);
aClass3.store(aDBProxy);
}
}
the second class :
public class Class2 implements IDBAccess{
public Class2(Class3 class3, boolean bool, double double1) {
super();
aBool = bool;
aClass3 = class3;
aDouble = double1;
}

protected int id;
protected double aDouble;
protected boolean aBool;

protected Class3 aClass3;

public void store(DBProxy aDBProxy){
if(aDBProxy.isMarked(this))return;
aDBProxy.store(this);
aClass3.store(aDBProxy);
}
}

and the third one :
public class Class3 implements IDBAccess{
public Class3(int anInteger1, int anInteger2) {
super();
this.anInteger1 = anInteger1;
this.anInteger2 = anInteger2;
}

protected int id;
protected int anInteger1;
protected int anInteger2;

public void store(DBProxy aDBProxy){
if(!aDBProxy.isMarked(this))
aDBProxy.store(this);
}
}
We define now the Main class where we store these 3 classes in the database :
public class MainClass {
public static void main(String[] args) {
DBProxy aDBProxy = new MySQLProxy();
Vector list = new Vector();
Class3 aClass3 = new Class3(1,2);
list.add(new Class1(aClass3, 1, "one"));
list.add(new Class1(aClass3, 2, "two"));
list.add(new Class2(new Class3(3,4), true, 1.1));

for (IDBAccess object : list) {
object.store(aDBProxy);
}
aDBProxy.commit();
}
}
In the Main class, we can see that we have defined a particular DBProxy subclass for MySQL which is called MySQLProxy. BDProxy will define generic mechanisms and MySQL actual translations between the application and the mysql database.

We also defined an interface called IDBAccess wich has to be implemented in each persistent class like Class1, Class2 and Class3. This interfac define the store and update methods which have to be define in the persistent classes. In this example, we only implemented the store method up to now.

How are defined the store methods? It is actually a graph marking algorithm. We run the object graph by marking objects. Once all the objects to be store are marked, we perform the storing by sending the commit method to the DBProxy instance.

The DBProxy class offers the isMarked method indicate the object has already been marked.
public interface IDBAccess {
public void store(DBProxy aDBProxy);
public void update(DBProxy aDBProxy);
}
We define hereafter the abstact DBproxy class where generic mechanism are implemented.
public abstract class DBProxy {

Hashtable map = new Hashtable();
Connection dbConnexion;
StringBuffer strBuf = new StringBuffer();

public DBProxy() {
super();
}

public void store(IDBAccess aDBClass) {
if(map.contains(aDBClass))
map.put(aDBClass, true);
}

public boolean isStored(IDBAccess aClass) {
return map.contains(aClass);
}

public abstract void commit();

}
We have defined above the MySQLproxy class :

public class MySQLProxy extends DBProxy {
public void store(IDBAccess aDBClass) {
super.store(aDBClass);
if (aDBClass instanceof Class1)
storeClass1(aDBClass);
if (aDBClass instanceof Class2)
storeClass2(aDBClass);
if (aDBClass instanceof Class3)
storeClass3(aDBClass);
}

protected void storeClass3(IDBAccess aClass3) {
// we store in the stringbuffer the sql code which will be executed
}

protected void storeClass1(IDBAccess aClass2) {
// we store in the stringbuffer the sql code which will be executed
}

protected void storeClass2(IDBAccess aClass1) {
// we store in the stringbuffer the sql code which will be executed
}

@Override
public void commit() {
String sqlCommand = strBuf.toString();
// 1) send and execute the sqlCommand to the database
// 2) we attribute an id number to the classes which have been stored (if needed)
}
}
This article is by far not complete ; it gives you the overall scheme how we could perform the store/update process by usinf IDBAccess, DBProxy, MySQLProxy and graph marking running.

We will see in the part 2 different scenarii of use, and how to retrieve data.

No comments: