@@ -46,6 +46,33 @@ public class CWLCollection {
46
46
// The main workflow
47
47
private String mainWorkflowKey ;
48
48
49
+ // Extension of CWL files
50
+ private final String CWL_EXTENSION = "cwl" ;
51
+
52
+ // Github API specific strings
53
+ private final String DIR = "dir" ;
54
+ private final String FILE = "file" ;
55
+
56
+ // CWL specific strings
57
+ private final String DOC_GRAPH = "$graph" ;
58
+ private final String CLASS = "class" ;
59
+ private final String WORKFLOW = "Workflow" ;
60
+ private final String STEPS = "steps" ;
61
+ private final String INPUTS = "inputs" ;
62
+ private final String IN = "in" ;
63
+ private final String OUTPUTS = "outputs" ;
64
+ private final String OUT = "out" ;
65
+ private final String ID = "id" ;
66
+ private final String TYPE = "type" ;
67
+ private final String LABEL = "label" ;
68
+ private final String DEFAULT = "default" ;
69
+ private final String OUTPUT_SOURCE = "outputSource" ;
70
+ private final String SOURCE = "source" ;
71
+ private final String DOC = "doc" ;
72
+ private final String DESCRIPTION = "description" ;
73
+ private final String ARRAY = "array" ;
74
+ private final String ARRAY_ITEMS = "items" ;
75
+
49
76
/**
50
77
* Creates a new collection of CWL files from a Github repository
51
78
* @param githubService Service to provide the Github API functionality
@@ -70,7 +97,7 @@ private void addDocs(List<RepositoryContents> repoContents) throws IOException {
70
97
for (RepositoryContents repoContent : repoContents ) {
71
98
72
99
// Parse subdirectories if they exist
73
- if (repoContent .getType ().equals ("dir" )) {
100
+ if (repoContent .getType ().equals (DIR )) {
74
101
75
102
// Get the contents of the subdirectory
76
103
GithubDetails githubSubdir = new GithubDetails (githubInfo .getOwner (),
@@ -81,15 +108,15 @@ private void addDocs(List<RepositoryContents> repoContents) throws IOException {
81
108
addDocs (subdirectory );
82
109
83
110
// Otherwise this is a file so add to the bundle
84
- } else if (repoContent .getType ().equals ("file" )) {
111
+ } else if (repoContent .getType ().equals (FILE )) {
85
112
86
113
// Get the file extension
87
114
int eIndex = repoContent .getName ().lastIndexOf ('.' ) + 1 ;
88
115
if (eIndex > 0 ) {
89
116
String extension = repoContent .getName ().substring (eIndex );
90
117
91
118
// If this is a cwl file which needs to be parsed
92
- if (extension .equals ("cwl" )) {
119
+ if (extension .equals (CWL_EXTENSION )) {
93
120
94
121
// Get the content of this file from Github
95
122
GithubDetails githubFile = new GithubDetails (githubInfo .getOwner (),
@@ -117,9 +144,9 @@ private void addDocs(List<RepositoryContents> repoContents) throws IOException {
117
144
*/
118
145
private void addDoc (JsonNode newDoc , String fileName ) {
119
146
// Make sure that this document is only one object and not multiple under a $graph directive
120
- if (newDoc .has ("$graph" )) {
147
+ if (newDoc .has (DOC_GRAPH )) {
121
148
// Add each of the sub documents
122
- for (JsonNode jsonNode : newDoc .get ("$graph" )) {
149
+ for (JsonNode jsonNode : newDoc .get (DOC_GRAPH )) {
123
150
cwlDocs .put (extractID (jsonNode ), jsonNode );
124
151
}
125
152
} else {
@@ -135,7 +162,7 @@ private void findMainWorkflow() {
135
162
// Find the first workflow we come across
136
163
// TODO: Consider relationship between run: parameters to better discover this
137
164
for (Map .Entry <String , JsonNode > doc : cwlDocs .entrySet ()) {
138
- if (doc .getValue ().get ("class" ).asText ().equals ("Workflow" )) {
165
+ if (doc .getValue ().get (CLASS ).asText ().equals (WORKFLOW )) {
139
166
mainWorkflowKey = doc .getKey ();
140
167
return ;
141
168
}
@@ -174,10 +201,10 @@ public Workflow getWorkflow() {
174
201
* @return A map of step IDs and details related to them
175
202
*/
176
203
private Map <String , CWLStep > getSteps (JsonNode cwlDoc ) {
177
- if (cwlDoc != null && cwlDoc .has ("steps" )) {
204
+ if (cwlDoc != null && cwlDoc .has (STEPS )) {
178
205
Map <String , CWLStep > returnMap = new HashMap <>();
179
206
180
- JsonNode steps = cwlDoc .get ("steps" );
207
+ JsonNode steps = cwlDoc .get (STEPS );
181
208
if (steps .getClass () == ArrayNode .class ) {
182
209
// Explicit ID and other fields within each input list
183
210
for (JsonNode step : steps ) {
@@ -208,8 +235,14 @@ private Map<String, CWLStep> getSteps(JsonNode cwlDoc) {
208
235
* @return A map of input IDs and details related to them
209
236
*/
210
237
private Map <String , CWLElement > getInputs (JsonNode cwlDoc ) {
211
- if (cwlDoc != null && cwlDoc .has ("inputs" )) {
212
- return getInputsOutputs (cwlDoc .get ("inputs" ));
238
+ if (cwlDoc != null ) {
239
+ if (cwlDoc .has (INPUTS )) {
240
+ // For workflow
241
+ return getInputsOutputs (cwlDoc .get (INPUTS ));
242
+ } else if (cwlDoc .has (IN )) {
243
+ // For steps
244
+ return getInputsOutputs (cwlDoc .get (IN ));
245
+ }
213
246
}
214
247
return null ;
215
248
}
@@ -220,8 +253,14 @@ private Map<String, CWLElement> getInputs(JsonNode cwlDoc) {
220
253
* @return A map of output IDs and details related to them
221
254
*/
222
255
private Map <String , CWLElement > getOutputs (JsonNode cwlDoc ) {
223
- if (cwlDoc != null && cwlDoc .has ("outputs" )) {
224
- return getInputsOutputs (cwlDoc .get ("outputs" ));
256
+ if (cwlDoc != null ) {
257
+ if (cwlDoc .has (OUTPUTS )) {
258
+ // For workflow
259
+ return getInputsOutputs (cwlDoc .get (OUTPUTS ));
260
+ } else if (cwlDoc .has (OUT )) {
261
+ // For steps
262
+ return getInputsOutputs (cwlDoc .get (OUT ));
263
+ }
225
264
}
226
265
return null ;
227
266
}
@@ -235,9 +274,9 @@ private Map<String, CWLElement> getInputsOutputs(JsonNode inputsOutputs) {
235
274
Map <String , CWLElement > returnMap = new HashMap <>();
236
275
237
276
if (inputsOutputs .getClass () == ArrayNode .class ) {
238
- // Explicit ID and other fields within each ilist
277
+ // Explicit ID and other fields within each list
239
278
for (JsonNode inputOutput : inputsOutputs ) {
240
- String id = inputOutput .get ("id" ).asText ();
279
+ String id = inputOutput .get (ID ).asText ();
241
280
returnMap .put (id , getDetails (inputOutput ));
242
281
}
243
282
} else if (inputsOutputs .getClass () == ObjectNode .class ) {
@@ -271,8 +310,8 @@ private CWLElement getDetails(JsonNode inputOutput) {
271
310
details .setDefaultVal (extractDefault (inputOutput ));
272
311
273
312
// Type is only for inputs
274
- if (inputOutput .has ("type" )) {
275
- details .setType (extractTypes (inputOutput .get ("type" )));
313
+ if (inputOutput .has (TYPE )) {
314
+ details .setType (extractTypes (inputOutput .get (TYPE )));
276
315
}
277
316
}
278
317
@@ -287,8 +326,12 @@ private CWLElement getDetails(JsonNode inputOutput) {
287
326
* @return The string for the id of the node
288
327
*/
289
328
private String extractID (JsonNode node ) {
290
- if (node != null && node .has ("id" )) {
291
- return node .get ("id" ).asText ();
329
+ if (node != null && node .has (ID )) {
330
+ String id = node .get (ID ).asText ();
331
+ if (id .startsWith ("#" )) {
332
+ return id .substring (1 );
333
+ }
334
+ return id ;
292
335
}
293
336
return null ;
294
337
}
@@ -299,8 +342,8 @@ private String extractID(JsonNode node) {
299
342
* @return The string for the label of the node
300
343
*/
301
344
private String extractLabel (JsonNode node ) {
302
- if (node != null && node .has ("label" )) {
303
- return node .get ("label" ).asText ();
345
+ if (node != null && node .has (LABEL )) {
346
+ return node .get (LABEL ).asText ();
304
347
}
305
348
return null ;
306
349
}
@@ -311,8 +354,8 @@ private String extractLabel(JsonNode node) {
311
354
* @return The string for the default value of the node
312
355
*/
313
356
private String extractDefault (JsonNode node ) {
314
- if (node != null && node .has ("default" )) {
315
- return node .get ("default" ).asText ();
357
+ if (node != null && node .has (DEFAULT )) {
358
+ return node .get (DEFAULT ).asText ();
316
359
}
317
360
return null ;
318
361
}
@@ -328,10 +371,10 @@ private List<String> extractOutputSource(JsonNode node) {
328
371
JsonNode sourceNode = null ;
329
372
330
373
// 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" );
374
+ if (node .has (OUTPUT_SOURCE )) {
375
+ sourceNode = node .get (OUTPUT_SOURCE );
376
+ } else if (node .has (SOURCE )) {
377
+ sourceNode = node .get (SOURCE );
335
378
}
336
379
337
380
if (sourceNode != null ) {
@@ -353,7 +396,7 @@ private List<String> extractOutputSource(JsonNode node) {
353
396
}
354
397
355
398
/**
356
- * Gets just the step ID from source of format 'stepID/ outputID'
399
+ * Gets just the step ID from source of format 'stepID</ or .> outputID'
357
400
* @param source The source
358
401
* @return The step ID
359
402
*/
@@ -364,14 +407,15 @@ private String stepIDFromSource(String source) {
364
407
source = source .substring (1 );
365
408
}
366
409
367
- // Get segment before / (step ID)
410
+ // Draft 3/V1 notation is 'stepID/outputID'
368
411
int slashSplit = source .indexOf ("/" );
369
412
if (slashSplit != -1 ) {
370
413
source = source .substring (0 , slashSplit );
371
414
} else {
415
+ // Draft 2 notation was 'stepID.outputID'
372
416
int dotSplit = source .indexOf ("." );
373
417
if (dotSplit != -1 ) {
374
- source = "#" + source .substring (0 , dotSplit );
418
+ source = source .substring (0 , dotSplit );
375
419
}
376
420
}
377
421
}
@@ -385,11 +429,11 @@ private String stepIDFromSource(String source) {
385
429
*/
386
430
private String extractDoc (JsonNode node ) {
387
431
if (node != null ) {
388
- if (node .has ("doc" )) {
389
- return node .get ("doc" ).asText ();
390
- } else if (node .has ("description" )) {
432
+ if (node .has (DOC )) {
433
+ return node .get (DOC ).asText ();
434
+ } else if (node .has (DESCRIPTION )) {
391
435
// This is to support older standards of cwl which use description instead of doc
392
- return node .get ("description" ).asText ();
436
+ return node .get (DESCRIPTION ).asText ();
393
437
}
394
438
}
395
439
return null ;
@@ -422,11 +466,11 @@ private String extractTypes(JsonNode typeNode) {
422
466
}
423
467
} else if (typeNode .getClass () == ArrayNode .class ) {
424
468
// This is a verbose type with sub-fields broken down into type: and other params
425
- if (type .get ("type" ).asText ().equals ("array" )) {
426
- typeDetails .append (type .get ("items" ).asText ());
469
+ if (type .get (TYPE ).asText ().equals (ARRAY )) {
470
+ typeDetails .append (type .get (ARRAY_ITEMS ).asText ());
427
471
typeDetails .append ("[], " );
428
472
} else {
429
- typeDetails .append (type .get ("type" ).asText ());
473
+ typeDetails .append (type .get (TYPE ).asText ());
430
474
}
431
475
}
432
476
}
@@ -444,8 +488,8 @@ private String extractTypes(JsonNode typeNode) {
444
488
445
489
} else if (typeNode .getClass () == ObjectNode .class ) {
446
490
// Type: array and items:
447
- if (typeNode .has ("items" )) {
448
- return typeNode .get ("items" ).asText () + "[]" ;
491
+ if (typeNode .has (ARRAY_ITEMS )) {
492
+ return typeNode .get (ARRAY_ITEMS ).asText () + "[]" ;
449
493
}
450
494
}
451
495
}
0 commit comments