Entries with the tag Groovy

MongoSF videos

 If you weren't able to attend MongoSF, you can now view the videos and slides from some of the sessions here. All the videos haven't been uploaded yet so check that link and often over the next week or so to see what's new.

Below is the video from my afternoon session. The morning session went without a hitch so karma fated this one to have technical difficulties (oh well). Enjoy!

 

Motej with Groovy

In my presentation at GeeCon 2010, I showed how you could use Groovy to interact with the Nintendo Wiimote, here is the code and a little explanation from one of my demos.

  • Install OS specific native Bluetooth libraries
  • Grab the jars for the Java JSR 82 implementation. Either BlueCove or Aventa. Note that Aventa only has a 14day trial and BlueCove requires linking to an extra gpl jar if you use it on Linux. Mac users on Snow Leopard will have to compile Bluecove from source.
  • Grab slf4j-api-1.5.8.jar and slf4j-simple-1.5.8.jar.

Open a Groovy console and add all the jars (bluecove-2.1.0.jar, bluecove-gpl-2.1.0.jar [if on Linux] and the slf4j jars) to the classpath using Script -> Add Jar to classpath.
Copy the following code into the console.

import motej.*
import motej.event.*

def listener = [moteFound:{Mote mote ->
      println("Found mote: " + mote.getBluetoothAddress())
      mote.setPlayerLeds([false, true, false, true] as boolean[])
      mote.rumble(2000l)
      Thread.sleep(10000l)
      mote.disconnect()
   }
] as MoteFinderListener        
                
MoteFinder finder = MoteFinder.getMoteFinder()
finder.addMoteFinderListener(listener)
                
finder.startDiscovery()
Thread.sleep(30000l)
finder.stopDiscovery()

The above code starts discovery for controllers, registers a listener that rumbles the wiimote and changes the LEDs, and disconnects and stops discovery after a delay. You can activate your Wiimote for discovery by pressing the 1 & 2 buttons at the same time.

You can also download the source and libs in a ready-made project here.

Griffon at Chicago Groovy Users Group

Next month, on June 8th, I'll be presenting at the Chicago Groovy Users Group on Griffon. I'll be covering the basics of Griffon development and give some tips on how to port legacy applications from Java. Come one, come all.

You can sign up to attend here.

Speaking at SpringOne2GX 2010

 Several weeks ago, I got a nice advance birthday gift by learning that I will be speaking at SpringOne2GX. The conference happens to start on the same day as my birthday. I'll be presenting "Griffon for the Enterprise" at 1630h(4:30P) on Thursday the 21st. Make sure to catch the other Griffon sessions presented by Andres Almiray at 12:45 and 1445(2:45P) that same day.

If you haven't signed up yet, do it now before the price jumps up. Register here

Create Lightweight Groovy Web Apps with Ratpack

Besides having one of the most awesome names for a Groovy project, well besides Griffon ;), Ratpack is a nice web framework to scaffold and prototype ideas.

Inspired by the Sinatra Ruby web framework, Ratpack puts routes (URL mappings) at the forefront. Compared to Grails, it's a more bootstraped experience but is useful for small projects. Just as Sinatra coexists with Rails, Ratpack can coexist with Grails.

Route Basics

Each route contains the code that will be executed when it is accessed. Here is a basic route that prints "Hello, World!" when someone navigates to localhost:5000/helloworld:

get("/helloworld") {
    "Hello, World!"
}

Behind the scenes, there is a handler that is injecting a HttpServletRequest and HttpServletResponse for us to interact with. That means that you don't have to learn a new protocol and you can leverage your Java Servlet knowledge. To further illustrate this, any of the following routes would work as well:

get("/") {
    response.sendRedirect("/helloworld")
}
get("/error/:error") {
    response.sendError(new Integer(urlparams.error))
}
get("/data") {
    request.toString()
}

We can see from the error route that the :variableName notation gives us an equivalent to $variableName in Grails. They aren't listed here for brevity but any of the HTTP verbs can be routed to.

Running Ratpack

After downloading the package from Github at https://github.com/bleedingwolf/Ratpack, you'll need to run the gradle task 

gradle deployRatpack

This retrieves Jetty and other dependencies, compiles the framework, and drops all the libs into your .groovy/libs directory. I haven't had any problems with these libraries specifically but in the past libs in the .groovy directory have caused version conflicts, so just be aware. After you have the libs installed, you can run Ratpack in two different ways. Static mode uses a bash script named ratpack and any changes to files won't be picked up until you bounce the server.

ratpack <application file>

Dynamic mode operates similar to grails run-app in dev mode bouncing the server automatically when a file in the watched directory is changed:

groovy <RatpackDir>scripts/runapp.groovy <app file> <dir to monitor>

Drop the code from the two code snippets in a file and you're off to the races. No import files needed.

It remains to be seen if an ecosystem of middleware extensions as vibrant as Sinatra or Node.js builds around it but I'm looking forward to playing more with Ratpack.

Serving Images (Favicons) with Ratpack Middleware

One of the things I noticed from running the sample material was that I would get a 404 error when clients try to retrieve the favicon.ico file. I thought it would be a matter of just dropping the favicon.ico file into the app directory. If only it were that simple... What ended up working is creating a new route for the favicon and working some HttpResponse mojo to get Ratpack to serve up the image. Adding a route directly to our app file is nice but a bit messy. I split out the new route into its own file in an attempt to create a pseudo-Ratpack middleware. The file is listed below:

class Helpers {
    static addFavicon = { app ->
	def handler = {
	    try {
		response.setContentType("image/ico");
		file = new File('favicon.ico')
		response.setContentLength((int)file.length())
					
		inStream = new FileInputStream(file)
		out = response.getOutputStream();
					
		// Copy the contents of the file to the output stream
		byte[] buf = new byte[1024];
		int count = 0;
		while ((count = inStream.read(buf)) >= 0) {
		    out.write(buf, 0, count);
		}
		inStream.close();
		out.close();
	    } catch(Exception ex) {}
		""
	}

	app.get('/favicon.ico', handler)
    }
}

The empty string at the end of the handler is to make sure Ratpack doesn't balk at us handling the strream ourselves.

The code from the last post was just a closure so we need to modify it a little bit to automagically handle the favicons. Be aware that saving the file as a script in this manner(below) somewhat breaks the script from working with the ratpack script file. The reason for this is because the ratpack file expects there to only be a closure in any file you pass to it. The scaffolding we added to the file duplicates what the ratpack script was already doing so it fusses at you ... something about being DRY ;) ... but you've already deployed the libs to your .groovy so you can run it like any other groovy script making sure to pass in the Helpers.groovy file as well.

import com.bleedingwolf.ratpack.*
import groovy.ratpack.*

def app = Ratpack.app({
    get("/") {
	response.sendRedirect("/helloworld")
    }
    get("/helloworld") {
	"Hello, World!"
    }	
    get("/error/:error") {
	response.sendError(new Integer(urlparams.error))
    }	
    get("/data") {
	request.toString()
    }	
})

Helpers.addFavicon(app)
RatpackServlet.serve(app)

Alternatively, we can add the Helpers.... line to the ratpack script file. Or even yet, one might provide a gradle script and have the file be copied somewhere that is accessible to all the Ratpack apps.

Quick News Items

  • After much prodding and poking(albeit the nicest kind), by @pstehlik since I started at @Taulia, I have agreed to speak at the San Francisco Grails Cafe Centro Meetup Group on July 19.
  • Earlier that month on the 7th of July, I'm speaking at the Sacremento Groovy Users Group(SacGRU). The topic for both talks will be Ratpack.
  • My book Learning HTML5 Game Programming, that you might have heard about once or twice on this site ;) is now available for pre-order on Amazon.com.

Making a Chat Server with Ratpack

In this post, we're going to use Ratpack and WebSocket4J to create a simple chat website and server. I used the method from here to get Ratpack installed into a local Maven store for use with Grape and I pulled in a couple other dependencies that I needed. WebSocket4J also had to be added manually to Maven.

The routing part of the application is fairly simple, the only new addition was setting the 'public' property which we will explain a bit later. Our sole route renders the index.html template. Our WebSocket code is where it gets a little bit interesting. We start a ServerSocket on port 5555 that will initially accept all connections. If the client is trying to connect on any other enpoint but "/chat", the socket is closed. Each client has a ChatServer thread spun up for it.

@Grapes([
    @Grab(group='com.bleedingwolf', module='Ratpack', version='0.2'),
    @Grab(group='org.mortbay.jetty', module='jetty', version='6.1.25'),
		@Grab(group='org.websocket4j', module='WebSocket4J', version='1.3'),    
		@Grab(group='org.json', module='json', version='20090211'),
    @Grab(group='net.sf.mime-util', module='mime-util', version='1.2'),
    @GrabConfig(systemClassLoader=true)
])
def app = Ratpack.app {
    set 'public', 'public'
    get("/") {
    	render 'index.html'
    }
}

WebServerSocket socket = new WebServerSocket(5555);
try {
	while (true) {

		WebSocket ws = socket.accept();
		System.out.println("GET " + ws.getRequestUri());
		if (ws.getRequestUri().equals("/chat"))
			(new ChatServer(ws)).start()
		else {
			System.out.println("Unsupported Request-URI");
			try {
				ws.close();
			} catch (IOException e) {
			}
		}
	}

} finally {
	socket.close();
}

This listing below shows the code for the Chat Server. When initialized, it kicks off a new thread and adds the socket to the list of sockets to communicate with. It has one main function that does work called processMessage. processMessage acts on messages with the operation code "broadcast" and sends them to all the other sockets.

 

import org.json.*
import websocket4j.server.WebSocket
import websocket4j.server.WebServerSocket
public class ChatServer extends Thread {
static ArrayList <WebSocket> sockets = []
WebSocket ws
public ChatServer(WebSocket ws) {
this.ws = ws
sockets.add(ws)
}
def processMessage = { msg ->
cleanupConnections()
// convert to JSON object
def json = new JSONObject(msg)
def op = json.getString('operation')
if (op == 'broadcast')
processBroadcast(json)
}
def cleanupConnections = {
def newList = []
sockets.each {
if (!it.isClosed()) {
newList.add(it)
}
}
println "cleaning up connections"
sockets = newList
}
def processBroadcast = { json ->
for (s in sockets) {
s.sendMessage(json.toString())
}
}
public void handleConnection() {
try {
while (true) {
String message = ws.getMessage();
processMessage(message)
if (message.equals("exit"))
break;
}
} catch (IOException e) {}
finally {
try {
ws.close();
} catch (IOException e) { }
}
}
public void run() {
handleConnection();
}
}

 

Lastly, we have our HTML code. One thing that you might notice at first glance is that some $ symbols are escaped. The reason for that is both Groovy (which is evaluating the template) and Zepto/JQuery use the $ symbol. Unescaped, Groovy will try to evaluate the contents, otherwise it treats it as text. The same is the case for \ literals like \n. I've colored the extra \'s in red.

I personally like the feel of CoffeeScript so that's what the interaction code is in. When the page loads, it attempts to connect to the chat server on localhost:5555/chat. If the session is new and the user hasn't entered his or her name, there is a popup prompt. When the user clicks send, the message is sent to the server and distributed to all the clients.

<html>
	<head>
		<title>Chat</title>
		<script src="/js/json2.js"></script>
		<script src="/js/zepto.min.js"></script>	

		<script src="/js/coffee-script.js"></script>	
		<script type="text/coffeescript">
			socket = null
			if window.name is ""
				name = prompt 'What is your name'
				window.name = name
			
			connectToServer = ->
				socket = new WebSocket "ws://localhost:5555/chat"
				socket.onmessage = (event) ->
					obj = JSON.parse(event.data)
					console.log(obj)
				
					val = \$('#chat').get(0).value
					val += obj.data.sender + ' said:' + obj.data.message + '\\n'
					\$('#chat').get(0).value = val
				window.socket = socket
				
			sendMessage = ->
				msg = \$("#message").get(0).value
				packet = {}
				packet.data = {'message':msg, 'sender':window.name}
				packet.operation = 'broadcast'
				json = JSON.stringify(packet)
				console.log(json)
				socket.send(json)
				
			window.connectToServer = connectToServer
			window.sendMessage = sendMessage
		</script>
	</head>
	<body onload="connectToServer()">
			<h1>Chat</h1>
			<textarea id='chat'readonly rows='10' columns='50' style='width:200px;height:550px'></textarea>
			<br/>
			<input type='text' columns='40' id='message'/>
			<input type='button' value='Send' onclick="sendMessage()"/>
	</body>
</html>

Static files: If you set the application config property "public" to anything, it will attempt to serve what it thinks are files out of that directory. There is currently a bug on trunk for static file serving, you can get the fix on my git fork. Zepto.js is a lightweight JQuery-like library. Here are the links for the other JavaScript libraries I used: json.js and coffee-script.js. All of these files would go in the public directory we specified in the app declaration.

Why Spark Will Not Ignite For Me

Let me first share this great comment someone on Reddit said about creating an open source project:

"if you made an open source project, you're automatically awesome; if your implementation is sound, you're doubly awesome. It doesn't matter if somebody thinks that your idea is flawed - you never know until you try." /via dcapacitor on @proggit

 

In that respect, I tip my hat to the creator of Spark, a Java Sinatra-inspired microframework but I can't endorse it as a solution.

Let's first look at the Hello World code:

import static spark.Spark.*;
import spark.*;

public class HelloWorld {
   public static void main(String[] args) {
      get(new Route("/hello") {
         @Override
         public Object handle(Request request, Response response) {
            return "Hello World!";
         }
      });
   }
}

It is definitely more concise than a traditional J2EE app, it is bloated compared to a similar Sinatra or Groovy Ratpack application. Way too much scafolding to get to the actual work at hand. Linked here is a less trivial example. You'll see how as the app grows in size, it begins to go out of control.

 

One the Why? page for Spark, Spark's creator incorrectly states:

Why not use Sinatra?

If you're an experienced programmer in functional languages you should definitely use Sinatra. However, if you're a Java developer and want to get the benefits you get from Sinatra but you don't want or have the time (money) to learn a new language, Spark is a really good alternative!

Edit: Page was edited to remove references of functional programming.

Firstly, Ruby is not a functional language and that shouldn't matter anyways. The greater problem with the statement is that it is conflating the concept of routing as the only benefit of Sinatra. Yes, routing is a plus but it is also the middleware that helps Sinatra to shine. As you can see with the non-trivial Spark examples, you get routing which is new, but everything else is the same old Java. Currently, it doesn't have a built-in template engine or seemingly any other niceties for static file serving, etc. I'm unsure that someone who would be looking for a solution that is trailblazing against the status quo would be someone that felt that exploring a new language was something they didn't have time for.

Should we always teach seeking knowledge is never a wasteful enterprise?

Basic Authentication with Ratpack

In this post, we're going to cover how to create a AJAX login request using JQuery. While the format of the request is specific to JQuery, any front side JS library will do. If you are new to Ratpack, check out my introductory post here.

Basic Authentication receives access to a resource by submitting a request and attaching a header formed by Base64 encoding the concatenation the username, a colon, and the password. It is easy to implement but relies on the connection between the client and the server be secure. A MITM attack could easily compromise data if it is transmitted using HTTP.
Starting from the front end, I created a HTML file to hold our AJAX code, show below. One thing that is useful to note is that although it appear to be a regular HTML file, it is also a Groovy template. That is why the $ that JQuery uses have to be escaped. The form takes a username and password, encodes them, and sets the header. On success, the result text is pushed to a div.

    <html>
	<head>
		<title>Login with Ratpack</title>
		<script src="/js/jquery.js"></script>
		<script src="/js/jquery.base64.js"></script>
		<script>
		function login() {
			var username = \$("#username").val();
			var password = \$("#password").val();
			\$.ajax({
					'type':'POST',
					'url': 'http://localhost:5000/login',
					'otherSettings': 'othervalues',
					'beforeSend': function(xhr) {
						xhr.setRequestHeader("Authorization", 
                                                      "Basic " + \$.base64.encode(username + ":" + password))
					},
					success: function(result) {
						\$("#results").html(result);
					}
			});
		}
		</script>
	</head>
	<body>
			<h2>Login Form with Ratpack</h2>
			<div>
				<span>Username:</span><input id="username" type="text" columns=20>
			</div>
			<div>
				<span>Password:</span><input id="password" type="password" columns=20>
			</div>
			<button onclick='login()' >Login</button>
			<div id="results"/>
	</body>
    </html>
    


Next, let's move to the backend. Let's start by creating a helper to assist with authentication requests. The handler takes a HttpServletRequest in as a parameter and attempts to pull off the Authorization header. From that header, it retrieves the encoded username and password (in non-demo code, use try-catch blocks, do as I say not as I do). The demo punts on any type of strong validation but you can see where it would go. We end by using meta-magic to attach the doAuth function to the application.

    class Auth {
	    static doAuth = {app ->
		    def handler = { req ->
    	        def authHeader = req.getHeader("Authorization")
    	        def encodedValue = authHeader.split(" ")[1]
    	        def decodedValue = new String(encodedValue.decodeBase64())?.split(":")
    	        // do some sort of validation here
    	        if (decodedValue[0] == "") {
    		        return "Unauthorized"
    	        } else {
    		        decodedValue
    	        }
            }
            app.metaClass.doAuth = handler;
        }
    }
    

Last but not least, we get to lay out the routes. After setting up the public and template directories, we render the HTML we declared above on "/." When the login button is clicked, a POST request is made to "/login" which executes the doAuth helper function on the request. If the auth was successful, the server echoes back the username and password submitted. Otherwise, it returns "Unauthorized." Before instructing the servlet to execute the app, we call the static doAuth function on app so that it can add itself to app's metaclass.

   def app = Ratpack.app {
	set 'public', 'public'
	set 'templateRoot', 'templates'
	
	get("/") {
		render 'index.html'
	}
	
	post("/login") {
		result = doAuth(request)
		if (result != "Unauthorized") {
			"Logged in with username ${result[0]} and password ${result[1]}"
		} else {
			"Unauthorized"
		}
	}
    }
    Auth.doAuth(app)
    RatpackServlet.serve(app)
    

Creating Ratpack Apps with the Gradle Application Plugin

Currently, there are two ways to run a Ratpack app, you can build and run the ratpack executable or you can use the runapp groovy script. Both methods are ok but I wanted a way to be able to easily move apps between computers and make sure I didn't miss a jar. I started poking around in the Gradle documentation and found what I needed in the application plugin.

Gradle's Application plugin provides tasks that are common to an application's lifecycle:
run, which runs the app,
installApp, which installs the app into a directory,
startScripts, which creates OS-specific scripts to start the app, and
distZip, which creates an archive of the app directories.

All of this functionality is provided mostly for free by including the following code in your build.gradle file:

    apply plugin: 'application'
    
    mainClassName = '<package and name of your class>'
    

In lieu of installing Ratpack to my local Maven repository and assuming anyone I sent a distro of the app would too, I dropped the file into a lib directory and created a flat repository for that directory.

    repositories {
        flatDir name:'lib', dirs:'lib'
        mavenCentral()    
    }

The Ratpack build jar does not contain all of its dependencies so I copied them over to my dependencies gradle block. You could just as easily drop the dependencies into your flat repo and reference them from dependencies. I decided to let Maven do the heavy lifting and retrieve them at run-time. I set up my source directories in the default Maven style and I was ready to go. gradle run actually started the app and I was able to respond to routes.

However, things failed tragically whenever I tried to access a public file or template from either the installed version, created using gradle installApp, or the extracted archive, created using gradle distZip. I quickly realized that it was because I naively thought gradle was going to package everything in the root directory. After a little wrangling, I happened upon the required incantations to make it work. The following code explicitly copies the template and public directories to the installed app and archive.

    installApp {
        into('build/install/'+applicationName){
            from ('templates').into '/templates'
        }
into('build/install/'+applicationName){ from ('public').into '/public' } }
distZip { into(applicationName){ from ('templates').into applicationName+'/templates' }
into(applicationName){ from ('public').into applicationName+'/public' } }

You can view the whole file here.

Griffon Todo App

At GR8USA last month, in my "Introduction to Griffon" session, I demoed a Todo App using the following features:

  • GlazedLists
  • Persistence (with Deckchair)
  • SwingX components
  • XSwingX prompts

Check out the source code here: https://github.com/jwill/Conference-Demos/tree/master/gr8-usa/2011/TodoApp

screen.png

 

Deploying a Ratpack App to a War File

Not much unlike making a deployable app with Ratpack, creating a deployable war file is pretty easy but there are some tweaks we need to make to the gradle file and in a couple of other places.

Under normal conditions, Ratpack spins up an embedded server, removing the need to create a web.xml file, so that's the first thing we need to do. For a basic app, you only need a single servlet as show in the listing below.

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

<servlet>
        <servlet-name>BlogServlet</servlet-name>
        <servlet-class>BlogServlet</servlet-class>
</servlet>

<servlet-mapping>
        <servlet-name>BlogServlet</servlet-name>
        <url-pattern>/*</url-pattern>
</servlet-mapping>

</web-app>

The servlet file RatpackServlet assumes that you are using a Groovy script file that it wants to load at run-time. You could alter the gradle war task to include the Groovy file, which is a good solution for a one-off app where all the code is in one file, or you could tweak the RatpackServlet file. The listing below is a snippet from BlogServlet, which essentially the stock RatpackServlet file with some modest tweaks, shown below. The first line of code instantiates the app followed by two lines to derive the relative path of any referenced static assets.

void init() {
    	app = new BlogApp().app
    	context = this.getServletContext()
    	rootDir = context.getRealPath("/")
    	// ...
}

Lastly, we need to format the war task in our gradle build file. That includes copying the static files and templates where they need to be, referencing a web.xml file and including the classpath dependencies.

war {
	into('/public') {	
		from('public')
	}
	
	into('/templates') {
		from('templates')
	}
	
	classpath fileTree('lib')
	webXml = file('resources/web.xml')
}

Using Markdown with Ratpack

Groovy's SimpleTemplateEngine provides a very simple way to create dynamic HTML from templates. It is lightweight enough that it is compatible with almost any templating engine. I started playing around with it because I wanted to find a way to create some dynamic client code and wanted something more expressive and compact than regular HTML but not as complex as a JSP. Using Markdown and SimpleTemplateEngine together allowed me to hit that sweet spot.

Overview of Markdown

Markdown was created by John Gruber (of Daring Fireball fame) and Aaron Schwartz to allow one to easily translate a shorthand written in text files to HTML. It uses a limited set of special characters to designate headings, listings, figures, links and code blocks. It's the type of system that allows the formatting of an article to get out of your way and not disrupt your flow. Below is a sample Markdown file.

A First Level Header

====================

This is just a regular paragraph.

 

<% num.times { %>;

<%= it %>. <%= it+1 %> squared = <%= (it+1)*(it+1) %>

<% } %>

 

The following are code blocks and will print as is:

`<br> means break

<hr> means horizontal rule

`

In addition to parsers/translators for almost every programming language imaginable, Markdown is one of the formats that PanDoc can convert to a number of other formats including DocBook and PDF. For this post, I used MarkdownJ.

Using Markdown in A Route

Ratpack receives a request for an endpoint which retrieves the Markdown template, injects the given params, and evaluates the Groovy code contained in it. The resulting text is passed to MarkdownJ where it is converted into HTML and pushed into the response. The code snippet below shows how it all works.

import com.petebevin.markdown.*
//... truncated code
get("/") {
    def m = new MarkdownProcessor()
    def p = render 'template.md', [num:4]
    m.markdown(p)
}

Links

MarkdownJ

Markdown Quick Reference

Building PlayN applications with Gradle

PlayN is a cross-platform game library that allows you to write Java code and build games for Desktop Java, HTML5 Browsers, and, Android. Rovio's AngryBirds used PlayN for the version that launched in the Chrome Web Store.

I've been messing around with PlayN ever since it was chuckle-inducingly named ForPlay. One of the things that bugged me a little bit was its embrace of Ant and Maven. Strategic because of the greater mindshare on Java no doubt but I very much prefer Gradle as a build system. It isn't constrained to Java as much as Ant and Maven are and doesn't require me to write miles-long command-line arguments or write XML.

In this post, we're going to set up a PlayN application to use Gradle for building and packaging code. This tutorial is going to assume that you have already got maven installed and have already built and installed PlayN. You could build it with Ant as well but that involves a bit more work. You can download my forked version of the PlayN Samples repo and follow along.

  1. Install Gradle.

Gradle is a build tool that uses Ivy for dependency management, can integrate with Maven repositories, and is highly extensible. Gradle has plugins for many common Java ecosystem tasks such as creating a installable application, creating a WAR file, and compilation support for other JVM and non-JVM languages(Groovy, Scala, Clojure, and C++ among others). That means that you can take the time and learn one tool rather than many. And installation is super easy too. Just download, extract to somewhere on your path and you are good to go.

  1. Organize your source files.

Unless you tell it otherwise, for a Java project, Gradle assumes that you are using a Maven style project directory structure (src/main/java, src/test/java, and the like). There wasn't much to do other that moving the images from src/main/java/.... to src/main/resources. This is easily configurable if you want to preserve the original structure.

  1. Create your main build.gradle file.

Like Ant's build.xml file and Maven's pom.xml, Gradle has a special build file to control builds. The native programming language of the build.gradle file is Groovy. In addition to managing dependencies, you can create new tasks in code and create complex build logic. One of the most basic build files is listed below.

apply plugin: 'java' 

It tells Gradle to expose the build tasks in the Java plugin. To find out what tasks are available, simply run the following at a command prompt.

gradle tasks 

Next we need to tell Gradle both what dependencies we have and where to find them. This is where our local Maven repository comes in.

subprojects {
  repositories {
    mavenRepo name:'Local', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
    mavenCentral()
  }
  playN_version = '1.0.1'
}

We are telling Gradle to check the local Maven repository for dependencies first and if not found, look on Maven Central. If you'd prefer not to use the local repository, you could instead use a local directory. groupId and artifactId from Maven correspond to group and name in Gradle parlance. The subprojects keyword indicates that the included instructions will be shared between all subprojects. View the main build gradle file.

  1. Create your settings.gradle file.

The settings.gradle file is where you declare what subprojects are present. If we were building only a single target and would never add any more, we could get away without having this file. But it is worth keeping modularity.

include "core", "java" 
  1. Create subproject build.gradle files.

We can see from the settings.gradle file that we have two more build files to create. Let's begin with the core project which is used by every other project. I grabbed the core dependencies from its pom.xml file. Gradle looks first in its repository, then to Maven or any other repositories we have set up to locate the files and their dependencies. The keyword in front of the Maven details is the phase for which this is a dependency. Many are available but you will mostly deal with compile or runtime.

playN_version = '1.0.1'

dependencies {
    compile (
        [group: 'com.googlecode.playn', name : 'playn-jbox2d', version: playN_version],
        [group: 'com.googlecode.playn', name : 'playn-core', version: playN_version],
        [group: 'com.threerings', name : 'tripleplay', version : '1.0']
    )
}

I'm now able to run gradle build to see my app get all the required dependencies and build. Let's move on to the java project, for creating a desktop Java game. It depends on the core project and has some desktop Java-specific APIs as show below.

dependencies {
  compile project(':core')
  compile group: 'com.googlecode.playn', name : 'playn-java', version: playN_version
}

I'd like to be able to run it straight from Gradle so let's start by applying the application plugin.

apply plugin: 'application' 

Adding to the build file gives us access to the tasks: run, installApp, and distZip. Those tasks allow us to run, install, and distribute an archive of the application, respectively. So that Gradle knows what class to execute, we also need to add the following somewhere in the file:

mainClassName = 'playn.sample.hello.java.HelloGameJava' 

Running gradle run gives us a Java Swing window with some cheerful spinning peas. We can even install it or zip it and the files will work. Here are the full core and java project build.gradle files.

Bonus: We can even run create Java desktop games with another JVM language like Groovy. Just drop in a some groovy files and add the following dependency and we're all set.

groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.10' 

I've only explored using Gradle for a Java-only PlayN application. Check back in the future for updates on using Gradle to produce projects for the other PlayN targets.

Building HTML5 PlayN Apps with Gradle

In the previous post, we setup a PlayN application with Gradle and worked through building the desktop Java version. In this post, we'll continue our work and build the HTML5(GWT) project.

  1. Add our HTML project to settings.gradle.

We need to tell gradle that we have a new subproject to deal with. All we need to do is modify the settings.gradle file to the one-liner below.

include "core", "java", "html" 
  1. Compile and install the Gradle GWT plugin.

Clone the repo from gwt-repo. Run gradle jar to build a jar of the plugin. The jar will be located under the build/libs directory. Move this jar to /lib/plugins and this will be available system-wide for our builds.

  1. Do some file shuffling.

The GWT plugin doesn't seem to properly import the core libraries as the Java project does. There are a couple ways of working around this like creating a task to copy over the core source files and resources to the proper place. I just did it by hand but a more modular solution would use tasks. I copied the core source files to src/main/java and the images resources to the src/main/webapp. A bit hacky I know.

  1. Creating the build.gradle file.

Most of this is stock from the documentation with the GWT Gradle plugin however there are a couple additions. To the dependencies, I added

gwt group: 'com.googlecode.playn', name : 'playn-html', version: playN_version 

and the following to the end of the file

gwtModules     = ['playn.sample.hello.HelloGame'] 

You can find out the nitty gritty of the full gradle file here.

The GWT target adds a couple GWT-specific tasks, compileGwt and gwtDevMode, to build the GWT targets and launch Dev mode, respectively. Because a GWT compile can involve multiple passes and be time-consuming, running the dev mode server doesn't automatically compile the GWT code. gwtDevMode launches a local server to test the application. Debugging is enabled so beware, it may be slow.

Also in the gradle script is the jetty plugin enabling you to create a war file or start/stop a Jetty server. It seems to generate the war file fine but the built-in Jetty doesn't seem to run it properly.