Skip to content

Commit 7dcd926

Browse files
authored
Merge pull request #34 from common-workflow-language/step-parsing-draft3
Step parsing draft-3
2 parents ad93b89 + c8fa3d0 commit 7dcd926

File tree

12 files changed

+638
-231
lines changed

12 files changed

+638
-231
lines changed

src/main/java/org/commonwl/viewer/domain/CWLCollection.java

Lines changed: 159 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ public class CWLCollection {
4040
private GitHubService githubService;
4141
private GithubDetails githubInfo;
4242

43-
private List<JsonNode> cwlDocs = new ArrayList<>();
44-
private int mainWorkflowIndex = -1;
43+
// Maps of ID to associated JSON
44+
private Map<String, JsonNode> cwlDocs = new HashMap<>();
45+
46+
// The main workflow
47+
private String mainWorkflowKey;
4548

4649
/**
4750
* Creates a new collection of CWL files from a Github repository
@@ -99,7 +102,7 @@ private void addDocs(List<RepositoryContents> repoContents) throws IOException {
99102
JsonNode cwlFile = mapper.valueToTree(reader.load(fileContent));
100103

101104
// Add document to those being considered
102-
addDoc(cwlFile);
105+
addDoc(cwlFile, repoContent.getName());
103106
}
104107
}
105108

@@ -110,17 +113,18 @@ private void addDocs(List<RepositoryContents> repoContents) throws IOException {
110113
/**
111114
* Adds a document to the group of those being parsed
112115
* @param newDoc The document to be added
116+
* @param fileName The name of the file this document has come from
113117
*/
114-
private void addDoc(JsonNode newDoc) {
118+
private void addDoc(JsonNode newDoc, String fileName) {
115119
// Make sure that this document is only one object and not multiple under a $graph directive
116120
if (newDoc.has("$graph")) {
117121
// Add each of the sub documents
118122
for (JsonNode jsonNode : newDoc.get("$graph")) {
119-
cwlDocs.add(jsonNode);
123+
cwlDocs.put(extractID(jsonNode), jsonNode);
120124
}
121125
} else {
122-
// Otherwise just add the document itself
123-
cwlDocs.add(newDoc);
126+
// Otherwise just add the document itself with ID of document name
127+
cwlDocs.put(fileName, newDoc);
124128
}
125129
}
126130

@@ -130,9 +134,9 @@ private void addDoc(JsonNode newDoc) {
130134
private void findMainWorkflow() {
131135
// Find the first workflow we come across
132136
// TODO: Consider relationship between run: parameters to better discover this
133-
for (int i=0; i < cwlDocs.size(); i++) {
134-
if (cwlDocs.get(i).get("class").asText().equals("Workflow")) {
135-
mainWorkflowIndex = 0;
137+
for (Map.Entry<String, JsonNode> doc : cwlDocs.entrySet()) {
138+
if (doc.getValue().get("class").asText().equals("Workflow")) {
139+
mainWorkflowKey = doc.getKey();
136140
return;
137141
}
138142
}
@@ -143,57 +147,95 @@ private void findMainWorkflow() {
143147
* @return A Workflow object representing the main workflow amongst the files added
144148
*/
145149
public Workflow getWorkflow() {
146-
if (mainWorkflowIndex < 0) {
150+
// Get the main workflow
151+
if (mainWorkflowKey == null) {
147152
findMainWorkflow();
148153

149154
// If it is still less than 0 there is no workflow to be found
150-
if (mainWorkflowIndex < 0) {
155+
if (mainWorkflowKey == null) {
151156
return null;
152157
}
153158
}
154-
JsonNode mainWorkflow = cwlDocs.get(mainWorkflowIndex);
155-
return new Workflow(extractLabel(mainWorkflow), extractDoc(mainWorkflow),
156-
getInputs(mainWorkflow), getOutputs(mainWorkflow));
159+
JsonNode mainWorkflow = cwlDocs.get(mainWorkflowKey);
160+
161+
// Use ID/filename for label if there is no defined one
162+
String label = extractLabel(mainWorkflow);
163+
if (label == null) {
164+
label = mainWorkflowKey;
165+
}
166+
167+
return new Workflow(label, extractDoc(mainWorkflow), getInputs(mainWorkflow),
168+
getOutputs(mainWorkflow), getSteps(mainWorkflow));
169+
}
170+
171+
/**
172+
* Get the steps for a particular document
173+
* @param cwlDoc The document to get steps for
174+
* @return A map of step IDs and details related to them
175+
*/
176+
private Map<String, CWLStep> getSteps(JsonNode cwlDoc) {
177+
if (cwlDoc != null && cwlDoc.has("steps")) {
178+
Map<String, CWLStep> returnMap = new HashMap<>();
179+
180+
JsonNode steps = cwlDoc.get("steps");
181+
if (steps.getClass() == ArrayNode.class) {
182+
// Explicit ID and other fields within each input list
183+
for (JsonNode step : steps) {
184+
CWLStep stepObject = new CWLStep(extractLabel(step), extractDoc(step),
185+
extractTypes(step), getInputs(step), getOutputs(step));
186+
returnMap.put(extractID(step), stepObject);
187+
}
188+
} else if (steps.getClass() == ObjectNode.class) {
189+
// ID is the key of each object
190+
Iterator<Map.Entry<String, JsonNode>> iterator = steps.fields();
191+
while (iterator.hasNext()) {
192+
Map.Entry<String, JsonNode> stepNode = iterator.next();
193+
JsonNode stepJson = stepNode.getValue();
194+
CWLStep stepObject = new CWLStep(extractLabel(stepJson), extractDoc(stepJson),
195+
extractTypes(stepJson), getInputs(stepJson), getOutputs(stepJson));
196+
returnMap.put(stepNode.getKey(), stepObject);
197+
}
198+
}
199+
200+
return returnMap;
201+
}
202+
return null;
157203
}
158204

159205
/**
160-
* Get a list of the inputs for a particular document
206+
* Get a the inputs for a particular document
161207
* @param cwlDoc The document to get inputs for
162208
* @return A map of input IDs and details related to them
163209
*/
164210
private Map<String, CWLElement> getInputs(JsonNode cwlDoc) {
165-
if (cwlDoc != null) {
166-
if (cwlDoc.has("inputs")) {
167-
return getInputsOutputs(cwlDoc.get("inputs"));
168-
}
211+
if (cwlDoc != null && cwlDoc.has("inputs")) {
212+
return getInputsOutputs(cwlDoc.get("inputs"));
169213
}
170214
return null;
171215
}
172216

173217
/**
174-
* Get a list of the outputs for a particular document
218+
* Get the outputs for a particular document
175219
* @param cwlDoc The document to get outputs for
176220
* @return A map of output IDs and details related to them
177221
*/
178222
private Map<String, CWLElement> getOutputs(JsonNode cwlDoc) {
179-
if (cwlDoc != null) {
180-
if (cwlDoc.has("outputs")) {
181-
return getInputsOutputs(cwlDoc.get("outputs"));
182-
}
223+
if (cwlDoc != null && cwlDoc.has("outputs")) {
224+
return getInputsOutputs(cwlDoc.get("outputs"));
183225
}
184226
return null;
185227
}
186228

187229
/**
188-
* Get a list of inputs or outputs from an inputs or outputs node
230+
* Get inputs or outputs from an inputs or outputs node
189231
* @param inputsOutputs The inputs or outputs node
190232
* @return A map of input IDs and details related to them
191233
*/
192234
private Map<String, CWLElement> getInputsOutputs(JsonNode inputsOutputs) {
193235
Map<String, CWLElement> returnMap = new HashMap<>();
194236

195237
if (inputsOutputs.getClass() == ArrayNode.class) {
196-
// Explicit ID and other fields within each input list
238+
// Explicit ID and other fields within each ilist
197239
for (JsonNode inputOutput : inputsOutputs) {
198240
String id = inputOutput.get("id").asText();
199241
returnMap.put(id, getDetails(inputOutput));
@@ -203,8 +245,7 @@ private Map<String, CWLElement> getInputsOutputs(JsonNode inputsOutputs) {
203245
Iterator<Map.Entry<String, JsonNode>> iterator = inputsOutputs.fields();
204246
while (iterator.hasNext()) {
205247
Map.Entry<String, JsonNode> inputOutputNode = iterator.next();
206-
String outputID = inputOutputNode.getKey();
207-
returnMap.put(outputID, getDetails(inputOutputNode.getValue()));
248+
returnMap.put(inputOutputNode.getKey(), getDetails(inputOutputNode.getValue()));
208249
}
209250
}
210251

@@ -224,13 +265,10 @@ private CWLElement getDetails(JsonNode inputOutput) {
224265
if (inputOutput.getClass() == TextNode.class) {
225266
details.setType(inputOutput.asText());
226267
} else {
227-
if (extractLabel(inputOutput) != null) {
228-
details.setLabel(extractLabel(inputOutput));
229-
}
230-
231-
if (extractDoc(inputOutput) != null) {
232-
details.setDoc(extractDoc(inputOutput));
233-
}
268+
details.setLabel(extractLabel(inputOutput));
269+
details.setDoc(extractDoc(inputOutput));
270+
extractOutputSource(inputOutput).forEach(details::addSourceID);
271+
details.setDefaultVal(extractDefault(inputOutput));
234272

235273
// Type is only for inputs
236274
if (inputOutput.has("type")) {
@@ -243,20 +281,103 @@ private CWLElement getDetails(JsonNode inputOutput) {
243281
return null;
244282
}
245283

284+
/**
285+
* Extract the id from a node
286+
* @param node The node to have the id extracted from
287+
* @return The string for the id of the node
288+
*/
289+
private String extractID(JsonNode node) {
290+
if (node != null && node.has("id")) {
291+
return node.get("id").asText();
292+
}
293+
return null;
294+
}
295+
246296
/**
247297
* Extract the label from a node
248298
* @param node The node to have the label extracted from
249299
* @return The string for the label of the node
250300
*/
251301
private String extractLabel(JsonNode node) {
302+
if (node != null && node.has("label")) {
303+
return node.get("label").asText();
304+
}
305+
return null;
306+
}
307+
308+
/**
309+
* Extract the default value from a node
310+
* @param node The node to have the label extracted from
311+
* @return The string for the default value of the node
312+
*/
313+
private String extractDefault(JsonNode node) {
314+
if (node != null && node.has("default")) {
315+
return node.get("default").asText();
316+
}
317+
return null;
318+
}
319+
320+
/**
321+
* Extract the source or outputSource from a node
322+
* @param node The node to have the sources extracted from
323+
* @return A list of strings for the sources
324+
*/
325+
private List<String> extractOutputSource(JsonNode node) {
252326
if (node != null) {
253-
if (node.has("label")) {
254-
return node.get("label").asText();
327+
List<String> sources = new ArrayList<String>();
328+
JsonNode sourceNode = null;
329+
330+
// outputSource and source treated the same
331+
if (node.has("outputSource")) {
332+
sourceNode = node.get("outputSource");
333+
} else if (node.has("source")) {
334+
sourceNode = node.get("source");
255335
}
336+
337+
if (sourceNode != null) {
338+
// Single source
339+
if (sourceNode.getClass() == TextNode.class) {
340+
sources.add(stepIDFromSource(sourceNode.asText()));
341+
}
342+
// Can be an array of multiple sources
343+
if (sourceNode.getClass() == ArrayNode.class) {
344+
for (JsonNode source : sourceNode) {
345+
sources.add(stepIDFromSource(source.asText()));
346+
}
347+
}
348+
}
349+
350+
return sources;
256351
}
257352
return null;
258353
}
259354

355+
/**
356+
* Gets just the step ID from source of format 'stepID/outputID'
357+
* @param source The source
358+
* @return The step ID
359+
*/
360+
private String stepIDFromSource(String source) {
361+
if (source != null) {
362+
// Strip leading # if it exists
363+
if (source.charAt(0) == '#') {
364+
source = source.substring(1);
365+
}
366+
367+
// Get segment before / (step ID)
368+
int slashSplit = source.indexOf("/");
369+
if (slashSplit != -1) {
370+
source = source.substring(0, slashSplit);
371+
} else {
372+
int dotSplit = source.indexOf(".");
373+
if (dotSplit != -1) {
374+
source = "#" + source.substring(0, dotSplit);
375+
}
376+
}
377+
}
378+
return source;
379+
}
380+
260381
/**
261382
* Extract the doc or description from a node
262383
* @param node The node to have the doc/description extracted from
@@ -330,5 +451,4 @@ private String extractTypes(JsonNode typeNode) {
330451
}
331452
return null;
332453
}
333-
334454
}

src/main/java/org/commonwl/viewer/domain/CWLElement.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,23 @@
1919

2020
package org.commonwl.viewer.domain;
2121

22+
import java.util.ArrayList;
23+
import java.util.List;
24+
2225
/**
23-
* Represents the input or output of a workflow/tool
26+
* Represents the input/output of a workflow/tool
2427
*/
2528
public class CWLElement {
2629

2730
private String label;
2831
private String doc;
2932
private String type;
33+
private List<String> sourceID;
34+
private String defaultVal;
35+
36+
public CWLElement() {
37+
this.sourceID = new ArrayList<String>();
38+
}
3039

3140
public String getLabel() {
3241
return label;
@@ -52,4 +61,21 @@ public void setType(String type) {
5261
this.type = type;
5362
}
5463

64+
public List<String> getSourceIDs() {
65+
return sourceID;
66+
}
67+
68+
public void addSourceID(String sourceID) {
69+
if (sourceID != null) {
70+
this.sourceID.add(sourceID);
71+
}
72+
}
73+
74+
public String getDefaultVal() {
75+
return defaultVal;
76+
}
77+
78+
public void setDefaultVal(String defaultVal) {
79+
this.defaultVal = defaultVal;
80+
}
5581
}

0 commit comments

Comments
 (0)