Parse workflows and command line tools recursively
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/CWLParser.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/CWLParser.java
index 5a4d6cf..382208d 100644
--- a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/CWLParser.java
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/CWLParser.java
@@ -51,7 +51,7 @@
Map<String, Integer> inputDepths = yamlHelper.processInputDepths(cwlFile);
if(inputs == null || inputDepths == null) {
- return null;
+ return new HashSet<PortDetail>();
}
Set<PortDetail> result = new HashSet<PortDetail>();
for(String id: inputs.keySet()) {
@@ -66,14 +66,15 @@
}
public Set<PortDetail> parseOutputs() {
- Map<String, PortDetail> inputs = yamlHelper.processOutputDetails(cwlFile);
+ Map<String, PortDetail> outputs = yamlHelper.processOutputDetails(cwlFile);
- if(inputs == null) {
- return null;
+ if(outputs == null) {
+ return new HashSet<PortDetail>();
}
Set<PortDetail> result = new HashSet<PortDetail>();
- for(String id: inputs.keySet()) {
- PortDetail port = inputs.get(id);
+ for(String id: outputs.keySet()) {
+ PortDetail port = outputs.get(id);
+ port.setId(id);
result.add(port);
}
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/Converter.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/Converter.java
index 7ddf9de..b607190 100644
--- a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/Converter.java
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/Converter.java
@@ -20,6 +20,8 @@
import java.util.Set;
import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
import org.apache.taverna.scufl2.api.core.Workflow;
import org.apache.taverna.scufl2.api.core.Processor;
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/Main.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/Main.java
new file mode 100644
index 0000000..d4fa6b8
--- /dev/null
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/Main.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.taverna.scufl2.cwl;
+
+import org.yaml.snakeyaml.Yaml;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class Main {
+
+ private static final String HELLO_WORLD_CWL = "/hello_world.cwl";
+ private static final String WORKFLOW_WITH_COMMAND = "/workflow_with_command.cwl";
+ private static JsonNode cwlFile;
+
+ public static void main(String[] args) {
+
+ Yaml reader = new Yaml();
+ ObjectMapper mapper = new ObjectMapper();
+ cwlFile = mapper.valueToTree(reader.load(Main.class.getResourceAsStream(WORKFLOW_WITH_COMMAND)));
+ System.out.println(cwlFile);
+
+ Process workflow = ProcessFactory.createProcess(cwlFile);
+ workflow.parse();
+ Converter converter = new Converter();
+ JsonNode node = converter.convertWorkflowProcessToJsonNode((WorkflowProcess) workflow);
+ System.out.println("NODE");
+ System.out.println(node);
+ }
+}
\ No newline at end of file
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/WorkflowParser.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/WorkflowParser.java
index 0b6c095..b18dc54 100644
--- a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/WorkflowParser.java
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/WorkflowParser.java
@@ -43,6 +43,7 @@
import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
import org.apache.taverna.scufl2.api.port.SenderPort;
import org.apache.taverna.scufl2.api.port.ReceiverPort;
+
import org.apache.taverna.scufl2.api.container.WorkflowBundle;
import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
@@ -67,6 +68,12 @@
JsonNode cwlFile = mapper.valueToTree(reader.load(WorkflowParser.class.getResourceAsStream(FILE_NAME)));
this.cwlParser = new CWLParser(cwlFile);
this.converter = new Converter();
+ workflowInputs = new HashMap<>();
+ workflowOutputs = new HashMap<>();
+ workflowProcessors = new HashMap<>();
+ processorInputs = new HashMap<>();
+ processorOutputs = new HashMap<>();
+ dataLinks = new HashSet<DataLink>();
}
public WorkflowParser(JsonNode cwlFile) {
@@ -144,7 +151,6 @@
Processor processor = converter.convertStepToProcessor(step);
workflowProcessors.put(step.getId(), processor);
- DataLink datalink = new DataLink();
for(StepInput stepInput: step.getInputs()) {
InputProcessorPort processorPort = new InputProcessorPort(processor, stepInput.getId());
processorInputs.put(stepInput.getId(), processorPort);
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/YAMLHelper.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/YAMLHelper.java
index dacdc4f..c9b10dc 100644
--- a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/YAMLHelper.java
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/YAMLHelper.java
@@ -108,42 +108,44 @@
public Set<Step> processSteps(JsonNode file) {
Set<Step> result = new HashSet<>();
- if(file == null) {
+ if(file == null || !file.has(STEPS)) {
return result;
}
- if(file.has(STEPS)) {
- JsonNode steps = file.get(STEPS);
- if(steps.isArray()) {
- for (JsonNode stepNode : steps) {
- Step step = new Step();
- String id = stepNode.get(ID).asText();
+ JsonNode steps = file.get(STEPS);
+ if(steps.isArray()) {
+ for (JsonNode stepNode : steps) {
+ Step step = new Step();
+ String id = stepNode.get(ID).asText();
- String run = stepNode.get(RUN).asText();
- Set<StepInput> inputs = processStepInput(stepNode.get(INPUTS));
- step.setId(id);
+ JsonNode runNode = stepNode.get(RUN);
+ Process run = ProcessFactory.createProcess(runNode);
+ run.parse(); // Recursively parse nested process
+ Set<StepInput> inputs = processStepInput(stepNode.get(INPUTS));
+ step.setId(id);
+ step.setRun(run);
+ step.setInputs(inputs);
+ result.add(step);
+ }
+ } else if(steps.isObject()) {
+ Iterator<Entry<String, JsonNode>> iterator = steps.fields();
+ while(iterator.hasNext()) {
+ Entry<String, JsonNode> entry = iterator.next();
+ Step step = new Step();
+
+ String id = entry.getKey();
+ JsonNode value = entry.getValue();
+ if(value.has(RUN)) {
+ JsonNode runNode = value.get(RUN);
+ Process run = ProcessFactory.createProcess(runNode);
+ run.parse();
step.setRun(run);
- step.setInputs(inputs);
- result.add(step);
}
- } else if(steps.isObject()) {
- Iterator<Entry<String, JsonNode>> iterator = steps.fields();
- while(iterator.hasNext()) {
- Entry<String, JsonNode> entry = iterator.next();
- Step step = new Step();
+ Set<StepInput> inputs = processStepInput(value.get(INPUTS));
+ step.setId(id);
+ step.setInputs(inputs);
- String id = entry.getKey();
- JsonNode value = entry.getValue();
- if(value.has(RUN)) {
- String run = entry.getValue().get(RUN).asText();
- step.setRun(run);
- }
- Set<StepInput> inputs = processStepInput(value.get(INPUTS));
- step.setId(id);
- step.setInputs(inputs);
-
- result.add(step);
- }
+ result.add(step);
}
}
@@ -156,7 +158,7 @@
if(inputs == null) {
return result;
}
- if (inputs.getClass() == ArrayNode.class) {
+ if (inputs.isArray()) {
for (JsonNode input : inputs) {
String id = input.get(ID).asText();
@@ -164,7 +166,7 @@
result.add(new StepInput(id, source));
}
- } else if (inputs.getClass() == ObjectNode.class) {
+ } else if (inputs.isObject()) {
Iterator<Entry<String, JsonNode>> iterator = inputs.fields();
while (iterator.hasNext()) {
Entry<String, JsonNode> entry = iterator.next();
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/CommandLineTool.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/CommandLineTool.java
new file mode 100644
index 0000000..d05d38a
--- /dev/null
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/CommandLineTool.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.taverna.scufl2.cwl;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+
+public class CommandLineTool implements Process {
+
+ private final static String BASE_COMMAND = "baseCommand";
+ private final static String ID = "id";
+ private final static String INPUT_BINDINDGS = "inputBinding";
+
+ private CWLParser cwlParser;
+
+ private JsonNode node;
+
+ private String baseCommand = null;
+ private Map<String, InputProcessorPort> processorInputs;
+ private Map<String, OutputProcessorPort> processorOutputs;
+
+ public CommandLineTool(JsonNode node) {
+ this.node = node;
+ this.cwlParser = new CWLParser(node);
+ this.processorInputs = new HashMap<>();
+ this.processorOutputs = new HashMap<>();
+ this.parse();
+ this.receiverPorts = new HashSet(processorInputs.values());
+ this.senderPorts = new HashSet(processorOutputs.values());
+ }
+
+ public void parse() {
+ baseCommand = node.get(BASE_COMMAND).asText();
+ parseInputs();
+ parseOutputs();
+ }
+
+ public void parseInputs() {
+ Set<PortDetail> cwlInputs = cwlParser.parseInputs();
+ for(PortDetail detail: cwlInputs) {
+ String portId = detail.getId();
+ InputProcessorPort port = new InputProcessorPort();
+ port.setName(portId);
+ processorInputs.put(portId, port);
+ }
+ }
+
+ public void parseOutputs() {
+ Set<PortDetail> cwlOutputs = cwlParser.parseOutputs();
+ for(PortDetail detail: cwlOutputs) {
+ String portId = detail.getId();
+ OutputProcessorPort port = new OutputProcessorPort();
+ port.setName(portId);
+ processorOutputs.put(portId, port);
+ }
+ }
+}
\ No newline at end of file
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Main.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Main.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Main.java
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Process.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Process.java
new file mode 100644
index 0000000..342864a
--- /dev/null
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Process.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.taverna.scufl2.cwl;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import org.apache.taverna.scufl2.api.port.SenderPort;
+import org.apache.taverna.scufl2.api.port.ReceiverPort;
+
+public interface Process {
+
+ Set<ReceiverPort> receiverPorts;
+ Set<SenderPort> senderPorts;
+
+ public void parse();
+
+}
\ No newline at end of file
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/ProcessFactory.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/ProcessFactory.java
new file mode 100644
index 0000000..301d417
--- /dev/null
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/ProcessFactory.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.taverna.scufl2.cwl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+public class ProcessFactory {
+
+ private final static String RUN = "run";
+ private final static String CLASS = "class";
+
+ public static Process createProcess(JsonNode node) {
+
+ Process process = null;
+
+ if(node.isValueNode()) {
+ return new Reference(node.asText());
+ }
+
+ JsonNode className = node.get(CLASS);
+ if(className != null) {
+ if(className.asText().equals("Workflow")) {
+ process = new WorkflowProcess(node);
+ } else if(className.asText().equals("CommandLineTool")) {
+ process = new CommandLineTool(node);
+ }
+ } else {
+ JsonNode runNode = node.get(RUN);
+ if(runNode.isValueNode()) {
+ process = new Reference(runNode.asText());
+ } else {
+ String runClass = runNode.get(CLASS).asText();
+ switch(runClass) {
+ case "CommandLineTool":
+ process = new CommandLineTool(runNode);
+ break;
+ case "Workflow":
+ process = new WorkflowProcess(runNode);
+ break;
+ }
+ }
+ }
+
+
+ return process;
+ }
+
+}
\ No newline at end of file
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Reference.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Reference.java
new file mode 100644
index 0000000..7a25744
--- /dev/null
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Reference.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.taverna.scufl2.cwl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+public class Reference implements Process {
+
+ private String source;
+
+ public Reference() {
+ source = "";
+ }
+
+ public Reference(String src) {
+ this.source = src;
+ }
+
+ public void parse() {
+ // TODO: read source file and parse nested workflow
+ }
+
+ public String toString() {
+ return source;
+ }
+}
\ No newline at end of file
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Step.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Step.java
index 3f3d653..cdcd46e 100644
--- a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Step.java
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/Step.java
@@ -28,7 +28,7 @@
private String id;
- private String run;
+ private Process run;
private Set<StepInput> inputs;
private Set<StepOutput> outputs;
@@ -46,11 +46,11 @@
this.id = id;
}
- public String getRun() {
+ public Process getRun() {
return run;
}
- public void setRun(String run) {
+ public void setRun(Process run) {
this.run = run;
}
diff --git a/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/WorkflowProcess.java b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/WorkflowProcess.java
new file mode 100644
index 0000000..c56cbb5
--- /dev/null
+++ b/taverna-scufl2-cwl/src/main/java/org/apache/taverna/scufl2/cwl/components/WorkflowProcess.java
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.taverna.scufl2.cwl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
+
+
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.DataLink;
+import org.apache.taverna.scufl2.api.core.Workflow;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+
+import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.OutputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+import org.apache.taverna.scufl2.api.port.SenderPort;
+import org.apache.taverna.scufl2.api.port.ReceiverPort;
+
+import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
+import org.apache.taverna.scufl2.api.io.WriterException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+public class WorkflowProcess implements Process {
+
+ private CWLParser cwlParser;
+
+ private Map<String, InputWorkflowPort> workflowInputs;
+ private Map<String, OutputWorkflowPort> workflowOutputs;
+ private Map<String, Processor> workflowProcessors;
+ private Map<String, InputProcessorPort> processorInputs;
+ private Map<String, OutputProcessorPort> processorOutputs;
+ private Set<DataLink> dataLinks;
+
+ private Converter converter;
+
+ public WorkflowProcess(JsonNode node) {
+ cwlParser = new CWLParser(node);
+ converter = new Converter();
+ workflowInputs = new HashMap<>();
+ workflowOutputs = new HashMap<>();
+ workflowProcessors = new HashMap<>();
+ processorInputs = new HashMap<>();
+ processorOutputs = new HashMap<>();
+ dataLinks = new HashSet<>();
+ this.parse();
+ this.receiverPorts = new HashSet(workflowInputs.values());
+ this.senderPorts = new HashSet(workflowOutputs.values());
+ }
+
+ public void parse() {
+ parseInputs();
+ parseOutputs();
+ Set<Step> cwlSteps = cwlParser.parseSteps();
+ parseProcessors(cwlSteps);
+ parseDataLinks(cwlSteps);
+
+ Workflow workflow = new Workflow();
+ Set<InputWorkflowPort> inputs = new HashSet<>(workflowInputs.values());
+ Set<OutputWorkflowPort> outputs = new HashSet<>(workflowOutputs.values());
+ Set<Processor> processors = new HashSet<>(workflowProcessors.values());
+
+ workflow.setInputPorts(inputs);
+ workflow.setOutputPorts(outputs);
+ workflow.setProcessors(processors);
+ workflow.setDataLinks(dataLinks);
+
+// System.out.println(workflow);
+// writeWorkflowToFile(workflow);
+//
+// System.out.println("DEBUG WORKFLOW");
+// System.out.println(workflow.getInputPorts());
+// System.out.println(workflow.getOutputPorts());
+// System.out.println(workflow.getProcessors());
+
+ }
+
+ public void writeWorkflowToFile(Workflow workflow) {
+ try {
+ WorkflowBundleIO io = new WorkflowBundleIO();
+ File scufl2File = new File("workflow.wfbundle");
+ WorkflowBundle bundle = io.createBundle();
+ Set<Workflow> workflowSet = new HashSet<>();
+ workflowSet.add(workflow);
+ bundle.setWorkflows(workflowSet);
+ bundle.setMainWorkflow(workflow);
+ io.writeBundle(bundle, scufl2File, "text/vnd.taverna.scufl2.structure");
+ } catch(WriterException e) {
+ System.out.println("Exception writing the workflow bundle");
+ } catch(IOException e) {
+ System.out.println("IOException");
+ }
+ }
+
+ public void parseInputs() {
+ Set<PortDetail> cwlInputs = cwlParser.parseInputs();
+ for (PortDetail port: cwlInputs) {
+ String portId = port.getId();
+ InputWorkflowPort workflowPort = converter.convertInputWorkflowPort(port);
+ workflowInputs.put(portId, workflowPort);
+ }
+ }
+
+ public void parseOutputs() {
+ Set<PortDetail> cwlOutputs = cwlParser.parseOutputs();
+ for(PortDetail port: cwlOutputs) {
+ String portId = port.getId();
+ OutputWorkflowPort workflowPort = converter.convertOutputWorkflowPort(port);
+ workflowOutputs.put(portId, workflowPort);
+ }
+ }
+
+ public void parseProcessors(Set<Step> cwlSteps) {
+ for(Step step: cwlSteps) {
+
+ Processor processor = converter.convertStepToProcessor(step);
+ workflowProcessors.put(step.getId(), processor);
+
+ // TODO: Add only receiver and sender ports from the Process interface
+ for(StepInput stepInput: step.getInputs()) {
+ InputProcessorPort processorPort = new InputProcessorPort(processor, stepInput.getId());
+ processorInputs.put(stepInput.getId(), processorPort);
+ }
+ for(StepOutput stepOutput: step.getOutputs()) {
+ OutputProcessorPort processorPort = new OutputProcessorPort(processor, stepOutput.getId());
+ processorOutputs.put(stepOutput.getId(), processorPort);
+ }
+ }
+ }
+
+ public void parseDataLinks(Set<Step> cwlSteps) {
+ for(Step step: cwlSteps) {
+ for(StepInput stepInput: step.getInputs()) {
+ String[] sourcePath = stepInput.getSource().split("/");
+ String source = sourcePath[sourcePath.length-1];
+ source = source.replace("#", "");
+
+ DataLink dataLink = new DataLink();
+ SenderPort sender = workflowInputs.get(source);
+ if(sender == null) {
+ sender = processorOutputs.get(source);
+ }
+ if(sender == null) {
+ throw new NullPointerException("Cannot find sender port with name: " + source);
+ }
+ String receiverId = stepInput.getId();
+ ReceiverPort receiver = workflowOutputs.get(receiverId);
+ if(receiver == null) {
+ receiver = processorInputs.get(receiverId);
+ }
+ if(receiver == null) {
+ throw new NullPointerException("Cannot find receiver port with name: " + receiverId);
+ }
+ dataLink.setSendsTo(receiver);
+ dataLink.setReceivesFrom(sender);
+ dataLinks.add(dataLink);
+ }
+ }
+ }
+
+ public Map<String, InputWorkflowPort> getWorkflowInputs() {
+ return workflowInputs;
+ }
+
+ public void setWorkflowInputs(Map<String, InputWorkflowPort> workflowInputs) {
+ this.workflowInputs = workflowInputs;
+ }
+
+ public Map<String, OutputWorkflowPort> getWorkflowOutputs() {
+ return workflowOutputs;
+ }
+
+ public void setWorkflowOutputs(Map<String, OutputWorkflowPort> workflowOutputs) {
+ this.workflowOutputs = workflowOutputs;
+ }
+
+ public Map<String, Processor> getWorkflowProcessors() {
+ return workflowProcessors;
+ }
+
+ public void setWorkflowProcessors(Map<String, Processor> workflowProcessors) {
+ this.workflowProcessors = workflowProcessors;
+ }
+
+ public Map<String, InputProcessorPort> getProcessorInputs() {
+ return processorInputs;
+ }
+
+ public void setProcessorInputs(Map<String, InputProcessorPort> processorInputs) {
+ this.processorInputs = processorInputs;
+ }
+
+ public Map<String, OutputProcessorPort> getProcessorOutputs() {
+ return processorOutputs;
+ }
+
+ public void setProcessorOutputs(Map<String, OutputProcessorPort> processorOutputs) {
+ this.processorOutputs = processorOutputs;
+ }
+
+ public Set<DataLink> getDataLinks() {
+ return dataLinks;
+ }
+
+ public void setDataLinks(Set<DataLink> dataLinks) {
+ this.dataLinks = dataLinks;
+ }
+}
\ No newline at end of file
diff --git a/taverna-scufl2-cwl/src/main/resources/hello_world.cwl b/taverna-scufl2-cwl/src/main/resources/hello_world.cwl
new file mode 100644
index 0000000..4207afa
--- /dev/null
+++ b/taverna-scufl2-cwl/src/main/resources/hello_world.cwl
@@ -0,0 +1,37 @@
+#!/usr/bin/env cwl-runner
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+cwlVersion: v1.0
+class: Workflow
+
+inputs:
+ name: string
+
+outputs:
+ output1: string
+
+steps:
+ step1:
+ run: example.cwl
+
+ inputs:
+ - id: text
+ source: "#x/name"
+
+ outputs: []
diff --git a/taverna-scufl2-cwl/src/main/resources/workflow_with_command.cwl b/taverna-scufl2-cwl/src/main/resources/workflow_with_command.cwl
new file mode 100644
index 0000000..e640ecc
--- /dev/null
+++ b/taverna-scufl2-cwl/src/main/resources/workflow_with_command.cwl
@@ -0,0 +1,45 @@
+#!/usr/bin/env cwl-runner
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+cwlVersion: v1.0
+class: Workflow
+
+inputs:
+ name: string
+
+outputs: []
+
+steps:
+ step1:
+ run:
+ class: CommandLineTool
+ baseCommand: echo
+ inputs:
+ message:
+ type: string
+
+ inputBinding:
+ position: 1
+ outputs: []
+
+ inputs:
+ - id: text
+ source: "#x/name"
+
+ outputs: []
diff --git a/taverna-scufl2-cwl/src/test/java/org/apache/taverna/scufl2/cwl/TestParser.java b/taverna-scufl2-cwl/src/test/java/org/apache/taverna/scufl2/cwl/TestParser.java
index 4e3e69e..20c494c 100644
--- a/taverna-scufl2-cwl/src/test/java/org/apache/taverna/scufl2/cwl/TestParser.java
+++ b/taverna-scufl2-cwl/src/test/java/org/apache/taverna/scufl2/cwl/TestParser.java
@@ -77,15 +77,6 @@
}
@Test
- public void testParseOutputs() throws Exception {
-
- NamedSet<OutputWorkflowPort> workflowOutputs = workflow.getOutputPorts();
- NamedSet<OutputWorkflowPort> expectedOutputs = new NamedSet<>();
-
- assertEquals(expectedOutputs, workflowOutputs);
- }
-
- @Test
public void testParseProcessors() throws Exception {
workflow.setParent(null);
diff --git a/taverna-scufl2-cwl/src/test/java/org/apache/taverna/scufl2/cwl/TestWorkflowProcess.java b/taverna-scufl2-cwl/src/test/java/org/apache/taverna/scufl2/cwl/TestWorkflowProcess.java
new file mode 100644
index 0000000..015ded4
--- /dev/null
+++ b/taverna-scufl2-cwl/src/test/java/org/apache/taverna/scufl2/cwl/TestWorkflowProcess.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.taverna.scufl2.cwl;
+
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+import org.yaml.snakeyaml.Yaml;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.DataLink;
+
+import org.apache.taverna.scufl2.api.common.NamedSet;
+
+import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.OutputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+
+
+public class TestWorkflowProcess {
+ private static final String HELLO_WORLD_CWL = "/hello_world.cwl";
+ private static final String WORKFLOW_WITH_COMMAND = "/workflow_with_command.cwl";
+
+ private static JsonNode cwlFile;
+
+ public JsonNode loadYamlFile(String filename) {
+
+ Yaml reader = new Yaml();
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode node = mapper.valueToTree(reader.load(TestWorkflowProcess.class.getResourceAsStream(filename)));
+
+ return node;
+ }
+
+ @Test
+ public void testWorkflowInputs() {
+ cwlFile = loadYamlFile(HELLO_WORLD_CWL);
+ WorkflowProcess workflow = new WorkflowProcess(cwlFile);
+ workflow.parseInputs();
+
+ Map<String, InputWorkflowPort> expected = new HashMap<>();
+ InputWorkflowPort expectedInput = new InputWorkflowPort();
+ expectedInput.setName("name");
+ expected.put("name", expectedInput);
+
+ assertEquals(expected, workflow.getWorkflowInputs());
+ }
+
+ @Test
+ public void testWorkflowOutputs() {
+ cwlFile = loadYamlFile(HELLO_WORLD_CWL);
+ WorkflowProcess workflow = new WorkflowProcess(cwlFile);
+ workflow.parseOutputs();
+
+ Map<String, OutputWorkflowPort> expected = new HashMap<>();
+ OutputWorkflowPort expectedOutput = new OutputWorkflowPort();
+ expectedOutput.setName("output1");
+ expected.put("output1", expectedOutput);
+
+ assertEquals(expected, workflow.getWorkflowOutputs());
+ }
+
+ @Test
+ public void testWorkflowSteps() {
+ cwlFile = loadYamlFile(WORKFLOW_WITH_COMMAND);
+ WorkflowProcess workflow = new WorkflowProcess(cwlFile);
+
+ }
+
+}
diff --git a/taverna-scufl2-cwl/src/test/resources/hello_world.cwl b/taverna-scufl2-cwl/src/test/resources/hello_world.cwl
index 2172578..4207afa 100644
--- a/taverna-scufl2-cwl/src/test/resources/hello_world.cwl
+++ b/taverna-scufl2-cwl/src/test/resources/hello_world.cwl
@@ -23,7 +23,8 @@
inputs:
name: string
-outputs: []
+outputs:
+ output1: string
steps:
step1: