Tuesday, October 05, 2010

Gaelyk: Routes + Parameters + Binding = Simple Controller

If you haven't heard it from me yet or anyone else, Groovy is an incredible dynamic language for the JVM that brings you(the Java developer) productivity like Parliament Funkadelic brings the funk. When you leverage the power of Grails and the underlying technologies(Spring, Hibernate, GORM...), Java Web development takes a monumental step in the direction of productivity. When you want to run a simple Java Web application on Google App Engine, Groovy/Grails is definitely a great option. Ah, but we do have another option for Groovy on Google App Engine, Gaelyk. It is definitely not Grails, but for simple Web applications, Gaelyk is another technology that helps at getting things done.

If you are familiar with Groovy and/or Grails and/or Groovlets, you can build a 0.1 version Web app in a few hours. One thing that I stumbled upon was utilizing WEB-INF/routes.groovy, parameters(params) and the binding property in the .groovy files to build a simple, easy to read controller. Let's take a look at an example WEB-INF/routes.groovy file first:
// routes
get  "/failure",    forward: "failure.gtpl"

get  "/",           forward: "controller.groovy"
get  "/@a",         forward: "controller.groovy?a=@a"

Above, we map the HTTP method(GET, POST...) and URL patterns to views(.gtpl files) or .groovy files(WEB-INF/groovy/). A GET request of http://myserver.com/failure would forward to and render the failure.gtpl view. Likewise, a GET request of http://myserver.com/ or http://myserver.com/anything(other than failure) would be forwarded to the WEB-INF/groovy/controller.groovy file below:
def index = {
    // do something
    forward "index.gtpl"

def list = {
    // do something
    forward "list.gtpl"

def view = {
    // do something
    forward "view.gtpl"

binding.setProperty("index", index)
binding.setProperty("list", list)
binding.setProperty("view", view)

if(params.a) {
    try {
        def var = binding.getVariable("${params.a}")
    } catch(Exception e) {
        redirect "/failure"
} else

In the WEB-INF/groovy/controller.groovy file above, I have created Closures for each http://myserver.com/anything that I would like to support. Using the script's binding property, I have added each Closure as a variable. When each request that contains a parameter we expect, in this case parameter a(params.a), I try to get that variable and execute the call() method on it. Here, the application supports http://myserver.com/index, http://myserver.com/list and http://myserver.com/view.  If params.a does not exist, we execute the default index Closure. If params.a is not supported(or not bound to the script), the binding.getVariable("${params.a}") call fails and the controller redirects to http://myserver.com/failure.

The nice thing is that we can keep better track of our .groovy files we have and tie them into our model(if needed). Here is a possible future WEB-INF/routes.groovy file:
// routes
get  "/failure",  forward: "failure.gtpl"

get  "/",            forward: "indexController.groovy"
get  "/book/@a",  forward: "bookController.groovy?a=@a"
get  "/author/@a",  forward: "authorController.groovy?a=@a"

Nothing too exciting, it is just something I found to be helpful when working with Gaelyk and I thought I would it share it. Gaelyk is pretty fun to work with. I suggest starting with downloading the Google App Engine Java SDK and the Gaelyk template project if you are new to Groovy. Gaelyk also makes working with Google App Engine super simple because of the Groovy-er access to GAE's API(check out the Gaelyk tutorial). Realistically, most Web developers should be able to get a nice application running in the Google App Engine cloud in a few hours and that is very Groovy!