diff --git a/pom.xml b/pom.xml
index e6294f7..10a9279 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,6 +71,13 @@
3.2.2
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+ 3.2.2
+
+
com.h2database
diff --git a/src/main/java/nl/esciencecenter/controller/RestApeController.java b/src/main/java/nl/esciencecenter/controller/RestApeController.java
index e8a4d12..e5ee418 100644
--- a/src/main/java/nl/esciencecenter/controller/RestApeController.java
+++ b/src/main/java/nl/esciencecenter/controller/RestApeController.java
@@ -33,16 +33,15 @@
import nl.esciencecenter.controller.dto.ConstraintElem;
import nl.esciencecenter.controller.dto.ImgFileInfo;
import nl.esciencecenter.controller.dto.TaxonomyElem;
+import nl.esciencecenter.restape.APEWorkflowMetadata;
import nl.esciencecenter.restape.ApeAPI;
import nl.esciencecenter.restape.IOUtils;
import nl.esciencecenter.restape.RestApeUtils;
import nl.uu.cs.ape.configuration.APEConfigException;
/**
- * This class represents the RESTful APE controller.
- * TODO: Setup response code 400 and 404 when needed.
+ * This class represents the RESTful APE controller. It provides the RESTful API for the APE library.
*
- * @author Vedran
*/
@RestController
public class RestApeController {
@@ -70,14 +69,24 @@ public String index() {
* @throws OWLOntologyCreationException
*/
@GetMapping("/data_taxonomy")
- @Operation(summary = "Retrieve data taxonomy", description = "Retrieve data (taxonomy) within the domain.", tags = {
- "Domain" }, parameters = {
- @Parameter(name = "config_path", description = "URL to the APE configuration file.", example = "https://raw.githubusercontent.com/Workflomics/domain-annotations/main/WombatP_tools/config.json") }, externalDocs = @ExternalDocumentation(description = "More information about the APE configuration file can be found here.", url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"), responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Taxonomy of data terms is provided.", content = @Content(schema = @Schema(implementation = TaxonomyElem.class), mediaType = MediaType.APPLICATION_JSON_VALUE)),
- @ApiResponse(responseCode = "400", description = "Invalid input"),
- @ApiResponse(responseCode = "404", description = "Not found")
-
- })
+ @Operation(summary = "Retrieve data taxonomy",
+ description = "Retrieve data (taxonomy) within the domain.",
+ tags = {"Domain"},
+ parameters = {
+ @Parameter(name = "config_path",
+ description = "URL to the APE configuration file.",
+ example = "https://raw.githubusercontent.com/Workflomics/domain-annotations/main/WombatP_tools/config.json")
+ },
+ externalDocs = @ExternalDocumentation(description = "More information about the APE configuration file can be found here.",
+ url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"),
+ responses = {
+ @ApiResponse(responseCode = "200",
+ description = "Successful operation. Taxonomy of data terms is provided.",
+ content = @Content(schema = @Schema(implementation = TaxonomyElem.class),
+ mediaType = MediaType.APPLICATION_JSON_VALUE)),
+ @ApiResponse(responseCode = "400", description = "Invalid input"),
+ @ApiResponse(responseCode = "404", description = "Not found")
+ })
public ResponseEntity getData(
@RequestParam("config_path") String configPath)
throws OWLOntologyCreationException, IOException, IllegalArgumentException {
@@ -95,14 +104,24 @@ public ResponseEntity getData(
* @throws OWLOntologyCreationException
*/
@GetMapping("/tools_taxonomy")
- @Operation(summary = "Retrieve tool taxonomy", description = "Retrieve tools (taxonomy) within the domain.", tags = {
- "Domain" }, parameters = {
- @Parameter(name = "config_path", description = "URL to the APE configuration file.", example = "https://raw.githubusercontent.com/Workflomics/domain-annotations/main/WombatP_tools/config.json") }, externalDocs = @ExternalDocumentation(description = "More information about the APE configuration file can be found here.", url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"), responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Taxonomy of data terms is provided.", content = @Content(schema = @Schema(implementation = TaxonomyElem.class), mediaType = MediaType.APPLICATION_JSON_VALUE)),
- @ApiResponse(responseCode = "400", description = "Invalid input"),
- @ApiResponse(responseCode = "404", description = "Not found")
-
- })
+ @Operation(summary = "Retrieve tool taxonomy",
+ description = "Retrieve tools (taxonomy) within the domain.",
+ tags = {"Domain"},
+ parameters = {
+ @Parameter(name = "config_path",
+ description = "URL to the APE configuration file.",
+ example = "https://raw.githubusercontent.com/Workflomics/domain-annotations/main/WombatP_tools/config.json")
+ },
+ externalDocs = @ExternalDocumentation(description = "More information about the APE configuration file can be found here.",
+ url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"),
+ responses = {
+ @ApiResponse(responseCode = "200",
+ description = "Successful operation. Taxonomy of tool terms is provided.",
+ content = @Content(schema = @Schema(implementation = TaxonomyElem.class),
+ mediaType = MediaType.APPLICATION_JSON_VALUE)),
+ @ApiResponse(responseCode = "400", description = "Invalid input"),
+ @ApiResponse(responseCode = "404", description = "Not found")
+ })
public ResponseEntity getTools(
@RequestParam("config_path") String configPath)
throws OWLOntologyCreationException, IOException {
@@ -119,14 +138,24 @@ public ResponseEntity getTools(
* @return Constraint templates.
*/
@GetMapping("/constraints")
- @Operation(summary = "Retrieve constraint templates", description = "Retrieve constraint templates used to specify synthesis problem.", tags = {
- "Domain" }, parameters = {
- @Parameter(name = "config_path", description = "URL to the APE configuration file.", example = "https://raw.githubusercontent.com/Workflomics/domain-annotations/main/WombatP_tools/config.json") }, externalDocs = @ExternalDocumentation(description = "More information about the APE configuration file can be found here.", url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"), responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Taxonomy of data terms is provided.", content = @Content(schema = @Schema(implementation = ConstraintElem.class), mediaType = MediaType.APPLICATION_JSON_VALUE)),
- @ApiResponse(responseCode = "400", description = "Invalid input"),
- @ApiResponse(responseCode = "404", description = "Not found")
-
- })
+ @Operation(summary = "Retrieve constraint templates",
+ description = "Retrieve constraint templates used to specify the synthesis problem.",
+ tags = {"Domain"},
+ parameters = {
+ @Parameter(name = "config_path",
+ description = "URL to the APE configuration file.",
+ example = "https://raw.githubusercontent.com/Workflomics/domain-annotations/main/WombatP_tools/config.json")
+ },
+ externalDocs = @ExternalDocumentation(description = "More information about the APE configuration file can be found here.",
+ url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"),
+ responses = {
+ @ApiResponse(responseCode = "200",
+ description = "Successful operation. Constraint templates are provided.",
+ content = @Content(schema = @Schema(implementation = ConstraintElem.class),
+ mediaType = MediaType.APPLICATION_JSON_VALUE)),
+ @ApiResponse(responseCode = "400", description = "Invalid input"),
+ @ApiResponse(responseCode = "404", description = "Not found")
+ })
public ResponseEntity getConstraints(@RequestParam("config_path") String configPath)
throws JSONException, OWLOntologyCreationException, IOException {
@@ -143,22 +172,33 @@ public ResponseEntity getConstraints(@RequestParam("config_path") String
* @throws OWLOntologyCreationException
*/
@PostMapping("/run_synthesis")
- @Operation(summary = "Run workflow synthesis", description = "Run workflow synthesis using the APE library. Returns the list of resulting solutions, where each element describes a workflow (name,length, run_id, etc.).", tags = {
- "APE" }, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "JSON object containing the configuration for the synthesis.", content = @Content(schema = @Schema(implementation = APEConfig.class))), parameters = {
- @Parameter(name = "configJson", description = "APE configuration JSON file.", example = "https://raw.githubusercontent.com/Workflomics/domain-annotations/main/WombatP_tools/config.json") }, externalDocs = @ExternalDocumentation(description = "More information about the APE configuration file can be found here.", url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"), responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Synthesis solutions are returned."),
- @ApiResponse(responseCode = "400", description = "Invalid input"),
- @ApiResponse(responseCode = "404", description = "Not found"),
- @ApiResponse(responseCode = "500", description = "Internal server error"),
-
- })
- public ResponseEntity runSynthesis(
+ @Operation(summary = "Run workflow synthesis",
+ description = "Run workflow synthesis using the APE library. Returns the list of resulting solutions, where each element describes a workflow (name, length, run_id, etc.).",
+ tags = {"APE"},
+ requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
+ description = "JSON object containing the configuration for the synthesis.",
+ required = true,
+ content = @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = APEConfig.class))
+ ),
+ externalDocs = @ExternalDocumentation(
+ description = "More information about the APE configuration file can be found here.",
+ url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"),
+ responses = {
+ @ApiResponse(responseCode = "200", description = "Successful operation. A list of synthesized workflow solutions is returned."
+ ),
+ @ApiResponse(responseCode = "400", description = "Invalid input"),
+ @ApiResponse(responseCode = "404", description = "Not found"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
+ public ResponseEntity> runSynthesis(
@RequestBody(required = true) Map configJson)
throws APEConfigException, JSONException, OWLOntologyCreationException, IOException {
JSONObject config = new JSONObject(configJson);
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON)
- .body(ApeAPI.runSynthesis(config, false).toString());
+ .body(ApeAPI.runSynthesis(config, false));
}
/**
@@ -170,47 +210,53 @@ public ResponseEntity runSynthesis(
* @throws IOException
*/
@PostMapping("/run_synthesis_and_bench")
- @Operation(summary = "Run workflow synthesis and provide design-time benchmarks", description = "Run workflow synthesis using the APE library. In addition, evaluate design time benchmarks of the generated workflows. Returns the list of resulting solutions, where each element describes a workflow (name,length, run_id, etc.).", tags = {
- "APE" }, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "JSON object containing the configuration for the synthesis.", content = @Content(schema = @Schema(implementation = APEConfig.class))), parameters = {
- @Parameter(name = "configJson", description = "APE configuration JSON file.", example = "https://raw.githubusercontent.com/Workflomics/domain-annotations/main/WombatP_tools/config.json") }, externalDocs = @ExternalDocumentation(description = "More information about the APE configuration file can be found here.", url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"), responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Synthesis solutions are returned."),
- @ApiResponse(responseCode = "400", description = "Invalid input"),
- @ApiResponse(responseCode = "404", description = "Not found"),
- @ApiResponse(responseCode = "500", description = "Internal server error"),
-
- })
- public ResponseEntity runSynthesisAndBench(
+ @Operation(summary = "Run workflow synthesis and provide design-time benchmarks",
+ description = "This endpoint triggers the synthesis of workflows using the APE library and evaluates design-time benchmarks for the generated workflows. It returns a list of APEWorkflowMetadata objects, each representing a synthesized workflow solution with detailed metadata.",
+ tags = { "APE" },
+ requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "JSON object containing the configuration for the synthesis.",
+ content = @Content(schema = @Schema(implementation = APEConfig.class))),
+ responses = {
+ @ApiResponse(responseCode = "200", description = "Successful operation. A list of synthesized workflow solutions is returned."),
+ @ApiResponse(responseCode = "400", description = "Invalid input. The request body does not match the expected schema."),
+ @ApiResponse(responseCode = "404", description = "Not found. The specified resource could not be found."),
+ @ApiResponse(responseCode = "500", description = "Internal server error. An unexpected error occurred.")
+ },
+ externalDocs = @ExternalDocumentation(description = "More information about the APE configuration file.",
+ url = "https://ape-framework.readthedocs.io/en/latest/docs/specifications/setup.html#configuration-file"))
+ public ResponseEntity> runSynthesisAndBench(
@RequestBody(required = true) Map configJson)
throws APEConfigException, JSONException, OWLOntologyCreationException, IOException {
JSONObject config = new JSONObject(configJson);
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON)
- .body(ApeAPI.runSynthesis(config, true).toString());
+ .body(ApeAPI.runSynthesis(config, true));
}
/**
* Retrieve the solution workflow based on the provided run ID and a candidate
* solution.
*
- * @param fileName Name of the workflow file (provided under 'name' after
- * the synthesis run).
- * @param runID ID of the corresponding synthesis run (provided under
- * 'run_id' after the synthesis run).
- * @return Image in PNG format representing the workflow.
- * @throws IOException
+ * @param imgFileInfo JSON object containing the configuration for the synthesis.
+ * @return ResponseEntity containing the image representing the workflow.
+ * @throws IOException if there is an error reading the image file.
*/
@PostMapping("/image")
- @Operation(summary = "Retrieve an image representing the workflow.", description = "Retrieve a image from the file system representing the workflow generated.", tags = {
- "Download" }, parameters = {
- @Parameter(name = "file_name", description = "Name of the image file (provided under 'name' after the synthesis run).", example = "workflowSolution_0"),
- @Parameter(name = "format", description = "Format of the image ('png' or 'svg').", example = "png"),
- @Parameter(name = "run_id", description = "ID of the corresponding synthesis run (provided under 'run_id' after the synthesis run).", example = "04ce2ef00c1685150252568")
-
- }, responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Taxonomy of data terms is provided.", content = @Content(mediaType = MediaType.IMAGE_PNG_VALUE)),
+ @Operation(summary = "Retrieve an image representing the workflow",
+ description = "Retrieve an image from the file system representing the workflow generated.",
+ tags = {"Download"},
+ requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
+ description = "JSON object containing the information about the image, including the name of the image file, format of the image ('png' or 'svg'), and ID of the corresponding synthesis run.",
+ required = true,
+ content = @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = ImgFileInfo.class))
+ ),
+ responses = {
+ @ApiResponse(responseCode = "200", description = "Successful operation. Image representing the workflow is provided.",
+ content = @Content(mediaType = MediaType.IMAGE_PNG_VALUE)),
@ApiResponse(responseCode = "400", description = "Invalid input"),
@ApiResponse(responseCode = "404", description = "Not found")
- })
+ })
public ResponseEntity> postImage(
@RequestBody(required = true) ImgFileInfo imgFileInfo) throws IOException {
@@ -231,18 +277,21 @@ public ResponseEntity> postImage(
* @return CWL file representing the workflow.
*/
@PostMapping("/cwl")
- @Operation(summary = "Retrieve a cwl file", description = "Retrieve a cwl file from the file system, describing the workflow.", tags = {
- "Download" }, parameters = {
-
- @Parameter(name = "file_name", description = "Name of the CWL file (provided under 'figure_name' after the synthesis run).", example = "workflowSolution_0.cwl"),
- @Parameter(name = "run_id", description = "ID of the corresponding synthesis run (provided under 'run_id' after the synthesis run).", example = "04ce2ef00c1685150252568")
-
- }, responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Taxonomy of data terms is provided.", content = @Content(mediaType = "application/x-yaml")),
+ @Operation(summary = "Retrieve a cwl file",
+ description = "Retrieve a cwl file from the file system, describing the workflow.",
+ tags = {"Download"},
+ requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
+ description = "JSON object containing the information for retrieving the CWL file, including the name of the CWL file (as 'figure_name') and the ID of the corresponding synthesis run.",
+ required = true,
+ content = @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = CWLFileInfo.class))
+ ),
+ responses = {
+ @ApiResponse(responseCode = "200", description = "Successful operation. CWL file describing the workflow is provided.", content = @Content(mediaType = "application/x-yaml")),
@ApiResponse(responseCode = "400", description = "Invalid input"),
@ApiResponse(responseCode = "404", description = "Not found")
-
- })
+ })
public ResponseEntity postCwl(
@RequestBody(required = true) CWLFileInfo cwlInfoJson) throws IOException {
@@ -259,16 +308,21 @@ public ResponseEntity postCwl(
* @return CWL input file (.yml) representing the workflow inputs.
*/
@GetMapping("/cwl_input")
- @Operation(summary = "Retrieve a cwl input file", description = "Retrieve a cwl input file from the file system, allowing to execute the workflows in the run.", tags = {
- "Download" }, parameters = {
- @Parameter(name = "run_id", description = "ID of the corresponding synthesis run (provided under 'run_id' after the synthesis run).", example = "04ce2ef00c1685150252568")
-
- }, responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Taxonomy of data terms is provided.", content = @Content(mediaType = "application/x-yaml")),
+ @Operation(summary = "Retrieve a cwl input file",
+ description = "Retrieve a cwl input file from the file system, allowing to execute the workflows in the run.",
+ tags = {"Download"},
+ parameters = {
+ @Parameter(name = "run_id",
+ description = "ID of the corresponding synthesis run (provided under 'run_id' after the synthesis run).",
+ example = "04ce2ef00c1685150252568")
+ },
+ responses = {
+ @ApiResponse(responseCode = "200",
+ description = "Successful operation. CWL input file representing the workflow inputs is provided.",
+ content = @Content(mediaType = "application/x-yaml")),
@ApiResponse(responseCode = "400", description = "Invalid input"),
@ApiResponse(responseCode = "404", description = "Not found")
-
- })
+ })
public ResponseEntity getCwlInput(
@RequestParam("run_id") String runID) {
if (!RestApeUtils.isValidRunID(runID)) {
@@ -295,17 +349,24 @@ public ResponseEntity getCwlInput(
* @return CWL file representing the workflow.
*/
@GetMapping("/design_time_benchmarks")
- @Operation(summary = "Retrieve a design-time benchmark file", description = "Retrieve a design-time benchmark file from the file system, describing the workflow.", tags = {
- "Download" }, parameters = {
- @Parameter(name = "file_name", description = "Name of the benchmark file (provided under 'bench_name' after the synthesis run).", example = "workflowSolution_0.json"),
- @Parameter(name = "run_id", description = "ID of the corresponding synthesis run (provided under 'run_id' after the synthesis run).", example = "04ce2ef00c1685150252568")
-
- }, responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Taxonomy of data terms is provided.", content = @Content(mediaType = "application/x-yaml")),
+ @Operation(summary = "Retrieve a design-time benchmark file",
+ description = "Retrieve a design-time benchmark file from the file system, describing the workflow.",
+ tags = {"Download"},
+ parameters = {
+ @Parameter(name = "file_name",
+ description = "Name of the benchmark file (provided under 'bench_name' after the synthesis run).",
+ example = "workflowSolution_0.json"),
+ @Parameter(name = "run_id",
+ description = "ID of the corresponding synthesis run (provided under 'run_id' after the synthesis run).",
+ example = "04ce2ef00c1685150252568")
+ },
+ responses = {
+ @ApiResponse(responseCode = "200",
+ description = "Successful operation. Design-time benchmark file describing the workflow is provided.",
+ content = @Content(mediaType = "application/json")),
@ApiResponse(responseCode = "400", description = "Invalid input"),
@ApiResponse(responseCode = "404", description = "Not found")
-
- })
+ })
public ResponseEntity getBenchmarks(
@RequestParam("file_name") String fileName,
@RequestParam("run_id") String runID) {
@@ -326,23 +387,28 @@ public ResponseEntity getBenchmarks(
/**
* Retrieve the CWL solution files based on the provided run ID and CWL file
* names.
- * TODO: Exeptions don't handle all cases or illegal arguments (e.g. invalid
- * workflow name that ends with an open quotation`candidate_workflow_1.cwl"`).
*
* @param cwlFilesJson JSON object containing the run_id and the list of CWL
* files.
* @return CWL file representing the workflow.
*/
@PostMapping("/cwl_zip")
- @Operation(summary = "Retrieve the zip of cwl files.", description = "Retrieve the zip comprising CWL files specified in the request body. The request body should be a JSON object with the following fields: 'run_id' and 'workflows'. The 'run_id' field specifies the ID of the synthesis run, while the 'workflows' field is a list of CWL file names (provided under 'name' after the synthesis run).", tags = {
- "Download" }, requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(description = "JSON object containing the following fields: 'run_id' and 'workflows'.", content = @Content(schema = @Schema(implementation = CWLZip.class))), parameters = {
- @Parameter(name = "cwlFilesJson", description = "Synthesis run_id and the cwl file names.") }, responses = {
- @ApiResponse(responseCode = "200", description = "Successful operation. Synthesis solutions are returned."),
- @ApiResponse(responseCode = "400", description = "Invalid input"),
- @ApiResponse(responseCode = "404", description = "Not found"),
- @ApiResponse(responseCode = "500", description = "Internal server error"),
-
- })
+ @Operation(summary = "Retrieve the zip of cwl files.",
+ description = "Retrieve the zip comprising CWL files specified in the request body. The request body should be a JSON object with the following fields: 'run_id' and 'workflows'. The 'run_id' field specifies the ID of the synthesis run, while the 'workflows' field is a list of CWL file names.",
+ tags = {"Download"},
+ requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
+ description = "JSON object containing the following fields: 'run_id' and 'workflows'.",
+ required = true,
+ content = @Content(schema = @Schema(implementation = CWLZip.class))
+ ),
+ responses = {
+ @ApiResponse(responseCode = "200",
+ description = "Successful operation. A zip file comprising specified CWL files is returned.",
+ content = @Content(mediaType = "application/zip")),
+ @ApiResponse(responseCode = "400", description = "Invalid input"),
+ @ApiResponse(responseCode = "404", description = "Not found"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
public ResponseEntity> postZipCWLs(
@RequestBody(required = true) CWLZip cwlZipInfo) {
try {
diff --git a/src/main/java/nl/esciencecenter/restape/APEWorkflowMetadata.java b/src/main/java/nl/esciencecenter/restape/APEWorkflowMetadata.java
new file mode 100644
index 0000000..0e32af4
--- /dev/null
+++ b/src/main/java/nl/esciencecenter/restape/APEWorkflowMetadata.java
@@ -0,0 +1,88 @@
+package nl.esciencecenter.restape;
+
+import org.json.JSONObject;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import nl.uu.cs.ape.solver.solutionStructure.SolutionWorkflow;
+
+/**
+ * The {@link APEWorkflowMetadata} class represents metadata for a workflow solution from the APE solver.
+ * This class encapsulates the details and metadata of a workflow solution,
+ * including descriptive names, descriptions, the length of the solution, and benchmark information.
+ * It provides functionality to convert these details into a JSONObject for serialization or further processing.
+ */
+@Getter
+@NoArgsConstructor
+public class APEWorkflowMetadata {
+
+ private String workflowName;
+ private String descriptiveName;
+ private String description;
+ private int workflowLength;
+ private String runId;
+ private String cwlName;
+ private String figureName;
+ private String benchmarkFile; // Optional, indicates if benchmark data should be included.
+
+ /**
+ * Constructs a APEWorkflowMetadata instance from a given SolutionWorkflow and run configuration.
+ *
+ * @param sol The SolutionWorkflow containing necessary details of the workflow solution.
+ * @param runID The identifier for the run to which this solution belongs.
+ * @param benchmark Indicates whether benchmark data is to be included for this solution.
+ */
+ public APEWorkflowMetadata(SolutionWorkflow sol, String runID, boolean benchmark) {
+ this.workflowName = sol.getFileName();
+ this.descriptiveName = sol.getDescriptiveName();
+ this.description = sol.getDescription();
+ this.workflowLength = sol.getSolutionLength();
+ this.runId = runID;
+ this.cwlName = sol.getFileName() + ".cwl";
+ this.figureName = sol.getFileName();
+ if (benchmark) {
+ this.benchmarkFile = sol.getFileName() + ".json";
+ }
+ }
+
+ /**
+ * Converts the APEWorkflowMetadata instance into a JSONObject representing its properties.
+ * This facilitates the serialization of the workflow solution's metadata to a JSON format,
+ * making it compatible with JSON-based data handling, APIs, and storage mechanisms.
+ *
+ * @return A JSONObject representation of the APEWorkflowMetadata instance.
+ */
+ public JSONObject toJSONObject() {
+ JSONObject json = new JSONObject();
+ json.put("workflow_name", this.workflowName);
+ json.put("descriptive_name", this.descriptiveName);
+ json.put("description", this.description);
+ json.put("workflow_length", this.workflowLength);
+ json.put("run_id", this.runId);
+ json.put("cwl_name", this.cwlName);
+ json.put("figure_name", this.figureName);
+ if (this.benchmarkFile != null) {
+ json.put("benchmark_file", this.benchmarkFile);
+ }
+ return json;
+ }
+
+ /**
+ * Converts the APEWorkflowMetadata instance into a JSON string representing its properties.
+ *
+ * @return A JSON string representation of the APEWorkflowMetadata instance.
+ */
+ public String toString() {
+ JSONObject json = new JSONObject();
+ json.put("workflow_name", this.workflowName);
+ json.put("descriptive_name", this.descriptiveName);
+ json.put("description", this.description);
+ json.put("workflow_length", this.workflowLength);
+ json.put("run_id", this.runId);
+ json.put("cwl_name", this.cwlName);
+ json.put("figure_name", this.figureName);
+ if (this.benchmarkFile != null && !this.benchmarkFile.isEmpty()) {
+ json.put("benchmark_file", this.benchmarkFile);
+ }
+ return json.toString();
+ }
+}
diff --git a/src/main/java/nl/esciencecenter/restape/ApeAPI.java b/src/main/java/nl/esciencecenter/restape/ApeAPI.java
index ef13213..7ac933f 100644
--- a/src/main/java/nl/esciencecenter/restape/ApeAPI.java
+++ b/src/main/java/nl/esciencecenter/restape/ApeAPI.java
@@ -1,7 +1,10 @@
package nl.esciencecenter.restape;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
+
import nl.uu.cs.ape.APE;
import nl.uu.cs.ape.configuration.APECoreConfig;
import nl.uu.cs.ape.configuration.APERunConfig;
@@ -10,7 +13,6 @@
import nl.uu.cs.ape.models.AllPredicates;
import nl.uu.cs.ape.models.AllTypes;
import nl.uu.cs.ape.models.logic.constructs.TaxonomyPredicate;
-import nl.uu.cs.ape.solver.solutionStructure.SolutionWorkflow;
import nl.uu.cs.ape.solver.solutionStructure.SolutionsList;
import nl.uu.cs.ape.utils.APEUtils;
@@ -139,13 +141,13 @@ public static JSONArray getConstraints(String configFileURL) throws OWLOntologyC
* @param configJson - configuration of the synthesis run
* @param benchmark - boolean to indicate if the workflows should be
* benchmarked
- * @return - JSONArray with the metadata results of the synthesis, each element
+ * @return - List of {@link APEWorkflowMetadata}s with the metadata results of the synthesis, each element
* describes a workflow solution (name, length, runID, path to a CWL
* file, etc.).
* @throws OWLOntologyCreationException
* @throws IOException
*/
- public static JSONArray runSynthesis(JSONObject configJson, boolean benchmark)
+ public static List runSynthesis(JSONObject configJson, boolean benchmark)
throws OWLOntologyCreationException, IOException {
// Define the synthesis run ID
@@ -205,32 +207,22 @@ private static SolutionsList executeSynthesis(JSONObject configJson, String runI
* of the synthesis as well as information about the
* synthesis run.
* @runID - ID of the synthesis run
- * @return - JSONArray with the results of the synthesis, each element describes
+ * @return - List of {@link APEWorkflowMetadata}s with the results of the synthesis, each element describes
* a workflow solution (name, length, runID, path to a CWL file, etc.).
*/
- private static JSONArray workflowMetadataToJson(SolutionsList candidateSolutions, String runID, boolean benchmark) {
- JSONArray generatedSolutionsJson = new JSONArray();
+ private static List workflowMetadataToJson(SolutionsList candidateSolutions, String runID, boolean benchmark) {
+ List generatedSolutionsJson = new ArrayList<>();
if (candidateSolutions.isEmpty()) {
- return new JSONArray();
+ return new ArrayList<>();
} else {
// Generate objects that return the solutions in JSON format
int noSolutions = candidateSolutions.getNumberOfSolutions();
for (int i = 0; i < noSolutions; i++) {
- SolutionWorkflow sol = candidateSolutions.get(i);
- JSONObject solutionJson = new JSONObject();
- solutionJson.put("workflow_name", sol.getFileName());
- solutionJson.put("descriptive_name", sol.getDescriptiveName());
- solutionJson.put("description", sol.getDescription());
- solutionJson.put("workflow_length", sol.getSolutionLength());
- solutionJson.put("run_id", runID);
- // Add reference to the generated cwl file and figure
- solutionJson.put("cwl_name", sol.getFileName() + ".cwl");
- solutionJson.put("figure_name", sol.getFileName());
- if (benchmark) {
- solutionJson.put("benchmark_file", sol.getFileName() + ".json");
- }
- generatedSolutionsJson.put(solutionJson);
+
+ APEWorkflowMetadata solutionJson = new APEWorkflowMetadata(candidateSolutions.get(i), runID, benchmark);
+
+ generatedSolutionsJson.add(solutionJson);
}
return generatedSolutionsJson;
}
diff --git a/src/test/java/nl/esciencecenter/controller/RestApeControllerTest.java b/src/test/java/nl/esciencecenter/controller/RestApeControllerTest.java
index f7a4c60..218829e 100644
--- a/src/test/java/nl/esciencecenter/controller/RestApeControllerTest.java
+++ b/src/test/java/nl/esciencecenter/controller/RestApeControllerTest.java
@@ -5,10 +5,9 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
+import java.util.List;
import org.apache.commons.io.FileUtils;
-import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,7 +17,7 @@
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
-import nl.esciencecenter.controller.dto.CWLZip;
+import nl.esciencecenter.restape.APEWorkflowMetadata;
import nl.esciencecenter.restape.ApeAPI;
import nl.uu.cs.ape.utils.APEFiles;
@@ -140,10 +139,10 @@ void testPostZipCWLs() throws Exception {
StandardCharsets.UTF_8);
JSONObject jsonObject = new JSONObject(content);
jsonObject.put("solutions", "1");
- JSONArray result = ApeAPI.runSynthesis(jsonObject, false);
+ List result = ApeAPI.runSynthesis(jsonObject, false);
assertFalse(result.isEmpty(), "The encoding should be SAT.");
- String runID = result.getJSONObject(0).getString("run_id");
- String cwlFile = result.getJSONObject(0).getString("cwl_name");
+ String runID = result.get(0).getRunId();
+ String cwlFile = result.get(0).getCwlName();
String jsonContent = "{\"run_id\": \"" + runID + "\", \"workflows\": [\"" + cwlFile + "\"]}";
diff --git a/src/test/java/nl/esciencecenter/restape/ApeAPITest.java b/src/test/java/nl/esciencecenter/restape/ApeAPITest.java
index ae2bab3..c80b5ed 100644
--- a/src/test/java/nl/esciencecenter/restape/ApeAPITest.java
+++ b/src/test/java/nl/esciencecenter/restape/ApeAPITest.java
@@ -5,9 +5,9 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.List;
import org.apache.commons.io.FileUtils;
-import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
@@ -32,7 +32,7 @@ void runSynthesisFail() throws IOException, OWLOntologyCreationException {
StandardCharsets.UTF_8);
JSONObject jsonObject = new JSONObject(content);
jsonObject.put("solutions", "1");
- JSONArray result = ApeAPI.runSynthesis(jsonObject, false);
+ List result = ApeAPI.runSynthesis(jsonObject, false);
assertTrue(result.isEmpty(), "The encoding should be UNSAT.");
}
@@ -50,7 +50,7 @@ void runSynthesisPass() throws IOException, OWLOntologyCreationException {
StandardCharsets.UTF_8);
JSONObject jsonObject = new JSONObject(content);
jsonObject.put("solutions", "1");
- JSONArray result = ApeAPI.runSynthesis(jsonObject, false);
+ List result = ApeAPI.runSynthesis(jsonObject, false);
assertFalse(result.isEmpty(), "The encoding should be SAT.");
}
@@ -68,7 +68,7 @@ void runSynthesisAndBenchmarkPass() throws IOException, OWLOntologyCreationExcep
StandardCharsets.UTF_8);
JSONObject jsonObject = new JSONObject(content);
jsonObject.put("solutions", "1");
- JSONArray result = ApeAPI.runSynthesis(jsonObject, true);
+ List result = ApeAPI.runSynthesis(jsonObject, true);
assertFalse(result.isEmpty(), "The encoding should be SAT.");
}
}
diff --git a/src/test/java/nl/esciencecenter/restape/IOUtilsTest.java b/src/test/java/nl/esciencecenter/restape/IOUtilsTest.java
index 2f35899..b69737f 100644
--- a/src/test/java/nl/esciencecenter/restape/IOUtilsTest.java
+++ b/src/test/java/nl/esciencecenter/restape/IOUtilsTest.java
@@ -6,7 +6,6 @@
import java.util.List;
import org.apache.commons.io.FileUtils;
-import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@@ -25,10 +24,10 @@ void testZipFilesForLocalExecution() throws Exception {
StandardCharsets.UTF_8);
JSONObject jsonObject = new JSONObject(content);
jsonObject.put("solutions", "1");
- JSONArray result = ApeAPI.runSynthesis(jsonObject, false);
+ List result = ApeAPI.runSynthesis(jsonObject, false);
assertFalse(result.isEmpty(), "The encoding should be SAT.");
- String runID = result.getJSONObject(0).getString("run_id");
- String cwlFile = result.getJSONObject(0).getString("cwl_name");
+ String runID = result.get(0).getRunId();
+ String cwlFile = result.get(0).getCwlName();
CWLZip cwlZip = new CWLZip();
cwlZip.setRunID(runID);