Chris Umbel

Google Wave Robots in Java

google wave logo When Google Wave was first announced I was pretty excited. The concept seemed perfect. Broad like twitter but rich like email. Brief like instant messenger but collaborative like a message board.

Things have been somewhat slow going in beta thus far. But hey, it's still beta. If Google refines it a bit and wave catches on (what actual does catch on these days seems to be a crap-shoot) it has the potential to provide tons of value.

One of the possibilities I find particularly interesting is the use of robots. No, there's nothing underhanded about it, a robust robot API is provided for that very purpose. Automated programs that are participants in the conversation.

Shortly after getting development sandbox access I had to get to work on one. While I'm going to keep the features of the actual bot I'm writing close to the vest for now I'll at least share an example I used while learning.

Platform

google app engine logo Google Wave robots must exist on Google's AppEngine, at least for now (this restriction will ultimately go away). That limits your language choice to either Python or Java while using the AppEngine SDK. When using Java you also have to include the json.jar and jsonrpc.jar libraries in your /war/WEB-INF/lib/, both of which can be found here.

I got started developing for Wave with Java. I'm not exactly sure how that happened considering how I love me some Python. Nonetheless I dusted off my Java cap and got to work. It's been a while, be patient with me, please.

Handling

From a Java point of view Wave robots are simply servelets that process events. What kind of events? Anything from a new participant entering a wave (a conversation) to a blip (the basic atom of a wave) being started or completed. What's important, however, is that you declare what events you plan on handling up front. That's accomplished by creating a /war/_wave/capabilities.xml file similar to what follows.



  
    
  
  1

That example specifies that the servlet will be called after a blip is completed. Note that if you want to change what events are handled in this file you must increment the version tag in order for your changes to take effect.

Servlet

I might as well hit you strait up with it. Essentially you have to subclass com.google.wave.api.AbstractRobotServlet and override processEvents. It's within processEvents that you'll perform your magic.

In the case of this example I'll read out the text of the previously completed blip (the one that fired this event) and try to find stock ticker symbols by way of the pattern "ticker:" i.e. "ticker:GOOG". If I think I've found any I'll use Google's Finance REST API to look up their prices and write them back as blips.

import com.google.wave.api.*;
import java.net.*;
import java.io.*;
import org.json.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class StockPriceBotServlet extends AbstractRobotServlet {
    private static final long serialVersionUID = 1L;

    @Override
    public void processEvents(RobotMessageBundle bundle) {
        Wavelet wavelet = bundle.getWavelet();
        String ticker;
        
        for (Event e: bundle.getEvents()) {
            if (e.getType() == EventType.BLIP_SUBMITTED) {
                /* grab the text of the blip that fired this event */
                String userBlipText = e.getBlip().getDocument().getText();
                
                /* search for the trigger to act */
                Matcher matcher = Pattern.compile("(ticker\\:)(\\w*)").matcher(userBlipText);
                
                /* iterate all matches */
                while (matcher.find()) {
                    /* add a blip to the wave */
                    Blip blip = wavelet.appendBlip();
                    TextView textView = blip.getDocument();
                    ticker = matcher.group(2);
                        
                    try {
                        /* connect to google */
                        URL url = new URL(String.format("http://www.google.com/finance/info?client=ig&q=%s", ticker));
                        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
                        String inputLine;
                        StringBuilder sb = new StringBuilder();
    
                        /* read response from google into a StringBuilder */
                        while ((inputLine = reader.readLine()) != null)
                            sb.append(inputLine);
    
                        /* get rid of wrapper google adds */
                        sb.delete(0, 4);	
                        /* parse response into a JSON object */
                        JSONObject o = new JSONObject(sb.toString());
                        /* pull out the property named "l" and send it back to wave */
                        textView.append(String.format("%s: %s", ticker, o.getString("l")));
    
                        reader.close();			        
                    } catch(Exception ex) { }   
                }
            }
        }
    }
}

Deployment

Before you deploy you must set up your /war/WEB-INF/web.xml like so:


    
        StockPriceBot
        StockPriceBotServlet
    
    
        StockPriceBot
        /_wave/robot/jsonrpc
    

Now you must deploy the bot to AppEngine as you would any Java AppEngine project.

Use

Now it's time to actually use this contraption. It's rather strait forward. Just invite @appspot.com to your wave where is the appspot designation of the code you just deployed. From there just have a conversation with the bot as follows:

example wave output

Next Steps

Wave Eliza, perhaps?

Mon Dec 07 2009 23:12:00 GMT+0000 (UTC)

Follow Chris
RSS Feed
Twitter
Facebook
CodePlex
github
LinkedIn
Google