package LONI.visitor;
import java.util.*;
import org.apache.commons.lang3.StringEscapeUtils;
import CLInterface.ConverterConstants;
import CLInterface.Printer;
import Core.Pair;
import Galaxy.Tree.Tool.Tool;
import Galaxy.Tree.Tool.Input.Input;
import Galaxy.Tree.Tool.Input.Param.Option;
import Galaxy.Tree.Tool.Output.Data;
import Galaxy.Tree.Workflow.ExternalOutput;
import Galaxy.Tree.Workflow.InputConnection;
import Galaxy.Tree.Workflow.Position;
import Galaxy.Tree.Workflow.Step;
import Galaxy.Tree.Workflow.Workflow;
import Galaxy.Tree.Workflow.ToolState.Primitive;
import Galaxy.Tree.Workflow.ToolState.PrimitiveOrMap;
import Galaxy.Visitor.DFSWorkflowVisitor.StepVisitor;
import Galaxy.Visitor.util.Context;
import LONI.tree.workflow.Connection;
import LONI.tree.workflow.Connections;
import LONI.tree.module.Output;
import LONI.tree.module.Parameter;
import LONI.tree.module.Value;
import LONI.tree.module.format.FileType;
import LONI.tree.workflow.Pipeline;
import LONI.tree.GraphObject.DataModule;
import LONI.tree.GraphObject.GraphObject;
import LONI.tree.GraphObject.Module;
import LONI.tree.GraphObject.ModuleGroup;
import LONI.visitor.util.GalaxyContext;
import Specification.GalaxySpecification;
public class LoniToGalaxyConverter extends DFSVisitor<Object,GalaxyContext> {
private static int NODE_COUNT = 0;
public static int getId() {
return NODE_COUNT++; /* whoa, using post-decrement properly in java! */
}
/**
* Convert a Pipeline to a Galaxy Workflow
*/
public Object visit(Pipeline pipeline) {
Workflow workflow;
ModuleGroup mgroup = pipeline.getPipelineModuleGroup();
Connections conns = pipeline.getConnections();
GalaxyContext context= new GalaxyContext();
context.getDatabase().clear();
NODE_COUNT = 0;
//convert the module group
Pair<List<Step>, Object> mystp = moduleVisitor.visit(mgroup, context);
/* Visit connections */
List<Pair<Pair<Integer,String>, InputConnection>> connlist;
connlist = (List<Pair<Pair<Integer,String>, InputConnection>>) visit(conns, context).getElem1();
/* Add resulting connections */
for(Pair<Pair<Integer,String>, InputConnection> myconn : connlist){
for(Step mystep : mystp.getElem1()){
if(mystep.getId() == myconn.getElem1().getElem1().intValue()){
mystep.getConnections().put(
myconn.getElem1().getElem2(), myconn.getElem2());
}
}
}
//create workflow from modulegroup, connections
workflow = new Workflow(mgroup.getName(),
mgroup.getDescription(),
pipeline.getVersion(),
true);
//add steps retrieved from visiting modulegroup.
for(Step s : mystp.getElem1())
workflow.addStep(s.getId(), s);
return workflow;
}
/*
* Convert a connection to an InputConnection and sink string.
*/
public Pair<Object,Object> visit(Connection connection, GalaxyContext context){
List<Pair<Integer,String>> src = context.getDatabase().getGalaxyMapping(connection.getSource());
List<Pair<Integer,String>> snk = context.getDatabase().getGalaxyMapping(connection.getSink());
List<Pair<Pair<Integer,String>,InputConnection>>result = new LinkedList<Pair<Pair<Integer,String>,InputConnection>>();
//if there are no mappings for either the source or sink, don't do anything.
if(src == null || snk == null){
Printer.log("No ID mappings found");
return new Pair<Object,Object>(result, null);
}
//if there are an uneven amount of source mappings to sink mappings.
if( src.size() != snk.size()){
Printer.log("Connection nodes do not have matching cardinalities");
return new Pair<Object,Object>(result, null);
}
//If the mappings are empty for either source or sink
if(src.size() == 0 || snk.size() == 0){
Printer.log("No entries");
return new Pair<Object,Object>(result, null);
}
//create InputConnection, sink pairs from src, snk mappings.
for(int i=0; i < src.size(); i++){
InputConnection inputConn = new InputConnection();
inputConn.setSourceId(src.get(i).getElem1());
inputConn.setOutputName(src.get(i).getElem2());
result.add(new Pair<Pair<Integer,String>,InputConnection>(snk.get(i), inputConn));
}
return new Pair<Object,Object>(result, null);
}
public Pair<Object,Object> visit(Connections connections, GalaxyContext o){
List<Pair<Pair<Integer,String>, InputConnection>> conns;
conns = new LinkedList<Pair<Pair<Integer,String>, InputConnection>>();
//visit each connection in the connections object
if(connections != null && connections.getConnections()!=null){
for(Connection connection : connections.getConnections()){
Pair<Object,Object> obj = visit(connection, o);
if(obj != null)
conns.addAll((List<Pair<Pair<Integer,String>,InputConnection>>)obj.getElem1());
}
}
//return the aggregation of returned objects.
return new Pair<Object,Object>(conns, null);
}
{
moduleVisitor = new ModuleVisitor<List<Step>>(){
public String nameToCardinalityName(String name, int num){
return name + "_CARD" + num;
}
// convert modulegroup to list of steps.
public Pair<List<Step>,Object> visit(ModuleGroup moduleGroup, GalaxyContext o){
List<Step> step = new ArrayList<Step>();
//visit each graphobject in module group.
for(GraphObject graphObject: moduleGroup.getModules()){
Pair<List<Step>, Object> obj = visit(graphObject, o);
step.addAll(obj.getElem1());
}
//return list of steps.
return new Pair<List<Step>, Object>(step, null);
}
//Double Dispatch: use polymorphism to call most specific visitor.
public Pair<List<Step>,Object> visit(GraphObject graphObject, GalaxyContext context) {
// TODO Auto-generated method stub
return graphObject.accept(this, context);
}
//Convert module to list of steps.
public Pair<List<Step>,Object> visit(Module module, GalaxyContext parentContext) {
List<Step> steps = new ArrayList<Step>();
Step step = new Step();
//get unique id from tooldatabase
String toolId = GalaxySpecification.getDatabase().getUniqueToolID(module.getId());
//create child context from parent context.
GalaxyContext childContext = parentContext.copy();
//set basic information
if(module.getDescription() != null)
step.setAnnotation(module.getDescription());
step.setId(getId());
step.setToolType("tool");
step.setName(module.getName());
step.setStepPosition(new Position(module.getPosX(), module.getPosY()));
step.setToolId(toolId);
//add tool state __page__ tag.
step.getToolState().getToolState().getSecond().put
("__page__", new PrimitiveOrMap(new Primitive("0")));
//set step id of child context. All visits using this context may
//refer to this step id.
childContext.setParentStepId(step.getId());
//create a new tool
Tool tool = new Tool();
tool.setId(toolId);
tool.setFullName(module.getId());
tool.setDescription(module.getDescription());
tool.setVersion("1.0.0");
//map self
//create a galaxy id-toolid-name association with loni id.
childContext.getDatabase().addMapping
(module.getName(), step.getId(), tool.getId());
/*
* Process high cardinality inputs:
* Turn them into multiple outputs
*/
List<Parameter> processed_in = new LinkedList<Parameter>();
if(module.getInputs() != null){
for(Parameter p : module.getInputs()){
int cardinality = p.getFormat().getCardinality();
if(cardinality > 1){
for(int i=0; i<cardinality; i++){
Parameter p_tmp = p.copy();
p_tmp.setId(nameToCardinalityName(p.getId(),i));
p_tmp.setName(nameToCardinalityName(p.getName(),i));
p_tmp.getFileFormat().setCardinality(1);
if(p.isPrefixAllArgs()==false &&
i>0){
p_tmp.setPrefix("");
p_tmp.setPrefixSpaced(false);
}
//If the values object is large enough
if(p.getValues() != null &&
p.getValues().getValues().size() > i){
Value singleVal = p.getValues().getValues().get(i);
p_tmp.getValues().clearValues();
p_tmp.getValues().addValue(singleVal);
}
childContext.getDatabase().addMapping(p.getId(), p_tmp.getId(), null, null);
processed_in.add(p_tmp);
}
}
else if(cardinality < 0){
Printer.log("Infinite Cardinalities not supported.");
p.getFileFormat().setCardinality(1);
processed_in.add(p);
}
else if(cardinality == 0){
Printer.log("Warning: Cardinality zero found.");
p.getFileFormat().setCardinality(1);
processed_in.add(p);
}
else{
processed_in.add(p);
}
}
module.getInputs().clear();
module.getInputs().addAll(processed_in);
}
//continued: Handle high cardinality i/o
List<Output> processed_out = new LinkedList<Output>();
if(module.getOutputs() != null){
for(Output o : module.getOutputs()){
int cardinality = o.getFormat().getCardinality();
if(cardinality > 1){
for(int i=0; i<cardinality; i++){
Output o_tmp = o.copy();
o_tmp.setId(nameToCardinalityName(o.getId(),i));
o_tmp.setName(nameToCardinalityName(o.getName(),i));
o_tmp.getFormat().setCardinality(1);
if(o.getPrefixAllArgs() != null &&
o.getPrefixAllArgs().equals(false)&&
i > 0){
o_tmp.setPrefix("");
o_tmp.setPrefixSpaced(false);
//l
}
childContext.getDatabase().addMapping(o.getId(), o_tmp.getId(), null, null);
processed_out.add(o_tmp);
//get the name
String src = o.getName();
List<String> sources = childContext.getConnections().getSources(src);
if(sources != null){
childContext.getConnections().removeConnectionsToSink(src);
for(String source : sources){
childContext.getConnections().addContext(source, o_tmp.getName());
}
}
}
}
else
processed_out.add(o);
}
module.getOutputs().clear();
module.getOutputs().addAll(processed_out);
}
String command_str;
/*
* Process localhost command
*
*/
command_str = module.getLocation();
if(command_str.startsWith(ConverterConstants.LOCALHOST_PATH))
command_str= command_str.replace(ConverterConstants.LOCALHOST_PATH, "");
else if(command_str.startsWith(ConverterConstants.PIPELINE_PATH))
command_str.replace(ConverterConstants.PIPELINE_PATH, "");
Map<Integer, List<Pair<String,String>>> commandStack = new HashMap<Integer, List<Pair<String,String>>>();
/*
* Construct command
*
*/
if(module.getInputs() != null){
for(Parameter p : module.getInputs()){
Pair<Pair<Object,Object>,Object> ob = propertyVisitor.visit(p, childContext);
Pair<String,String> state = (Pair<String,String>) ob.getElem1().getElem1();
Galaxy.Tree.Tool.Input.Param.Parameter input = (Galaxy.Tree.Tool.Input.Param.Parameter) ob.getElem1().getElem2();
String prefix = "";
if(p.getPrefix() != null)
prefix = p.getPrefix();
if(p.isPrefixSpaced())
prefix += " ";
String arg = "$"+input.getName();
//Add parameter to command stack
if(!commandStack.containsKey(p.getOrder()))
commandStack.put(p.getOrder(), new ArrayList<Pair<String,String>>());
commandStack.get(p.getOrder()).add(new Pair(prefix, arg));
step.getToolState().addState(state.getElem1(), input.getFormat() == null || input.getFormat().equals("") ? "\"" + StringEscapeUtils.escapeJava(state.getElem2()) + "\"" : state.getElem2());
tool.getToolInputs().getInputList().add(input);
}
}
if(module.getOutputs() != null){
for(Output out : module.getOutputs()){
Pair<Object,Object> ob = propertyVisitor.visit(out, childContext);
Pair<ExternalOutput,Data> datapair= (Pair<ExternalOutput,Data>) ob.getElem1();
String prefix = "";
if(out.getPrefix() != null)
prefix = out.getPrefix();
if(out.getPrefixSpaced() != null &&
out.getPrefixSpaced()==true)
prefix += " ";
String arg = "$"+datapair.getElem2().getName();
//Add parameter to command stack
if(!commandStack.containsKey(out.getOrder()))
commandStack.put(out.getOrder(), new ArrayList<Pair<String,String>>());
commandStack.get(out.getOrder()).add(new Pair(prefix, arg));
step.getExternalOutputs().add(datapair.getElem1());
tool.getToolOutputs().getOutputs().add(datapair.getElem2());
}
}
for(Integer currPos = 0; commandStack.containsKey(currPos); currPos++){
for(Pair<String,String> elem : commandStack.get(currPos)){
command_str += " " + elem.getElem1()+elem.getElem2();
}
}
//finished creating command
Galaxy.Tree.Tool.Command.Command command = new Galaxy.Tree.Tool.Command.Command();
command.setCommand(command_str);
tool.setToolCommand(command);
//Step step = new Step(getId(), module.getName(), module.getDescription(), module.getId(), module.getVersion(),"", "tool", new Position(module.getPosX(), module.getPosY()));
//add tool to database
String pkg =module.getPackage();
if(pkg == null)
pkg = "default";
GalaxySpecification.getDatabase().addTool(pkg, tool);
steps.add(step);
return new Pair<List<Step>,Object>(steps,null);
}
public Pair<List<Step>,Object> visit(DataModule dataModule, GalaxyContext parentContext) {
List<Step> steps = new ArrayList<Step>();
GalaxyContext childContext = parentContext.copy();
if(dataModule.isDirSource() || dataModule.isDirDump()){
Printer.log("Directory Data Modules not Supported.");
return null;
}
//do not process sinks
if(dataModule.isSource() == false ){
Printer.log("Sink Discarded.");
return new Pair<List<Step>,Object>(steps, null);
}
//spawn several inputs if the datamodule has a cardinality greater than 1
if(dataModule.getValues() != null){
int num_entries = dataModule.getValues().getValues().size();
if(num_entries > 1){
String parentId = dataModule.getId();
String outputId = dataModule.getOutputs().get(0).getId();
for(int i=0 ; i < num_entries; i++){
DataModule childData = dataModule.copy();
String childId = nameToCardinalityName(parentId, i);
String childOutputId = nameToCardinalityName(outputId, i);
//change childDataID
childData.setId(childId);
childData.getValues().clearValues();
childData.getOutputs().get(0).setId(childOutputId);
parentContext.getDatabase().addMapping(parentId, childId, null, null);
parentContext.getDatabase().addMapping(outputId, childOutputId, null, null);
Pair<List<Step>,Object> galDataModule = visit(childData, parentContext);
steps.addAll(galDataModule.getElem1());
}
return new Pair<List<Step>, Object>(steps, null);
}
}
//Step step = new Step(getId(), dataModule.getName(), dataModule.getDescription(), dataModule.getId(), dataModule.getVersion(), "", "tool", new Position(dataModule.getPosX(), dataModule.getPosY()));
Step step = new Step();
if(dataModule.isSource() || dataModule.isDirSource()){
step.setId(getId());
step.setName(dataModule.getName());
if(dataModule.getDescription() != null)
step.setAnnotation(dataModule.getDescription());
step.setToolType("data_input");
step.setStepPosition(new Position(dataModule.getPosX(), dataModule.getPosY()));
step.setToolVersion(dataModule.getVersion());
//step.setToolState("");
step.getToolState().getToolState().getSecond().put
("input", new PrimitiveOrMap(new Primitive("null")));
step.getToolState().getToolState().getSecond().put
("__page__", new PrimitiveOrMap(new Primitive("0")));
childContext.setParentStepId(step.getId());
steps.add(step);
}
if(dataModule.getInputs() != null){
for(Parameter p : dataModule.getInputs()){
Pair<Pair<Object,Object>, Object> ob;
//get the incoming connections into a module
//visit the parameter
ob = propertyVisitor.visit(p, childContext);
Input in = (Input) ob.getElem1().getElem2();
Pair<String,String> statepair = (Pair<String,String>) ob.getElem1().getElem1();
//update tool, step information
step.getToolState().addState(statepair.getElem1(), statepair.getElem2());
}
}
if(dataModule.getOutputs() != null){
for(Output o: dataModule.getOutputs()){
Pair<Object, Object> ob;
ob = propertyVisitor.visit(o, childContext);
Pair<ExternalOutput,Data> datapair= (Pair<ExternalOutput,Data>) ob.getElem1();
childContext.getDatabase().addMapping(o.getId(), step.getId(), "output");
datapair.getElem1().setName("output");
step.getExternalOutputs().add(datapair.getElem1());
}
}
return new Pair<List<Step>,Object>(steps, null);
}
};
}
{
propertyVisitor = new PropertyVisitor<Pair<Object,Object>>(){
public String sanitizeName(String name){
name = name.replaceAll(" ", "");
return name;
}
public <T> String commaDelimited(List<T> list){
String commadelim="";
int token_count = 1;
for(Object l : list){
commadelim += l.toString();
if(token_count < list.size())
commadelim += ",";
token_count++;
}
return commadelim;
}
public Pair<Pair<Object,Object>, Object> visit(Parameter parameter, GalaxyContext context){
Galaxy.Tree.Tool.Input.Param.Parameter param = new Galaxy.Tree.Tool.Input.Param.Parameter();
param.setName(sanitizeName(parameter.getName()));
param.setLabel(parameter.getName()+":"+parameter.getDescription());
param.setOptional((parameter.isRequired()==false));
String loniType = parameter.getFormat().getType();
String mytype;
//Determine type of parameter
if(loniType.equals("File"))
mytype= "data";
else if(loniType.equals("String"))
mytype = "text";
else if(loniType.equals("Number"))
mytype = "integer";
else if(loniType.equals("Enumerated")){
mytype = "select";
}
else
mytype = "unknown";
param.setType(mytype);
//If we have an enumeration, compile list
if(mytype.equals("select") &&
parameter.getFormat().getEnumerations() != null){
for(String e : parameter.getFormat().getEnumerations()){
Option opt = new Option();
opt.setValue(e);
opt.setContents(e);
param.getOptionList().add(opt);
}
}
if(mytype.equals("integer")){
param.setValue("0");
param.setSize("4");
}
//Determine format
if(parameter.getFormat().getFileTypes() != null){
String formatString="";
List<FileType> fileTypes = parameter.getFormat().getFileTypes().getFileTypes();
for(FileType ft : fileTypes){
formatString += "," + ft.getName();
}
if(formatString.length() > 0)
formatString = formatString.substring(1);
param.setFormat(formatString);
}
//map this id to the galaxy id
context.getDatabase().addMapping(
parameter.getId(),
context.getParentStepId(),
param.getName());
//String fformat= parameter.getFileFormat().getType();
//param.setFormat(fformat);
Pair<String,String> statepair;
if(mytype.equals("data")){
statepair = new Pair<String,String>(param.getName(),"null");
}
else{
String value = "null";
if(parameter.getValues()!= null &&
parameter.getValues().getValues().isEmpty() == false)
value= parameter.getValues().getValues().get(0).getValue().toString();
statepair = new Pair<String,String>(param.getName(), value);
}
Pair<Object,Object> toolStepPair;
toolStepPair= new Pair<Object,Object>(statepair, param);
return new Pair<Pair<Object,Object>, Object>(toolStepPair, null);
}
public Pair<Pair<Object,Object>, Object> visit(Output parameter, GalaxyContext context){
Data toolData = new Data();
toolData.setName(sanitizeName(parameter.getName()));
toolData.setLabel(parameter.getDescription());
//Create the external output
ExternalOutput ep = new ExternalOutput();
ep.setName(toolData.getName());
String mytype;
String type = parameter.getFormat().getType();
if(type.equals("File"))
mytype = "data";
else
mytype = "unknown";
ep.setType(mytype);
if(parameter.getFormat().getFileTypes() != null){
String formatString="";
List<FileType> fileTypes = parameter.getFormat().getFileTypes().getFileTypes();
for(FileType ft : fileTypes){
formatString += "," + ft.getName();
}
formatString = formatString.substring(1);
toolData.setFormat(formatString);
}
context.getDatabase().addMapping(parameter.getId(), context.getParentStepId(), toolData.getName());
return new Pair(new Pair<ExternalOutput, Data>(ep,toolData), null);
}
};
}
}