Web-apps using Groovlets

When you feel that a framework is way too much, but you still want to leverage Groovy for your web application, you may use some Groovlets.

Groovlets are like Groovy scripts for a web application. They are run on request having the whole web context (request, response, etc.) bound to the evaluation context.

This means:

  • live reloading (if you are able to sync files with your webapp).
  • no clumsy web.xml configuration
  • no groovy compiler, the groovy.jar is the only dependency

Using groovlets

Setup

To setup a webapp for Groovlets:

  1. Configure the handling servlet in your web.xml

     <!-- setup the GroovyServlet in your web.xml
                and bind the script file extension -->
        
        <servlet>
            <servlet-name>groovlets</servlet-name>
            <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>groovlets</servlet-name>
            <url-pattern>*.groovy</url-pattern>
        </servlet-mapping>
  2. Add groovy.jar dependency to your project, for example with gradle:

    apply plugin: 'groovy' // java is ok too
    apply plugin: 'war'
    
    repositories {
      mavenCentral()
      mavenLocal()
    }
    
    dependencies {
      providedCompile 'javax.servlet:servlet-api:2.5'
      compile 'org.codehaus.groovy:groovy-all:2.2.0'
    }

Handle a GET

Output HTML on GET request is pretty easy using the built-in MarkupBuilder

// if present use name parameter from
// query string (eg. ?name=Francesco)
// else use "World"

def name = params.name ?: "World"

// output some html

html.html {
    head {
        title "Hello from Groovlet!"
    }
    body {
        h1 "Hello, ${name}!"
    }
}

In the example above you see also Groovy native template engine: (G)String concatenation.

Handle a POST

With built-in variables bound from the Servlet request via the GrailsServlet, you can also perform more complicated operation like handling some JSON in POST request.

response.contentType = 'application/json'

// Access headers, with context bound variable
if (headers['Content-Type'] != "application/json") {
    throw new RuntimeException("Please use 'application/json' header")
}

// Get content from POST body
def jsonContent = request.reader.text

// Parse JSON to Map
def content = null
if (jsonContent) {
    content = new JsonSlurper()
                .parseText(jsonContent)
}

// build JSON output
json."echo" {
    "original" content
}

Dealing with the JSON payload is really easy

$ curl -X POST -H "Content-Type:application/json" -d '{"name": "Ben"}' \
          http://localhost:8080/groovlets-webapp-sample/echo.groovy

{"echo":{"original":{"name":"Ben"}}}

in the example above we leverage both a JsonSlurper to parse POST request body and the built-in JsonBuilder to convert a Java Map to the JSON payload of the response.

Pros and Cons

Pros:

  • A simple way to leverage the power of Groovy in a web-application

Cons:

  • Things can get messy as the complexity grows (switch to Grails)
  • You do not have a framework and you could end reinventing the (switch to Grails)

Download

Sample web-app with source code available for download here.

Under the hood

The magic happens in the GroovyServlet that is responsible for executing the script, passing the web context to a GroovyConsole created ad-hoc.

// snippet from 
// GroovyServlet.service(HttpServletRequest request,
//                            HttpServletResponse response)

final ServletBinding binding = new ServletBinding(request, response, servletCtx);
setVariables(binding);

// Run the script

Closure closure = new Closure(gse) {

    public Object call() {
        try {
            GroovyScriptEngine gse = getDelegate()
            return gse.run(scriptUri, binding);
        } catch (ResourceException e) {
            throw new RuntimeException(e);
        } catch (ScriptException e) {
            throw new RuntimeException(e);
        }
    }

};

GroovyCategorySupport.use(ServletCategory.class, closure);

The full source for GroovyServlet, more info about Groovlets