From 2009.igem.org
/*
Copyright: synbiowave
License: GPL
Authors: Jörg Wassolesk & Paul Staab
Version: 0.1
DESCRIPTION:
Make the main Servlet of your Robot extend this class instead of AbstractRobotServelt
to turn him into a SynBioWave Robot!
*/
package org.synbiowave.robot;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.synbiowave.database.DatastoreManager;
import org.synbiowave.database.Sequence;
import org.synbiowave.sequence.SequenceView;
import org.synbiowave.servlet.AbstractSynBioWaveServlet;
import com.google.wave.api.Annotation;
import com.google.wave.api.Blip;
import com.google.wave.api.Element;
import com.google.wave.api.ElementType;
import com.google.wave.api.Event;
import com.google.wave.api.EventType;
import com.google.wave.api.Gadget;
import com.google.wave.api.GadgetView;
import com.google.wave.api.Range;
import com.google.wave.api.RobotMessageBundle;
import com.google.wave.api.TextView;
import com.google.wave.api.Wavelet;
/*
* Make the main Servlet of your Robot extend this class instead of AbstractRobotServelt
* to turn him into a SynBioWave Robot!
*/
public abstract class AbstractSbwRobotServlet extends AbstractSynBioWaveServlet
{
private static final long serialVersionUID = -6809702107249455183L;
private final String gadgetURL = "http://synbiowave.svn.sourceforge.net/viewvc/synbiowave/trunk/menuGadget/menuGadget.xml";
/**
* Override this function to return the robots URL used for identification
*/
public abstract String myName();
/**
* Override this to generate the menu this robot offers
* @param menu
*/
public abstract void createMenu(MenuItem menu);
/**
* Use this instead of Google's "processEvents"-function
* @param bundle The original MessageBundle triggered by some events
*/
public abstract void processSbwEvents(RobotMessageBundle bundle);
/**
* i don't want to add own events to the google-api in pre-beta-state of wave,
* so please use this function to react on menu events.
* @param buttonLabel
* @param event
*/
public abstract void processSbwMenuEvents(String buttonLabel, LinkedHashMap<String, String> formValues , Event event);
/**
* generates a key used for identifying menu-events
*/
protected String generateKey()
{
return "ui_" + this.myName().replaceAll("@", "_").replaceAll("\\.", "_") + "_";
}
private void addMenuRobot(Wavelet wavelet)
{
if ( ! wavelet.getParticipants().contains("robotremake@appspot.com") )
{
wavelet.addParticipant("robotremake@appspot.com");
}
}
private void removeMenu(Wavelet wavelet)
{
wavelet.setDataDocument("ui.menu." + myName(), "{ }");
wavelet.setDataDocument("menu.update", "1");
}
private void generateMenu(Wavelet wavelet)
{
MenuItem ui = new MenuItem("ui","ui", generateKey());
MenuItem menu = ui.createSubItem("toolbar", "toolbar",generateKey());
createMenu(menu);
wavelet.setDataDocument("ui.menu." + myName(), ui.writeJson() );
wavelet.setDataDocument("menu.update", "1");
wavelet.appendBlip().getDocument().append("Hallo!");
}
private void listenForMenuEvents(Event event) throws Exception
{
for ( Element gadget : event.getBlip().getDocument().getElements(ElementType.GADGET) )
{
for ( Entry<String, String> entry : gadget.getProperties().entrySet() )
{
if ( entry.getKey().contains(this.generateKey()) )
{
if ( this.getEventTypeFromMenuAnswer((String)entry.getValue()).contentEquals("changeValue") )
{
this.reloadMenu(event.getBlip());
this.processSbwMenuEvents(entry.getKey(), this.getValuesFromMenuAnswer((String)entry.getValue()) , event);
}
if ( this.getEventTypeFromMenuAnswer((String)entry.getValue()).contentEquals("completed") )
{
this.reloadMenu(event.getBlip());
this.processSbwMenuEvents(entry.getKey(), null , event);
}
if ( this.getEventTypeFromMenuAnswer((String)entry.getValue()).contentEquals("execute") )
{
this.reloadMenu(event.getBlip());
this.processSbwMenuEvents(entry.getKey(), null , event);
}
}
if ( entry.getKey().contains("ui.removerobot." + this.myName()))
{
event.getWavelet().setDataDocument("menu.update", "1");
event.getWavelet().removeParticipant(this.myName());
event.getBlip().getDocument().append(this.myName() + " removed \n ");
}
}
}
}
private String getEventTypeFromMenuAnswer(String answer) throws Exception
{
answer = answer.replaceAll("'", "\"");
JSONObject obj = (JSONObject)JSONValue.parse(answer);
return (String)obj.get("event");
}
@SuppressWarnings("unchecked")
private LinkedHashMap<String, String> getValuesFromMenuAnswer(String answer) throws Exception
{
LinkedHashMap<String, String> ret = new LinkedHashMap<String, String>();
answer = answer.replaceAll("'", "\"");
JSONObject obj = (JSONObject)JSONValue.parse(answer);
if ( obj.containsKey("value") )
{
ret.putAll( (Map<String, String>)obj.get("value") );
}
return ret;
}
private void reloadMenu(Blip blip) throws Exception
{
GadgetView gv = blip.getDocument().getGadgetView();
for ( Gadget gadget : gv.getGadgets() )
{
if ( gadget.getField("url").contentEquals(this.gadgetURL) )
{
Gadget menuGadget = new Gadget(this.gadgetURL);
menuGadget.setField("ui.structure", blip.getWavelet().getDataDocument("ui.completemenu") );
gv.replace(gadget, menuGadget);
}
}
}
public void processEvents(RobotMessageBundle bundle)
{
for (Event event : bundle.getEvents())
{
try
{
if (event.getType() == EventType.WAVELET_SELF_ADDED)
{
this.generateMenu(event.getWavelet());
}
if (event.getType() == EventType.WAVELET_SELF_REMOVED)
{
this.removeMenu(event.getWavelet());
}
if (event.getType() == EventType.DOCUMENT_CHANGED &&
event.getWavelet().getDataDocument("menu.update").contains("0") )
{
this.listenForMenuEvents(event);
}
}
catch (Exception error)
{
event.getWavelet().setDataDocument("menu.update", "0");
event.getBlip().getDocument().append(" \n ERROR:" + error.getMessage() + " \n ");
}
finally
{
processSbwEvents(bundle);
}
}
}
protected void appendSimpleView(Event event,String sequence){
ArrayList<String> sequences=new ArrayList<String>();
sequences.add(sequence);
appendSimpleView(event,sequences);}
protected void appendSimpleView(Event event,ArrayList<String> sequences){
insertSimpleView(event,event.getBlip().getDocument().getText().length(),sequences);}
protected void insertSimpleView(Event event,int start,String sequence){
ArrayList<String> sequences=new ArrayList<String>();
sequences.add(sequence);
insertSimpleView(event,start,sequences);}
protected void insertSimpleView(Event event,int start,ArrayList<String> sequences){
int maxLength=0;
for(String sequence:sequences){if(sequence.length()>maxLength){maxLength=sequence.length();}}
for(int i=0;i<sequences.size();i++){
String sequence=sequences.get(i);
while(sequence.length()<maxLength){sequence+=" ";}
sequences.set(i,sequence);}
TextView tv=event.getBlip().getDocument();
int index=start;
tv.insert(index,"\n\n");
index+=2;
List<Annotation> cAnnotations=new ArrayList<Annotation>();
ArrayList<String> scales=SequenceView.getScale(maxLength);
for(String scale:scales){
cAnnotations.add(new Annotation("Scale","scale",new Range(index,index+scale.length())));
tv.insert(index,scale);
index+=scale.length();
if(maxLength>50){
for(int i=0;i<sequences.size();i++){
String sequence=sequences.get(i);
cAnnotations.addAll(SequenceView.getColor(sequence.substring(0,50),SequenceView.isSequence(sequence),index));
cAnnotations.add(new Annotation("Sequence",Integer.toString(i),new Range(index,index+52)));
tv.insert(index,sequence.substring(0,50)+"\n");
index+=51;
sequence=sequence.substring(50);
sequences.set(i,sequence);}
tv.insert(index,"\n");
index++;
maxLength-=50;}
else{
for(int i=0;i<sequences.size();i++){
String sequence=sequences.get(i);
cAnnotations.addAll(SequenceView.getColor(sequence,SequenceView.isSequence(sequence),index));
cAnnotations.add(new Annotation("Sequence",Integer.toString(i),new Range(index,index+sequence.length()+2)));
tv.insert(index,sequence+"\n");
index+=sequence.length()+1;}
tv.insert(index,"\n");
index++;}}
cAnnotations.add(new Annotation("style/fontFamily","monospace",new Range(start,index)));
cAnnotations.add(new Annotation("style/fontSize","9pt",new Range(start,index)));
cAnnotations.add(new Annotation("SimpleView","sv",new Range(start,index)));
for(Annotation a:cAnnotations){tv.setAnnotation(a.getRange(),a.getName(),a.getValue());}}
protected void replaceWithSimpleView(Event event,Range range,String sequence){
ArrayList<String> sequences=new ArrayList<String>();
sequences.add(sequence);
replaceWithSimpleView(event,range, sequences);}
protected void replaceWithSimpleView(Event event,Range range,ArrayList<String> sequences){
TextView tv=event.getBlip().getDocument();
if(range.getEnd()==tv.getText().length()){tv.append(" ");}
tv.delete(range);
insertSimpleView(event,range.getStart(),sequences);}
}