Tuesday, March 12, 2013

Groovy and HTTP Servers

This article originally appeared in the January 2013 issue of GroovyMag.

There’s no denying that the World Wide Web has become absolutely integral for information storage and delivery. There are more than 600 million sites serving up over 80 billion individual pages and many more pages and web services being added every day(http://news.netcraft.com/archives/2012/09/10/september-2012-web-server-survey.html). And behind each site is – you guessed it! – a web server. Nowadays we have a large number of JVM web server alternatives for serving up content, and some serious Groovy and polyglot contenders as well. In this article I’ll detail some of the alternatives with a focus on embeddable options, and describe what Groovy can do to make things easier than traditional Java-only implementation and configuration. We’ll
 
configure some different servers to host a single service that reverses a query parameter and returns the result. All of these solutions can be embedded in a Groovy program and require little or no external configuration.

Note: Some of the solutions described are appropriate for a production environment while others are more suitable for smaller tasks like serving documents exclusively for an internal network or providing simple testing environments.

The test project

In order to provide an environment for standing up multiple web servers and demonstrating various HTTP requests, we’ll be using a Gradle build and some simple Spock tests. The full source code is available at https://github.com/kellyrob99/groovy-http and I hope you’ll clone a copy to take a closer look. This is the same project previously used(GroovyMag December 2012) to detail Groovy for working with http clients but expanded to look at the server-side capabilities as well. It includes the Gradle wrapper, so you should be able to check it out and run all tests with a simple invocation of ./gradlew build.

Java 1.6 HttpServer

The simplest alternative to serve up content with no external library dependencies in Java is the HttpServer included starting in Java 1.6. Standing up a server is extremely simple, requiring no external configuration – or much of anything else really. You simply create the server, declare some contexts(which match to paths) and assign a handler for each context. The entire code in Groovy for configuring the server to host our ‘reverse’ service is shown in Listing 1.

//configuring a Java 6 HttpServerInetSocketAddress addr = new InetSocketAddress(HTTP_SERVER_PORT)httpServer = com.sun.net.httpserver.HttpServer.create(addr, 0)httpServer.with {    createContext('/', new ReverseHandler())    createContext('/groovy/', new GroovyReverseHandler())    setExecutor(Executors.newCachedThreadPool())    start()}

Listing 1: Configuring an HttpServer in Groovy

So we’re binding to a port for incoming requests, assigning a handler for all requests on the root context path, configuring the server with a thread pool and starting it up. The only part we have to supply are the handlers, of which a Java version implementing HttpHandler is shown in Listing 2. All it does is return the single expected ‘string’ parameter in reverse. It also performs some simple error handling in case the parameter is missing and returns an HTTP 400 Bad request code in this case.

class ReverseHandler implements HttpHandler {    @Override    public void handle(HttpExchange httpExchange) throws IOException    {        String requestMethod = httpExchange.getRequestMethod();        if (requestMethod.equalsIgnoreCase('GET')) {            Headers responseHeaders = httpExchange.getResponseHeaders();            responseHeaders.set('Content-Type', 'text/plain');            OutputStream responseBody = httpExchange.getResponseBody();            final String query = httpExchange.getRequestURI().getRawQuery();            if (query == null || !query.contains('string')) {                httpExchange.sendResponseHeaders(400, 0);                return;            }            final String[] param = query.split('=');            assert param.length == 2 && param[0].equals('string');            httpExchange.sendResponseHeaders(200, 0);            responseBody.write(new StringBuffer(param[1]).reverse().toString().getBytes());            responseBody.close();        }    }}

Listing 2: Simple handler for HttpServer requests

We can make this somewhat less verbose by coding the handler in Groovy(see the GroovyReverseHandler in the source code), but the very low level API makes the difference in this example pretty small. More importantly, since we can code both the HttpHandler implementation and the server code into a single Groovy script, we can launch a simple web server from the command line with ease, i.e. groovy server.groovy
You’re not going to want to use this for hosting an entire web site, but it is perfectly usable for serving up small amounts of content, providing simple services or perhaps mocking up services for testing a client implementation.

Embedded Jetty

This is a complete solution for including all of the power of Jetty within your application. Since Jetty is a Servlet container, we can immediately make use of the GroovyServlet available in the standard Groovy distribution and serve up Groovlets that can be created and modified dynamically at runtime. First, let’s configure a Jetty 8 server and context to serve files using the GroovyServlet, as shown in Listing 3.

//configuring Jetty 8 with GroovyServlet supportServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS)context.with {    contextPath = '/'    resourceBase = 'src/main/webapp'    addServlet(GroovyServlet, '*.groovy')}jettyServer = new Server(JETTY_SERVER_PORT)jettyServer.with {    setHandler(context)    start()}

Listing 3: Configuring Jetty 8 with GroovyServlet

This will serve up any files under the directory src/main/webapp with the suffix .groovy. These files are compiled on the fly and the GroovyServlet detects if the files are modified so that it can recompile them as necessary. For the purpose of our simple ‘reverse’ service, the code in Listing 4 shows a Groovlet implementation. Because within the Groovlet our output is wired into the Servlet output stream, a simple println is sufficient for writing back a limited response. It’s simple things like this that make you almost forget that you’re coding a Servlet as so much of the normal boilerplate involved in coding one isn’t required.

import javax.servlet.http.HttpServletResponsefinal string = request.parameterMap.stringif (!string || string.size() != 1){    response.setStatus(HttpServletResponse.SC_BAD_REQUEST)    return}print URLDecoder.decode(string[0], 'UTF-8').reverse()

Listing 4: Groovlet which returns the passed in parameter in reverse

Notice that in this case the passed in parameters are unmarshalled for us and available in the request.parameterMap variable. And I hope that you agree this implementation is significantly less verbose and easier to understand that the HttpHandler we defined earlier to do the same thing in Java.
Perhaps more importantly, this entire web server can be defined and executed as a Groovy script with the help of a single @Grab annotation. The full script is shown in Listing 5.

@Grab('org.eclipse.jetty.aggregate:jetty-all-server:8.1.0.v20120127')import org.eclipse.jetty.servlet.ServletContextHandlerimport groovy.servlet.GroovyServletimport org.eclipse.jetty.server.Serverint JETTY_SERVER_PORT = 8094ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS)context.with {    contextPath = '/'    resourceBase = 'src/main/webapp'    addServlet(GroovyServlet, '*.groovy')}jettyServer = new Server(JETTY_SERVER_PORT)jettyServer.with {    setHandler(context)    start()}

Listing 5: Groovy script which launches a Jetty web server in under 20 lines

Jetty is a very versatile server platform and Groovy makes it extremely easy to stand up and work with. The full scope of capabilities is definitely beyond the scope of this article, but if you can do it with Jetty in a plain Java environment, you can do it in Groovy as well – just with less typing

And with just-Java you would definitely need to configure some extra pieces in order to get going, whereas Groovy can do it using nothing more than the default tools that come along with the distribution(and an internet connection, of course). If you are in need of a lightweight web server for pretty much any purpose this would be my first suggestion. Oh, and unlike deploying Jetty in a stand-alone fashion, there’s no XML configuration required – always a bonus in my books.

Restlet and Groovy-Restlet

Restlet is a platform specifically designed to help build RESTful applications quickly and reliably. I’m not personally very familiar with it, but having developed and worked with many different REST APIs I definitely appreciate the idea of a framework designed specifically for the use case. Java classes in the Restlet API are mapped directly to the REST concepts, making it very easy to implement the required services while abstracting away any specific protocol being used to communicate between resources. The Groovy-Restlet project adds a DSL built extending Groovy’s FactoryBuilderSupport class to the equation. In the simplest case, we create a GroovyRestlet object and configure our Restlet system using an external Groovy file expressing the DSL. Listing 6 shows the code used to bootstrap the Restlet application. Notice how we’re passing in a variable for the port to be used during the script evaluation.

//configuring a Restlet Server and Client using an external dsl fileGroovyRestlet gr = new GroovyRestlet()gr.builder.setVariable('port', RESTLET_SERVER_PORT)(restletClient, restletServer) = gr.build(new File('src/test/resources/restlet/reverseRestlet.groovy').toURI()) as List

Listing 6: Initializing a Restlet application in Groovy

Here we’re using the Groovy multiple assignment feature so that we can return handles to both the org.restlet.Server and org.restlet.Client objects created in the script. The DSL script shown in Listing 7 shows how these objects are initialized. This is our ‘reverse’ service implemented taking advantage of some of the niceties of Restlet, including easy parameter parsing using the Form abstraction, easy HTTP status handling and the ability to immediately create a matching Client for a Server.

import org.restlet.data.*def myPort = builder.getVariable('port')def server = builder.server(protocol: protocol.HTTP, port: myPort) {    restlet(handle: {Request req, Response resp ->        Form form = req.resourceRef.queryAsForm        if (form.isEmpty() || !form[0].name == 'string') {            resp.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, 'Missing 'string' param')        }        else {            resp.setEntity(form[0].value.reverse(), mediaType.TEXT_PLAIN)        }    })}server.start();def client = builder.client(protocol: protocol.HTTP)[client, server] //return a list so we can work with the client and eventually stop the server

Listing 7: Groovy-Restlet configuration DSL

We can test the Client behaviour for correct execution and for error conditions using Spock, as shown in Listings 8 and 9 respectively.

def 'restlet reverse test'() {    when: 'We use the Restlet Client to execute a GET request against the Restlet Server'    String response = restletClient.get('http://localhost:$RESTLET_SERVER_PORT/?string=$TEST_STRING').entity.text    then: 'We get the same text back in reverse'    TEST_STRING.reverse() == response}

Listing 8: Executing a GET request with the Restlet Client

Restlet also exposes some handy methods for inspecting error status and messaging in Listing 9.

def 'restlet failure with client error'() {    when: 'We forget to include the required parameter to Restlet'    org.restlet.data.Response response = restletClient.get('http://localhost:$RESTLET_SERVER_PORT')    then: 'An exception is thrown and we get an HTTP 400 response indicated as a client error'    response.status.isClientError()    !response.status.isServerError()    response.status.code == 400    response.status.description == MISSING_STRING_PARAM    null == response.entity.text}

Listing 9: Executing a failing GET request with the Restlet Client

The Groovy-Restlet DSL makes it fairly easy to configure a Restlet application but I wouldn’t necessarily suggest it for “real world” use. For one thing, it only works with an older version of Restlet, and for another it does not appear to be actively maintained. There’s a sparsity of documentation available but that’s not really a problem if you’re willing to check out and read the very small implementation and available examples. It would be nice to see this project updated to utilize the latest Restlet version, in which case it would be a lot more attractive to keep up with. That said, you can still deploy a complete web server using this all of this technology in a single Groovy script.

Embedded vert.x

The vert.x project(http://vertx.io/) describes itself as:

“Vert.x is the framework for the next generation of asynchronous, effortlessly scalable, concurrent applications.
Vert.x is an event driven application framework that runs on the JVM – a run-time with real concurrency and unrivaled performance. Vert.x then exposes the API in Ruby, Java, Groovy, JavaScript and Python. So you choose what language you want to use. Scala and Clojure support is on the roadmap too.”

Essentially vert.x provides a Reactor pattern based server platform that supports polyglot programming at its lowest level. It has also been touted as a JVM polyglot alternative to Node.js. You can install vert.x locally and then use its command line program vertx to load specifications from files written in Groovy, JavaScript, Ruby and other languages. Or you can embed the library in the JVM program of choice and configure it directly in code. For Groovy at least, the syntax is almost identical and looks like that shown in Listing 10 for configuring a org.vertx.groovy.core.http.HttpServer object.

Vertx vertx = Vertx.newVertx()final org.vertx.groovy.core.http.HttpServer server = vertx.createHttpServer()server.requestHandler { HttpClientRequest req ->    if (req.params['string'] == null) {        req.response.with {            statusCode = 400            statusMessage = MISSING_STRING_PARAM            end()        }    }    else {        req.response.end(req.params['string'].reverse())    }}.listen(VERTX_PORT, 'localhost')

Listing 10: Configuring a vert.x HttpServer in Groovy

Vert.x will automatically unmarshall parameters into a Map for us, and the HttpClientRequest class used in the handler provides access to a variety of convenience method for interacting with both the request and response objects.
Creating a org.vertx.groovy.core.http.HttpClient object is even easier and demonstrated in Listing 11.

def client = vertx.createHttpClient(port: VERTX_PORT, host: 'localhost')

Listing 11: One liner to create a vert.x HttpClient in Groovy

Interacting with this client is very easy and again provides convenience methods for dealing with the response, including buffering the returned data. It should be noted that in this particular example we’re negating that last benefit by calling toString() on the returned buffer for convenience. Assertions are embedded in the code in Listing 12 as I’m pulling it directly from a Spock test exercising the vert.x client.

client.getNow('/') { resp ->    400 == resp.statusCode    MISSING_STRING_PARAM == resp.statusMessage}client.getNow('/?string=$TEST_STRING') { resp ->    200 == resp.statusCode    resp.dataHandler { buffer ->        TEST_STRING.reverse() == buffer.toString()    }}

Listing 12: Exercising GET requests for passing and failing conditions using a vert.x Client in a Spock test

This is pretty much the simplest possible example, and really doesn’t do a good job of showing off the features of vert.x. The platform boasts a public repository for sharing and accessing modules, a built in event bus for communicating internally and externally and a concurrency model that allows you to forget about synchronizing code and concentrate on business logic – among other things. Asynchronous servers like this and node.js are almost certainly going to continue playing a bigger part on the internet with the enormous increase in web service usage. They provide some answers to classic scaling problems, and are a very natural fit with newer technology requirements like WebSockets.

Note that since vert.x depends on the asynchronous NIO features in Java 7, it will only work with Java versions higher than 1.7

Other alternatives

This is hardly an exhaustive list of the web server platforms nowadays supporting Groovy and/or polyglot capabilities. Some others include:

  • Graffitti is inspired by the Ruby Sinatra server and implemented entirely in Groovy. The project is hosted at https://github.com/webdevwilson/graffiti
  • Ratpack is again a Groovy port of the Sinatra server. The project is hosted at https://github.com/tlberglund/Ratpack
  • The Google App Engine can be used to serve up Servlets/Groovlets and the Gaelyk framework greatly simplifies interacting with the available Google services. Gaelyk is hosted at https://github.com/gaelyk/gaelyk
  • Gretty is a very promising Groovy wrapper around the Java Netty(https://netty.io/) server, providing a DSL for simplified declaration and configuration of Netty components. Unfortunately this project appears largely dormant and does not appear to work with newer versions of Groovy. The code is hosted at https://github.com/groovypp/gretty. Vert.x also employs Netty under the hood to get things done.

As usual, anything you can get done in Java you can also get done in Groovy. We’ve covered a few of the available options for creating and interacting with a variety of open source web servers that run on the JVM. More and more there is support for polyglot programming on the JVM, and hopefully this article has given you some ideas for using Groovy to help you be more productive with web server development. In particular, where a particular platform provides a fluent interface or DSL(like Groovy-Restlet and vert.x do) for configuration the benefits are immediately apparent. For me personally, the main benefits can be summarized as:

  • less code to maintain due to basic Groovy syntactic sugar for common functions and availability of DSLs to create expressive code in a terse fashion
  • removal of the need for XML configuration common in most web server deployment environments
  • ability to encapsulate all functionality into a single script for deployment, depending only on having Groovy available to run the script

Please give some of these ideas a try, and I would love to hear back from you regarding your own experiences using Groovy and HTTP.

Learn more

Reference: Groovy and HTTP Servers from our JCG partner Kelly Robinson at the The Kaptain on … stuff blog.


Source : feedproxy[dot]google[dot]com

No comments:

Post a Comment