Team:Freiburg software/Code/AbstractSbwServlet.java

From 2009.igem.org


org.synbiowave.servlet.AbstractSbwServlet

/*
    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);}

}