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 Link to heading

Setup Link to heading

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 Link to heading

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 Link to heading

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 Link to heading

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 Link to heading

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

Under the hood Link to heading

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