This week some code was push to the repository to implement some kind of agents for the federation server. A simple EchoAgent was added to demonstrate the code.

With this as starting point I implemented a small TwitterAgent. Just add the TwitterAgent to a wave.  The agent listens to every message  and updates your twitter status. I took the twitter4j API which is pretty easy to use.

package org.waveprotocol.wave.examples.fedone.agents.twitter;

import java.util.ArrayList;
import java.util.List;
import org.waveprotocol.wave.examples.fedone.agents.agent.AbstractAgent;
import org.waveprotocol.wave.examples.fedone.agents.agent.AgentConnection;
import org.waveprotocol.wave.examples.fedone.util.Log;
import org.waveprotocol.wave.model.document.operation.AnnotationBoundaryMap;
import org.waveprotocol.wave.model.document.operation.Attributes;
import org.waveprotocol.wave.model.document.operation.AttributesUpdate;
import org.waveprotocol.wave.model.document.operation.BufferedDocOp;
import org.waveprotocol.wave.model.document.operation.DocOpCursor;
import org.waveprotocol.wave.model.operation.wave.WaveletDocumentOperation;
import org.waveprotocol.wave.model.wave.ParticipantId;

import twitter4j.Twitter;
import twitter4j.TwitterException;

public class TwitterAgent extends AbstractAgent {
  private static final Log LOGGER = Log.get(TwitterAgent.class);
  private Twitter twitter;

  private TwitterAgent(String username, String hostname, int port, String twitterUsername, String twitterPassword) {
    super(AgentConnection.newConnection(username, hostname, port));
    this.twitter = new Twitter(twitterUsername, twitterPassword);

  private void tweetLines(List lines) {
    for (String line : lines) {"updateStatus: " + line);
      try {
      } catch (TwitterException e) {
        LOGGER.warning(e.getMessage(), e);

  public void onDocumentChanged(WaveletData wavelet, WaveletDocumentOperation documentOperation) {
    BufferedDocOp docOp = documentOperation.getOperation();
    final List lines = new ArrayList();
    docOp.apply(new DocOpCursor() {
      @Override public void annotationBoundary(AnnotationBoundaryMap map) { }
      @Override public void characters(String chars) { lines.add(chars); }
      @Override public void deleteCharacters(String chars) { }
      @Override public void deleteElementEnd() { }
      @Override public void deleteElementStart(String type, Attributes attrs) { }
      @Override public void elementEnd() { }
      @Override public void elementStart(String type, Attributes attrs) { }
      @Override public void replaceAttributes(Attributes oldAttrs, Attributes newAttrs) { }
      @Override public void retain(int itemCount) { }
      @Override public void updateAttributes(AttributesUpdate attrUpdate) { }

  public void onParticipantAdded(WaveletData wavelet, ParticipantId participant) { }

  public void onParticipantRemoved(WaveletData wavelet, ParticipantId participant) { }

  @Override public void onSelfAdded(WaveletData wavelet) { }

  @Override public void onSelfRemoved(WaveletData wavelet) { }

  public static void main(String[] args) {
    try {
      if (args.length == 5) {
        int port;
        try {
          port = Integer.parseInt(args[2]);
        } catch (NumberFormatException e) {
          throw new IllegalArgumentException("Must provide valid port.");

        TwitterAgent agent = new TwitterAgent(args[0], args[1], port, args[3], args[4]);;
      } else {
        System.out.println("usage: java TwitterAgent
    } catch (Exception e) {
      System.err.println("Catastrophic failure: " + e);


One issue with the current implementation should be mentioned: If you’ll restart the TwitterAgent all the messages will be resubmitted to your twitter account! If someone knows how to avoid this, please leave a comment.

Within in the next days, I’ll add some more little features (e.g. grab status updates and add them to a wave, twitter direct message gateway, …). What else could you think of?

This should be considered as a small demonstration and is far away from a Twitter and Google Wave integration 😉

Currently, there isn’t so much hype concerning the Wave Federation Server and with particular regards to the Gadgets API or the Robot API. But there are some people around the world starting their own client application. Unfortunately, the Wave Federation Server is a moving target and there are daily changes to the code base. The client-server RPC (based on protocoll buffers) communication is far from feature complete. Some people are complaining they won’t start projects until the Wave Federation Server is stable and almost feature complete.

As far as i know there are three projects working on a client:

As the first two projects do not have any implementation yet I took a first look into the “Java Desktop Client”:

A very simple GUI based client to be used with the reference server. This is a small experiment I investigated and thus unfortunately I cannot keep the project updated or fix bugs etc at the moment, especially as google keep updating the reference code. This may or may not work with the current distribution of the google wave reference server again I haven’t tested it.

The desktop client implements a very basic set of funtcions: new wave, open wave, add and remove participants, send a message. I took a screenshot so you can see how the desktop client looks like:

Unfortunately, there is no binary or webstart version of the Desktop Client, but you can pull the sources from github and build a binary. There is no ant or maven file, so i give you a short step-by-step installation guide how to get a running version:

  • git clone git://
  • create a new eclipse java project in the newley created directory
  • add the “console” directory to sources
  • create a new package “org.waveprotocol.wave.examples.fedone.waveclient.console” and move all classes to this package
  • add the fedone-client.jar from the wave-protocol project to the classpath
  • run the application with the parameters: ConsoleClient <userAtDomain> <server> <port>

If everything is fine you’ll see a Java GUI:

Java Desktop Client

The Wave Federation Server is written in Java, so it is very handy to run the server as linux daemon. The JavaServiceWrapper (JWS) turns java applications into robust services that boot up automatically and restart automatically following crashes. It’s free for open source programs and has very reasonable licensing fees for commercial software.

I used JWS to start the Wave Federation Server instead of starting the server with the original bash script.

Download the JavaServiceWrapper:

%> wget
%> tar xvf wrapper-linux-x86-64-3.3.5.tar.gz

I created a new directory (e.g. bin) in the wave-protocol workspace and copied the relevant wrapper files into this directory. You should have the following files in the ./bin directory:

%> bin/wrapper
%> bin/
%> bin/wrapper.jar
%> bin/wrapper.conf
%> bin/wave.key
%> bin/wave.cert
%> bin/

The important files are the configuration “wrapper.conf” and the startup script “”. I just took the script from the JavaSericeWrapper distribution and renamed it to The changes to the default script are to adjust the application name and application long name.

My wrapper.conf:<secret>

Now start the server with:

%> ./ console

This will start the server as a foreground process and you can kill it with CTRL-C. To start the server as daemon just type:

%> ./ start