<?xml version="1.0" encoding="UTF-8"?>
<s:scufl xmlns:s="http://org.embl.ebi.escience/xscufl/0.1alpha" version="0.2" log="0">
  <s:workflowdescription lsid="urn:lsid:www.mygrid.org.uk:operation:03POCSJ1HQ5" author="Peter Li" title="Using RServe in taverna - generating a boxplot">This workflow reads a CSV file containing microarray data into R, calculates gene level frequencies and plots these as a histogram.</s:workflowdescription>
  <s:processor name="createPdf">
    <s:beanshell>
      <s:scriptvalue>import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ByteArrayOutputStream;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Image;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfWriter;
import com.lowagie.text.Element;

System.out.println("Creating PDF");

//Create document object
Document document = new Document();

ByteArrayOutputStream baos;

try
{
  //Create writer that listens to document
  //and direct PDF-stream to file
  baos = new ByteArrayOutputStream();
  PdfWriter.getInstance(document, baos);

  //Open document
  document.open();

  //Add title
  Paragraph p = new Paragraph("Output from R - Box plot of gene expression values");
  p.setAlignment(Element.ALIGN_CENTER);
  document.add(p);

  //Add images
  Image png = Image.getInstance(image);
  png.scaleAbsolute(320, 240);
  png.setAlignment(Image.MIDDLE);
  document.add(png);

  //Add summary
  Paragraph pSummary = new Paragraph(summary);
  pSummary.setAlignment(Element.ALIGN_CENTER);
  document.add(pSummary);
  
}
catch (DocumentException de)
{
  System.err.println(de.getMessage());
}
catch (IOException ioe)
{
  System.err.println(ioe.getMessage());
}

//Close document
document.close();

//String pdf = "Done!";
byte[] pdf = baos.toByteArray();</s:scriptvalue>
      <s:beanshellinputlist>
        <s:beanshellinput s:syntactictype="'image/png'">image</s:beanshellinput>
        <s:beanshellinput s:syntactictype="'text/plain'">summary</s:beanshellinput>
      </s:beanshellinputlist>
      <s:beanshelloutputlist>
        <s:beanshelloutput s:syntactictype="'application/pdf'">pdf</s:beanshelloutput>
      </s:beanshelloutputlist>
      <s:dependencies s:classloader="iteration">
        <s:jarfile>itext-2.0.1.jar</s:jarfile>
      </s:dependencies>
    </s:beanshell>
    <s:mergemode input="image" mode="merge" />
  </s:processor>
  <s:processor name="mergeMaxdOutput">
    <s:beanshell>
      <s:scriptvalue>/*
 * Merge transposed measurements output from MaxdBrowse
 */

String out = "Some output data"; //The output of this beanshell

String colName = "";
ArrayList features = new ArrayList(); 
ArrayList measurementNames = new ArrayList(); 
ArrayList listOfData = new ArrayList(); //To hold gene expn data

for(int i = 0; i &lt; in.size(); i++)
{
  String inStr = in.get(i);
  String[] lines = inStr.split("\n");
  String measurementName = lines[1];
  measurementName = measurementName.replaceAll("_Measurement", "");

  //Replace 'Normalised data' column name with proper measurement name
  inStr = inStr.replace("RMA Normalised Expression", measurementName);
  inStr = inStr.replace("Normalised data", measurementName);
  lines = inStr.split("\n");

  measurementNames.add(measurementName);

  //Get probe set identifiers from 1st dataset
  if(i == 0)
  {    
    String featureLine = lines[3];
    String[] featureItems = featureLine.split("\t");
    for(int x = 0; x &lt; featureItems.length; x++)
    {
      features.add(featureItems[x]);
    }     
  }

  String data = lines[6];  //gene exp values
  listOfData.add(data);

}

String str = listOfData.get(0);
String[] items = str.split("\t");
ArrayList joinedData = new ArrayList();
//Add first load of exp values into arraylist
for(int s = 0; s &lt; items.length; s ++)
{
  joinedData.add((String) items[s]);
}

//Concat exp values
for(int e = 1; e &lt; listOfData.size(); e++)
{
  String str = listOfData.get(e);
  String[] moreItems = str.split("\t");
  
  for(int u = 0; u &lt; moreItems.length; u++)
  {
    String joinedStr = joinedData.get(u) + "," + moreItems[u];
    joinedData.remove(u);
    joinedData.add(u, joinedStr);
  }
}

System.out.println("Size of features: " + features.size());
System.out.println("Size of joinedData: " + joinedData.size());

//Create csv
StringBuffer csvSb = new StringBuffer();
for(int y = 0; y &lt; features.size(); y ++)
{
  //Not specifying row names so create header line with one less entry than the number of columns,
  //the first column will be taken to be the row names when csv file is read in by R
  if(y == 0)  
  {
    csvSb = csvSb.append(joinedData.get(y) + "\n");
    continue;
  }

  csvSb = csvSb.append(features.get(y) + "," + joinedData.get(y) + "\n");
}

out = csvSb.toString();</s:scriptvalue>
      <s:beanshellinputlist>
        <s:beanshellinput s:syntactictype="l('text/plain')">in</s:beanshellinput>
      </s:beanshellinputlist>
      <s:beanshelloutputlist>
        <s:beanshelloutput s:syntactictype="'text/plain'">out</s:beanshelloutput>
      </s:beanshelloutputlist>
      <s:dependencies s:classloader="iteration" />
    </s:beanshell>
    <s:mergemode input="in" mode="merge" />
  </s:processor>
  <s:processor name="cleanSummary">
    <s:beanshell>
      <s:scriptvalue>import java.util.regex.*;

//Output
String out = "";

String[] lines = in.split(",");
for(int i = 0; i &lt; lines.length; i++)
{
  String line = lines[i];
  
  //Remove leading and ending square brackets
  if(line.startsWith("["))
    line = line.substring(1);
  if(line.endsWith("]"))
    line = line.substring(0, line.length() - 1);
  
  line = line.trim(); //Clean up line

  //line = line.replaceAll("   :", " :");
  //line = line.replaceAll("       ", "     ");
  //line = line.replaceAll("   ", "     ");

  out = out + line + "\n";
}</s:scriptvalue>
      <s:beanshellinputlist>
        <s:beanshellinput s:syntactictype="'text/plain'">in</s:beanshellinput>
      </s:beanshellinputlist>
      <s:beanshelloutputlist>
        <s:beanshelloutput s:syntactictype="'text/plain'">out</s:beanshelloutput>
      </s:beanshelloutputlist>
      <s:dependencies s:classloader="iteration" />
    </s:beanshell>
  </s:processor>
  <s:processor name="generateboxplot">
    <s:rshell s:hostname="" s:port="6311" s:username="" s:password="" s:keepSessionAlive="false">
      png(boxplot, width = 800, height = 600);
maxd &lt;- read.csv(file=csv,head=TRUE,sep=",");
boxplot(maxd, ylab='Gene expression level', boxwex = 0.25,
col = 'azure2');

s &lt;- summary(maxd);
t &lt;- t(s);

summary &lt;- capture.output(t);

dev.off();
      <s:rshellInputPortList>
        <s:rshellInputPort s:syntacticType="'text/plain'" s:symanticType="TEXT_FILE">csv</s:rshellInputPort>
      </s:rshellInputPortList>
      <s:rshellOutputPortList>
        <s:rshellOutputPort s:syntacticType="'image/png'" s:symanticType="PNG_FILE">boxplot</s:rshellOutputPort>
        <s:rshellOutputPort s:syntacticType="'text/plain'" s:symanticType="STRING">summary</s:rshellOutputPort>
      </s:rshellOutputPortList>
    </s:rshell>
  </s:processor>
  <s:processor name="flattenList">
    <s:local>
      org.embl.ebi.escience.scuflworkers.java.FlattenList
      <s:extensions>
        <s:flattenlist s:depth="3" />
      </s:extensions>
    </s:local>
  </s:processor>
  <s:processor name="SelectWorker">
    <s:beanshell>
      <s:scriptvalue>/**
 * Class representing the selected values of this beanshell processor
 */
class SelectedValues
{
  ArrayList selectedValues;

  SelectedValues()
  {
    selectedValues = new ArrayList();
  }

  synchronized void addToValues(ArrayList values)
  {
    for(int i = 0; i &lt; values.size(); i ++)
      selectedValues.add(values.get(i));

    notifyAll();
  }

  synchronized ArrayList getValues()
  {
    while (selectedValues.size() == 0)
    {
      try
      {
        wait();
      }
      catch (InterruptedException e)
      {
        e.printStackTrace();
      }
    }

    return selectedValues;
  }
}

/**
 * Class representing the GUI for selecting the values to be
 * processed by the remainder of the workflow.
 */
MultipleSelectWorkerGUI(ArrayList input, SelectedValues values)
{
  JList list;
  DefaultListModel listModel;
  final String submitString = "Submit";
  JButton submitButton;
  int[] accessions;
  SelectedValues selectedValues;
  ArrayList inputdata;
  

  void init()
  {
    super.frame = new JFrame("Select data to be analysed");
    pane = new JPanel(); 
    super.frame.getContentPane().add(pane); 
    pane.setLayout(new BorderLayout()); 

    // Set up input data available for selection
    listModel = new DefaultListModel();
    for (int i = 0; i &lt; input.size(); i++)
      listModel.addElement(input.get(i));
    
    selectedValues = values;

    //Create the list and put it in a scroll pane
    list = new JList(listModel);
    list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    list.setSelectedIndex(0);
    list.addListSelectionListener(this);
    list.setVisibleRowCount(10);
    list.setSize(800,500);
    list.setFixedCellHeight(20);

    JScrollPane listScrollPane = new JScrollPane(list);

    submitButton = new JButton(submitString);
    submitButton.setActionCommand(submitString);
    submitButton.addActionListener(this);

    //Create a panel
    JPanel buttonPane = new JPanel();
    buttonPane.add(submitButton);
    buttonPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

    pane.add(listScrollPane, BorderLayout.CENTER);
    pane.add(buttonPane, BorderLayout.PAGE_END);

    frame.setVisible(true); 
    frame.pack(); 
  }

  //This method is required by ListSelectionListener.
  void valueChanged(ListSelectionEvent e)
  {
    if (!e.getValueIsAdjusting())
    {
      if (list.getSelectedIndex() == -1)
      {
        //No selection so disable fire button
        submitButton.setEnabled(false);
      }
      else
      {
        //Selection made so enable the fire button.
        submitButton.setEnabled(true);
      }
    }

  }

  // This method is called only if there is a valid selection
  void actionPerformed(ActionEvent e)
  {
    ArrayList al = new ArrayList();

    if (list.getSelectedIndices().length == 0)
    {
      // Nothing selected so disable firing
      submitButton.setEnabled(false);
    }
    else
    {
      accessions = list.getSelectedIndices();
      System.out.println(accessions);
      
      for(int i = 0; i &lt; accessions.length; i++)
      {
        String str = listModel.elementAt(accessions[i]);
        System.out.println(str);
        //String[] strArray = str.split(": ");
        al.add(str);
      }
      
      selectedValues.addToValues(al);
      super.frame.dispose();

    }
  }

  init(); 
  return this; 
}

/**
 * Wrapper for MultipleSelectWorkerGUI
 */ 
class WorkerWrapper extends Thread
{
  SelectedValues selectedValues;
  ArrayList inputdata;

  WorkerWrapper(ArrayList input, SelectedValues v)
  {
    inputdata = input;
    selectedValues = v;
  }

  void run()
  {
    msw = MultipleSelectWorkerGUI(inputdata, selectedValues);
  }
}


sv = new SelectedValues();
wrapper = new WorkerWrapper(input, sv);
wrapper.start();
output = sv.getValues();</s:scriptvalue>
      <s:beanshellinputlist>
        <s:beanshellinput s:syntactictype="l('text/plain')">input</s:beanshellinput>
      </s:beanshellinputlist>
      <s:beanshelloutputlist>
        <s:beanshelloutput s:syntactictype="l('text/plain')">output</s:beanshelloutput>
      </s:beanshelloutputlist>
      <s:dependencies s:classloader="iteration" />
    </s:beanshell>
  </s:processor>
  <s:processor name="XPath_getNames">
    <s:defaults>
      <s:default name="xpath">/entries/browse/Measurement/@Name</s:default>
    </s:defaults>
    <s:local>net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker</s:local>
  </s:processor>
  <s:processor name="queryMaxdTransposed">
    <s:description>Will take a list of Gene names, a list of Measurement names and a list of Column Types and produce a table. All values are coloured in relation to the a reference. In the list of Measurement names, the first Measurement listed is taken to be the reference. Formatted as text.</s:description>
    <s:defaults>
      <s:default name="ColumnTypes">*</s:default>
      <s:default name="listSplitter">,</s:default>
      <s:default name="profileANDppass">ProfilePasswordRequired</s:default>
    </s:defaults>
    <s:arbitrarywsdl>
      <s:wsdl>http://dbkgroup.org/software/maxd/maxdBrowse/sequences/MeasurementDataTabTextFASTTransposed/wsdl.xml</s:wsdl>
      <s:operation>query</s:operation>
    </s:arbitrarywsdl>
  </s:processor>
  <s:processor name="GetAllMeasurementNames">
    <s:description>Displays the measurement names for a database.</s:description>
    <s:defaults>
      <s:default name="MeasurementNames">*</s:default>
      <s:default name="listSplitter">,</s:default>
      <s:default name="profileANDppass">BigExN:9dj2n5g7l</s:default>
    </s:defaults>
    <s:arbitrarywsdl>
      <s:wsdl>http://dbkgroup.org/software/maxd/maxdBrowse/sequences/GetAllMeasurementNames/wsdl.xml</s:wsdl>
      <s:operation>query</s:operation>
    </s:arbitrarywsdl>
  </s:processor>
  <s:link source="GetAllMeasurementNames:return" sink="XPath_getNames:xml-text" />
  <s:link source="SelectWorker:output" sink="queryMaxdTransposed:MeasurementNames" />
  <s:link source="XPath_getNames:nodelist" sink="SelectWorker:input" />
  <s:link source="cleanSummary:out" sink="createPdf:summary" />
  <s:link source="createPdf:pdf" sink="flattenList:inputlist" />
  <s:link source="flattenList:outputlist" sink="pdf" />
  <s:link source="generateboxplot:boxplot" sink="createPdf:image" />
  <s:link source="generateboxplot:summary" sink="cleanSummary:in" />
  <s:link source="mergeMaxdOutput:out" sink="generateboxplot:csv" />
  <s:link source="queryMaxdTransposed:return" sink="mergeMaxdOutput:in" />
  <s:sink name="pdf">
    <s:metadata>
      <s:mimeTypes>
        <s:mimeType>application/pdf</s:mimeType>
      </s:mimeTypes>
    </s:metadata>
  </s:sink>
</s:scufl>

