Wednesday, August 13, 2008

Real programmer don't eat much quiche (Part I)

I don't know much about Glen and Peter. I am just a fan of Gravl and a reader of Glen's blog but I am sure that their book "Grails in Action" will be a blockbuster in the community.
So feel free to buy the book, the TOC is quite appealing and I am sure that we will get plenty of practical examples.

Tuesday, August 12, 2008

My Wordle

Sunday, August 10, 2008

Street soccer (part I)

Remi Gaillard is a French actor who has set up his own web TV. His well known for one video done for Nike in a kind of street soccer precision shoots.
Here are two of his short movies:

If you wan to see more videos, go directly on his web site.

Saturday, June 21, 2008

YUI Treeview & Grails

In a project I need a kind of CMS in order to store/retrieve large files. Basically my choices were narrowed down to Alfresco and Grails.
Alfresco was seen as the "low entry cost" solution, Grails requiring more work but being more flexible.
Obviously my main requirement was to be able to upload large files (>10 GB). Obviously this can not be done using the browser and a specific (but simple) client had to be designed. Testing this with Grails took me one day, many tutorials being available [1][2]. With Alfresco despite many post to the forum, I am still stuck to the 2GB limit ...

I decided to go on with Grails. My next step was to be able to visualize the data being stored on the server. For this I decided to use the YUI Treeview component. Here is the controller I used:

// show.gsp will be used
def show = {

def dir = {
def cmsId = params.cms
def dir = params.dir?:"/"

// Removing some characters from the path
dir = dir.replaceAll("\\.\\./","")

// Get the root dir for the CMS
String configDir = grailsApplication.config.cmsdata.dir

String target = configDir + cmsId + dir

def files = []
File d = new File(target)
if (d.exists() && d.isDirectory()){
files = d.listFiles()

// return back a JSON structure
response.setHeader("Cache-Control", "no-store")
render(contentType: "text/json") {
nodes {
for (f in files) {
node(name:, isDir: f.isDirectory())

The view is really simple. When you click on a tree node, the path is constructed the controller is called, the JSON is parsed and new tree nodes are created dynamically differentiating leaf nodes. (Here is the jscript part).


// Creating the tree
function buildTree() {
var tree;
tree = new YAHOO.widget.TreeView("treeDiv");


var root = tree.getRoot();

var tempNode = new YAHOO.widget.TextNode("/", root, false);


// Processing new nodes
function loadNodeData(node, fnLoadComplete) {
var path = "";
var leafNode = node;
while (!leafNode.isRoot()) {
path = leafNode.label + "/" + path;
leafNode = leafNode.parent;

var nodelabel = encodeURI(path);

var sUrl = "${params.cms}/dir?dir="+nodelabel;

var callback = {
success: function(oResponse){
var oResults = YAHOO.lang.JSON.parse(oResponse.responseText);

if ((oResults.nodes)&&(oResults.nodes.length)){
if (YAHOO.lang.isArray(oResults.nodes)) {
for (var i=0; i < oResults.nodes.length; i++){
var tempNode = new YAHOO.widget.TextNode(oResults.nodes[i].name, node, false);
tempNode.isLeaf = !oResults.nodes[i].isDir;
failure: function(oResponse){
"node": node,

YAHOO.util.Connect.asyncRequest('GET', sUrl, callback);


If you want to work offline (as I did), you have to install the excellent YUI Plugin.

The next step for me is to package this in a YUI panel :)

Saturday, May 3, 2008

Groovy 1.6-beta-1: c'est de la bombe :-)

>groovy -v
Groovy Version: 1.5.6 JVM: 1.5.0_13-119
>date; groovy Mandelbrot.groovy ; date
Sat May 3 22:03:53 SGT 2008
Groovy Elapsed 25.721
Groovy Elapsed 24.552
Groovy Elapsed 26.606
Sat May 3 22:05:12 SGT 2008

>/Applications/groovy-1.6-beta-1/bin/groovy -v
Groovy Version: 1.6-beta-1 JVM: 1.5.0_13
>date; /Applications/groovy-1.6-beta-1/bin/groovy Mandelbrot.groovy; date
Sat May 3 22:31:16 SGT 2008
Groovy Elapsed 5.198
Groovy Elapsed 5.174
Groovy Elapsed 5.273
Sat May 3 22:31:32 SGT 2008

x5 !
Congrats to the team !

Friday, May 2, 2008

Groovy and Twitter (Part 1)

Looks like Twitter will be under the spotlight at JavaOne this year. Posts on this topic are popping everywhere. I already talked about the "Script Bowl" session but if you are attending JavaOne you should probably have a look to this post.

But back to Groovy, I propose to write a simple class to interface to Twitter and then build mashup. But first, let's draft some specs. All communication with the server goes through http and sticks to the REST approach. You can find most of what I used here and there. Before going further, you must be familiar with some of the Twitter's terminology:
  • Tweet
    Every person has a status. Updating the status with a new one is the same as sending a tweet. Tweets have to be smaller than 140 characters.
  • Friends
    people you are subscribed to (following)
  • Followers
    people who are subscribed to your tweets
Some other concepts are:
  • Direct message
    a private message sent between two (or more) users.
  • Replies
    you can reply to another users’ tweets using the @username prefix in your own tweets.
In order to start, I would like my class to be able to:
  • authenticate to the server using a given login (and associated password)
  • retrieve the friends of that user
  • update it's status
So let's go ...

1. Authentication. This is fairly easy since Twitter uses Basic Authentication. I propose to set an authenticator using a Groovy syntax ;-)

[getPasswordAuthentication : { return new PasswordAuthentication(name, password as char[]) } ] as Authenticator

2.Retrieve friends. Fairly easy as well, we just need to send a GET request to${}.xml and yes you have to add ?page=$page if you have plenty of them. In this request, user is a Twitter user returned by getUser().
3.Update your status. Last by not least, we need to update our status. This is done by sending a POST request to using a RESTful request.

An example is worth thousands of words:

twitter = new Twitter("", "****")
twitter.postUpdate("Finalizing my Groovy Twitter API")

def u = twitter.getUser("glaforge")
println "Id of Groovy grand master is ${}"

def f = twitter.friends

Obviously this API is still in its infancy, I have been playing with it few hours. You will be able to get it here:

Thursday, May 1, 2008

Still alive ...

Well you could wonder if this blog is still alive ... Alas it has not been very active these last few months but I will try to resurrect it a bit. A lot has happen recently:
  • Apache CXF has graduated,
  • G2One and the Groovy team have released version 1.5.6
  • Gradle has been out
It then time for a new version of GroovyWS !

JavaOne 08 is next week. "Au Menu" will be a "Script Bowl" session. I will try to post some examples on the proposed apps (twitter & the world web app) before the conference starts (as I am sure you will get better solution there ;-))

So see you soon !

Saturday, January 5, 2008

Using GroovyWS with the TerraService (Part 1)

I got recently a post on the difficulty of retrieving complex elements by some webservices, I will try to clarify some issues on this in this post using the Microsoft Terra webservice.
The TerraService is an WebService API which allows you to query the Microsoft TerraServer database of high resolution aerial imagery. Among other things, you can:
  • Find Geographic and Image Coordinates by Place Name
  • Convert coordinates from one projection system to another
  • Fetch tile meta-data and image-data
Today, I will just concentrate on using the search API to show how to deal with arrays with GroovyWS.

If you look at the TerraService WSDL you will notice that some functions return arrays. This is clear from the following part of the WSDL:

<s:element name="GetPlaceList">
<s:element minOccurs="0" maxOccurs="1" name="placeName" type="s:string"/>
<s:element minOccurs="1" maxOccurs="1" name="MaxItems" type="s:int"/>
<s:element minOccurs="1" maxOccurs="1" name="imagePresence" type="s:boolean"/>

<s:element name="GetPlaceListResponse">
<s:element minOccurs="0" maxOccurs="1" name="GetPlaceListResult" type="tns:ArrayOfPlaceFacts"/>
<s:complexType name="ArrayOfPlaceFacts">
<s:element minOccurs="0" maxOccurs="unbounded" name="PlaceFacts" type="tns:PlaceFacts"/>

<wsdl:message name="GetPlaceListSoapIn">
<wsdl:part name="parameters" element="tns:GetPlaceList"/>
<wsdl:message name="GetPlaceListSoapOut">
<wsdl:part name="parameters" element="tns:GetPlaceListResponse"/>

<wsdl:operation name="GetPlaceList">
<wsdl:input message="tns:GetPlaceListSoapIn"/>
<wsdl:output message="tns:GetPlaceListSoapOut">

Therefore, the following call to GetPlaceList will return an object embedding an array of PlaceFacts.

def proxy = new WSClient("", this.class.classLoader)
def plist = proxy.GetPlaceList("mountain view", 5, true)

From this object, one can call getPlaceFacts to get the array. Here we asked for its size:

println plist.placeFacts.size()

Then one call go through all the places returned by the call to the TerraService:

for (pfact in plist.placeFacts) {

All this might look a bit cryptic, and it is probably. The fact is that there is no magic. When you want to call a remote service, you have to know its signature. If you don't have any manual then you have to read and understand the WSDL which represents the contract you are offered.

If you have any idea on how thing could be improved by GroovyWS for helping you in writing your scripts then do not hesitate to give your feedback.

Tuesday, January 1, 2008

Happy new year - Bonne année 2008

Quelques petites nouvelles de début d'année: 2007 s'est finie pour nous par un séjour de quelques jours à Malacca (Malaisie). Nul doute que soph postera prochainement une description plus complète de nos visites. J'en profite pour vous souhaitez une très bonne année 2008; quelle vous apporte surtout la santé (le reste suivra, j'en suis sûr).

Dans le chapître des bonnes résolutions (car point de nouvelle année sans de nouveaux objectifs), je vous dirais bien que j'essayerai d'être plus présent sur ces pages, que je prendrai plus de vacances, que je ferai le marathon de Singapour, .... M'enfin n'y croyez pas trop !

A toutes fins utiles, et pour ceux qui voudraient se joindre à moi, le marathon de Singapour aura lieu cette année le 7 décembre.

Sur ces bonnes résolutions, je vous laisse et n'hésitez pas à me communiquer vos bonnes résolutions en commentaires.