diff --git a/docker/README.md b/docker/README.md index 36a3e1245c7b0ffce433854dc7b7678f8644bd3f..8693aad09f765b12de66b77c37f700563fa4eec7 100644 --- a/docker/README.md +++ b/docker/README.md @@ -24,7 +24,7 @@ To use this image, you need a running instance of PostgreSQL and to configure th ### EXTERNAL SERVICES ### -* MIPENGINE_URL: URL to MIPENGINE server. Default is "http://192.168.124.129:5000" . +* MIPENGINE_URL: URL to MIPENGINE server. Default is "http://localhost:5000" . * EXAREME_URL: URL to Exareme server. Default is "http://localhost:9090" . diff --git a/docker/config/application.tmpl b/docker/config/application.tmpl index 6059a902be06193d8a57c3c72f5c820d66e1b7ff..a8bfdf9ff3d49b00668dc9b3e8b581dd054180a6 100644 --- a/docker/config/application.tmpl +++ b/docker/config/application.tmpl @@ -35,7 +35,7 @@ spring: ### EXTERNAL SERVICES ### services: mipengine: - algorithmsUrl: {{ default .Env.MIPENGINE_URL "http://192.168.124.129:5000" }}/algorithms + algorithmsUrl: {{ .Env.MIPENGINE_URL}}/algorithms exareme: queryExaremeUrl: {{ default .Env.EXAREME_URL "http://localhost:9090" }}/mining/query diff --git a/src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java b/src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java index aea67b056981111fceede22ce964adab2ae7f57d..5ac49a402094cf3c435537ddf95f60d162dbbd46 100644 --- a/src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java +++ b/src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java @@ -76,17 +76,17 @@ public class AlgorithmsAPI { logger.LogUserAction("Loaded " + galaxyAlgorithms.size() + " galaxy algorithms"); ArrayList<ExaremeAlgorithmDTO> algorithms = new ArrayList<>(); - if (!exaremeAlgorithms.isEmpty()) { + if (exaremeAlgorithms != null) { algorithms.addAll(exaremeAlgorithms); } else { logger.LogUserAction("Getting exareme algorithms failed and returned null"); } - if (!mipengineAlgorithms.isEmpty()) { + if (mipengineAlgorithms != null) { algorithms.addAll(mipengineAlgorithms); } else { logger.LogUserAction("Getting mipengine algorithms failed and returned null"); } - if (!galaxyAlgorithms.isEmpty()) { + if (galaxyAlgorithms != null) { algorithms.addAll(galaxyAlgorithms); } else { logger.LogUserAction("Getting galaxy workflows failed and returned null"); @@ -159,7 +159,7 @@ public class AlgorithmsAPI { } ArrayList<ExaremeAlgorithmDTO> algorithms = new ArrayList<>(); - mipEngineAlgorithms.forEach(mipEngineAlgorithm -> algorithms.add(mipEngineAlgorithm.convertToAlgorithmDTO())); + mipEngineAlgorithms.forEach(mipEngineAlgorithm -> algorithms.add(new ExaremeAlgorithmDTO(mipEngineAlgorithm))); logger.LogUserAction("Completed, returned " + algorithms.size() + " algorithms."); return algorithms; diff --git a/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java b/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java index e5d0b04c54b0fd8652f5d284cb8690eaf14d3acf..449765fc999b0a9187d58446ca5dfc9695bf321d 100644 --- a/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java +++ b/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java @@ -78,6 +78,7 @@ public class ExperimentAPI { @ApiOperation(value = "Create an experiment", response = ExperimentDTO.class) @RequestMapping(method = RequestMethod.POST) public ResponseEntity<String> createExperiment(Authentication authentication, @RequestBody ExperimentDTO experimentDTO) { + new Logger(activeUserService.getActiveUser().getUsername(),"(POST) /experiments").LogUserAction("TEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEST"); experimentDTO = experimentService.createExperiment(authentication, experimentDTO, new Logger(activeUserService.getActiveUser().getUsername(),"(POST) /experiments")); return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.CREATED); } @@ -103,6 +104,7 @@ public class ExperimentAPI { @ApiOperation(value = "Create a transient experiment", response = ExperimentDTO.class) @RequestMapping(value = "/transient", method = RequestMethod.POST) public ResponseEntity<String> createTransientExperiment(Authentication authentication, @RequestBody ExperimentDTO experimentDTO) { + new Logger(activeUserService.getActiveUser().getUsername(),"(POST) /experiments").LogUserAction("TEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEST"); experimentDTO = experimentService.createTransientExperiment(authentication, experimentDTO, new Logger(activeUserService.getActiveUser().getUsername(), "(POST) /experiments/transient")); return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.OK); } diff --git a/src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java b/src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java index 4e206fae0d3605e6b0ffcaab5fded486eef25d45..8eb343c9cc658b97e8f0c1a1b6a7be19f09c9c94 100644 --- a/src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java +++ b/src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java @@ -3,12 +3,9 @@ package eu.hbp.mip.models.DAOs; import com.fasterxml.jackson.annotation.JsonInclude; import com.google.gson.Gson; import com.google.gson.annotations.Expose; -import eu.hbp.mip.models.DTOs.ExaremeAlgorithmDTO; -import eu.hbp.mip.models.DTOs.ExperimentDTO; -import eu.hbp.mip.utils.JsonConverters; import io.swagger.annotations.ApiModel; -import lombok.Getter; -import lombok.Setter; +import lombok.AllArgsConstructor; +import lombok.Data; import javax.persistence.*; import java.util.*; @@ -17,8 +14,8 @@ import java.util.*; * Created by habfast on 21/04/16. */ @Entity -@Getter -@Setter +@Data +@AllArgsConstructor @Table(name = "`experiment`") @ApiModel @JsonInclude(JsonInclude.Include.NON_NULL) @@ -95,22 +92,4 @@ public class ExperimentDAO { */ } - public ExperimentDTO convertToDTO(boolean includeResult) - { - ExperimentDTO experimentDTO = new ExperimentDTO(); - experimentDTO.setAlgorithm(JsonConverters.convertJsonStringToObject(this.algorithm, ExaremeAlgorithmDTO.class)); - experimentDTO.setCreated(this.created); - experimentDTO.setUpdated(this.updated); - experimentDTO.setFinished(this.finished); - experimentDTO.setCreatedBy(this.createdBy.getUsername()); - experimentDTO.setName(this.name); - if(includeResult){ - experimentDTO.setResult(JsonConverters.convertJsonStringToObject(String.valueOf(this.result), new ArrayList<>().getClass())); - } - experimentDTO.setStatus(this.status); - experimentDTO.setShared(this.shared); - experimentDTO.setUuid(this.uuid); - experimentDTO.setViewed(this.viewed); - return experimentDTO; - } } diff --git a/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java b/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java index 9279b3793c44c449302c083b823da674d7e4d46f..3bb43f3eec865cc92cd1be4e97fdf660d90e3089 100644 --- a/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java +++ b/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java @@ -7,16 +7,16 @@ package eu.hbp.mip.models.DAOs; import com.fasterxml.jackson.annotation.JsonInclude; import com.google.gson.annotations.Expose; import io.swagger.annotations.ApiModel; -import lombok.Getter; -import lombok.Setter; +import lombok.AllArgsConstructor; +import lombok.Data; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity -@Getter -@Setter +@Data +@AllArgsConstructor @Table(name = "`user`") @ApiModel @JsonInclude(JsonInclude.Include.NON_NULL) diff --git a/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmDTO.java index 887733de88a395d9c5f7a31b5c55c32024b56312..584ffd424f4c691a168cd26b3b8b1fa2566658bf 100644 --- a/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmDTO.java @@ -1,15 +1,13 @@ package eu.hbp.mip.models.DTOs; import com.google.gson.annotations.SerializedName; -import eu.hbp.mip.utils.JsonConverters; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; +import lombok.Data; import java.util.*; -@Getter -@Setter +@Data +@AllArgsConstructor public class ExaremeAlgorithmDTO { @SerializedName("name") @@ -27,9 +25,30 @@ public class ExaremeAlgorithmDTO { @SerializedName("parameters") private List<ExaremeAlgorithmRequestParamDTO> parameters; + public ExaremeAlgorithmDTO() + { + + } - @Getter - @Setter + public ExaremeAlgorithmDTO(MIPEngineAlgorithmDTO mipEngineAlgorithm ) + { + this.name = mipEngineAlgorithm.getName().toUpperCase(); + this.label = mipEngineAlgorithm.getLabel(); + this.desc = mipEngineAlgorithm.getDesc(); + this.type = "mipengine"; + List<ExaremeAlgorithmRequestParamDTO> parameters = new ArrayList<>(); + parameters.add(new ExaremeAlgorithmRequestParamDTO("x", mipEngineAlgorithm.getInputdata().getX())); + parameters.add(new ExaremeAlgorithmRequestParamDTO("y", mipEngineAlgorithm.getInputdata().getY())); + parameters.add(new ExaremeAlgorithmRequestParamDTO("pathology", mipEngineAlgorithm.getInputdata().getPathology())); + parameters.add(new ExaremeAlgorithmRequestParamDTO("dataset", mipEngineAlgorithm.getInputdata().getDatasets())); + parameters.add(new ExaremeAlgorithmRequestParamDTO("filter", mipEngineAlgorithm.getInputdata().getFilter())); + mipEngineAlgorithm.getParameters().forEach((name, parameterDTO) -> { + ExaremeAlgorithmRequestParamDTO parameter = new ExaremeAlgorithmRequestParamDTO(name, parameterDTO); + parameters.add(parameter); + }); + this.setParameters(parameters); + } + @Data @AllArgsConstructor static class Rule { @@ -45,47 +64,4 @@ public class ExaremeAlgorithmDTO { @SerializedName("value") private Object value; } - public MIPEngineAlgorithmRequestDTO convertToMIPEngineBody() - { - MIPEngineAlgorithmRequestDTO mipEngineAlgorithmRequestDTO = new MIPEngineAlgorithmRequestDTO(); - MIPEngineAlgorithmRequestDTO.InputData inputData = new MIPEngineAlgorithmRequestDTO.InputData(); - HashMap<String, Object> mipEngineParameters = new HashMap<>(); - - List<Object> rules = new ArrayList<>(); - this.parameters.forEach(parameter -> { - - switch (parameter.getName()) { - case "x": - List<String> x = Arrays.asList(parameter.getValue().split(",")); - x.forEach(column -> rules.add(new Rule(column, parameter.getColumnValuesSQLType(), "is_not_null", null))); - inputData.setX(x); - break; - case "y": - List<String> y = Arrays.asList(parameter.getValue().split(",")); - y.forEach(column -> rules.add(new Rule(column, parameter.getColumnValuesSQLType(), "is_not_null", null))); - inputData.setY(y); - break; - case "dataset": - List<String> datasets = Arrays.asList(parameter.getValue().split(",")); - rules.add(new Rule("dataset", "string", "in", datasets)); - inputData.setDatasets(datasets); - break; - case "pathology": - inputData.setPathology(parameter.getValue()); - break; - case "filter": - if (!parameter.getValue().equals("")) - rules.add(JsonConverters.convertJsonStringToObject(parameter.getValue(), MIPEngineAlgorithmRequestDTO.Filter.class)); - break; - default: - mipEngineParameters.put(parameter.getName(), Arrays.asList(parameter.getValue().split(","))); - break; - } - }); - MIPEngineAlgorithmRequestDTO.Filter filter = new MIPEngineAlgorithmRequestDTO.Filter("AND", rules, true); - inputData.setFilters(filter); - mipEngineAlgorithmRequestDTO.setInputdata(inputData); - mipEngineAlgorithmRequestDTO.setParameters(mipEngineParameters); - return mipEngineAlgorithmRequestDTO; - } } diff --git a/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmRequestParamDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmRequestParamDTO.java index 6f7d21655c0e5fb7cb8eea1f5bcded5183de55b8..4109c5e5916b65c0b1af9f0eaed04aa96249c640 100644 --- a/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmRequestParamDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmRequestParamDTO.java @@ -1,14 +1,16 @@ package eu.hbp.mip.models.DTOs; import com.google.gson.annotations.SerializedName; -import lombok.Getter; -import lombok.Setter; +import eu.hbp.mip.utils.Exceptions.InternalServerError; +import lombok.AllArgsConstructor; +import lombok.Data; +import java.util.Arrays; import java.util.List; //The request of an exareme algorithm is a list of ExaremeAlgorithmRequestParamDTOs. -@Getter -@Setter +@Data +@AllArgsConstructor public class ExaremeAlgorithmRequestParamDTO { @SerializedName("name") private String name; @@ -51,4 +53,54 @@ public class ExaremeAlgorithmRequestParamDTO { @SerializedName("valueEnumerations") private List<String> valueEnumerations; + public ExaremeAlgorithmRequestParamDTO (){} + + public ExaremeAlgorithmRequestParamDTO (String name, MIPEngineAlgorithmDTO.MIPEngineAlgorithmParameterDTO parameter){ + this.name = name; + this.desc = parameter.getDesc(); + this.valueType = parameter.getType(); + this.type = "other"; + this.defaultValue = parameter.getDefault_value(); + this.valueNotBlank = parameter.getNotblank(); + this.label = parameter.getLabel(); + this.valueEnumerations = parameter.getEnums(); + this.valueMultiple = parameter.getMultiple(); + this.valueMax = parameter.getMin(); + this.valueMin = parameter.getMax(); + } + + public ExaremeAlgorithmRequestParamDTO (String name, MIPEngineAlgorithmDTO.MIPEngineAlgorithmInputDataDetailDTO inputDataDetail){ + this.name = name; + this.desc = inputDataDetail.getDesc(); + this.value = ""; + this.valueNotBlank = inputDataDetail.getNotblank(); + this.valueMultiple = inputDataDetail.getMultiple(); + String[] hidden = {"x","y","dataset", "filter","pathology","centers","formula"}; + this.label = (Arrays.asList(hidden).contains(this.name) ? this.name : inputDataDetail.getLabel()); + if(name.equals("dataset") || name.equals("filter") || name.equals("pathology")){ + this.valueType = inputDataDetail.getTypes().get(0); + this.type = this.name; + } + else{ + this.type = "column"; + this.columnValuesSQLType = String.join(", ", inputDataDetail.getTypes()); + this.columnValuesIsCategorical = getColumnValuesIsCategorical(inputDataDetail.getStattypes()); + } + } + + private String getColumnValuesIsCategorical(List<String> stattypes){ + + if (stattypes.contains("nominal") && stattypes.contains("numerical")){ + return ""; + } + else if (stattypes.contains("nominal")){ + return "true"; + } + else if (stattypes.contains("numerical")){ + return "false"; + } + else{ + throw new InternalServerError("Invalid stattypes"); + } + } } diff --git a/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmResultDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmResultDTO.java index ca556bb7341c838271c03cd1d75249d2fba59f37..d1f5947c889c6581b341e4561e0c65e336f980ff 100644 --- a/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmResultDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/ExaremeAlgorithmResultDTO.java @@ -1,13 +1,11 @@ package eu.hbp.mip.models.DTOs; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; +import lombok.Data; import java.util.List; -@Getter -@Setter +@Data @AllArgsConstructor public class ExaremeAlgorithmResultDTO { private int code; diff --git a/src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java index 765c20144a3a376124d717980acff6dd8991543a..0dd28c1d6c4fde45164d9077aa5c9be3c90f57fb 100644 --- a/src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java @@ -2,15 +2,17 @@ package eu.hbp.mip.models.DTOs; import com.fasterxml.jackson.annotation.JsonInclude; import eu.hbp.mip.models.DAOs.ExperimentDAO; -import lombok.Getter; -import lombok.Setter; +import eu.hbp.mip.utils.JsonConverters; +import lombok.AllArgsConstructor; +import lombok.Data; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.UUID; -@Getter -@Setter +@Data +@AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) public class ExperimentDTO { @@ -30,4 +32,23 @@ public class ExperimentDTO { private ExperimentDAO.Status status; private ExaremeAlgorithmDTO algorithm; + public ExperimentDTO(){ + + } + public ExperimentDTO(boolean includeResult, ExperimentDAO experimentDAO) + { + this.algorithm = JsonConverters.convertJsonStringToObject(experimentDAO.getAlgorithm(), ExaremeAlgorithmDTO.class); + this.created = experimentDAO.getCreated(); + this.updated = experimentDAO.getUpdated(); + this.finished = experimentDAO.getFinished(); + this.createdBy = experimentDAO.getCreatedBy().getUsername(); + this.name = experimentDAO.getName(); + if(includeResult){ + this.result = JsonConverters.convertJsonStringToObject(String.valueOf(experimentDAO.getResult()), new ArrayList<>().getClass()); + } + this.status = experimentDAO.getStatus(); + this.uuid = experimentDAO.getUuid(); + this.shared = experimentDAO.isShared(); + this.viewed = experimentDAO.isViewed(); + } } diff --git a/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmDTO.java index 98677991e486e2fca38b8c7688a0d77e6eec084c..5edfbfe77827179234caf339f3f627235f72e967 100644 --- a/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmDTO.java @@ -1,17 +1,14 @@ package eu.hbp.mip.models.DTOs; import com.google.gson.annotations.SerializedName; -import eu.hbp.mip.utils.Exceptions.InternalServerError; -import lombok.Getter; -import lombok.Setter; +import lombok.AllArgsConstructor; +import lombok.Data; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Hashtable; import java.util.List; -@Getter -@Setter +@Data +@AllArgsConstructor public class MIPEngineAlgorithmDTO { @SerializedName("name") @@ -27,17 +24,17 @@ public class MIPEngineAlgorithmDTO { private String type; @SerializedName("parameters") - private Hashtable<String, ParameterDTO> parameters; + private Hashtable<String, MIPEngineAlgorithmParameterDTO> parameters; @SerializedName("crossvalidation") private String crossvalidation; @SerializedName("inputdata") - private InputdataDTO inputdata; + private MIPEngineAlgorithmInputdataDTO inputdata; - @Getter - @Setter - public static class ParameterDTO { + @Data + @AllArgsConstructor + public static class MIPEngineAlgorithmParameterDTO { @SerializedName("label") private String label; @@ -65,56 +62,30 @@ public class MIPEngineAlgorithmDTO { @SerializedName("enums") private List<String> enums; - - public ExaremeAlgorithmRequestParamDTO convertToexaremeAlgorithmRequestDTO(String name){ - ExaremeAlgorithmRequestParamDTO exaremeAlgorithmRequestParamDTO = new ExaremeAlgorithmRequestParamDTO(); - exaremeAlgorithmRequestParamDTO.setName(name); - exaremeAlgorithmRequestParamDTO.setDesc(this.desc); - exaremeAlgorithmRequestParamDTO.setValueType(this.type); - exaremeAlgorithmRequestParamDTO.setType("other"); - exaremeAlgorithmRequestParamDTO.setDefaultValue(this.default_value); - exaremeAlgorithmRequestParamDTO.setValueNotBlank(this.notblank); - exaremeAlgorithmRequestParamDTO.setLabel(this.label); - exaremeAlgorithmRequestParamDTO.setValueEnumerations(this.enums); - exaremeAlgorithmRequestParamDTO.setValueMultiple(this.multiple); - exaremeAlgorithmRequestParamDTO.setValueMin(this.min); - exaremeAlgorithmRequestParamDTO.setValueMax(this.max); - return exaremeAlgorithmRequestParamDTO; - } } - @Getter - @Setter - public static class InputdataDTO { + @Data + @AllArgsConstructor + public static class MIPEngineAlgorithmInputdataDTO { @SerializedName("x") - private InputDataDetailDTO x; + private MIPEngineAlgorithmInputDataDetailDTO x; @SerializedName("y") - private InputDataDetailDTO y; + private MIPEngineAlgorithmInputDataDetailDTO y; @SerializedName("pathology") - private InputDataDetailDTO pathology; + private MIPEngineAlgorithmInputDataDetailDTO pathology; @SerializedName("datasets") - private InputDataDetailDTO datasets; + private MIPEngineAlgorithmInputDataDetailDTO datasets; @SerializedName("filter") - private InputDataDetailDTO filter; - - public List<ExaremeAlgorithmRequestParamDTO> convertToAlgorithmRequestParamDTOs(){ - List<ExaremeAlgorithmRequestParamDTO> exaremeAlgorithmRequestParamDTOS = new ArrayList<>(); - exaremeAlgorithmRequestParamDTOS.add(this.x.convertToExaremeAlgorithmRequestDTO("x")); - exaremeAlgorithmRequestParamDTOS.add(this.y.convertToExaremeAlgorithmRequestDTO("y")); - exaremeAlgorithmRequestParamDTOS.add(this.pathology.convertToExaremeAlgorithmRequestDTO("pathology")); - exaremeAlgorithmRequestParamDTOS.add(this.datasets.convertToExaremeAlgorithmRequestDTO("dataset")); - exaremeAlgorithmRequestParamDTOS.add(this.filter.convertToExaremeAlgorithmRequestDTO("filter")); - return exaremeAlgorithmRequestParamDTOS; - } + private MIPEngineAlgorithmInputDataDetailDTO filter; } - @Getter - @Setter - public static class InputDataDetailDTO { + @Data + @AllArgsConstructor + public static class MIPEngineAlgorithmInputDataDetailDTO { @SerializedName("stattypes") private List<String> stattypes; @@ -136,58 +107,5 @@ public class MIPEngineAlgorithmDTO { @SerializedName("desc") private String desc; - - public ExaremeAlgorithmRequestParamDTO convertToExaremeAlgorithmRequestDTO(String name){ - ExaremeAlgorithmRequestParamDTO exaremeAlgorithmRequestParamDTO = new ExaremeAlgorithmRequestParamDTO(); - exaremeAlgorithmRequestParamDTO.setName(name); - exaremeAlgorithmRequestParamDTO.setDesc(this.desc); - exaremeAlgorithmRequestParamDTO.setValue(""); - exaremeAlgorithmRequestParamDTO.setValueNotBlank(this.notblank); - exaremeAlgorithmRequestParamDTO.setValueMultiple(this.multiple); - String[] hidden = {"x","y","dataset", "filter","pathology","centers","formula"}; - exaremeAlgorithmRequestParamDTO.setLabel(Arrays.asList(hidden).contains(exaremeAlgorithmRequestParamDTO.getName()) ? exaremeAlgorithmRequestParamDTO.getName():this.label); - if(name.equals("dataset") || name.equals("filter") || name.equals("pathology")){ - exaremeAlgorithmRequestParamDTO.setValueType(this.types.get(0)); - exaremeAlgorithmRequestParamDTO.setType(exaremeAlgorithmRequestParamDTO.getName()); - } - else{ - exaremeAlgorithmRequestParamDTO.setType("column"); - exaremeAlgorithmRequestParamDTO.setColumnValuesSQLType(String.join(", ", this.types)); - exaremeAlgorithmRequestParamDTO.setColumnValuesIsCategorical(getColumnValuesIsCategorical(this.stattypes)); - } - return exaremeAlgorithmRequestParamDTO; - } - - private String getColumnValuesIsCategorical(List<String> stattypes){ - - if (stattypes.contains("nominal") && stattypes.contains("numerical")){ - return ""; - } - else if (stattypes.contains("nominal")){ - return "true"; - } - else if (stattypes.contains("numerical")){ - return "false"; - } - else{ - throw new InternalServerError("Invalid stattypes"); - } - } - } - - public ExaremeAlgorithmDTO convertToAlgorithmDTO() - { - ExaremeAlgorithmDTO exaremeAlgorithmDTO = new ExaremeAlgorithmDTO(); - exaremeAlgorithmDTO.setName(this.name.toUpperCase()); - exaremeAlgorithmDTO.setLabel(this.label); - exaremeAlgorithmDTO.setDesc(this.desc); - exaremeAlgorithmDTO.setType("mipengine"); - List<ExaremeAlgorithmRequestParamDTO> parameters = new ArrayList<>(this.inputdata.convertToAlgorithmRequestParamDTOs()); - this.parameters.forEach((name, parameterDTO) -> { - ExaremeAlgorithmRequestParamDTO parameter = parameterDTO.convertToexaremeAlgorithmRequestDTO(name); - parameters.add(parameter); - }); - exaremeAlgorithmDTO.setParameters(parameters); - return exaremeAlgorithmDTO; } } diff --git a/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmRequestDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmRequestDTO.java index ff8229e372ddd480d58aee2a5c3af36b9536a41f..a5604f2e7b9b619d023523535c636531c139f937 100644 --- a/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmRequestDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmRequestDTO.java @@ -1,23 +1,68 @@ package eu.hbp.mip.models.DTOs; import com.google.gson.annotations.SerializedName; +import eu.hbp.mip.utils.JsonConverters; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; +import lombok.Data; -import java.util.Hashtable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; -@Getter -@Setter +@Data +@AllArgsConstructor public class MIPEngineAlgorithmRequestDTO { @SerializedName("inputdata") private InputData inputdata; @SerializedName("parameters") - private Hashtable<String, Object> parameters; + private HashMap<String, Object> parameters; - @Getter - @Setter + public MIPEngineAlgorithmRequestDTO(List<ExaremeAlgorithmRequestParamDTO> exaremeAlgorithmRequestParamDTOs) + { + MIPEngineAlgorithmRequestDTO.InputData inputData = new MIPEngineAlgorithmRequestDTO.InputData(); + HashMap<String, Object> mipEngineParameters = new HashMap<>(); + + List<Object> rules = new ArrayList<>(); + exaremeAlgorithmRequestParamDTOs.forEach(parameter -> { + + switch (parameter.getName()) { + case "x": + List<String> x = Arrays.asList(parameter.getValue().split(",")); + x.forEach(column -> rules.add(new ExaremeAlgorithmDTO.Rule(column, parameter.getColumnValuesSQLType(), "is_not_null", null))); + inputData.setX(x); + break; + case "y": + List<String> y = Arrays.asList(parameter.getValue().split(",")); + y.forEach(column -> rules.add(new ExaremeAlgorithmDTO.Rule(column, parameter.getColumnValuesSQLType(), "is_not_null", null))); + inputData.setY(y); + break; + case "dataset": + List<String> datasets = Arrays.asList(parameter.getValue().split(",")); + rules.add(new ExaremeAlgorithmDTO.Rule("dataset", "string", "in", datasets)); + inputData.setDatasets(datasets); + break; + case "pathology": + inputData.setPathology(parameter.getValue()); + break; + case "filter": + if (!parameter.getValue().equals("")) + rules.add(JsonConverters.convertJsonStringToObject(parameter.getValue(), MIPEngineAlgorithmRequestDTO.Filter.class)); + break; + default: + mipEngineParameters.put(parameter.getName(), Arrays.asList(parameter.getValue().split(","))); + break; + } + }); + MIPEngineAlgorithmRequestDTO.Filter filter = new MIPEngineAlgorithmRequestDTO.Filter("AND", rules); + inputData.setFilters(filter); + this.inputdata = inputData; + this.parameters = mipEngineParameters; + } + + + @Data + @AllArgsConstructor public static class InputData { @SerializedName("pathology") private String pathology; @@ -29,10 +74,12 @@ public class MIPEngineAlgorithmRequestDTO { private List<String> x; @SerializedName("y") private List<String> y; + public InputData(){ + + } } - @Getter - @Setter + @Data @AllArgsConstructor public static class Filter { @@ -41,8 +88,5 @@ public class MIPEngineAlgorithmRequestDTO { @SerializedName("rules") private List<Object> rules; - - @SerializedName("valid") - private boolean valid; } } diff --git a/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmResultDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmResultDTO.java index 087adb1f84072ba0188d0b8e300ba0d5ee535e20..4491ddb443ddaba506e3165ab95c0e2ba3e20d87 100644 --- a/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmResultDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineAlgorithmResultDTO.java @@ -1,23 +1,14 @@ package eu.hbp.mip.models.DTOs; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; +import lombok.Data; -import java.util.HashMap; import java.util.List; -@Getter -@Setter +@Data @AllArgsConstructor public class MIPEngineAlgorithmResultDTO { private final String title; - private final List<MIPEngineTabularVisualizationDTO.Field> columns; + private final List<TabularVisualizationDTO.Field> columns; private final List<List<Object>> data; - - public MIPEngineTabularVisualizationDTO convertToVisualization() { - HashMap<String, List<MIPEngineTabularVisualizationDTO.Field>> schema = new HashMap<>(); - schema.put("fields", columns); - return new MIPEngineTabularVisualizationDTO(this.title, "tabular-data-resource", schema, this.data); - } } \ No newline at end of file diff --git a/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineTabularVisualizationDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineTabularVisualizationDTO.java deleted file mode 100644 index 7be3fad336e3bf4642f09c6985909d38fb2c4abc..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/models/DTOs/MIPEngineTabularVisualizationDTO.java +++ /dev/null @@ -1,27 +0,0 @@ -package eu.hbp.mip.models.DTOs; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; - -import java.util.HashMap; -import java.util.List; - -@Getter -@Setter -@AllArgsConstructor -public class MIPEngineTabularVisualizationDTO { - private final String name; - private final String profile; - private final HashMap<String, List<Field>> schema; - private final List<List<Object>> data; - - @Getter - @Setter - @AllArgsConstructor - public static class Field { - private final String name; - private final String type; - } -} - diff --git a/src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java index aa78ef8b0e315a2f71261dc1fed480cb8617ccb2..ecc5b723bef81a572c61ac14dd46f48a5593eb50 100644 --- a/src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java +++ b/src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java @@ -1,13 +1,13 @@ package eu.hbp.mip.models.DTOs; import com.google.gson.annotations.SerializedName; -import lombok.Getter; -import lombok.Setter; +import lombok.AllArgsConstructor; +import lombok.Data; import java.util.List; -@Getter -@Setter +@Data +@AllArgsConstructor public class PathologyDTO { @SerializedName("code") @@ -22,8 +22,11 @@ public class PathologyDTO { @SerializedName("datasets") private List<PathologyDatasetDTO> datasets; - @Getter - @Setter + public PathologyDTO(){ + + } + @Data + @AllArgsConstructor public static class PathologyDatasetDTO { @SerializedName("code") private String code; diff --git a/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java b/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java index 9ac54cada906b78ad5ab5ac41d77d05562bedc4e..b776b6c46d147e0c146305b4567a0c518b3ea11c 100644 --- a/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java +++ b/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java @@ -1,9 +1,17 @@ package eu.hbp.mip.repositories; import eu.hbp.mip.models.DAOs.ExperimentDAO; +import eu.hbp.mip.models.DAOs.UserDAO; +import eu.hbp.mip.models.DTOs.ExperimentDTO; +import eu.hbp.mip.utils.Exceptions.BadRequestException; +import eu.hbp.mip.utils.Exceptions.ExperimentNotFoundException; +import eu.hbp.mip.utils.Exceptions.InternalServerError; +import eu.hbp.mip.utils.JsonConverters; +import eu.hbp.mip.utils.Logger; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; +import java.util.Date; import java.util.Optional; import java.util.UUID; @@ -14,4 +22,91 @@ import java.util.UUID; public interface ExperimentRepository extends CrudRepository<ExperimentDAO, UUID>, JpaSpecificationExecutor<ExperimentDAO> { ExperimentDAO findByUuid(UUID experimentUuid); + + /** + * The loadExperiment access the database and load the information of a specific experiment + * + * @param uuid is the id of the experiment to be retrieved + * @return the experiment information that was retrieved from database + */ + default ExperimentDAO loadExperiment(String uuid, Logger logger) { + UUID experimentUuid; + ExperimentDAO experimentDAO; + + try { + experimentUuid = UUID.fromString(uuid); + } catch (Exception e) { + logger.LogUserAction( e.getMessage()); + throw new BadRequestException(e.getMessage()); + } + + experimentDAO = findByUuid(experimentUuid); + if (experimentDAO == null) { + logger.LogUserAction( "Experiment with uuid : " + uuid + "was not found."); + throw new ExperimentNotFoundException("Experiment with uuid : " + uuid + " was not found."); + } + + return experimentDAO; + } + + /** + * The createExperimentInTheDatabase will insert a new experiment in the database according to the given experiment information + * + * @param experimentDTO is the experiment information to inserted in the database + * @return the experiment information that was inserted into the database + * @Note In the database there will be stored Algorithm Details that is the whole information about the algorithm + * and an Algorithm column that is required for the filtering with algorithm name in the GET /experiments. + */ + default ExperimentDAO createExperimentInTheDatabase(ExperimentDTO experimentDTO, UserDAO user, Logger logger) { + + ExperimentDAO experimentDAO = new ExperimentDAO(); + experimentDAO.setUuid(UUID.randomUUID()); + experimentDAO.setCreatedBy(user); + experimentDAO.setAlgorithm(JsonConverters.convertObjectToJsonString(experimentDTO.getAlgorithm())); + experimentDAO.setAlgorithmId(experimentDTO.getAlgorithm().getName()); + experimentDAO.setName(experimentDTO.getName()); + experimentDAO.setStatus(ExperimentDAO.Status.pending); + + try { + save(experimentDAO); + } catch (Exception e) { + logger.LogUserAction("Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); + throw new InternalServerError(e.getMessage()); + } + + logger.LogUserAction(" id : " + experimentDAO.getUuid()); + logger.LogUserAction(" algorithm : " + experimentDAO.getAlgorithm()); + logger.LogUserAction(" name : " + experimentDAO.getName()); + return experimentDAO; + } + + default void saveExperiment(ExperimentDAO experimentDAO, Logger logger) { + + logger.LogUserAction(" id : " + experimentDAO.getUuid()); + logger.LogUserAction(" algorithm : " + experimentDAO.getAlgorithm()); + logger.LogUserAction(" name : " + experimentDAO.getName()); + logger.LogUserAction(" historyId : " + experimentDAO.getWorkflowHistoryId()); + logger.LogUserAction(" status : " + experimentDAO.getStatus()); + + try { + save(experimentDAO); + } catch (Exception e) { + logger.LogUserAction("Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); + throw new InternalServerError(e.getMessage()); + } + + logger.LogUserAction("Saved experiment"); + } + + default void finishExperiment(ExperimentDAO experimentDAO, Logger logger) { + experimentDAO.setFinished(new Date()); + + try { + save(experimentDAO); + } catch (Exception e) { + logger.LogUserAction( "Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); + throw new InternalServerError(e.getMessage()); + } + } + } diff --git a/src/main/java/eu/hbp/mip/services/ExperimentService.java b/src/main/java/eu/hbp/mip/services/ExperimentService.java index 3c52503c23ac6976495e3e006e8b765fbb8c9794..c421fd4717e85b99e06d46f9c6be304f8b22c2da 100644 --- a/src/main/java/eu/hbp/mip/services/ExperimentService.java +++ b/src/main/java/eu/hbp/mip/services/ExperimentService.java @@ -1,23 +1,10 @@ package eu.hbp.mip.services; -import com.github.jmchilton.blend4j.galaxy.GalaxyInstance; -import com.github.jmchilton.blend4j.galaxy.GalaxyInstanceFactory; -import com.github.jmchilton.blend4j.galaxy.WorkflowsClient; -import com.github.jmchilton.blend4j.galaxy.beans.Workflow; -import com.github.jmchilton.blend4j.galaxy.beans.WorkflowDetails; -import com.github.jmchilton.blend4j.galaxy.beans.WorkflowInputDefinition; import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import com.google.gson.internal.LinkedTreeMap; -import eu.hbp.mip.controllers.galaxy.retrofit.RetroFitGalaxyClients; -import eu.hbp.mip.controllers.galaxy.retrofit.RetrofitClientInstance; import eu.hbp.mip.models.DAOs.ExperimentDAO; import eu.hbp.mip.models.DAOs.UserDAO; import eu.hbp.mip.models.DTOs.*; -import eu.hbp.mip.models.galaxy.GalaxyWorkflowResult; -import eu.hbp.mip.models.galaxy.PostWorkflowToGalaxyDtoResponse; import eu.hbp.mip.repositories.ExperimentRepository; import eu.hbp.mip.services.Specifications.ExperimentSpecifications; import eu.hbp.mip.utils.ClaimUtils; @@ -25,8 +12,6 @@ import eu.hbp.mip.utils.Exceptions.*; import eu.hbp.mip.utils.HTTPUtil; import eu.hbp.mip.utils.JsonConverters; import eu.hbp.mip.utils.Logger; -import org.codehaus.jettison.json.JSONException; -import org.codehaus.jettison.json.JSONObject; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -34,13 +19,8 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; -import retrofit2.Call; -import retrofit2.Response; - -import java.io.IOException; import java.util.*; -import static java.lang.Thread.sleep; @Service public class ExperimentService { @@ -52,22 +32,18 @@ public class ExperimentService { @Value("#{'${services.mipengine.algorithmsUrl}'}") private String mipengineAlgorithmsUrl; - @Value("#{'${services.galaxy.galaxyUrl}'}") - private String galaxyUrl; - - @Value("#{'${services.galaxy.galaxyApiKey}'}") - private String galaxyApiKey; - @Value("#{'${authentication.enabled}'}") private boolean authenticationIsEnabled; private static final Gson gson = new Gson(); private final ActiveUserService activeUserService; + private final GalaxyService galaxyService; private final ExperimentRepository experimentRepository; - public ExperimentService(ActiveUserService activeUserService, ExperimentRepository experimentRepository) { + public ExperimentService(ActiveUserService activeUserService, GalaxyService galaxyService, ExperimentRepository experimentRepository) { this.activeUserService = activeUserService; + this.galaxyService = galaxyService; this.experimentRepository = experimentRepository; } @@ -121,7 +97,7 @@ public class ExperimentService { throw new NoContent("No experiment found with the filters provided."); List<ExperimentDTO> experimentDTOs = new ArrayList<>(); - experimentDAOs.forEach(experimentDAO -> experimentDTOs.add(experimentDAO.convertToDTO(false))); + experimentDAOs.forEach(experimentDAO -> experimentDTOs.add(new ExperimentDTO(false, experimentDAO))); Map<String, Object> response = new HashMap<>(); response.put("experiments", experimentDTOs); @@ -146,7 +122,7 @@ public class ExperimentService { logger.LogUserAction("Loading Experiment with uuid : " + uuid); - experimentDAO = loadExperiment(uuid, logger); + experimentDAO = experimentRepository.loadExperiment(uuid, logger); if ( !experimentDAO.isShared() && !experimentDAO.getCreatedBy().getUsername().equals(user.getUsername()) @@ -156,7 +132,7 @@ public class ExperimentService { logger.LogUserAction("Accessing Experiment is unauthorized."); throw new UnauthorizedException("You don't have access to the experiment."); } - ExperimentDTO experimentDTO = experimentDAO.convertToDTO(true); + ExperimentDTO experimentDTO = new ExperimentDTO(true, experimentDAO); logger.LogUserAction("Experiment was Loaded with uuid : " + uuid + "."); return experimentDTO; @@ -193,7 +169,7 @@ public class ExperimentService { // Run with the appropriate engine if (algorithmType.equals("workflow")) { logger.LogUserAction("Algorithm runs on Galaxy."); - return runGalaxyWorkflow(experimentDTO, logger); + return galaxyService.runGalaxyWorkflow(experimentDTO, logger); } else { logger.LogUserAction("Algorithm runs on Exareme."); return createExperiment(experimentDTO, logger); @@ -253,7 +229,7 @@ public class ExperimentService { UserDAO user = activeUserService.getActiveUser(); logger.LogUserAction("Updating experiment with uuid : " + uuid + "."); - experimentDAO = loadExperiment(uuid, logger); + experimentDAO = experimentRepository.loadExperiment(uuid, logger); //Verify (PATCH) /experiments non editable fields. verifyPatchExperimentNonEditableFields(experimentDTO, logger); @@ -281,7 +257,7 @@ public class ExperimentService { logger.LogUserAction("Updated experiment with uuid : " + uuid + "."); - experimentDTO = experimentDAO.convertToDTO(true); + experimentDTO = new ExperimentDTO(true, experimentDAO); return experimentDTO; } @@ -296,7 +272,7 @@ public class ExperimentService { UserDAO user = activeUserService.getActiveUser(); logger.LogUserAction("Deleting experiment with uuid : " + uuid + "."); - experimentDAO = loadExperiment(uuid, logger); + experimentDAO = experimentRepository.loadExperiment(uuid, logger); if (!experimentDAO.getCreatedBy().getUsername().equals(user.getUsername())) throw new UnauthorizedException("You don't have access to the experiment."); @@ -409,106 +385,10 @@ public class ExperimentService { return experimentDatasets; } - /** - * The loadExperiment access the database and load the information of a specific experiment - * - * @param uuid is the id of the experiment to be retrieved - * @return the experiment information that was retrieved from database - */ - private ExperimentDAO loadExperiment(String uuid, Logger logger) { - UUID experimentUuid; - ExperimentDAO experimentDAO; - - try { - experimentUuid = UUID.fromString(uuid); - } catch (Exception e) { - logger.LogUserAction( e.getMessage()); - throw new BadRequestException(e.getMessage()); - } - - experimentDAO = experimentRepository.findByUuid(experimentUuid); - if (experimentDAO == null) { - logger.LogUserAction( "Experiment with uuid : " + uuid + "was not found."); - throw new ExperimentNotFoundException("Experiment with uuid : " + uuid + " was not found."); - } - - return experimentDAO; - } - - /** - * The createExperimentInTheDatabase will insert a new experiment in the database according to the given experiment information - * - * @param experimentDTO is the experiment information to inserted in the database - * @return the experiment information that was inserted into the database - * @Note In the database there will be stored Algorithm Details that is the whole information about the algorithm - * and an Algorithm column that is required for the filtering with algorithm name in the GET /experiments. - */ - private ExperimentDAO createExperimentInTheDatabase(ExperimentDTO experimentDTO, Logger logger) { - UserDAO user = activeUserService.getActiveUser(); - - ExperimentDAO experimentDAO = new ExperimentDAO(); - experimentDAO.setUuid(UUID.randomUUID()); - experimentDAO.setCreatedBy(user); - experimentDAO.setAlgorithm(JsonConverters.convertObjectToJsonString(experimentDTO.getAlgorithm())); - experimentDAO.setAlgorithmId(experimentDTO.getAlgorithm().getName()); - experimentDAO.setName(experimentDTO.getName()); - experimentDAO.setStatus(ExperimentDAO.Status.pending); - - try { - experimentRepository.save(experimentDAO); - } catch (Exception e) { - logger.LogUserAction("Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); - throw new InternalServerError(e.getMessage()); - } - - logger.LogUserAction(" id : " + experimentDAO.getUuid()); - logger.LogUserAction(" algorithm : " + experimentDAO.getAlgorithm()); - logger.LogUserAction(" name : " + experimentDAO.getName()); - return experimentDAO; - } - - private void saveExperiment(ExperimentDAO experimentDAO, Logger logger) { - - logger.LogUserAction(" id : " + experimentDAO.getUuid()); - logger.LogUserAction(" algorithm : " + experimentDAO.getAlgorithm()); - logger.LogUserAction(" name : " + experimentDAO.getName()); - logger.LogUserAction(" historyId : " + experimentDAO.getWorkflowHistoryId()); - logger.LogUserAction(" status : " + experimentDAO.getStatus()); - - try { - experimentRepository.save(experimentDAO); - } catch (Exception e) { - logger.LogUserAction("Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); - throw new InternalServerError(e.getMessage()); - } - - logger.LogUserAction("Saved experiment"); - } - - private void finishExperiment(ExperimentDAO experimentDAO, Logger logger) { - experimentDAO.setFinished(new Date()); - - try { - experimentRepository.save(experimentDAO); - } catch (Exception e) { - logger.LogUserAction( "Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); - throw new InternalServerError(e.getMessage()); - } - } - - private String formattingGalaxyResult(String result) { - List<LinkedTreeMap<String,Object>> jsonObject = JsonConverters.convertJsonStringToObject(result, new ArrayList<ArrayList<Object>>().getClass()); - LinkedTreeMap<String,Object> firstResult = jsonObject.get(0); - jsonObject = (List<LinkedTreeMap<String, Object>>) firstResult.get("result"); - List<LinkedTreeMap<String,Object>> finalJsonObject = new ArrayList<>(); - finalJsonObject.add(jsonObject.get(0)); - return JsonConverters.convertObjectToJsonString(finalJsonObject); - } - private ExaremeAlgorithmResultDTO convertMIPEngineResultToExaremeAlgorithmResult(int code, String result) { MIPEngineAlgorithmResultDTO mipVisualization = JsonConverters.convertJsonStringToObject(result, MIPEngineAlgorithmResultDTO.class); LinkedTreeMap<String,Object> data = new LinkedTreeMap<>(); - data.put("data", mipVisualization.convertToVisualization()); + data.put("data", new TabularVisualizationDTO(mipVisualization)); data.put("type", "application/vnd.dataresource+json"); List<Object> finalObject = new ArrayList<>(); finalObject.add(data); @@ -531,7 +411,7 @@ public class ExperimentService { // Run with the appropriate engine if (algorithmType.equals("mipengine")) { - MIPEngineAlgorithmRequestDTO mipEngineAlgorithmRequestDTO = experimentDTO.getAlgorithm().convertToMIPEngineBody(); + MIPEngineAlgorithmRequestDTO mipEngineAlgorithmRequestDTO = new MIPEngineAlgorithmRequestDTO(experimentDTO.getAlgorithm().getParameters()); String body = JsonConverters.convertObjectToJsonString(mipEngineAlgorithmRequestDTO); String url = mipengineAlgorithmsUrl + "/" + algorithmName.toLowerCase(); logger.LogUserAction("url: " + url + ", body: " + body); @@ -609,10 +489,9 @@ public class ExperimentService { logger.LogUserAction("Running the algorithm..."); - ExperimentDAO experimentDAO = createExperimentInTheDatabase(experimentDTO, logger); + ExperimentDAO experimentDAO = experimentRepository.createExperimentInTheDatabase(experimentDTO, activeUserService.getActiveUser(), logger); logger.LogUserAction("Created experiment with uuid :" + experimentDAO.getUuid()); - logger.LogUserAction("Starting execution in thread"); ExperimentDTO finalExperimentDTO = experimentDTO; new Thread(() -> { @@ -635,402 +514,13 @@ public class ExperimentService { experimentDAO.setStatus(ExperimentDAO.Status.error); } - finishExperiment(experimentDAO, logger); + experimentRepository.finishExperiment(experimentDAO, logger); Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Finished the experiment: " + experimentDAO); }).start(); - experimentDTO = experimentDAO.convertToDTO(true); + experimentDTO = new ExperimentDTO(true, experimentDAO); return experimentDTO; } /* --------------------------------------- GALAXY CALLS ---------------------------------------------------------*/ - - /** - * The runWorkflow will POST the algorithm to the galaxy client - * - * @param experimentDTO is the request with the experiment information - * @return the response to be returned - */ - public ExperimentDTO runGalaxyWorkflow(ExperimentDTO experimentDTO, Logger logger) { - logger.LogUserAction("Running a workflow..."); - - ExperimentDAO experimentDAO = createExperimentInTheDatabase(experimentDTO, logger); - logger.LogUserAction("Created experiment with uuid :" + experimentDAO.getUuid()); - - - // Run the 1st algorithm from the list - String workflowId = experimentDTO.getAlgorithm().getName(); - - // Get the parameters - List<ExaremeAlgorithmRequestParamDTO> algorithmParameters - = experimentDTO.getAlgorithm().getParameters(); - - // Convert the parameters to workflow parameters - HashMap<String, String> algorithmParamsIncludingEmpty = new HashMap<>(); - if (algorithmParameters != null) { - for (ExaremeAlgorithmRequestParamDTO param : algorithmParameters) { - algorithmParamsIncludingEmpty.put(param.getName(), param.getValue()); - } - } - - // Get all the algorithm parameters because the frontend provides only the non-null - final GalaxyInstance instance = GalaxyInstanceFactory.get(galaxyUrl, galaxyApiKey); - final WorkflowsClient workflowsClient = instance.getWorkflowsClient(); - Workflow workflow = null; - for (Workflow curWorkflow : workflowsClient.getWorkflows()) { - if (curWorkflow.getId().equals(workflowId)) { - workflow = curWorkflow; - break; - } - } - if (workflow == null) { - logger.LogUserAction("Could not find algorithm code: " + workflowId); - throw new BadRequestException("Could not find galaxy algorithm."); - } - final WorkflowDetails workflowDetails = workflowsClient.showWorkflow(workflow.getId()); - for (Map.Entry<String, WorkflowInputDefinition> workflowParameter : workflowDetails.getInputs().entrySet()) { - if (!(algorithmParamsIncludingEmpty.containsKey(workflowParameter.getValue().getUuid()))) { - algorithmParamsIncludingEmpty.put(workflowParameter.getValue().getUuid(), ""); - } - } - - // Create the body of the request - HashMap<String, HashMap<String, String>> requestBody = new HashMap<>(); - requestBody.put("inputs", algorithmParamsIncludingEmpty); - JsonObject requestBodyJson = new JsonParser().parse(gson.toJson(requestBody)).getAsJsonObject(); - - // Create the request client - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - logger.LogUserAction("Running Galaxy workflow with id: " + workflow.getId()); - - // Call Galaxy to run the workflow - Call<PostWorkflowToGalaxyDtoResponse> call = service.postWorkflowToGalaxy(workflow.getId(), galaxyApiKey, requestBodyJson); - try { - Response<PostWorkflowToGalaxyDtoResponse> response = call.execute(); - - if (response.code() == 200) { // Call succeeded - String responseBody = gson.toJson(response.body()); - logger.LogUserAction("Response: " + responseBody); - - String historyId = (String) new JSONObject(responseBody).get("history_id"); - experimentDAO.setWorkflowHistoryId(historyId); - experimentDAO.setStatus(ExperimentDAO.Status.success); - - } else { // Something unexpected happened - String msgErr = gson.toJson(response.errorBody()); - logger.LogUserAction("Error Response: " + msgErr); - experimentDTO.setStatus((response.code() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); - } - - } catch (Exception e) { - logger.LogUserAction("An exception occurred: " + e.getMessage()); - experimentDAO.setStatus(ExperimentDAO.Status.error); - } - saveExperiment(experimentDAO, logger); - - // Start the process of fetching the status - updateWorkflowExperiment(experimentDAO, logger); - - logger.LogUserAction("Run workflow completed!"); - - experimentDTO = experimentDAO.convertToDTO(true); - return experimentDTO; - } - - - /** - * This method creates a thread that will fetch the workflow result when it is ready - * - * @param experimentDAO will be used to fetch it's workflow status, it should have the workflowHistoryId initialized - * and the result should not already be fetched - */ - public void updateWorkflowExperiment(ExperimentDAO experimentDAO, Logger logger) { - - if (experimentDAO == null) { - logger.LogUserAction("The experiment does not exist."); - return; - } - - logger.LogUserAction(" Experiment id : " + experimentDAO.getUuid()); - if (experimentDAO.getWorkflowHistoryId() == null) { - logger.LogUserAction("History Id does not exist."); - return; - } - - logger.LogUserAction("Starting Thread..."); - new Thread(() -> { - while (true) { - // ATTENTION: Inside the Thread only LogExperimentAction should be used, not LogExperimentAction! - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Thread is running..."); - - try { - sleep(2000); - } catch (InterruptedException e) { - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Sleep was disrupted: " + e.getMessage()); - } - - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Fetching status for experiment Id: " + experimentDAO.getUuid()); - - String state = getWorkflowStatus(experimentDAO); - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "State is: " + state); - - switch (state) { - case "pending": - // Do nothing, when the experiment is created the status is set to running - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Workflow is still running."); - break; - - case "success": - // Get only the job result that is visible - List<GalaxyWorkflowResult> workflowJobsResults = getWorkflowResults(experimentDAO); - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Results are: " + workflowJobsResults.toString()); - - boolean resultFound = false; - for (GalaxyWorkflowResult jobResult : workflowJobsResults) { - if (jobResult.getVisible()) { - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Visible result are: " + jobResult.getId()); - - String result = getWorkflowResultBody(experimentDAO, jobResult.getId()); - - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO: " + result); - if (result == null) { - experimentDAO.setStatus(ExperimentDAO.Status.error); - } else { - experimentDAO.setResult(result); - experimentDAO.setStatus(ExperimentDAO.Status.success); - resultFound = true; - } - } - } - - if (!resultFound) { // If there is no visible result - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "No visible result"); - experimentDAO.setStatus(ExperimentDAO.Status.error); - } - - finishExperiment(experimentDAO, logger); - break; - - case "error": - // Get the job result that failed - workflowJobsResults = getWorkflowResults(experimentDAO); - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Error results are: " + workflowJobsResults.toString()); - - boolean failedJobFound = false; - for (GalaxyWorkflowResult jobResult : workflowJobsResults) { - if (jobResult.getState().equals("error")) { - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Failed job is: " + jobResult.getId()); - - String result = getWorkflowJobError(jobResult.getId(), experimentDAO); - - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Job result: " + result); - if (result == null) { - experimentDAO.setStatus(ExperimentDAO.Status.error); - } - experimentDAO.setStatus(ExperimentDAO.Status.error); - failedJobFound = true; - } - } - - if (!failedJobFound) { // If there is no visible failed job - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "No failed result"); - experimentDAO.setStatus(ExperimentDAO.Status.error); - } - finishExperiment(experimentDAO, logger); - break; - - default: // InternalError or unexpected result - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "An unexpected error occurred."); - experimentDAO.setStatus(ExperimentDAO.Status.error); - finishExperiment(experimentDAO, logger); - break; - } - - // If result exists return - if (experimentDAO.getResult() != null) { - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO exists: " + experimentDAO.getResult()); - return; - } - } - }).start(); - } - - - /** - * @param experimentDAO The experiment of the workflow - * @return "pending" -> When the workflow is still running - * "internalError" -> When an exception or a bad request occurred - * "error" -> When the workflow produced an error - * "success" -> When the workflow completed successfully - */ - public String getWorkflowStatus(ExperimentDAO experimentDAO) { - String historyId = experimentDAO.getWorkflowHistoryId(); - String experimentName = experimentDAO.getName(); - UUID experimentId = experimentDAO.getUuid(); - - // ATTENTION: This function is used from a Thread. Only LogExperimentAction should be used, not LogUserAction! - Logger.LogExperimentAction(experimentName, experimentId, " History Id : " + historyId); - - // Create the request client - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - Call<Object> call = service.getWorkflowStatusFromGalaxy(historyId, galaxyApiKey); - - String result; - try { - Response<Object> response = call.execute(); - if (response.code() >= 400) { - Logger.LogExperimentAction(experimentName, experimentId, " Response code: " - + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); - return "internalError"; - } - result = new Gson().toJson(response.body()); - Logger.LogExperimentAction(experimentName, experimentId, " ResultDTO: " + result); - - } catch (IOException e) { - Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); - return "internalError"; - } - - String state; - try { - JSONObject resultJson = new JSONObject(result); - state = resultJson.getString("state"); - } catch (JSONException e) { - Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); - return "internalError"; - } - - Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); - switch (state) { - case "ok": - return "success"; - case "error": - return "error"; - case "pending": - case "new": - case "waiting": - case "queued": - return "pending"; - default: - return "internalError"; - } - } - - /** - * @param experimentDAO The experiment of the workflow - * @return a List<GalaxyWorkflowResult> or null when an error occurred - */ - public List<GalaxyWorkflowResult> getWorkflowResults(ExperimentDAO experimentDAO) { - - String historyId = experimentDAO.getWorkflowHistoryId(); - String experimentName = experimentDAO.getName(); - UUID experimentId = experimentDAO.getUuid(); - Logger.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); - - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - Call<List<GalaxyWorkflowResult>> call = service.getWorkflowResultsFromGalaxy(historyId, galaxyApiKey); - - List<GalaxyWorkflowResult> getGalaxyWorkflowResultList; - try { - Response<List<GalaxyWorkflowResult>> response = call.execute(); - if (response.code() >= 400) { - Logger.LogExperimentAction(experimentName, experimentId, " Response code: " - + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); - return null; - } - getGalaxyWorkflowResultList = response.body(); - Logger.LogExperimentAction(experimentName, experimentId, " ResultDTO: " + response.body()); - - } catch (IOException e) { - Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); - return null; - } - - Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); - return getGalaxyWorkflowResultList; - - } - - /** - * @param experimentDAO The experiment of the workflow - * @param contentId the id of the job result that we want - * @return the result of the specific workflow job, null if there was an error - */ - public String getWorkflowResultBody(ExperimentDAO experimentDAO, String contentId) { - - String historyId = experimentDAO.getWorkflowHistoryId(); - String experimentName = experimentDAO.getName(); - UUID experimentId = experimentDAO.getUuid(); - - Logger.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); - - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - Call<Object> call = - service.getWorkflowResultsBodyFromGalaxy(historyId, contentId, galaxyApiKey); - - String resultJson; - try { - Response<Object> response = call.execute(); - if (response.code() >= 400) { - Logger.LogExperimentAction(experimentName, experimentId, " Response code: " - + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); - return null; - } - resultJson = new Gson().toJson(response.body()); - Logger.LogExperimentAction(experimentName, experimentId, " ResultDTO: " + resultJson); - - } catch (IOException e) { - Logger.LogExperimentAction(experimentName, experimentId, - " An exception happened: " + e.getMessage()); - return null; - } - - Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); - return formattingGalaxyResult(resultJson); - } - - - /** - * @param jobId the id of the workflow job that failed - * @return the error that was produced or null if an error occurred - */ - public String getWorkflowJobError(String jobId, ExperimentDAO experimentDAO) { - String experimentName = experimentDAO.getName(); - UUID experimentId = experimentDAO.getUuid(); - - Logger.LogExperimentAction(experimentName, experimentId, " jobId : " + jobId); - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - Call<Object> callError = service.getErrorMessageOfWorkflowFromGalaxy(jobId, galaxyApiKey); - - String fullError; - String returnError; - try { - Response<Object> response = callError.execute(); - if (response.code() >= 400) { - Logger.LogExperimentAction(experimentName, experimentId, "Response code: " - + response.code() + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); - return null; - } - - // Parsing the stderr of the job that failed - String jsonString = new Gson().toJson(response.body()); - JsonElement jsonElement = new JsonParser().parse(jsonString); - JsonObject rootObject = jsonElement.getAsJsonObject(); - fullError = rootObject.get("stderr").getAsString(); - Logger.LogExperimentAction(experimentName, experimentId, "Error: " + fullError); - - String[] arrOfStr = fullError.split("ValueError", 0); - String specError = arrOfStr[arrOfStr.length - 1]; - returnError = specError.substring(1); - Logger.LogExperimentAction(experimentName, experimentId, "Parsed Error: " + returnError); - - } catch (IOException e) { - Logger.LogExperimentAction(experimentName, experimentId, "Exception: " + e.getMessage()); - return null; - } - - Logger.LogExperimentAction(experimentName, experimentId, "Completed successfully!"); - - return returnError; - } } diff --git a/src/main/java/eu/hbp/mip/services/GalaxyService.java b/src/main/java/eu/hbp/mip/services/GalaxyService.java new file mode 100644 index 0000000000000000000000000000000000000000..80590c7be75a5603996d9b792921b8bb73a42b99 --- /dev/null +++ b/src/main/java/eu/hbp/mip/services/GalaxyService.java @@ -0,0 +1,454 @@ +package eu.hbp.mip.services; + +import com.github.jmchilton.blend4j.galaxy.GalaxyInstance; +import com.github.jmchilton.blend4j.galaxy.GalaxyInstanceFactory; +import com.github.jmchilton.blend4j.galaxy.WorkflowsClient; +import com.github.jmchilton.blend4j.galaxy.beans.Workflow; +import com.github.jmchilton.blend4j.galaxy.beans.WorkflowDetails; +import com.github.jmchilton.blend4j.galaxy.beans.WorkflowInputDefinition; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.internal.LinkedTreeMap; +import eu.hbp.mip.controllers.galaxy.retrofit.RetroFitGalaxyClients; +import eu.hbp.mip.controllers.galaxy.retrofit.RetrofitClientInstance; +import eu.hbp.mip.models.DAOs.ExperimentDAO; +import eu.hbp.mip.models.DTOs.ExaremeAlgorithmRequestParamDTO; +import eu.hbp.mip.models.DTOs.ExperimentDTO; +import eu.hbp.mip.models.galaxy.GalaxyWorkflowResult; +import eu.hbp.mip.models.galaxy.PostWorkflowToGalaxyDtoResponse; +import eu.hbp.mip.repositories.ExperimentRepository; +import eu.hbp.mip.utils.Exceptions.BadRequestException; +import eu.hbp.mip.utils.JsonConverters; +import eu.hbp.mip.utils.Logger; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import retrofit2.Call; +import retrofit2.Response; + +import java.io.IOException; +import java.util.*; + +import static java.lang.Thread.sleep; + +@Service +public class GalaxyService { + + private final ActiveUserService activeUserService; + private final ExperimentRepository experimentRepository; + public GalaxyService( + ActiveUserService activeUserService, + ExperimentRepository experimentRepository + ) { + this.activeUserService = activeUserService; + this.experimentRepository = experimentRepository; + } + @Value("#{'${services.galaxy.galaxyUrl}'}") + private String galaxyUrl; + + @Value("#{'${services.galaxy.galaxyApiKey}'}") + private String galaxyApiKey; + + private static final Gson gson = new Gson(); + + /** + * The runWorkflow will POST the algorithm to the galaxy client + * + * @param experimentDTO is the request with the experiment information + * @return the response to be returned + */ + public ExperimentDTO runGalaxyWorkflow(ExperimentDTO experimentDTO, Logger logger) { + logger.LogUserAction("Running a workflow..."); + + ExperimentDAO experimentDAO = experimentRepository.createExperimentInTheDatabase(experimentDTO, activeUserService.getActiveUser(), logger); + logger.LogUserAction("Created experiment with uuid :" + experimentDAO.getUuid()); + + + // Run the 1st algorithm from the list + String workflowId = experimentDTO.getAlgorithm().getName(); + + // Get the parameters + List<ExaremeAlgorithmRequestParamDTO> algorithmParameters + = experimentDTO.getAlgorithm().getParameters(); + + // Convert the parameters to workflow parameters + HashMap<String, String> algorithmParamsIncludingEmpty = new HashMap<>(); + if (algorithmParameters != null) { + for (ExaremeAlgorithmRequestParamDTO param : algorithmParameters) { + algorithmParamsIncludingEmpty.put(param.getName(), param.getValue()); + } + } + + // Get all the algorithm parameters because the frontend provides only the non-null + final GalaxyInstance instance = GalaxyInstanceFactory.get(galaxyUrl, galaxyApiKey); + final WorkflowsClient workflowsClient = instance.getWorkflowsClient(); + Workflow workflow = null; + for (Workflow curWorkflow : workflowsClient.getWorkflows()) { + if (curWorkflow.getId().equals(workflowId)) { + workflow = curWorkflow; + break; + } + } + if (workflow == null) { + logger.LogUserAction("Could not find algorithm code: " + workflowId); + throw new BadRequestException("Could not find galaxy algorithm."); + } + final WorkflowDetails workflowDetails = workflowsClient.showWorkflow(workflow.getId()); + for (Map.Entry<String, WorkflowInputDefinition> workflowParameter : workflowDetails.getInputs().entrySet()) { + if (!(algorithmParamsIncludingEmpty.containsKey(workflowParameter.getValue().getUuid()))) { + algorithmParamsIncludingEmpty.put(workflowParameter.getValue().getUuid(), ""); + } + } + + // Create the body of the request + HashMap<String, HashMap<String, String>> requestBody = new HashMap<>(); + requestBody.put("inputs", algorithmParamsIncludingEmpty); + JsonObject requestBodyJson = new JsonParser().parse(gson.toJson(requestBody)).getAsJsonObject(); + + // Create the request client + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + logger.LogUserAction("Running Galaxy workflow with id: " + workflow.getId()); + + // Call Galaxy to run the workflow + Call<PostWorkflowToGalaxyDtoResponse> call = service.postWorkflowToGalaxy(workflow.getId(), galaxyApiKey, requestBodyJson); + try { + Response<PostWorkflowToGalaxyDtoResponse> response = call.execute(); + + if (response.code() == 200) { // Call succeeded + String responseBody = gson.toJson(response.body()); + logger.LogUserAction("Response: " + responseBody); + + String historyId = (String) new JSONObject(responseBody).get("history_id"); + experimentDAO.setWorkflowHistoryId(historyId); + experimentDAO.setStatus(ExperimentDAO.Status.success); + + } else { // Something unexpected happened + String msgErr = gson.toJson(response.errorBody()); + logger.LogUserAction("Error Response: " + msgErr); + experimentDTO.setStatus((response.code() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); + } + + } catch (Exception e) { + logger.LogUserAction("An exception occurred: " + e.getMessage()); + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + experimentRepository.saveExperiment(experimentDAO, logger); + + // Start the process of fetching the status + updateWorkflowExperiment(experimentDAO, logger); + + logger.LogUserAction("Run workflow completed!"); + + experimentDTO = new ExperimentDTO(true, experimentDAO); + return experimentDTO; + } + + + + /** + * @param experimentDAO The experiment of the workflow + * @return "pending" -> When the workflow is still running + * "internalError" -> When an exception or a bad request occurred + * "error" -> When the workflow produced an error + * "success" -> When the workflow completed successfully + */ + public String getWorkflowStatus(ExperimentDAO experimentDAO) { + String historyId = experimentDAO.getWorkflowHistoryId(); + String experimentName = experimentDAO.getName(); + UUID experimentId = experimentDAO.getUuid(); + + // ATTENTION: This function is used from a Thread. Only LogExperimentAction should be used, not LogUserAction! + Logger.LogExperimentAction(experimentName, experimentId, " History Id : " + historyId); + + // Create the request client + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + Call<Object> call = service.getWorkflowStatusFromGalaxy(historyId, galaxyApiKey); + + String result; + try { + Response<Object> response = call.execute(); + if (response.code() >= 400) { + Logger.LogExperimentAction(experimentName, experimentId, " Response code: " + + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); + return "internalError"; + } + result = new Gson().toJson(response.body()); + Logger.LogExperimentAction(experimentName, experimentId, " ResultDTO: " + result); + + } catch (IOException e) { + Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); + return "internalError"; + } + + String state; + try { + JSONObject resultJson = new JSONObject(result); + state = resultJson.getString("state"); + } catch (JSONException e) { + Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); + return "internalError"; + } + + Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); + switch (state) { + case "ok": + return "success"; + case "error": + return "error"; + case "pending": + case "new": + case "waiting": + case "queued": + return "pending"; + default: + return "internalError"; + } + } + + /** + * @param experimentDAO The experiment of the workflow + * @return a List<GalaxyWorkflowResult> or null when an error occurred + */ + public List<GalaxyWorkflowResult> getWorkflowResults(ExperimentDAO experimentDAO) { + + String historyId = experimentDAO.getWorkflowHistoryId(); + String experimentName = experimentDAO.getName(); + UUID experimentId = experimentDAO.getUuid(); + Logger.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); + + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + Call<List<GalaxyWorkflowResult>> call = service.getWorkflowResultsFromGalaxy(historyId, galaxyApiKey); + + List<GalaxyWorkflowResult> getGalaxyWorkflowResultList; + try { + Response<List<GalaxyWorkflowResult>> response = call.execute(); + if (response.code() >= 400) { + Logger.LogExperimentAction(experimentName, experimentId, " Response code: " + + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); + return null; + } + getGalaxyWorkflowResultList = response.body(); + Logger.LogExperimentAction(experimentName, experimentId, " ResultDTO: " + response.body()); + + } catch (IOException e) { + Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); + return null; + } + + Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); + return getGalaxyWorkflowResultList; + + } + + /** + * @param experimentDAO The experiment of the workflow + * @param contentId the id of the job result that we want + * @return the result of the specific workflow job, null if there was an error + */ + public String getWorkflowResultBody(ExperimentDAO experimentDAO, String contentId) { + + String historyId = experimentDAO.getWorkflowHistoryId(); + String experimentName = experimentDAO.getName(); + UUID experimentId = experimentDAO.getUuid(); + + Logger.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); + + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + Call<Object> call = + service.getWorkflowResultsBodyFromGalaxy(historyId, contentId, galaxyApiKey); + + String resultJson; + try { + Response<Object> response = call.execute(); + if (response.code() >= 400) { + Logger.LogExperimentAction(experimentName, experimentId, " Response code: " + + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); + return null; + } + resultJson = new Gson().toJson(response.body()); + Logger.LogExperimentAction(experimentName, experimentId, " ResultDTO: " + resultJson); + + } catch (IOException e) { + Logger.LogExperimentAction(experimentName, experimentId, + " An exception happened: " + e.getMessage()); + return null; + } + + Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); + return formattingGalaxyResult(resultJson); + } + + private String formattingGalaxyResult(String result) { + List<LinkedTreeMap<String,Object>> jsonObject = JsonConverters.convertJsonStringToObject(result, new ArrayList<ArrayList<Object>>().getClass()); + LinkedTreeMap<String,Object> firstResult = jsonObject.get(0); + jsonObject = (List<LinkedTreeMap<String, Object>>) firstResult.get("result"); + List<LinkedTreeMap<String,Object>> finalJsonObject = new ArrayList<>(); + finalJsonObject.add(jsonObject.get(0)); + return JsonConverters.convertObjectToJsonString(finalJsonObject); + } + + + /** + * @param jobId the id of the workflow job that failed + * @return the error that was produced or null if an error occurred + */ + public String getWorkflowJobError(String jobId, ExperimentDAO experimentDAO) { + String experimentName = experimentDAO.getName(); + UUID experimentId = experimentDAO.getUuid(); + + Logger.LogExperimentAction(experimentName, experimentId, " jobId : " + jobId); + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + Call<Object> callError = service.getErrorMessageOfWorkflowFromGalaxy(jobId, galaxyApiKey); + + String fullError; + String returnError; + try { + Response<Object> response = callError.execute(); + if (response.code() >= 400) { + Logger.LogExperimentAction(experimentName, experimentId, "Response code: " + + response.code() + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); + return null; + } + + // Parsing the stderr of the job that failed + String jsonString = new Gson().toJson(response.body()); + JsonElement jsonElement = new JsonParser().parse(jsonString); + JsonObject rootObject = jsonElement.getAsJsonObject(); + fullError = rootObject.get("stderr").getAsString(); + Logger.LogExperimentAction(experimentName, experimentId, "Error: " + fullError); + + String[] arrOfStr = fullError.split("ValueError", 0); + String specError = arrOfStr[arrOfStr.length - 1]; + returnError = specError.substring(1); + Logger.LogExperimentAction(experimentName, experimentId, "Parsed Error: " + returnError); + + } catch (IOException e) { + Logger.LogExperimentAction(experimentName, experimentId, "Exception: " + e.getMessage()); + return null; + } + + Logger.LogExperimentAction(experimentName, experimentId, "Completed successfully!"); + + return returnError; + } + + /** + * This method creates a thread that will fetch the workflow result when it is ready + * + * @param experimentDAO will be used to fetch it's workflow status, it should have the workflowHistoryId initialized + * and the result should not already be fetched + */ + public void updateWorkflowExperiment(ExperimentDAO experimentDAO, Logger logger) { + + if (experimentDAO == null) { + logger.LogUserAction("The experiment does not exist."); + return; + } + + logger.LogUserAction(" Experiment id : " + experimentDAO.getUuid()); + if (experimentDAO.getWorkflowHistoryId() == null) { + logger.LogUserAction("History Id does not exist."); + return; + } + + logger.LogUserAction("Starting Thread..."); + new Thread(() -> { + while (true) { + // ATTENTION: Inside the Thread only LogExperimentAction should be used, not LogExperimentAction! + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Thread is running..."); + + try { + sleep(2000); + } catch (InterruptedException e) { + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Sleep was disrupted: " + e.getMessage()); + } + + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Fetching status for experiment Id: " + experimentDAO.getUuid()); + + String state = getWorkflowStatus(experimentDAO); + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "State is: " + state); + + switch (state) { + case "pending": + // Do nothing, when the experiment is created the status is set to running + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Workflow is still running."); + break; + + case "success": + // Get only the job result that is visible + List<GalaxyWorkflowResult> workflowJobsResults = getWorkflowResults(experimentDAO); + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Results are: " + workflowJobsResults.toString()); + + boolean resultFound = false; + for (GalaxyWorkflowResult jobResult : workflowJobsResults) { + if (jobResult.getVisible()) { + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Visible result are: " + jobResult.getId()); + + String result = getWorkflowResultBody(experimentDAO, jobResult.getId()); + + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO: " + result); + if (result == null) { + experimentDAO.setStatus(ExperimentDAO.Status.error); + } else { + experimentDAO.setResult(result); + experimentDAO.setStatus(ExperimentDAO.Status.success); + resultFound = true; + } + } + } + + if (!resultFound) { // If there is no visible result + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "No visible result"); + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + + experimentRepository.finishExperiment(experimentDAO, logger); + break; + + case "error": + // Get the job result that failed + workflowJobsResults = getWorkflowResults(experimentDAO); + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Error results are: " + workflowJobsResults.toString()); + + boolean failedJobFound = false; + for (GalaxyWorkflowResult jobResult : workflowJobsResults) { + if (jobResult.getState().equals("error")) { + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Failed job is: " + jobResult.getId()); + + String result = getWorkflowJobError(jobResult.getId(), experimentDAO); + + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Job result: " + result); + if (result == null) { + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + experimentDAO.setStatus(ExperimentDAO.Status.error); + failedJobFound = true; + } + } + + if (!failedJobFound) { // If there is no visible failed job + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "No failed result"); + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + experimentRepository.finishExperiment(experimentDAO, logger); + break; + + default: // InternalError or unexpected result + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "An unexpected error occurred."); + experimentDAO.setStatus(ExperimentDAO.Status.error); + experimentRepository.finishExperiment(experimentDAO, logger); + break; + } + + // If result exists return + if (experimentDAO.getResult() != null) { + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO exists: " + experimentDAO.getResult()); + return; + } + } + }).start(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8aadac388979fa2c7af445fa88c1f697fb8fed22..d8d542b6bb2d78a46f0f52d87057ab71acca04cd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -35,7 +35,7 @@ spring: ### EXTERNAL SERVICES ### services: mipengine: - algorithmsUrl: "http://192.168.124.129:5000/algorithms" + algorithmsUrl: "http://127.0.0.1:5000/algorithms" exareme: queryExaremeUrl: "http://127.0.0.1:9090/mining/query" algorithmsUrl: "http://127.0.0.1:9090/mining/algorithms.json"