@@ -40,8 +40,11 @@ public class CWLCollection {
40
40
private GitHubService githubService ;
41
41
private GithubDetails githubInfo ;
42
42
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 ;
45
48
46
49
/**
47
50
* Creates a new collection of CWL files from a Github repository
@@ -99,7 +102,7 @@ private void addDocs(List<RepositoryContents> repoContents) throws IOException {
99
102
JsonNode cwlFile = mapper .valueToTree (reader .load (fileContent ));
100
103
101
104
// Add document to those being considered
102
- addDoc (cwlFile );
105
+ addDoc (cwlFile , repoContent . getName () );
103
106
}
104
107
}
105
108
@@ -110,17 +113,18 @@ private void addDocs(List<RepositoryContents> repoContents) throws IOException {
110
113
/**
111
114
* Adds a document to the group of those being parsed
112
115
* @param newDoc The document to be added
116
+ * @param fileName The name of the file this document has come from
113
117
*/
114
- private void addDoc (JsonNode newDoc ) {
118
+ private void addDoc (JsonNode newDoc , String fileName ) {
115
119
// Make sure that this document is only one object and not multiple under a $graph directive
116
120
if (newDoc .has ("$graph" )) {
117
121
// Add each of the sub documents
118
122
for (JsonNode jsonNode : newDoc .get ("$graph" )) {
119
- cwlDocs .add ( jsonNode );
123
+ cwlDocs .put ( extractID ( jsonNode ), jsonNode );
120
124
}
121
125
} 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 );
124
128
}
125
129
}
126
130
@@ -130,9 +134,9 @@ private void addDoc(JsonNode newDoc) {
130
134
private void findMainWorkflow () {
131
135
// Find the first workflow we come across
132
136
// 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 () ;
136
140
return ;
137
141
}
138
142
}
@@ -143,57 +147,95 @@ private void findMainWorkflow() {
143
147
* @return A Workflow object representing the main workflow amongst the files added
144
148
*/
145
149
public Workflow getWorkflow () {
146
- if (mainWorkflowIndex < 0 ) {
150
+ // Get the main workflow
151
+ if (mainWorkflowKey == null ) {
147
152
findMainWorkflow ();
148
153
149
154
// If it is still less than 0 there is no workflow to be found
150
- if (mainWorkflowIndex < 0 ) {
155
+ if (mainWorkflowKey == null ) {
151
156
return null ;
152
157
}
153
158
}
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 ;
157
203
}
158
204
159
205
/**
160
- * Get a list of the inputs for a particular document
206
+ * Get a the inputs for a particular document
161
207
* @param cwlDoc The document to get inputs for
162
208
* @return A map of input IDs and details related to them
163
209
*/
164
210
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" ));
169
213
}
170
214
return null ;
171
215
}
172
216
173
217
/**
174
- * Get a list of the outputs for a particular document
218
+ * Get the outputs for a particular document
175
219
* @param cwlDoc The document to get outputs for
176
220
* @return A map of output IDs and details related to them
177
221
*/
178
222
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" ));
183
225
}
184
226
return null ;
185
227
}
186
228
187
229
/**
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
189
231
* @param inputsOutputs The inputs or outputs node
190
232
* @return A map of input IDs and details related to them
191
233
*/
192
234
private Map <String , CWLElement > getInputsOutputs (JsonNode inputsOutputs ) {
193
235
Map <String , CWLElement > returnMap = new HashMap <>();
194
236
195
237
if (inputsOutputs .getClass () == ArrayNode .class ) {
196
- // Explicit ID and other fields within each input list
238
+ // Explicit ID and other fields within each ilist
197
239
for (JsonNode inputOutput : inputsOutputs ) {
198
240
String id = inputOutput .get ("id" ).asText ();
199
241
returnMap .put (id , getDetails (inputOutput ));
@@ -203,8 +245,7 @@ private Map<String, CWLElement> getInputsOutputs(JsonNode inputsOutputs) {
203
245
Iterator <Map .Entry <String , JsonNode >> iterator = inputsOutputs .fields ();
204
246
while (iterator .hasNext ()) {
205
247
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 ()));
208
249
}
209
250
}
210
251
@@ -224,13 +265,10 @@ private CWLElement getDetails(JsonNode inputOutput) {
224
265
if (inputOutput .getClass () == TextNode .class ) {
225
266
details .setType (inputOutput .asText ());
226
267
} 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 ));
234
272
235
273
// Type is only for inputs
236
274
if (inputOutput .has ("type" )) {
@@ -243,20 +281,103 @@ private CWLElement getDetails(JsonNode inputOutput) {
243
281
return null ;
244
282
}
245
283
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
+
246
296
/**
247
297
* Extract the label from a node
248
298
* @param node The node to have the label extracted from
249
299
* @return The string for the label of the node
250
300
*/
251
301
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 ) {
252
326
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" );
255
335
}
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 ;
256
351
}
257
352
return null ;
258
353
}
259
354
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
+
260
381
/**
261
382
* Extract the doc or description from a node
262
383
* @param node The node to have the doc/description extracted from
@@ -330,5 +451,4 @@ private String extractTypes(JsonNode typeNode) {
330
451
}
331
452
return null ;
332
453
}
333
-
334
454
}
0 commit comments