Friday, May 11, 2007

(Helma + H2) == "to easy"

So I'd come across H2, the pure java sql rdbms engine written by Thomas Mueller (the original author of hsqldb) and had been menaing to give it a go, but never got past just firing it up and having a few quick clicks in the webbrowser based admin (which was pretty impressive all by itself!)
But then the other day I was working on the windows partition of my laptop and needed a db for a Helma app and couldn't be bothered downloading and installing the current win32 mysql package so decided to see if I could quickly get up and running with H2 instead. I was also thinking it would be good to have a quick and easy DB for a rapid prototyping and in memory db for testing of my helma webapps, so it was all worth spending a little time on and if it didn't work out I could always go through installing mysql.

But boy did it work out. H2 is a fantastic app, with alot of thought put into it. Not only is it easy to get up and running, but its very well documented and has a a lot of nice features such as a batch file that not only starts the dbserver running with web-console enabled, but also puts a little icon in your system tray and opens up a new browser window all ready for you to login!
The experience gets even better once you login with a nice ui that includes sql syntax auto-completion, history AND unbelievably editable tables of results! This puts to shame many of the dedicated java/native sql clients I've used in the past.

And what about using it with helma? (the whole point of the exercise), well that was a piece of cake, just drop the h2.jar into helmas lib/ext folder, restart helma, pop the connection details into my applications db.properties and hey presto!

But you want more? well for just $0 more, you get the full DB *embedded* inside your helma server.
Yep that's right, since H2 has an "embedded" as well as client/server mode, all you need to do is shutdown the H2 server (right click on the systray icon), change the connection URL in your helma apps db.properties from say:
jdbc:h2:tcp://localhost/col

TO:
jdbc:h2:/data/h2/col
and bam! your H2 db is now running in the same JVM process as helma (very handy on a cheap, strapped for RAM webserver for example).

But wait there's more! Yes how would you like to still have that nice web interface into the embedded DB? not possible you say, since now H2 is not running in a separate JVM - but in fact the H2 docs tell you exactly what to do[1], you just need to fire up H2's webserver when your app starts, so in your apps Global folder:
functions.js:
function onStart() {
writeln("H2 web server started by"+app.name);
app.data.h2WebServer = Packages.org.h2.tools.Server.createWebServer(null);
app.data.h2WebServer.start();
}

function onStop() {
writeln("H2 web server stopped by"+app.name);
app.data.h2WebServer.stop();
}
Then in your browser, goto http://localhost:8082/ and there's H2's web console waiting for you admin-ing pleasure!

If you've got more then 1 app in your helma server, you won't want to start a new h2 webserver for each one, so in that case just make a new empty helma app, call it maybe h2admin, pop the above code in there and your done[2].

Now that's what I call RAD!
I wonder if the rails crowd will even believe me without a funky screencast demo...

[1] Well actually the H2 docs tell you about how to fire up a DB in a servlet to be accessed by multiple webapps in the same tomcat container, but with a bit of lateral thinking and a quick look at h2.bat I got the idea.

[2] Of course this way H2 is running its own webserver alongside helma's one and I a nice future project would be to 'port' the admin web ui to be a helma app :-)

Update: I'm now confident (crazy?) enough to use this on the test server, but by default the H2 web console won't accept connections for machines other than localhost, so to get this to work you need to use this code instead:
function onStart() {
writeln("H2 web server started by "+app.name);
var args = java.lang.reflect.Array.newInstance(java.lang.String, 2);
args[0] = "-webAllowOthers";
args[1] = "true";
app.data.h2WebServer = Packages.org.h2.tools.Server.createWebServer(args);
app.data.h2WebServer.start();
}

Labels: ,