Develop your first wave robot in Java

This post will show you how to develop a simple Google Wave Robot in Java using Eclipse IDE.

Right now, you have to deploy your robot application to google app engine. Google plans to make wave robot application portable on other web container. Moreover, google only support Python and Java as developing languages right now. No, you actually can use any JVM languages which work on Google app engine to develop your robot, such as Groovy, JRuby, Scala. In this post, we only focus on Java.

This post is based on Google officially tutorial.

Requirements for developing and testing a wave robot:

Java 6 http://java.sun.com/javase/downloads/index.jsp
Google Wave robot lib http://code.google.com/p/wave-robot-java-client/downloads/list
Eclipse http://www.eclipse.org/
Google Plugin for Eclipse http://code.google.com/eclipse/
Google App engine account https://appengine.google.com
Google Wave account http://wave.google.com/

Note: In this post, I am going to use Eclipse3.4 (Ganymede), but Google also has a plug-in for Galileo. So there should be no significantly different.

Step 1. Install Google Plugin
In the Eclipse, Click “Help” -> “Software Updates…”, and then click “Add Site” in the popup window, put http://dl.google.com/eclipse/plugin/3.4to the location, install the Google Update Site for Eclipse 3.4 (both Plugin and SDKs) . (if you are using Galileo the update location should be http://dl.google.com/eclipse/plugin/3.5 ) After accepting the term of use, the plugin and Google app engine SDK will be installed. If installation is successful, the Eclipse will ask to restart, click ok.

Now, let’s start the development.

Step 2. Creating a project
Create a new “Web Application project” by click the icon in the toolbar.

1. Give a project name, such as : first-Robot
2. Give a package name, (optional, but a good practice ), such as com.onthetopofthewave
3. Uncheck “Use Google Web Toolkit”, since our robot will have any UI. Make sure “Use Google App Engine“is checked. at the moment of writing, google App engine SDK for Java’s version is 1.2.6
4. Click “Finish”

Project Overview
Figure.1 Project Structure

Your project should look like the above figure.

Step 3. Import the libraries
So go to http://code.google.com/p/wave-robot-java-client/downloads/list , download all the jar files. Drag them into your project’s war/WEB-INF/lib directory in Eclipse IDE. So your war/WEB-INF/lib should look like Figure 2. And then, right click your project, choose Properties, in the Properties window, select “Java Build Path”, click “Libraries” tab, then click the Add JARS. Add these new JARS in your war/WEB-INF/lib directory. After it, still in the Properties Window select “Google”, choose “Web Application”, click “Add” button at the right. Add new JARS. Click “OK” to close the Properties Window.

lib
Figure. 2 Libraries

Step 4. Develop Robot Servlet
Create a new class in your project package,give a name for this class such as “FirstRobot” , its superclass is the AbstractRobotServlet class(from the com.google.wave.api package). So the name indicates it is a servlet, it can handle HTTP request. (In wave, almost every request is a POST). In runtime, the robot hosting server (in our case, google app engine) will create instance of the class to handle the events in the wave which robot is participating (such as new message, or new user added into the wave). This is a way how wave robot interacts with other participants in a wave: response to their events. Another way is schedule job: you can schedule a CRON job to your robot, base on the schedule, the robot will execute the pre-define job. Currently, there are the only two ways that robot can interact with other participants.

AbstractRobotServlet is a abstract class, we have to implement its processEvent(RobotMessageBundle bundle) method. This method will be invoked when new event(s) happen in the wave(s) the robot is in. This method takes an argument RobotMessageBundle (from the com.google.wave.api.RobotMessageBundle), this interface represents all information relate an event or a series of events. Currently only one implements class RobotMessageBundleImpl. As a hello world example, let’s make our robot can do a simple trivial task: send message and greet to other participants. Following is the code for doing that, let’s break it down.

package com.onthetopofthewave;

import com.google.wave.api.AbstractRobotServlet;
import com.google.wave.api.Blip;
import com.google.wave.api.Event;
import com.google.wave.api.EventType;
import com.google.wave.api.RobotMessageBundle;
import com.google.wave.api.TextView;
import com.google.wave.api.Wavelet;
public class FirstRobot extends AbstractRobotServlet {
private static final long serialVersionUID = 1L;

@Override
public void processEvents(RobotMessageBundle bundle) {
    Wavelet wavelet = bundle.getWavelet();
    // send a pre-define message when the robot is added to a wave
    if(bundle.wasSelfAdded()){
        Blip blip = wavelet.appendBlip();
        TextView textView = blip.getDocument();
        textView.append("I'm a robot from onthetopofthewave.com");
    }
    // greet when participants change
    for (Event e: bundle.getEvents()){
        if(e.getType() == EventType.WAVELET_PARTICIPANTS_CHANGED) {
            Blip blip = wavelet.appendBlip();
            TextView textView = blip.getDocument();
            textView.append("Hi everybody!");
        }
    }
}

At line 17, Wavelet wavelet = bundle.getWavelet();

We access the wavelet where the event occurs by bundle.getWavelet(). Let me remind you, in a wave, there is a public conversion, there maybe also some private conversion between some participants. Wavelet is the mechanism for the conversion privacy control. So a wave has at least a wavelet, represent these conversions. Each wave and wavelet has a String to represent its ID. The bundle.wasSelfAdded()method is to check whether this robot was just added to the wave. I think this method should have a different name, like justAdded(). If the robot is added, we want it to send a message. In order to do that, we need to append a new blip to the wavelet. A blip is a unit of conversion in a wave, ( a message in our case). The blips of a wavelet are stored in a tree structure. Each node (a blip) may have a parent or children. (A blip to reply another blip will become its child). Each blip has a String ID, blip can be deleted, when a blip is removed, its children will be removed too.

Blip also contains some metadata to keep track of author and versioning.
Blip blip = wavelet.appendBlip();

The above statement is to append a new blip to the wavelet, and store the reference of new blip to variable blip. The next statement:
TextView textView = blip.getDocument();

The getDocument method returns the document content (TextView from com.google.wave.api package) associated with this blip. The document can contain text, XHTML (represented in String), non-text content (Element from com.google.wave.api package).
textView.append(”I’m a robot from onthetopofthewave.com”);
This statement simply adds a text to the end of document.
The second thing we want our robot to do is to greet every participant when the participants are changed.
To notice whether the participants are changed, we need to access the RobotMessageBudle information.


bundle.getEvents();
This method returns a list of events in this bundle, there should be at least one event in the bundle. So we iterate the collection, and check the type of each event:
e.getType();


This method returns the type of event (EventType Enum from com.google.wave.api package) this instance represents. EventType is an Java enumeration, it contains following type of event:
Event Type Name Note
BLIP_CONTRIBUTORS_CHANGED The authors of the blip changed
BLIP_DELETED Blip is deleted
BLIP_TIMESTAMP_CHANGED Blip’s late modified time is changed
BLIP_VERSION_CHANGED Blip’s latest version is changed
DOCUMENT_CHANGED The associated document of the blip is changed
FORM_BUTTON_CLICKED The form button in the blip is clicked
WAVELET_BLIP_CREATED A new blip in this wavelet is created
WAVELET_BLIP_REMOVED A blip is removed in this wavelet
WAVELET_PARTICIPANTS_CHANGED The participants of the wavelet is changed
WAVELET_SELF_ADDED Just added to a new wavelet
WAVELET_SELF_REMOVED Just removed from a wavelet
WAVELET_TIMESTAMP_CHANGED The last modified time of the wavelet is changed
WAVELET_TITLE_CHANGED The title of the wavelet is changed
WAVELET_VERSION_CHANGED The version of the wavelet is change

You can see some events are tie to others. For example, if a blip is deleted, the BLIP_DELETED, WAVELET_BLIP_REMOVED, WAVELET_TIMESTAMP_CHANGED, WAVELET_VERSION_CHANGE events will be trigged.
Beside event type, Event interface also contain other related information. Such as: the new added participants’ email addresses, the removed participants’ email addresses, new title name, and etc.
For our case, we only care about the participants of the wavelet is changed ( EventType.WAVELET_PARTICIPANTS_CHANGED).
If so, as previously, we create a blip, and add a greeting message to the end of the document of that blip.

Step 5. Configure our robot
Before deployment, our robot needs some external XML to configure just like any Jave EE application. First, in the war/WEB-INF.web.xml file, we need to map the /_wave/robot/jsonrpc/ URL to our robot servlet.

< ?xml version=”1.0″ encoding=”utf-8″?>

< xmlns=”http://java.sun.com/xml/ns/javaee
xmlns:web=”http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd
xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd” version=”2.5″>

<servlet>
<servlet-name>robot</servlet-name>
<servlet-class>com.onthetopofthewave.FirstRobot</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>robot</servlet-name>
<url-pattern>/_wave/robot/jsonrpc</url-pattern>
</servlet-mapping>
</web-app>

You can see /_wave/robot/jsonrpc is the communication channel for Wave robot.

Beside web.xml, we need an additional configuration file. Create a new folder _wave under the war directory, add a XML inside new folder, name capabilities.xml with the following contents:

<?xml version=”1.0″ encoding=”utf-8″?>
<w:robot xmlns:w=”http://wave.google.com/extensions/robots/1.0″>
<w:version>1</w:version>
<w:capabilities>
<w:capability name=”WAVELET_PARTICIPANTS_CHANGED” content=”true” />
<w:capability name=”WAVELET_SELF_ADDED” content=”true” />
</w:capabilities>
<w:profile name=”onthetopofthewaveRobot”/>
</w:robot>

As you can see, first we import google wave robot namespace http://wave.google.com/extensions/robots/1.0, and then we specify the capabilities of this robot: WAVELET_PARTICIPANTS_CHANGED,WAVELET_SELF_ADDED. don’t forget content=”true”. This file basically tell wave server when WAVELET_PARTICIPANTS_CHANGED or WAVELET_SELF_ADDED events occur, contact this robot by send a message bundle to /_wave/robot/jsonrpc URL .

There are some other important events:
WAVELET_BLIP_CREATED
WAVELET_TITLE_CHANGED
BLIP_CONTRIBUTORS_CHANGED
BLIP_DELETED
BLIP_SUBMITTED
DOCUMENT_CHANGED

Of course, more capabilities your robot has more bundles it will receive from wave server. As an application hosts on Google app engine, quotas and billing always are issues. :-)

STEP 6. Deployment
You need assign an application ID to your robot application.
Go the https://appengine.google.com/ create an application, copy the name of the application. (the unique name is the application ID)
Right click the project, choose Properties, in the Properties window, select “Google” > App Engine, put your application ID at there.
Now click the “Deploy to App engine” button in toolbar, enter your google account email address and password, Eclipse builds your project, and then upload the war folder to App Engine.

Figure 3. Robot snapshot

Step 7. Testing
Login to your google wave, add your robot, its address should its application ID plus appspot.com. For example ontopwaverobot@appspot.com. After you added your robot, create a new wave and add your robot into the wave. The result should look like the following figure.


Robot Versioning

after you first upload, every time you changed capabilities.xml file, you need to update your wave robot version number (NOT your google app engine application version number).

<?xml version=”1.0″ encoding=”utf-8″?>
<w:robot xmlns:w=”http://wave.google.com/extensions/robots/1.0″>
<w:version>1</w:version>
<w:capabilities>
<w:capability name=”WAVELET_PARTICIPANTS_CHANGED” content=”true” />
<w:capability name=”WAVELET_SELF_ADDED” content=”true” />
</w:capabilities>
<w:profile name=”onthetopofthewaveRobot”/>

change 1, to a bigger number: 1.1 , 1.2. By this, google wave server will no longer cache the old version of your robot.

Trouble Shooting:
At the moment, it seems testing robot is tricky, you have deploy it to google app engine, and then to check it. You cannot test it’s functionalities locally.
However, there still something you test locally.
1. Debug or run your application locally, go to http://localhost:8080/_wave/capabilities.xml (or other port number you specify) you should see the wave robot capabilities configuration XMLfile.
2. Debug or run your application locally, go to http://localhost:8080/_wave/robot/jsonrpc it should show Error: HTTP method GET is not supported by this URL.
If some things going wrong here, it means your configuration must be wrong. So just check it.
If it is all right, upload it to google app engine.
And then check
http://applicationID.appspot.com/_wave/capabilities.xml
http://applicaitonID.appspot.com/_wave/robot/jsonrpc
They should work.
Another place for debug is google app engine dashboard, just login to your app engine account, check your robot application’s log. You can check the request history at there.


Thank for reading, We hope this post help you develop your first robot and understand Java version’s google wave api .

Stay onthetopofthewave!

Tags: development, eclipse, featured, java, robot, Robot Development, sdk, Wave Robots


If you like what you see, please, support us:

  • PDF
  • Digg
  • del.icio.us
  • TwitThis
  • Facebook
  • Google Bookmarks
  • StumbleUpon
  • RSS
  • Print


Posts that may be of your interest:

  1. JDebuggy – Robot
  2. Google Wave in the 2010
  3. Growlie – Robot
  4. Tips & Tricks on Google Wave extension development ( Seekdroid )
  5. Robots Collection

This entry was posted in On the top of the Wave, Robot Development and tagged development, eclipse, featured, java, robot, Robot Development, sdk, Wave Robots. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

This website uses IntenseDebate comments, but they are not currently loaded because either your browser doesn't support JavaScript, or they didn't load fast enough.