However, recently I used some time to have a look at some topics of interest.
One of these points were Groovy. Currently, there is a lot of momentum in the area of dynamic languages. Groovy is part of it and it's really cool. I think it as a natural complementary fit to Java if used in the right way.
You can choose between dynamic and static typed programming. This freedom may be heaven and hell. However, it brings some useful and well though language constucts and features to ease programming. Just to mention a few: Closures, Everything is an object, Handling of list and maps, Proxying, Meta-class programming, construction of DSL.
The latter one is based on a groovy's builder concept.
Since I wanted to check it out, I used my favourite object oriented database db4o and built a db4o builder on top of it. It is hosted on google. You can download it here or browse the svn for the latest code.
The Groovy builder pattern is a powerful concept to provide arbitrary nested trees of objects or events, providing a tree-like façade. Though the db4o API is already very simple to use on its own, the db4o builder provides another easy way of accessing db4o databases. A Groovy builder relies on closures to setup its tree-like structure based on nodes.
Db4o has a very easy Java API that can be used in groovy as is. Open a database by and work on a Db4oContainer object to store and access objects by simply calling set and get or performing complex queries.
Well, that is already really easy.
// Open the database
Db4oObjectContainer oc = Db4o.openFile(“d:/Db4oSampleDatabase.yap”);
// Store an object
oc.set(new Person("Doe","John") );
// query data
Query q = oc.query();
q.constrain(Person.class);
ObjectSet objectSet = q.execute();
…
// close it again, database operations are committed automatically
oc.close();
However, in groovy you can leverage the builder concept to let it open and close the database automatically. Same when specifying a query the builder may execute the query automatically when the query has been set.
That is what the db4o builder is about.You can do the same as above using the following syntax.
As you see, there is nothing special in creating a db4o builder object. You create it like any other java or groovy object. A db4o database is opened and close by using the file method (well to open a remote database server there is also a client method that takes the host, port, user name and password which should work but I haven't tested it yet).
Db4oBuilder builder = new Db4oBuilder();
builder.file('d:/Db4oSampleDatabase.yap') {
set(new Person("Doe","John") )
query(Person.class) {
}
// query executed, process result
}
The db4o database is opened on entering the file node and closed on leaving it. The file method is equipped with a closure to take the custom action.
Db4oBuilder builder = new Db4oBuilder();Within the closure, we now can use additional methods to store, update, delete or query objects. In order to store objects, you simply call the set method within the closure of the file method. The set method takes the object to store as argument.
builder.file('d:/Db4oSampleDatabase.yap') {
}
Db4oBuilder builder = new Db4oBuilder();If you need access to the opened db4o database, the db4o builder provides access to a variable called objectContainer which is of type com.db4o.ObjectContainer and represents the opened db4o database connection.
builder.file('test.yap') {
set( new Person("Doe","John"))
}
Db4oBuilder builder = new Db4oBuilder();That’s it basically. You can insert any code within the closure. For example, the following code stores 10 Person objects into the database.
builder.file('test.yap') {
println objectContainer.ext().version()
}
Db4oBuilder builder2 = new Db4oBuilder();Objects can be deleted by using the delete method.
builder2.file('test.yap') {
(1..10).each {
def pers = new Person("Doe"+it,"John");
set(pers)
}
}
Queries supported are based on SQL or the S.O.D.A. concept.
S.O.D.A. queries are built like a tree. A basic example
Db4oBuilder builder3 = new Db4oBuilder();The output of this query are all persons stored in the db4o database.
builder3.file('d:/Db4oSampleDatabase.yap') {
query() {
constrain(Person.class) {
}
}
}
This query can also be simplified by using the person class as a parameter to the query node.
Db4oBuilder builder3 = new Db4oBuilder();The result of the query can be evaluated or processed either within the builder or outside of it.
builder3.file('d:/Db4oSampleDatabase.yap') {
query(Person.class) {
}
}
Db4oBuilder builder3 = new Db4oBuilder();Query results are automatically available in a variable called objectSet. Here is more complex example using or operator to combine to subqueries.
builder3.file('d:/Db4oSampleDatabase.yap') {
query(Person.class) {
}
if( objectSet ) {
println ("${objectSet.size()}")
objectSet.each() { p ->
println "Person: ${p.lastName},${p.firstName},${p.age}"
}
}
}
import com.db4o.groovy.Db4oBuilder;SQL Queries are done the same way by using a special node called sqlquery. In addition to query the results after the node and outside of the builder, the query result can be processed within the sqlquery node itself as well. An example:
import gk.samples.db4o.domain.Person;
Db4oBuilder builder3 = new Db4oBuilder();
builder3.file('d:/Db4oSampleDatabase.yap') {
query(Person.class) {
descend("lastName") {
constrain("KL") {
startsWith() {
or() {
descend("age") {
constrain(34) {
greater()
}
}
}
}
}
}
}
if( objectSet ) {
println "${objectSet.size()}"
objectSet.each() { p -> println "Person: ${p.lastName},${p.firstName},${p.age}" } }
}
Db4oBuilder builder = new Db4oBuilder();Db4o allows you to setup configuration parameters. Most of them have to be set before opening the database. That is supported by the db4oBuilder by using a special configuration node.
builder.file('d:/Db4oSampleDatabase.yap') {
sqlquery("from gk.samples.db4o.domain.Person") {
if( objectSet ) {
println ("${objectSet.size()}")
objectSet.each() { p -> println "Person: ${p.lastName},${p.firstName},${p.age}"}
}
}
}
Db4oBuilder builder = new Db4oBuilder();The configuration node sets up a reference the db4o configuration object. This reference is available by using the config variable can be use to set any db4o configuration parameter.
builder.configuration() {
}
Db4oBuilder builder = new Db4oBuilder();Alternatively, you can pass a map of configuration parameters as argument to the configuration node. These will then be set by the db4o builder automatically.
builder.configuration() {
config.activationDepth(5)
config.updateDepth(5)
config.freespace().discardSmallerThan(5)
}
def config = ["activationDepth" : 5, "updateDepth": 5]After setting the configuration the db4o database can be opened as seen before.
builder.configuration( config ) {
}
builder.configuration() {I will continue looking at Groovy and check out more concepts provided by Groovy.
config.activationDepth(5)
file('d:/Db4oSampleDatabase.yap') {
// store or query objects
}
}