Wave Robot Using Groovy and Gaelyk Part 1 UPDATE

When I first saw Google Wave, all sorts of ideas came to me right away. I wanted to use Google App Engine and Google Wave to do some prototyping on some of the gaming ideas I have. Really, real time XMPP open system with the scalability of Google App Engine, what’s not to like?

The question is, what tools to use. Right now Wave Robot has to be hosted on Google App Engine. I tend to use Groovy for rapid prototyping. That quickly narrows it down to Grails vs Gaelyk. I decided to go with Gaelyk because this really isn’t a traditional web application. Wave Robots interact with people through a series of servlets. Using Grails would be unnecessary for my needs. The approach Guillaume Laforge took with Gaelyk where he effectively groovifed the GAE API is a good fit. My plan is to split the code into three parts. Groovy servlets to handle Wave Robot interaction. Gaelyk to handle the GAE interaction such as DataStore, TaskQueue, Mail, and also to display some simple info if people come to the app itself. The final part is the Game AI part. Given GAE’s daily cpu quota, I don’t know if a complex AI engine will burn it up. I’ll find out soon enough.

I’ll be using IntelliJ 8.1.3. It has terrific support for Groovy and Google App Engine. So let’s get started. You need to download the Google App Engine SDK if you don’t already have it.

First let’s create a new Google App Engine project. For details on how to do that,  check here

Then we need to set it up for Gaelyk.

Edit web/WEB-INF/appengine-web.xml
You have to put in the application id you’ve registered for Google App Engine.
Version number default is 1. That’s fine. Version number is a string, so you can put anything. you can put “theawesomeapp” if you like. If you do that, that particular version of the app will be available under the url theawesomeapp.latest.(yourappid).appspot.com. This let you test and deploy multiple versions of the app.

Add the following to the file

<static-files>
<exclude path="/WEB-INF/**.groovy" />
<exclude path="**.gtpl" />
</static-files>

Now to edit web/WEB-INF/web.xml

Add the following

<!-- The Gaelyk Groovlet servlet -->
<servlet>
<servlet-name>GroovletServlet</servlet-name>
<servlet-class>groovyx.gaelyk.GaelykServlet</servlet-class>
</servlet>

<!-- The Gaelyk template servlet -->
<servlet>
<servlet-name>TemplateServlet</servlet-name>
<servlet-class>groovyx.gaelyk.GaelykTemplateServlet</servlet-class>
</servlet>

<!-- Specify a mapping between *.groovy URLs and Groovlets -->
<servlet-mapping>
<servlet-name>GroovletServlet</servlet-name>
<url-pattern>*.groovy</url-pattern>
</servlet-mapping>

<!-- Specify a mapping between *.gtpl URLs and templates -->
<servlet-mapping>
<servlet-name>TemplateServlet</servlet-name>
<url-pattern>*.gtpl</url-pattern>
</servlet-mapping>

<!-- Define index.gtpl as a welcome file -->
<welcome-file-list>
<welcome-file>index.gtpl</welcome-file>
</welcome-file-list>

now create web/index.gtpl
put the following in the file.

<html>
<body>
<p>
<% def message = "Gaelyk is working!" %>
</p>
<ul>
<% 3.times { %>
<li>${message}</li>
<% } %>
</ul>
</body>
</html>

under web/WEB-INF, create a groovy directory and a lib directory.

edit web/WEB-INF/groovy/dostuff.groovy
put the following in the file.

html.html {
body {
[1, 2, 3, 4].each { number -> p number }

p "Let's have a thumb war!"
}
}

you also need to put the following jars in web/WEB-INF/lib

first the two jars from Google App Engine SDK:appengine-api-1.0-sdk-1.2.6.jar and appengine-api-labs-1.2.6.jar.

the Groovy jar: groovy-all-1.6.5.jar

Then the Gaelyk jar. I build gaelyk-0.3-SNAPSHOT.jar from github. Mostly because Guillaume hasn’t had time to build 0.3 yet. You can use 0.2 from Gaelyk site..

After this, add lib to your module library path.

Congratulation, your Gaelyk environment is all set. Run it, and you’ll see the output “Gaelyk is working!” 3 times. That comes from index.gtpl. Now go to http://localhost:8080/dostuff.groovy you’ll see the output from the dostuff.groovy Groovlet.

With Gaelyk setup out of the way, it’s time to get to the Wave Bot.  First you need to download a few files from Wave Robot Java Client Library. Get all 4 of them and place them under WEB-INF/lib.  We only need 3 of them right now. But oauth will come in handy later.

Create a new directory called _wave under web. And create a file web/_wave/capabilities.xml,

<?xml version="1.0"?>
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
<w:capabilities>
<w:capability name="blip_submitted"/>
</w:capabilities>
<w:version>Alpha1</w:version>
</w:robot>

This is where we tell Wave which events our Wave Robot cares about. In this case, we want blip_submitted. This event occurs everytime someone “completes” a blip by either clicking on “Done”, or hit shift-enter. There is also a version number for the Wave Robot. This version number has NOTHING to do with the Google App Engine version number. Everytime you create a new version of the Wave Robot you have to change this. Because Google Wave caches your robot. Again, it’s a string. So you can put whatever you want.

Now to create the servelets that let our Wave Robot to pretend to be human. Under src, create a groovy directory.

First create src/groovy/ProfileServlet.groovy using the following

import com.google.wave.api.ProfileServlet

class ProfileServlet extends com.google.wave.api.ProfileServlet {

  String RobotName="Wave Nakama"
  String RobotAvatarUrl="http://wavenakama.appspot.com/images/wnlogo.gif"
  String RobotProfilePageUrl="http://wavenakama.appspot.com/"

}

This servlet is called whenever someone try to get the profile on your Wave Robot.

Then create src/groovy/SayanythingServlet.groovy using the following

import com.google.wave.api.*

class SayanythingServlet extends AbstractRobotServlet {

    void processEvents(RobotMessageBundle bundle) {
        def wavelet = bundle.wavelet
        if (bundle.wasSelfAdded()) {
            def blip = wavelet.appendBlip()
            def textView = blip.document
            textView.append("Your wish is my command!")
        }
        for (event in bundle.events) {
            if (event.type == EventType.BLIP_SUBMITTED) {
                def blip = wavelet.appendBlip()
                def textView = blip.document
                textView.append("Tell me more about ${event.blip.document.text} Please. You are so interesting!")
            }
        }
    }

The servlet responds to two events. The first was is “wasSelfAdded”. This happens when the Wave Robot is first added to the Wave. Think of it as your Wave Robot’s greeting. The second one is what we marked back in the capabilities.xml, BLIP_SUBMITTED. You can access the blip that just occurred in event.blip.document.text.

Now we have to edit the the web.xml again to register the two servlets. Google Wave expects the Wave Robot to repsond to specific urls.

Add the following to the web.xml

<servlet>
<servlet-name>Sayanything</servlet-name>
<servlet-class>SayanythingServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>Sayanything</servlet-name>
<url-pattern>/_wave/robot/jsonrpc</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>Profile</servlet-name>
<servlet-class>ProfileServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>Profile</servlet-name>
<url-pattern>/_wave/robot/profile</url-pattern>
</servlet-mapping>

The Profile servlet must respond to the url /_wave/robot/profile. The Wave Robot communicate with the Wave system using /_wave/robot/jsonrpc

That’s it. Right now there is no way to test Wave Robot locally. However, you can see if the Wave Robot is responding to the Profile call correctly by going to http://localhost:8080/_wave/robot/profile. If everything is working, you’ll see a JSON output of the Wave Robot profile.

I created an image to be used as the Wave Robot profile picture and placed it under web/images.
Final step, time to upload the application to Google App Engine.

When it’s done, try it out by going to (applicationid).appspot.com to verify your app is working. Then create a new Wave. Add your Wave Robot as a participant by using the address (applicationid)@appspot.com. For example, in my case it’s wavenakama@appspot.com.

If all goes well, you now have the basic Gaelyk and Wave Robot setup for you to experiment with.

One thing you’ll notice is the Profile url for the Wave Robot doesn’t appear to be working. I’m guessing it’s a bug of the API.

UPDATE: Thanks to Tim Yate who tracked this done. The official code is wrong. It’s RobotProfilePageUrl, not RobotProfileUrl. I’ve corrected the code sample, and filed an issue with Google.

Comments (5)

Guillaume LaforgeNovember 6th, 2009 at 4:58 am

Excellent tutorial! I’m wondering whether Gaelyk should have some extensions so as to provide some additional sugar around the Robot and Wave APIs!

MNovember 6th, 2009 at 11:06 am

Thank you! I’d be all for that. :) though even at the current stage, writing the servelets using groovy via java is so much more concise.

Yiguang HuNovember 6th, 2009 at 7:40 pm

Yes it would be great if config stuff could be automated in Gaelyk. About make profile stuff configurable though it is already so short.

The groovy servlet and the dostuff.groovy is sleek.

MNovember 7th, 2009 at 10:12 pm

yea, Profile as implemented in groovy, unlike java doesn’t have any explicit getters/setters. so I don’t know how we can make it “better”. :)

[...] found another Google Wave Robot tutorial. This one is based on Gaelyk, "a lightweight Groovy toolkit for Google App Engine [...]