1919import nl .uu .cs .ape .constraints .ConstraintTemplateParameter ;
2020import nl .uu .cs .ape .utils .APEFiles ;
2121import nl .uu .cs .ape .utils .APEUtils ;
22+ import nl .uu .cs .ape .utils .cwl_parser .CWLData ;
23+ import nl .uu .cs .ape .utils .cwl_parser .CWLParser ;
2224import nl .uu .cs .ape .models .AbstractModule ;
2325import nl .uu .cs .ape .models .AllModules ;
2426import nl .uu .cs .ape .models .AllTypes ;
2729import nl .uu .cs .ape .models .Module ;
2830import nl .uu .cs .ape .models .SATAtomMappings ;
2931import nl .uu .cs .ape .models .Type ;
32+ import nl .uu .cs .ape .models .enums .ToolAnnotationType ;
3033import nl .uu .cs .ape .models .logic .constructs .TaxonomyPredicate ;
3134
3235/**
@@ -59,7 +62,8 @@ public class APEDomainSetup {
5962
6063 @ Setter
6164 /**
62- * Object used to write locally CNF SAT problem specification (in human readable format).
65+ * Object used to write locally CNF SAT problem specification (in human readable
66+ * format).
6367 */
6468 private String writeLocalCNF = null ;
6569
@@ -325,15 +329,162 @@ public boolean annotateToolFromJson(JSONObject toolAnnotationsFile) throws IOExc
325329 }
326330
327331 /**
328- * Creates/updates a module from a tool annotation instance from a JSON file and
329- * updates the list of modules ({@link AllModules}) in the domain accordingly.
330- *
331- * @param jsonModule JSON representation of a module
332+ * Parse the tool annotation from a JSON file and update the module in the
333+ * domain ({@link AllModules}) accordingly.
334+ *
335+ * @param jsonModule JSON annotation of a module/tool
332336 * @return {@code true} if the domain was updated, false otherwise.
333337 * @throws JSONException Error if the JSON file was not properly formatted.
338+ * @throws APEDimensionsException
339+ * @throws IOException
334340 */
335341 public Optional <Module > updateModuleFromJson (JSONObject jsonModule )
342+ throws JSONException , APEDimensionsException , IOException {
343+
344+ ToolAnnotationType annotationType ;
345+ try {
346+ annotationType = ToolAnnotationType
347+ .fromString (jsonModule .getString (ToolAnnotationTag .TYPE .toString ()));
348+ } catch (JSONException e ) {
349+ log .debug ("Tool annotation type not specified. Defaulting to APE annotation." );
350+ return updateModuleFromJsonAPE (jsonModule );
351+ }
352+
353+ switch (annotationType ) {
354+ case APE_ANNOTATION :
355+ return updateModuleFromJsonAPE (jsonModule );
356+ case CWL_ANNOTATION :
357+ String cwlURL = jsonModule .getString (ToolAnnotationTag .CWL_REFERENCE .toString ());
358+ return updateModuleFromCWL (cwlURL );
359+ default :
360+ log .warn ("Tool annotation format not specified. Using default APE annotations." );
361+ return updateModuleFromJsonAPE (jsonModule );
362+ }
363+ }
364+
365+ /**
366+ * Parse the tool annotation from a CWL file and update the module in the
367+ * domain ({@link AllModules}) accordingly. The annotations are expected to
368+ * follow EDAM ontology.
369+ *
370+ * @param cwlFileLocation path to the CWL file (URL or local file) containing
371+ * the tool annotations
372+ * @return {@code true} if the domain was updated, false otherwise.
373+ * @throws IOException Error in accessing or parsing the CWL file.
374+ */
375+ public Optional <Module > updateModuleFromCWL (String cwlFileLocation ) throws IOException {
376+
377+ // Initialize CWL parser
378+ CWLParser cwlParser = new CWLParser (cwlFileLocation );
379+
380+ // Extract the module's label and ID
381+ String moduleLabel = (String ) cwlParser .getField ("label" );
382+ String moduleIRI = APEUtils .createClassIRI (moduleLabel , ontologyPrefixIRI );
383+
384+ if (allModules .get (moduleIRI ) != null ) {
385+ moduleIRI = moduleIRI + "[tool]" ;
386+ }
387+
388+ // Extract taxonomy operations
389+ Set <String > taxonomyOperations = new HashSet <>(cwlParser .getOperations ());
390+ Set <String > taxonomyParentModules = APEUtils .createIRIsFromLabels (taxonomyOperations , ontologyPrefixIRI );
391+
392+ // Validate taxonomy parent modules
393+ List <String > toRemove = new ArrayList <>();
394+ for (String parentModule : taxonomyParentModules ) {
395+ String parentModuleIRI = APEUtils .createClassIRI (parentModule , ontologyPrefixIRI );
396+ if (allModules .get (parentModuleIRI ) == null ) {
397+ log .debug ("Tool '" + moduleIRI + "' annotation issue. " +
398+ "Referenced taxonomy operation: '" + parentModuleIRI + "' cannot be found." );
399+ wrongToolTax .add (moduleLabel );
400+ toRemove .add (parentModuleIRI );
401+ }
402+ }
403+ taxonomyParentModules .removeAll (toRemove );
404+
405+ if (taxonomyParentModules .isEmpty ()) {
406+ log .debug ("Tool '" + moduleIRI + "' annotation issue. " +
407+ "No valid taxonomy operations found. Using root module as fallback." );
408+ taxonomyParentModules .add (allModules .getRootModuleID ());
409+ }
410+
411+ /*
412+ * Set the inputs and outputs of the module. If the inputs and outputs are not
413+ * valid, the module is not added to the domain.
414+ */
415+ List <Type > inputs = new ArrayList <>();
416+ List <String > inputCWLKeys = new ArrayList <>();
417+ List <Type > outputs = new ArrayList <>();
418+ List <String > outputCWLKeys = new ArrayList <>();
419+ try {
420+ List <CWLData > inputsRaw = cwlParser .getInputs ();
421+ for (CWLData inputRaw : inputsRaw ) {
422+ inputs .add (Type .taxonomyInstanceFromCWLData (inputRaw , this , false ));
423+ inputCWLKeys .add (inputRaw .getCwlFieldID ());
424+ }
425+ updateMaxNoToolInputs (inputs .size ());
426+
427+ List <CWLData > outputsRaw = cwlParser .getOutputs ();
428+ for (CWLData outputRaw : outputsRaw ) {
429+ outputs .add (Type .taxonomyInstanceFromCWLData (outputRaw , this , true ));
430+ outputCWLKeys .add (outputRaw .getCwlFieldID ());
431+ }
432+ updateMaxNoToolOutputs (outputs .size ());
433+
434+ if (inputs .isEmpty () && outputs .isEmpty ()) {
435+ emptyTools .add (moduleLabel );
436+ log .debug ("Operation '" + moduleLabel
437+ + "' was not included as it has no (valid) inputs and outputs specified." );
438+ return Optional .empty ();
439+ }
440+
441+ } catch (APEDimensionsException badDimension ) {
442+ wrongToolIO .add (moduleLabel );
443+ log .debug ("Operation '" + moduleLabel + "' was not included. " + badDimension .getMessage ());
444+ return Optional .empty ();
445+ }
446+
447+ /* Set the implementation cwl file reference of the module, if specified. */
448+ String cwlReference = cwlFileLocation ;
449+
450+ /*
451+ * Add the module and make it sub module of the currSuperModule (if it was not
452+ * previously defined)
453+ */
454+ Module currModule = (Module ) allModules
455+ .addPredicate (
456+ new Module (moduleLabel , moduleIRI , allModules .getRootModuleID (), cwlReference , null ));
457+
458+ /* For each parent module add the current module as a subset and vice versa. */
459+ for (String parentModuleID : taxonomyParentModules ) {
460+ AbstractModule parentModule = allModules .get (parentModuleID );
461+ if (parentModule != null ) {
462+ parentModule .addSubPredicate (currModule );
463+ currModule .addParentPredicate (parentModule );
464+ }
465+ }
466+
467+ currModule .setModuleInput (inputs );
468+ currModule .setModuleCWLInputKeys (inputCWLKeys );
469+ currModule .setModuleOutput (outputs );
470+ currModule .setModuleCWLOutputKeys (outputCWLKeys );
471+ currModule .setAsRelevantTaxonomyTerm (allModules );
472+
473+ return Optional .of (currModule );
474+ }
475+
476+
477+ /**
478+ * Parse the tool annotation from a JSON file and update the module in the
479+ * domain ({@link AllModules}) accordingly.
480+ *
481+ * @param jsonModule JSON annotation of a module/tool
482+ * @return {@code true} if the domain was updated, false otherwise.
483+ * @throws JSONException Error if the JSON file was not properly formatted.
484+ */
485+ public Optional <Module > updateModuleFromJsonAPE (JSONObject jsonModule )
336486 throws JSONException , APEDimensionsException {
487+
337488 String moduleIRI = APEUtils .createClassIRI (jsonModule .getString (ToolAnnotationTag .ID .toString ()),
338489 ontologyPrefixIRI );
339490 if (allModules .get (moduleIRI ) != null ) {
@@ -384,7 +535,8 @@ public Optional<Module> updateModuleFromJson(JSONObject jsonModule)
384535
385536 if (inputs .isEmpty () && outputs .isEmpty ()) {
386537 emptyTools .add (moduleLabel );
387- log .debug ("Operation '" + moduleLabel + "' was not included as it has no (valid) inputs and outputs specified." );
538+ log .debug ("Operation '" + moduleLabel
539+ + "' was not included as it has no (valid) inputs and outputs specified." );
388540 return Optional .empty ();
389541 }
390542
@@ -405,7 +557,8 @@ public Optional<Module> updateModuleFromJson(JSONObject jsonModule)
405557 * previously defined)
406558 */
407559 Module currModule = (Module ) allModules
408- .addPredicate (new Module (moduleLabel , moduleIRI , allModules .getRootModuleID (), cwlReference , executionCode ));
560+ .addPredicate (
561+ new Module (moduleLabel , moduleIRI , allModules .getRootModuleID (), cwlReference , executionCode ));
409562
410563 /* For each parent module add the current module as a subset and vice versa. */
411564 for (String parentModuleID : taxonomyParentModules ) {
@@ -461,16 +614,20 @@ private List<Type> getToolOutputsFromAnnotation(JSONObject jsonModule) throws AP
461614 return outputs ;
462615 }
463616
464- /**
617+ /**
465618 * Get the implementation code of the module, if specified.
466619 *
467620 * @param jsonToolAnnotation the json tool annotation
468- * @param implementationType the implementation type ({@link ToolAnnotationTag#CWL_REFERENCE} or {@link ToolAnnotationTag#CODE})
621+ * @param implementationType the implementation type
622+ * ({@link ToolAnnotationTag#CWL_REFERENCE} or
623+ * {@link ToolAnnotationTag#CODE})
469624 * @return The implementation code of the module, if specified.
470625 */
471- private String getModuleImplementationFromAnnotation (JSONObject jsonToolAnnotation , ToolAnnotationTag implementationType ) {
626+ private String getModuleImplementationFromAnnotation (JSONObject jsonToolAnnotation ,
627+ ToolAnnotationTag implementationType ) {
472628 try {
473- JSONObject implementationJson = jsonToolAnnotation .getJSONObject (ToolAnnotationTag .IMPLEMENTATION .toString ());
629+ JSONObject implementationJson = jsonToolAnnotation
630+ .getJSONObject (ToolAnnotationTag .IMPLEMENTATION .toString ());
474631 String implementation = implementationJson .getString (implementationType .toString ());
475632 if (implementation .equals ("" )) {
476633 return null ;
@@ -566,15 +723,15 @@ public List<AuxiliaryPredicate> getHelperPredicates() {
566723 * Write locally the SAT (CNF) workflow specification in human readable format.
567724 *
568725 * @param satInputFile File containing the SAT problem specification.
569- * @param mappings Mappings between the SAT problem and the domain.
726+ * @param mappings Mappings between the SAT problem and the domain.
570727 * @throws IOException Error in writing the file to the local file system.
571728 */
572729 public void localCNF (File satInputFile , SATAtomMappings mappings ) throws IOException {
573730 if (writeLocalCNF != null ) {
574731 FileInputStream cnfStream = new FileInputStream (satInputFile );
575732 String encoding = APEUtils .convertCNF2humanReadable (cnfStream , mappings );
576733 cnfStream .close ();
577-
734+
578735 APEFiles .write2file (encoding , new File (writeLocalCNF ), false );
579736 }
580737 }
0 commit comments