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).
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.
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."
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.
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.
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.
Learn
- "Groovy++ in action: Gretty/GridGain/REST/Websockets" (Alex Tkachman, DZone, May 2011): Very little has so far been written about Gretty. This introduction by its author offers a few more example applications implemented with Groovy++.
- Java development 2.0: This dW series explores technologies that are redefining the Java development landscape. Topics include
Amazon
Elastic Beanstalk (February 2011), JavaScript
for Java developers (April 2011), MongoDB (September 2010), and NoSQL (May 2010).
- Grape user guide: Curious about Grape? Get a quick introduction from the Codehaus user guide.
- Netty homepage: Learn about the Java NIO client-server socket framework.
- "Getting started with new I/O (NIO)" (Greg Travis, developerWorks, July 2003): This hands-on tutorial covers the NIO library, including buffers and channels, asynchronous I/O, and direct buffers.
- Knowledge path: Cloud computing fundamentals (March 2011): Introduces cloud computing concepts and the service models IaaS, PaaS, and SaaS.
- The
busy Java developer's guide to Scala (Ted Neward, 2008-2009): Ted Neward dives into the Scala programming language, cutting to the chase and providing a look at its linguistic capabilities in action.
-
Browse the
Java technology bookstore for books on these and other technical topics.
-
developerWorks Java technology zone: Find hundreds of articles about every aspect of Java programming.
Get products and technologies
- The Play framework: Focuses on developer productivity and targets RESTful architectures.
- Get Gretty: All you need to get started is Groovy 1.8.0.
- Download IBM product evaluation versions or explore the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- Get involved in the developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.

Andrew 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.



