Java development 2.0: Ultra-lightweight Java web services with Gretty

Gretty drops the web stack for real rapid application development

Gretty is one of a new school of ultra-lightweight frameworks made for building web services. Built on top of the blazingly fast Java™ NIO APIs, Gretty leverages Groovy as a domain-specific language for web endpoints and Grape's Maven-style dependency management. In this article, get started with using Gretty to build and deploy Java web service applications.

Andrew Glover, Author and developer, Beacon50

Andrew GloverAndrew Glover is a developer, author, speaker, and entrepreneur with a passion for behavior-driven development, Continuous Integration, and Agile software development. He is the founder of the easyb Behavior-Driven Development (BDD) framework and is the co-author of three books: Continuous Integration, Groovy in Action, and Java Testing Patterns. You can keep up with him at his blog and by following him on Twitter.



16 August 2011

Also available in Chinese Russian Japanese Portuguese

Throughout the last few articles in Java development 2.0, I've been building upon a simple cloud-to-mobile application. This application, called Magnus, serves as an HTTP endpoint listening for mobile-device location information. It functions by receiving HTTP PUT requests, each one containing a JSON document that indicates an account's location at a given time. So far, I've used the web framework Play to develop and extend Magnus (see Resources).

About this series

The Java development landscape has changed radically since Java technology first emerged. Thanks to mature open source frameworks and reliable for-rent deployment infrastructures, it's now possible to assemble, test, run, and maintain Java applications quickly and inexpensively. In this series, Andrew Glover explores the spectrum of technologies and tools that make this new Java development paradigm possible.

Play is much like Grails in that it provides an MVC stack. With Play, you can easily define controllers (servlets) that leverage views (JSPs, GSPs, templates, you name it), which in some way manipulate models. Models are implemented using POJOs (plain old Java objects) enhanced with Hibernate, JPA, or some other nifty ORM-like technology.

Although MVC is an older standard, much has changed with the advent of frameworks like Grails and Play. Simply recall the amount of effort it once took to stand up a simple web request-response interaction — say, using Struts — and you will appreciate how far we've come toward rapidly built MVC web apps. Still, not all web apps need MVC infrastructure to work. These days, some web apps don't need an MVC "stack" at all.

Before you close your browser in order to protest such a heretical statement, remember Magnus. While devised strictly for the purpose of demonstration, my cloud-to-mobile app contains no traditional view component and largely models itself off of existing, successful services. Like Twitter or Foursquare, Magnus receives messages from disparate devices around the globe. Broadly speaking, Magnus is a web service, and not every web service needs an MVC stack framework to get the job done. In some cases, all you need is a super lightweight web framework without the web stack.

This month, we'll be looking at one of these: a rapid development framework so bleeding new it doesn't even have its own homepage, and perhaps may not need one. Gretty's lineage and affiliations (including Netty and Groovy, respectively) are respectable enough that it's already part of the Java 2.0 web development family. It fills a need that many developers don't yet know they have (that's the true Web 2.0 style, don't you know?). And it's stable enough for production use — if you're willing to walk on the wild side.

A history of rapid Java development

Those of us old enough to remember when the Servlets API was first introduced have reason to be skeptical of the new "lightweight" paradigm; just a simple servlet lets you build a web service without a lot of code and consequent JAR files, after all. Web service frameworks, such as Restlet or Jersey, take a slightly different approach to development speed, building upon class extensions, annotations, and even standard JSRs to create RESTful web services. Both of these are still good options for some scenarios.

But it turns out that some new lightweight (as opposed to old lightweight) frameworks are making web services, or simple HTTP endpoints (also known as routes), amazingly simple to define. Even more simple than hand jamming a servlet!

These frameworks first emerged on other platforms, notably Sinatra for Ruby and Express for Node.js. But interesting projects have begun to emerge for the Java platform, too. One of them is Gretty, which is of course home-brewed for Groovy and the JVM.


I'm with Gretty

Gretty has at least two things going for it as far as I'm concerned: First is its use of Groovy's Grape (which I'll describe in more detail shortly) to facilitate dependency management. Second is its simple DSL-like syntax for defining endpoints. With Gretty, you can very quickly (in just a few short lines of code) define and deploy a working web routing framework that handles real business logic. As an example, watch me whip up the canonical hello world example in Listing 1:

Listing 1. Hello, World: It's Gretty!
import org.mbte.gretty.httpserver.* 

@GrabResolver(name='gretty', 
  root='http://groovypp.artifactoryonline.com/groovypp/libs-releases-local')
@Grab('org.mbte.groovypp:gretty:0.4.279') 

GrettyServer server = [] 
server.groovy = [ 
    localAddress: new InetSocketAddress("localhost", 8080), 
    defaultHandler: { 
        response.redirect "/" 
    }, 
    "/:name": {
        get {
            response.text = "Hello ${request.parameters['name']}"
        } 
    } 
] 
server.start()

In Listing 1, I created a server listening on port 8080, then set up a simple root endpoint containing the parameter name. Any request to some other endpoint will be routed back to / via the defaultHandler. The handler basically sends the requesting client an HTTP 301 "moved permanently" code, with the location of /. All requests will receive a response (with the content-type set to text/plain) containing the string "Hello" along with the value of any parameter passed; for instance, /Andy would yield "Hello Andy."

Gretty and NIO

Gretty was built using Netty, which is a client-server framework that heavily uses Java's NIO libraries. The NIO, or New I/O, package of I/O libraries was introduced way back when Java 1.4 came out. NIO mostly gets attention for its non-blocking IO operations, which permit scalable server construction. That comes in handy with frameworks like Netty and Gretty.

So what's interesting about Listing 1? First and foremost, that what you see in the listing is all you need for the application. There are no configuration files. I didn't need to download or install anything directly (other than Groovy 1.8). To fire this example up, I simply typed groovy server.groovy.

Now what if your responses need a bit more sophistication than simple text? For this, Gretty has a number of options, two of which are quite easy. First, you could simply set the response type to HTML, like I've done in Listing 2:

Listing 2. HTML responses in Gretty
"/:name": {
 get {
  response.html = "Hello ${request.parameters['name']}"
 } 
}

In this case, the response content-type would be set to text/html. Alternately, Gretty makes it possible to leverage static and dynamic templates. For instance, I could define a template using a simple JSP/GSP-like construct, like Listing 3:

Listing 3. An HTML template in Gretty
<html>
 <head>
  <title>Hello!</title>
 </head>
 <body>
  <p>${message}</p>
 </body>
</html>

I could then reference the template in the body of a response:

Listing 4. A Groovy++ template in Gretty
"/:name" {
  get {
   response.html = template("index.gpptl", 
     [message: "Hello ${request.parameters['name']}"])
  }
}

Dependency management with Gretty and Grape

Some of Gretty's rapid development impressiveness is thanks to Grape (see Resources), which it uses to automatically download binary dependencies, or JAR files. All files are loaded with Maven-style transitive dependencies. All I had to do in Listing 1 was type in the annotation @Grab('org.mbte.groovypp:gretty:0.4.279') and I got the JAR file associated with Gretty, along with Gretty's dependencies. The annotation @GrabResolver(name='gretty', root='http://groovypp.artifactoryonline.com/groovypp/libs-releases-local') indicated where Grape could find the needed files.

Gretty isn't just Groovy

Gretty isn't limited to the Groovy language. Like everything that runs on the JVM, you could try writing Gretty applications in the Java language or even Scala.

Grape may look simple, but that doesn't mean it's unfit for production. In fact, Grape's auto-downloading of required dependencies isn't any different from Maven's. It's just that it is done at runtime, the first time that you run an application, whereas Maven downloads required dependencies at build time. If Grape can find the required dependencies locally, no download is necessary. Required JARs are automatically placed in the application's classpath. As a result, you only pay a performance cost the first time you run a Grape-configured application. Of course, you'll also take a small performance hit any time you change the required version of a specified dependency.


Gretty meets Magnus

Hopefully by now you've seen that Gretty is simple, which makes it easy to do seriously fast development. Plus, Gretty (or frameworks like it) are perfectly suited for applications like Magnus — HTTP endpoints listening for data. So let's see what happens when I completely replace a respectably lightweight framework like Play or Grails with an even more lightweight app written with Gretty.

For this incarnation of Magnus, I'll use Morphia and MongoHQ, both of which you might recall from my introduction to Amazon Elastic Beanstalk. In order to leverage Groovy's Grape utility with the new config, I'll need to add the annotations in Listing 5 to my server:

Listing 5. Adding Morphia and its dependencies
@GrabResolver(name='morphia', root='http://morphia.googlecode.com/svn/mavenrepo/')
@Grab(group='com.google.code.morphia', artifactId='morphia', module="morphia", 
  version='0.99')

My Morphia classes are the same as they have been for earlier incarnations of Magnus: I have an Account and a Location. In this endpoint, I'm simply updating a location for a given account. Because clients to Morphia will send JSON documents to Gretty's endpoint, I'm also going to use Jackson, a nifty JSON-handling framework that already is part of Gretty's internals. Thanks to Grape's handling of transitive dependencies, I've now got access to everything I need to parse the incoming JSON document and transform it into a simple Java Map.

Listing 6. Updating locations in Gretty
def server = new GrettyServer().localAddress(new InetSocketAddress("localhost", 8080)).
 "/location/:account" {
  put {
    def jacksonMapper = new ObjectMapper()
    def json = jacksonMapper.readValue(request.contentText, Map.class)
    def formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm")
    def dt = formatter.parse(json['timestamp'])
    def res = [:]
    try{
      new Location(request.parameters['account'], dt, json['latitude'].doubleValue() , 
          json['longitude'].doubleValue() ).save()
	  res['status'] = 'success'
    }catch(exp){
      res['status'] = "error ${exp.message}"
    }
    response.json = jacksonMapper.writeValueAsString(res)
  }
}
server.start ()

As you can see in Listing 6, a Map of the incoming JSON document is created (dubbed json) and then correspondingly inserted into MongoDB via my Location class in Listing 7:

Listing 7. Creating the location document — Gretty redux
import com.google.code.morphia.annotations.Entity

@Entity(value = "locations", noClassnameStored = true)
class Location extends AbstractModel {
 String accountId
 double latitude
 double longitude
 Date timestamp

 public Location(String accountId, Date timestamp, double lat, double lon) {
  this.accountId = accountId
  this.timestamp = timestamp
  this.latitude = lat
  this.longitude = lon
 }
}

What's more, my Location has a Groovy superclass, shown in Listing 8:

Listing 8. Location's base class
import com.google.code.morphia.Morphia
import com.google.code.morphia.annotations.Id
import com.mongodb.Mongo
import org.bson.types.ObjectId

abstract class AbstractModel {
  @Id
  private ObjectId id;

  def save() throws Exception {
    def mongo = new Mongo("fame.mongohq.com", 32422)
    def datastore = new Morphia().createDatastore(mongo, "xxxx", 
      "xxxx", "xxxx".toCharArray())
    datastore.save(this)
    return this.id
  }
}

You might remember this code from Listing 3 of "Climb the Elastic Beanstalk." The only change I made for the Gretty implementation was to rename the actual file from Location.java to Location.groovy, which means I don't have to compile it before firing up the server. I also added a base class. The location is tied to an account via the incoming parameter account obtained from the URI.

A response is then sent in JSON indicating success. In the case of an error, another response would be generated.


In conclusion: Gretty is ready

Gretty is as light as light can be. There is no embedded ORM-framework. There is no robust view framework aside from simple templates, but plugging in some other framework is completely doable. Does all of this mean Gretty isn't ready for everyday usage? Does its lack of a testing framework imply the same? The answer is no: First, Gretty is built off of Netty's well-regarded code, so you get some assurance right out of the gate. Second, you can test Gretty just like you would any other web endpoint, automatically or not. In fact, if you want to see how Gretty tests, check its source code — there are plenty of tests in there!

Gretty is the antithesis of the modern full-stack web framework, precisely because sometimes you don't need an entire stack. If you find yourself doing too much with a framework like Gretty, then you might be better off with one of the many full stack, well-documented Java web frameworks. Likewise, if you find yourself wondering why you need an entire stack to handle web service requests and responses, then Gretty could be just what you need.

Resources

Learn

Get products and technologies

Discuss

  • Get involved in the developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, Cloud computing, Web development, Open source
ArticleID=751974
ArticleTitle=Java development 2.0: Ultra-lightweight Java web services with Gretty
publish-date=08162011