In Our last installment, we configured Eclipse to use Jython and DB4O, and we wrote some simple code to create Pilot objects and store them. In this installment, we are going to retrieve those objects.
This tutorial is based on the Formula One DB4O tutorial.
Retrieving objects
db4o supplies three different quering systems, Query by Example (QBE), Native Queries (NQ) and the SODA Query API (SODA). In this first example we will introduce QBE. Once you are familiar with storing objects, we encourage you to use Native Queries, the main db4o querying interface. When using Jython, this may present some challenges – more on that later.
When using Query-By-Example, you create a prototypical object for db4o to use as an example of what you wish to retrieve. db4o will retrieve all objects of the given type that contain the same (non- default) field values as the example. The results will be returned as an ObjectSet instance. We will use a convenience method #listResult() to display the contents of our result ObjectSet :
Java Code:
public static void listResult (ObjectSet result){
System.out.println(result.size());
while(result.hasNext()) {
System.out.println(result.next());
}
}
Jython Equivilant:
def listResult (result):
print result.size()
while result.hasNext():
print result.next()
To retrieve all pilots from our database, we provide an ‘empty’ prototype:
Java Code:
// retrieveAllPilotQBE Pilot proto=new Pilot(null,0); ObjectSet result=db.get(proto); listResult(result);
Jython Equivilant:
proto=Pilot(None,0)
result=db.get(proto)
listResult(result)
The output is:
2
Michael Schumacher/100
Rubens Barrichello/99
Note that we specify 0 points, but our results were not constrained to only those Pilots with 0 points; 0 is the default value for int fields. Also note that where we employ null in Java, we use None in Jython.
db4o also supplies a shortcut to retrieve all instances of a class:
Java Code:
ObjectSet result=db.get(Pilot.class); listResult(result);
Jython Equivilant:
result=db.get(Pilot) listResult(result)
Jython vs Java:
You will notice that the Jython is nicer to read and write. (I think so, at any rate.) Functions return objects that are typed, but we do not have to declare the type in the code. Some people make a fuss about type safety in Java, C# and other languages. My own opinion is that while type declarations do help the compiler, most of the time they do not help the programmer. Type declarations are more work than I want to do most of the time – developer productivity is what I want.
(Note: Because my clients these days tend to be departments of the Canadian government, I am unlikely to have a chance to use Python or Jython in the near future for anything but my own interest. However, one must always be prepared to offer alternatives, and one must always be willing to advocate. )
In our next installment, we will look at updating and deleting DB4O objects. After that, perhaps we can start to think about the Active Record pattern.
I have watched Carl Rosenberger’s talk at ICOODB 2008 in Berlin. You can find it on German Viscuso’s blog. You will notice that he not only talks about LINQ, and LINQ for Java, but he also talks about the possible use of annotations for transactional demarkation.
Separation of Concerns Using Decorators
I was thinking that I could have some fun with DB4O and Jython. If I create a generic object factory to instantiate the Java classes I want to use with DB4O, it would be possible for me to wrap the Java classes in a Python class. This would allow me to decorate method calls to indicate that a method is transactional – basically, by using a Python adapter on a Java class, I could use decorators to separate any one of a number of concerns.
I was thinking that when the object factory produces an object, it would use the generic reflector to populate a dictionary of methods or properties that can be called – basically, the factory would examine the Java object to identify its attributes. For the wrapper/mapper to work, I may have to impose some conventions – the basic idea could be useful and cool.
Remember, the far off goal is something that looks and works like Active Record, but for DB40 using Jython. The programmer would need to know very little about DB4O, but each object would know how to save, update and delete itself, and there would a simply way to dynamically query the repository.
Basically, I think Jython may provide the means to play with syntax, and to toy with various nifty ideas. I will post my next installment in the Formula One tutorial series soon.
Forgive me for blithering – I just want to use my blog entries to record my thoughts where I can.
Much has been written about NOSQL databases, but DB4O often goes umentioned. Since people also have a keen interest in Python, I thought I would look at ways to use use Python and DB4O together. This tutorial mirrors the DB4O tutorial many of us cut our teeth on: the DB4O Formula One Tutorial.
Assumptions
This tutorial makes a few assumptions. Let’s get them out there to help some people avoid frustration. I assume the following:
Everything used in this tutorial is free to download and use, and the code you write will run on a number of operating systems including Windows, Linux and Apple. I use Ubuntu Linux, and my examples refer to my setup not yours.
It would be a good idea to follow the DB4O Java tutorial first, and then repeat your work in Jython. However, feel to just dive in the Jython code, if you wish.
First Steps:
Let’s get started as simply as possible. We are going to learn how to open, store, retrieve, update and delete instances of a single class that only contains primitive and String members. In our example this will be a Formula One (F1) pilot whose attributes are his name and the F1 points he has already gained this season.
We are going to create a Java class to use in our example, and then we are going to put it in a jar. DB4O can persist Java objects, not Python objects. Other than the object itself, all of our other code with be in Jython.
First let’s set out classpath to refer to the DB4O jar, and let’s create our Pilot class. Most of you will have a strong understanding of classpaths. However, if you happen to have trouble defining a classpath environment variable, Eclipse provides the means to manage a classpath. A classpath tells Java where to find its libraries. Read the Eclipse documentation to learn how to configure a build path to the appropriate DB4O Jar. (I am using db4o-7.4.58.11547-java5.jar.)
Once you reference the DB4O Jar, you should see something like this:

First we create a native class. As was mentioned above, this is necessary because DB4O does not persist Python classes. Create a Java package such as:
package org.electricmousetrap.db4o.jython;
public class Pilot {
private String name;
private int points;
public Pilot(String name,int points) {
this.name=name;
this.points=points;
}
public int getPoints() {
return points;
}
public void addPoints(int points) {
this.points+=points;
}
public String getName() {
return name;
}
public String toString() {
return name+"/"+points;
}
}
Create A JAR Using Eclipse
A JAR is a convenient way to package up class definitions in a single file. It is easy to create a JAR using Eclipse. If you need help, you will find a tutorial here. If you are desperate, and you are willing to run the risk of having things work the first time, you can always read the eclipse help file. I named my Jar DB4OJython.
Once you have created your Jar, create a new Jython project.
Configure and Create A Jython Project
The Pydev plugin will allow you to create a new Jython project if you have correctly configured Eclipse to run with Jython, but there is a dirty trick you will need to use if you want to use the latest version of Jython, which is currently in beta.
Dirty Trick: To use Jython, you need to to tell Eclipse which JAR file to use. Pydev seems to expect a jar called jython.jar, but the beta ships with a jar called jython-complete.jar. Make a copy of this jar and rename it jython.jar. Other than that, follow the instructions for installing Jython, and you should have no problem. I would love to provide some other troubleshooting tips – perhaps later.
Then, using the Window->Preferences options, configure Pydev to use the new jar as the Jython interpreter. Having configured Jython, create a new Pydev project and specify the Jython 2.1 project type. This will work fine, although it is not accurate.
To keep things simple, create a new file and just call it DB4OExample.py, and then you are almost ready to go. The last thing you need is to put the DB4O jar in the classpath so that you use the DB4O library. You also need a reference to the jar we created earlier that contains the Pilot class. There are two ways to do this:
import sys
sys.path.append('/path/to/your/db4o-7.4/lib/db4o-7.4.58.11547-java5.jar')
sys.path.append('/path/to/your/jython/Java/DB4OJython.jar')
My code examples will employ the second approach, but there is good reason to separate configuration concerns from your code. Now we are ready to write Jython code that uses DB4O.
Opening the database
To access a db4o database file or create a new one, call Db4o.openFile() and provide the path to your database file as the parameter, to obtain an ObjectContainer instance. ObjectContainer represents “The Database”, and will be your primary interface to db4o. Closing the ObjectContainer with the #close() method will close the database file and release all resources associated with it.
In Java, the code looked like this:
// accessDb4o
ObjectContainer db=Db4o.openFile(Util.DB4OFILENAME);
try {
// storeFirstPilot
Pilot pilot1=new Pilot("Michael Schumacher",100);
db.set(pilot1);
System.out.println("Stored "+pilot1);
Pilot pilot2=new Pilot("Rubens Barrichello",99);
db.set(pilot2);
System.out.println("Stored "+pilot2);
}
catch
{
// Handle exceptions
}
finally {
db.close();
}
}
Because Jython is dynamically typed, you can end up typing less code. Here is a full example of how to save objects using DB4O – it coresponds to the DB4O formula one tutorial.
# Configure Jython environment
import sys
sys.path.append('/path/to/your/db4o/lib/db4o-7.4.58.11547-java5.jar')
sys.path.append('/path/to/your/jars/DB4OJython.jar')
#import java dependencies
from com.db4o import Db4o
from org.electricmousetrap.db4o.jython import Pilot
try:
try:
db=Db4o.openFile('/home/path/to/your/pilots.db4O')
print "The following were saved"
pilot1=Pilot("Michael Schumacher",1006)
db.store(pilot1)
print pilot1
pilot2= Pilot("Rubens Barrichello",996)
db.store(pilot2)
print pilot2
except:
print sys.exc_info()
finally:
db.commit()
In my next installment, I will show you how to retrieve these objects.
Please note that I am using Jython without creating classes or objects of my own for now. That is the beauty of Python/Jython – it is great for prototyping and figuring things out. You can write a more robust Jython application later, or you can write the eventual code in pure Java.