We hope you enjoyed
Invity, our group management robot for Google Wave. Now we want to reveal the code behind our robot and share our thoughts and problems with you.
At first, we developed Invity as a pure robot without any sophisticated user interface. One had to type something like "#groups.save myFriends" in a Blip to save a group. However, we quickly realized it would be cool to have a gadget that allows more comfortable user interaction. But as gadgets are not able to invite people, it was obvious to us that the robot has in some way to interact with the gadget. The reason is that the gadget has to delegate the user input to the robot and the robot has to push the info about a user's groups to the gadget.
We use the
state of the gadget to save the input of a user.
When someone clicks on "Invite!", we do the following:
var state = wave.getState();
var viewer = wave.getViewer().getId();
var value = gadgets.json.stringify({ 'action' : action, 'groupName' : groupName, 'viewer' : viewer });
state.submitValue('command', value);
On the robot side, we parse and execute the action the user specified like this:
JSONObject json = new JSONObject(command);
String action = json.getString("action");
String groupName = json.getString("groupName");
String viewer = json.getString("viewer");
if (action.equals("save")) {
saveGroup(event, groupName, viewer);
}
The saveGroup method look like this:
private void saveGroup(RobotMessageBundle bundle, String groupName, String viewer) {
PersistenceManager db = PMF.get().getPersistenceManager();
List<String> participants = bundle.getWavelet().getParticipants();
List<Group> groups = fetchGroupByName(groupName, viewer, db);
if (groups.isEmpty()) {
participants.remove("pw-invity@appspot.com");
Group group = new Group(groupName, participants, viewer);
db.makePersistent(group);
}
db.close();
}
We were quite impressed how easy and reliable this saving of groups in the Data Viewer works. However, from the robot to the gadget, the communication does not work quite that well. When we tried to display the current groups of a user in the gadget, we encountered a strange behaviour:
We use the setProperty method in the following way to save the groups of all participants of a wave in the gadget state:
String allGroups = createJSONFromGroups(participants);
gadget.setProperty("allGroups", allGroups);
We expected that this call would trigger the updateState callback as specified on the gadget side:
wave.setStateCallback(displayState);
Unfortunately, the displayState method is
not called when the robot changes the gadget state. So we had to build an ugly workaround which deletes the gadget and reinserts it after the robot commits a change:
private void reinsertGadget(RobotMessageBundle bundle) {
List<Blip> allBlips = bundle.getWavelet().getRootBlip().getChildren();
Blip gadgetBlip = deleteGadgetFromBlips(allBlips);
Gadget newGadget = new Gadget(gadgetURL);
updateGadgetState(bundle, newGadget);
gadgetBlip.getDocument().getGadgetView().append(newGadget);
}
We're not really happy with this solution, but as Google knows about this issue, we hope we can delete it soon.
Sources
You can get the full source code for the Robot and for the Gadget at
http://wave-samples-gallery.appspot.com/about_app?app_id=77015. Feel free to modify and reuse under the terms of the MIT License (
http://www.opensource.org/licenses/mit-license.php).
If you have not tried out Invity yet, just add
pw-invity@appspot.com to one of your waves.