diff --git a/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java b/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java index e5d0b04c54b0fd8652f5d284cb8690eaf14d3acf..8e0178479cfd31a1838d23462a61926458aaa7f6 100644 --- a/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java +++ b/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java @@ -103,7 +103,8 @@ 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) { - experimentDTO = experimentService.createTransientExperiment(authentication, experimentDTO, new Logger(activeUserService.getActiveUser().getUsername(), "(POST) /experiments/transient")); + experimentDTO = experimentService. + runTransientExperiment(authentication, experimentDTO, new Logger(activeUserService.getActiveUser().getUsername(), "(POST) /experiments/transient")); return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.OK); } } \ No newline at end of file diff --git a/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java b/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java index b776b6c46d147e0c146305b4567a0c518b3ea11c..4960f27c44a7f81c5a53dfa5eb811d250b48ab21 100644 --- a/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java +++ b/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java @@ -104,7 +104,9 @@ public interface ExperimentRepository extends CrudRepository<ExperimentDAO, UUID try { save(experimentDAO); } catch (Exception e) { - logger.LogUserAction( "Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); + logger.LogUserAction( + "Attempted to save changes to database but an error occurred : " + 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 1bd848ed64f22c27c2170a450ca103a723199f0c..8ba1332614bc0941d8dbedfceb31445e8f545751 100644 --- a/src/main/java/eu/hbp/mip/services/ExperimentService.java +++ b/src/main/java/eu/hbp/mip/services/ExperimentService.java @@ -1,14 +1,16 @@ package eu.hbp.mip.services; import com.google.gson.Gson; -import com.google.gson.internal.LinkedTreeMap; import eu.hbp.mip.models.DAOs.ExperimentDAO; import eu.hbp.mip.models.DAOs.UserDAO; import eu.hbp.mip.models.DTOs.*; import eu.hbp.mip.repositories.ExperimentRepository; import eu.hbp.mip.services.Specifications.ExperimentSpecifications; import eu.hbp.mip.utils.ClaimUtils; -import eu.hbp.mip.utils.Exceptions.*; +import eu.hbp.mip.utils.Exceptions.BadRequestException; +import eu.hbp.mip.utils.Exceptions.InternalServerError; +import eu.hbp.mip.utils.Exceptions.NoContent; +import eu.hbp.mip.utils.Exceptions.UnauthorizedException; import eu.hbp.mip.utils.HTTPUtil; import eu.hbp.mip.utils.JsonConverters; import eu.hbp.mip.utils.Logger; @@ -19,6 +21,7 @@ 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 java.util.*; @@ -50,16 +53,16 @@ public class ExperimentService { /** * The getExperiments will retrieve the experiments from database according to the filters. * - * @param name is optional, in case it is required to filter the experiments by name - * @param algorithm is optional, in case it is required to filter the experiments by algorithm name - * @param shared is optional, in case it is required to filter the experiments by shared - * @param viewed is optional, in case it is required to filter the experiments by viewed - * @param includeShared is optional, in case it is required to retrieve the experiment that is shared - * @param page is the page that is required to be retrieve - * @param size is the size of each page - * @param orderBy is the column that is required to ordered by - * @param descending is a boolean to determine if the experiments will be order by descending or ascending - * @param logger contains username and the endpoint. + * @param name is optional, in case it is required to filter the experiments by name + * @param algorithm is optional, in case it is required to filter the experiments by algorithm name + * @param shared is optional, in case it is required to filter the experiments by shared + * @param viewed is optional, in case it is required to filter the experiments by viewed + * @param includeShared is optional, in case it is required to retrieve the experiment that is shared + * @param page is the page that is required to be retrieve + * @param size is the size of each page + * @param orderBy is the column that is required to ordered by + * @param descending is a boolean to determine if the experiments will be order by descending or ascending + * @param logger contains username and the endpoint. * @return a list of mapped experiments */ @@ -70,16 +73,14 @@ public class ExperimentService { if (size > 50) throw new BadRequestException("Invalid size input, max size is 50."); Specification<ExperimentDAO> spec; - if(!authenticationIsEnabled || ClaimUtils.validateAccessRightsOnExperiments(authentication, logger)) - { + if (!authenticationIsEnabled || ClaimUtils.validateAccessRightsOnExperiments(authentication, logger)) { spec = Specification .where(new ExperimentSpecifications.ExperimentWithName(name)) .and(new ExperimentSpecifications.ExperimentWithAlgorithm(algorithm)) .and(new ExperimentSpecifications.ExperimentWithShared(shared)) .and(new ExperimentSpecifications.ExperimentWithViewed(viewed)) .and(new ExperimentSpecifications.ExperimentOrderBy(orderBy, descending)); - } - else { + } else { spec = Specification .where(new ExperimentSpecifications.MyExperiment(user.getUsername())) .or(new ExperimentSpecifications.SharedExperiment(includeShared)) @@ -111,8 +112,8 @@ public class ExperimentService { /** * The getExperiment will retrieve the experiment from database according to the input uuid * - * @param uuid is the id of the experiment to be retrieved - * @param logger contains username and the endpoint. + * @param uuid is the id of the experiment to be retrieved + * @param logger contains username and the endpoint. * @return the experiment information that was retrieved from the database */ public ExperimentDTO getExperiment(Authentication authentication, String uuid, Logger logger) { @@ -125,9 +126,9 @@ public class ExperimentService { experimentDAO = experimentRepository.loadExperiment(uuid, logger); if ( !experimentDAO.isShared() - && !experimentDAO.getCreatedBy().getUsername().equals(user.getUsername()) - && authenticationIsEnabled - && ClaimUtils.validateAccessRightsOnExperiments(authentication, logger) + && !experimentDAO.getCreatedBy().getUsername().equals(user.getUsername()) + && authenticationIsEnabled + && ClaimUtils.validateAccessRightsOnExperiments(authentication, logger) ) { logger.LogUserAction("Accessing Experiment is unauthorized."); throw new UnauthorizedException("You don't have access to the experiment."); @@ -143,7 +144,7 @@ public class ExperimentService { * * @param authentication is the role of the user * @param experimentDTO is the experiment information - * @param logger contains username and the endpoint. + * @param logger contains username and the endpoint. * @return the experiment information which was created */ public ExperimentDTO createExperiment(Authentication authentication, ExperimentDTO experimentDTO, Logger logger) { @@ -154,7 +155,7 @@ public class ExperimentService { // Get the type and name of algorithm String algorithmType = experimentDTO.getAlgorithm().getType(); - if(algorithmType == null){ + if (algorithmType == null) { logger.LogUserAction("Please provide algorithm type."); throw new BadRequestException("Please provide algorithm type."); } @@ -169,22 +170,22 @@ public class ExperimentService { // Run with the appropriate engine if (algorithmType.equals("workflow")) { logger.LogUserAction("Algorithm runs on Galaxy."); - return galaxyService.runGalaxyWorkflow(experimentDTO, logger); + return galaxyService.createGalaxyExperiment(experimentDTO, logger); } else { logger.LogUserAction("Algorithm runs on Exareme."); - return createExperiment(experimentDTO, logger); + return createSynchronousExperiment(experimentDTO, logger); } } /** - * The createTransientExperiment will run synchronous a transient experiment into exareme and provide results + * Will run synchronously an experiment and return the result * * @param authentication is the role of the user * @param experimentDTO is the experiment information - * @param logger contains username and the endpoint. + * @param logger contains username and the endpoint. * @return the experiment information which was created */ - public ExperimentDTO createTransientExperiment(Authentication authentication, ExperimentDTO experimentDTO, Logger logger) { + public ExperimentDTO runTransientExperiment(Authentication authentication, ExperimentDTO experimentDTO, Logger logger) { //Checking if check (POST) /experiments has proper input. checkPostExperimentProperInput(experimentDTO, logger); @@ -192,7 +193,7 @@ public class ExperimentService { // Get the type and name of algorithm String algorithmType = experimentDTO.getAlgorithm().getType(); - if(algorithmType.equals("workflow")){ + if (algorithmType.equals("workflow")) { logger.LogUserAction("You can not run workflow algorithms transiently."); throw new BadRequestException("You can not run workflow algorithms transiently."); } @@ -206,13 +207,17 @@ public class ExperimentService { logger.LogUserAction("Completed, returning: " + experimentDTO); - // Results are stored in the experiment object - ExaremeAlgorithmResultDTO exaremeAlgorithmResultDTO = runExperiment(experimentDTO, logger); + ExaremeAlgorithmResultDTO exaremeAlgorithmResultDTO = runSynchronousExperiment(experimentDTO, logger); - logger.LogUserAction("Experiment with uuid: " + experimentDTO.getUuid() + "gave response code: " + exaremeAlgorithmResultDTO.getCode() + " and result: " + exaremeAlgorithmResultDTO.getResult()); + logger.LogUserAction( + "Experiment with uuid: " + experimentDTO.getUuid() + + "gave response code: " + exaremeAlgorithmResultDTO.getCode() + + " and result: " + exaremeAlgorithmResultDTO.getResult() + ); - experimentDTO.setResult((exaremeAlgorithmResultDTO.getCode() >= 400) ? null : exaremeAlgorithmResultDTO.getResult()); - experimentDTO.setStatus((exaremeAlgorithmResultDTO.getCode() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); + experimentDTO.setResult(exaremeAlgorithmResultDTO.getResult()); + experimentDTO.setStatus((exaremeAlgorithmResultDTO.getCode() >= 400) + ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); return experimentDTO; } @@ -222,7 +227,7 @@ public class ExperimentService { * * @param uuid is the id of the experiment to be updated * @param experimentDTO is the experiment information to be updated - * @param logger contains username and the endpoint. + * @param logger contains username and the endpoint. */ public ExperimentDTO updateExperiment(String uuid, ExperimentDTO experimentDTO, Logger logger) { ExperimentDAO experimentDAO; @@ -264,8 +269,8 @@ public class ExperimentService { /** * The deleteExperiment will delete an experiment from the database * - * @param uuid is the id of the experiment to be deleted - * @param logger contains username and the endpoint. + * @param uuid is the id of the experiment to be deleted + * @param logger contains username and the endpoint. */ public void deleteExperiment(String uuid, Logger logger) { ExperimentDAO experimentDAO; @@ -301,49 +306,49 @@ public class ExperimentService { && experimentDTO.getUuid() == null; if (!properInput) { - logger.LogUserAction( "Invalid input."); + logger.LogUserAction("Invalid input."); throw new BadRequestException("Please provide proper input."); } } private void verifyPatchExperimentNonEditableFields(ExperimentDTO experimentDTO, Logger logger) { - if (experimentDTO.getUuid() != null ) { - logger.LogUserAction( "Uuid is not editable."); + if (experimentDTO.getUuid() != null) { + logger.LogUserAction("Uuid is not editable."); throw new BadRequestException("Uuid is not editable."); } - if (experimentDTO.getAlgorithm() != null ) { - logger.LogUserAction( "Algorithm is not editable."); + if (experimentDTO.getAlgorithm() != null) { + logger.LogUserAction("Algorithm is not editable."); throw new BadRequestException("Algorithm is not editable."); } if (experimentDTO.getCreated() != null) { - logger.LogUserAction( "Created is not editable."); + logger.LogUserAction("Created is not editable."); throw new BadRequestException("Created is not editable."); } if (experimentDTO.getCreatedBy() != null) { - logger.LogUserAction( "CreatedBy is not editable."); + logger.LogUserAction("CreatedBy is not editable."); throw new BadRequestException("CreatedBy is not editable."); } if (experimentDTO.getUpdated() != null) { - logger.LogUserAction( "Updated is not editable."); + logger.LogUserAction("Updated is not editable."); throw new BadRequestException("Updated is not editable."); } if (experimentDTO.getFinished() != null) { - logger.LogUserAction( "Finished is not editable."); + logger.LogUserAction("Finished is not editable."); throw new BadRequestException("Finished is not editable."); } if (experimentDTO.getResult() != null) { - logger.LogUserAction( "Result is not editable."); + logger.LogUserAction("Result is not editable."); throw new BadRequestException("Result is not editable."); } if (experimentDTO.getStatus() != null) { - logger.LogUserAction( "Status is not editable."); + logger.LogUserAction("Status is not editable."); throw new BadRequestException("Status is not editable."); } } @@ -365,7 +370,7 @@ public class ExperimentService { * The getDatasetFromExperimentParameters will retrieve the dataset from the experiment parameters * * @param experimentDTO is the experiment information - * @param logger contains username and the endpoint. + * @param logger contains username and the endpoint. * @return the dataset from the experiment */ private String getDatasetFromExperimentParameters(ExperimentDTO experimentDTO, Logger logger) { @@ -385,142 +390,175 @@ public class ExperimentService { return experimentDatasets; } - private ExaremeAlgorithmResultDTO convertMIPEngineResultToExaremeAlgorithmResult(int code, String result) { - MIPEngineAlgorithmResultDTO mipVisualization = JsonConverters.convertJsonStringToObject(result, MIPEngineAlgorithmResultDTO.class); - LinkedTreeMap<String,Object> data = new LinkedTreeMap<>(); - data.put("data", new TabularVisualizationDTO(mipVisualization)); - data.put("type", "application/vnd.dataresource+json"); - List<Object> finalObject = new ArrayList<>(); - finalObject.add(data); - return new ExaremeAlgorithmResultDTO(code, finalObject); + private List<Object> convertMIPEngineToExaremeAlgorithmResult( + MIPEngineAlgorithmResultDTO mipEngineAlgorithmResultDTO + ) { + Map<String, Object> exaremeResultElement = new HashMap<>(); + exaremeResultElement.put("data", new TabularVisualizationDTO(mipEngineAlgorithmResultDTO)); + exaremeResultElement.put("type", "application/vnd.dataresource+json"); + + List<Object> exaremeResult = new ArrayList<>(); + exaremeResult.add(exaremeResultElement); + return exaremeResult; } /** - * The runExperiment will run the experiment to exareme or MIPEngine. + * Creates an experiment and runs it on the background. + * Uses the exareme or mip-engine engine that run an experiment synchronously. * * @param experimentDTO is the request with the experiment information - * @return the result of experiment as well as the http status that was retrieved + * @param logger contains username and the endpoint. + * @return the experiment information that was retrieved from exareme */ - public ExaremeAlgorithmResultDTO runExperiment(ExperimentDTO experimentDTO, Logger logger) { + private ExperimentDTO createSynchronousExperiment(ExperimentDTO experimentDTO, Logger logger) { - // Algorithm type - String algorithmType = experimentDTO.getAlgorithm().getType(); + logger.LogUserAction("Running the algorithm..."); - // Run the 1st algorithm from the list - String algorithmName = experimentDTO.getAlgorithm().getName(); + ExperimentDAO experimentDAO = experimentRepository.createExperimentInTheDatabase(experimentDTO, activeUserService.getActiveUser(), logger); + logger.LogUserAction("Created experiment with uuid :" + experimentDAO.getUuid()); - // Run with the appropriate engine + logger.LogUserAction("Starting execution in thread"); + ExperimentDTO finalExperimentDTO = experimentDTO; + new Thread(() -> { + + try { + ExaremeAlgorithmResultDTO exaremeAlgorithmResultDTO = runSynchronousExperiment(finalExperimentDTO, logger); + + logger.LogUserAction( + "Experiment with uuid: " + experimentDAO.getUuid() + + " gave response code: " + exaremeAlgorithmResultDTO.getCode() + + " and result: " + exaremeAlgorithmResultDTO.getResult() + ); + + experimentDAO.setResult(JsonConverters.convertObjectToJsonString(exaremeAlgorithmResultDTO.getResult())); + experimentDAO.setStatus((exaremeAlgorithmResultDTO.getCode() >= 400) + ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); + } catch (Exception e) { + logger.LogUserAction("There was an exception: " + e.getMessage()); + + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + + experimentRepository.finishExperiment(experimentDAO, logger); + logger.LogUserAction("Finished the experiment: " + experimentDAO); + }).start(); + + experimentDTO = new ExperimentDTO(true, experimentDAO); + return experimentDTO; + } + + /** + * Runs the experiment to exareme or MIPEngine, waiting for the response from them. + * Exareme and MIP-Engine do not support async fetching of an algorithm result. + * + * @param experimentDTO is the request with the experiment information + * @return the result of experiment as well as the http status that was retrieved + */ + private ExaremeAlgorithmResultDTO runSynchronousExperiment(ExperimentDTO experimentDTO, Logger logger) { + String algorithmType = experimentDTO.getAlgorithm().getType(); if (algorithmType.equals("mipengine")) { - MIPEngineAlgorithmRequestDTO mipEngineAlgorithmRequestDTO = new MIPEngineAlgorithmRequestDTO(experimentDTO.getAlgorithm().getParameters()); - String body = JsonConverters.convertObjectToJsonString(mipEngineAlgorithmRequestDTO); - String url = mipengineAlgorithmsUrl + "/" + algorithmName.toLowerCase(); - logger.LogUserAction("url: " + url + ", body: " + body); - logger.LogUserAction("Algorithm runs on MIPEngine."); - return runMIPEngineExperiment(url, body); + return runMIPEngineExperiment(experimentDTO, logger); } else { - List<ExaremeAlgorithmRequestParamDTO> algorithmParameters - = experimentDTO.getAlgorithm().getParameters(); - String body = gson.toJson(algorithmParameters); - String url = queryExaremeUrl + "/" + algorithmName; - logger.LogUserAction("url: " + url + ", body: " + body); - logger.LogUserAction("Algorithm runs on Exareme."); - return runExaremeExperiment(url, body); + return runExaremeExperiment(experimentDTO, logger); } } - /** - * The runExaremeExperiment will run to exareme the experiment + * The runExaremeExperiment will run an experiment using Exareme * - * @param url is the url that contain the results of the experiment - * @param body is the parameters of the algorithm + * @param experimentDTO contains the information needed to run the experiment + * @param logger used to log information * @return the result of exareme as well as the http status that was retrieved */ - public ExaremeAlgorithmResultDTO runExaremeExperiment(String url, String body) { + private ExaremeAlgorithmResultDTO runExaremeExperiment(ExperimentDTO experimentDTO, Logger logger) { + String algorithmName = experimentDTO.getAlgorithm().getName(); + logger.LogUserAction("Starting Exareme algorithm execution, algorithm: " + algorithmName); - StringBuilder results = new StringBuilder(); - int code; + String algorithmEndpoint = queryExaremeUrl + "/" + algorithmName; + List<ExaremeAlgorithmRequestParamDTO> algorithmParameters + = experimentDTO.getAlgorithm().getParameters(); + String algorithmBody = gson.toJson(algorithmParameters); + logger.LogUserAction("Exareme algorithm execution. Endpoint: " + algorithmEndpoint); + logger.LogUserAction("Exareme algorithm execution. Body: " + algorithmBody); + + StringBuilder requestResponseBody = new StringBuilder(); + int requestReponseCode; try { - code = HTTPUtil.sendPost(url, body, results); + requestReponseCode = HTTPUtil.sendPost(algorithmEndpoint, algorithmBody, requestResponseBody); } catch (Exception e) { throw new InternalServerError("Error occurred : " + e.getMessage()); } // Results are stored in the experiment object ExaremeAlgorithmResultDTO exaremeResult = JsonConverters.convertJsonStringToObject( - String.valueOf(results), ExaremeAlgorithmResultDTO.class + String.valueOf(requestResponseBody), ExaremeAlgorithmResultDTO.class ); - exaremeResult.setCode(code); + exaremeResult.setCode(requestReponseCode); return exaremeResult; } /** - * The runExaremeExperiment will run to exareme the experiment + * The runMIPEngineExperiment will run an experiment using the MIP-Engine * - * @param url is the url that contain the results of the experiment - * @param body is the parameters of the algorithm - * @return the result of exareme as well as the http status that was retrieved + * @param experimentDTO contains the information needed to run the experiment + * @param logger is used to log + * @return the result of the algorithm */ - public ExaremeAlgorithmResultDTO runMIPEngineExperiment(String url, String body) { + private ExaremeAlgorithmResultDTO runMIPEngineExperiment(ExperimentDTO experimentDTO, Logger logger) { + String algorithmName = experimentDTO.getAlgorithm().getName(); + logger.LogUserAction("Starting MIP-Engine algorithm execution, algorithm: " + algorithmName); - StringBuilder results = new StringBuilder(); - int code; + String algorithmEndpoint = mipengineAlgorithmsUrl + "/" + algorithmName.toLowerCase(); + MIPEngineAlgorithmRequestDTO mipEngineAlgorithmRequestDTO = + new MIPEngineAlgorithmRequestDTO(experimentDTO.getAlgorithm().getParameters()); + String algorithmBody = JsonConverters.convertObjectToJsonString(mipEngineAlgorithmRequestDTO); + logger.LogUserAction("MIP-Engine algorithm execution. Endpoint: " + algorithmEndpoint); + logger.LogUserAction("MIP-Engine algorithm execution. Body: " + algorithmBody); + + StringBuilder requestResponseBody = new StringBuilder(); + int requestResponseCode; try { - code = HTTPUtil.sendPost(url, body, results); + requestResponseCode = HTTPUtil.sendPost(algorithmEndpoint, algorithmBody, requestResponseBody); } catch (Exception e) { - throw new InternalServerError("Error occurred : " + e.getMessage()); + logger.LogUserAction("An unexpected error occurred when running a mip experiment: " + e.getMessage()); + throw new InternalServerError(""); } - System.out.println(results); - // Results are stored in the experiment object - return convertMIPEngineResultToExaremeAlgorithmResult(code, String.valueOf(results)); - } - - /* -------------------------------------- EXAREME CALLS ---------------------------------------------------------*/ - /** - * The createExaremeExperiment will POST the algorithm to the exareme client - * - * @param experimentDTO is the request with the experiment information - * @param logger contains username and the endpoint. - * @return the experiment information that was retrieved from exareme - */ - public ExperimentDTO createExperiment(ExperimentDTO experimentDTO, Logger logger) { - - logger.LogUserAction("Running the algorithm..."); - - ExperimentDAO experimentDAO = experimentRepository.createExperimentInTheDatabase(experimentDTO, activeUserService.getActiveUser(), logger); - logger.LogUserAction("Created experiment with uuid :" + experimentDAO.getUuid()); + List<Object> exaremeAlgorithmResult = new ArrayList<>(); + if (requestResponseCode == 200) { + MIPEngineAlgorithmResultDTO mipEngineAlgorithmResultDTO = + JsonConverters.convertJsonStringToObject(String.valueOf(requestResponseBody), MIPEngineAlgorithmResultDTO.class); + exaremeAlgorithmResult = convertMIPEngineToExaremeAlgorithmResult(mipEngineAlgorithmResultDTO); + + } else if (requestResponseCode == 400) { + Map<String, Object> exaremeAlgorithmResultElement = new HashMap<>(); + exaremeAlgorithmResultElement.put("data", String.valueOf(requestResponseBody)); + exaremeAlgorithmResultElement.put("type", "text/plain+error"); + exaremeAlgorithmResult.add(exaremeAlgorithmResultElement); + + } else if (requestResponseCode == 460) { + Map<String, Object> exaremeAlgorithmResultElement = new HashMap<>(); + exaremeAlgorithmResultElement.put("data", String.valueOf(requestResponseBody)); + exaremeAlgorithmResultElement.put("type", "text/plain+user_error"); + exaremeAlgorithmResult.add(exaremeAlgorithmResultElement); + + } else if (requestResponseCode == 500) { + Map<String, Object> exaremeAlgorithmResultElement = new HashMap<>(); + exaremeAlgorithmResultElement.put("data", + "Something went wrong. Please inform the system administrator or try again later." + ); + exaremeAlgorithmResultElement.put("type", "text/plain+error"); + exaremeAlgorithmResult.add(exaremeAlgorithmResultElement); - logger.LogUserAction("Starting execution in thread"); - ExperimentDTO finalExperimentDTO = experimentDTO; - new Thread(() -> { - - // ATTENTION: Inside the Thread only LogExperimentAction should be used, not LogUserAction! - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Thread named :" + Thread.currentThread().getName() + " with id :" + Thread.currentThread().getId() + " started!"); - - try { - - // Results are stored in the experiment object - ExaremeAlgorithmResultDTO exaremeAlgorithmResultDTO = runExperiment(finalExperimentDTO, logger); - - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Experiment with uuid: " + experimentDAO.getUuid() + "gave response code: " + exaremeAlgorithmResultDTO.getCode() + " and result: " + exaremeAlgorithmResultDTO.getResult()); - - experimentDAO.setResult((exaremeAlgorithmResultDTO.getCode() >= 400) ? null : JsonConverters.convertObjectToJsonString(exaremeAlgorithmResultDTO.getResult())); - experimentDAO.setStatus((exaremeAlgorithmResultDTO.getCode() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); - } catch (Exception e) { - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "There was an exception: " + e.getMessage()); + } else { + logger.LogUserAction( + "MIP-Engine execution responded with an unexpected status code: " + requestResponseCode + ); + throw new InternalServerError(""); + } - experimentDAO.setStatus(ExperimentDAO.Status.error); - } + return new ExaremeAlgorithmResultDTO(requestResponseCode, exaremeAlgorithmResult); - experimentRepository.finishExperiment(experimentDAO, logger); - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Finished the experiment: " + experimentDAO); - }).start(); - experimentDTO = new ExperimentDTO(true, experimentDAO); - return experimentDTO; } - - /* --------------------------------------- GALAXY CALLS ---------------------------------------------------------*/ - } diff --git a/src/main/java/eu/hbp/mip/services/GalaxyService.java b/src/main/java/eu/hbp/mip/services/GalaxyService.java index cc10afebdfdff26008947c6b24b7eb5865e6918b..61d5629fdc0e5ce52845638be65f71b8608574a2 100644 --- a/src/main/java/eu/hbp/mip/services/GalaxyService.java +++ b/src/main/java/eu/hbp/mip/services/GalaxyService.java @@ -56,12 +56,12 @@ public class GalaxyService { private static final Gson gson = new Gson(); /** - * The runWorkflow will POST the algorithm to the galaxy client + * Creates an experiment and runs it on Galaxy * * @param experimentDTO is the request with the experiment information * @return the response to be returned */ - public ExperimentDTO runGalaxyWorkflow(ExperimentDTO experimentDTO, Logger logger) { + public ExperimentDTO createGalaxyExperiment(ExperimentDTO experimentDTO, Logger logger) { logger.LogUserAction("Running a workflow..."); ExperimentDAO experimentDAO = experimentRepository.createExperimentInTheDatabase(experimentDTO, activeUserService.getActiveUser(), logger); @@ -161,8 +161,8 @@ public class GalaxyService { 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); + // ATTENTION: This function is used from a Thread. Only LogBackgroundAction should be used, not LogUserAction! + Logger.LogBackgroundAction(experimentName, experimentId, " History Id : " + historyId); // Create the request client RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); @@ -172,15 +172,15 @@ public class GalaxyService { try { Response<Object> response = call.execute(); if (response.code() >= 400) { - Logger.LogExperimentAction(experimentName, experimentId, " Response code: " + Logger.LogBackgroundAction(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); + Logger.LogBackgroundAction(experimentName, experimentId, " ResultDTO: " + result); } catch (IOException e) { - Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); + Logger.LogBackgroundAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); return "internalError"; } @@ -189,11 +189,11 @@ public class GalaxyService { JSONObject resultJson = new JSONObject(result); state = resultJson.getString("state"); } catch (JSONException e) { - Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); + Logger.LogBackgroundAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); return "internalError"; } - Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); + Logger.LogBackgroundAction(experimentName, experimentId, " Completed!"); switch (state) { case "ok": return "success"; @@ -218,7 +218,7 @@ public class GalaxyService { String historyId = experimentDAO.getWorkflowHistoryId(); String experimentName = experimentDAO.getName(); UUID experimentId = experimentDAO.getUuid(); - Logger.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); + Logger.LogBackgroundAction(experimentName, experimentId, " historyId : " + historyId); RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); Call<List<GalaxyWorkflowResult>> call = service.getWorkflowResultsFromGalaxy(historyId, galaxyApiKey); @@ -227,19 +227,19 @@ public class GalaxyService { try { Response<List<GalaxyWorkflowResult>> response = call.execute(); if (response.code() >= 400) { - Logger.LogExperimentAction(experimentName, experimentId, " Response code: " + Logger.LogBackgroundAction(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()); + Logger.LogBackgroundAction(experimentName, experimentId, " ResultDTO: " + response.body()); } catch (IOException e) { - Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); + Logger.LogBackgroundAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); return null; } - Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); + Logger.LogBackgroundAction(experimentName, experimentId, " Completed!"); return getGalaxyWorkflowResultList; } @@ -255,7 +255,7 @@ public class GalaxyService { String experimentName = experimentDAO.getName(); UUID experimentId = experimentDAO.getUuid(); - Logger.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); + Logger.LogBackgroundAction(experimentName, experimentId, " historyId : " + historyId); RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); Call<Object> call = @@ -265,20 +265,20 @@ public class GalaxyService { try { Response<Object> response = call.execute(); if (response.code() >= 400) { - Logger.LogExperimentAction(experimentName, experimentId, " Response code: " + Logger.LogBackgroundAction(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); + Logger.LogBackgroundAction(experimentName, experimentId, " ResultDTO: " + resultJson); } catch (IOException e) { - Logger.LogExperimentAction(experimentName, experimentId, + Logger.LogBackgroundAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); return null; } - Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); + Logger.LogBackgroundAction(experimentName, experimentId, " Completed!"); return formattingGalaxyResult(resultJson); } @@ -300,7 +300,7 @@ public class GalaxyService { String experimentName = experimentDAO.getName(); UUID experimentId = experimentDAO.getUuid(); - Logger.LogExperimentAction(experimentName, experimentId, " jobId : " + jobId); + Logger.LogBackgroundAction(experimentName, experimentId, " jobId : " + jobId); RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); Call<Object> callError = service.getErrorMessageOfWorkflowFromGalaxy(jobId, galaxyApiKey); @@ -309,7 +309,7 @@ public class GalaxyService { try { Response<Object> response = callError.execute(); if (response.code() >= 400) { - Logger.LogExperimentAction(experimentName, experimentId, "Response code: " + Logger.LogBackgroundAction(experimentName, experimentId, "Response code: " + response.code() + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); return null; } @@ -319,19 +319,19 @@ public class GalaxyService { JsonElement jsonElement = new JsonParser().parse(jsonString); JsonObject rootObject = jsonElement.getAsJsonObject(); fullError = rootObject.get("stderr").getAsString(); - Logger.LogExperimentAction(experimentName, experimentId, "Error: " + fullError); + Logger.LogBackgroundAction(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); + Logger.LogBackgroundAction(experimentName, experimentId, "Parsed Error: " + returnError); } catch (IOException e) { - Logger.LogExperimentAction(experimentName, experimentId, "Exception: " + e.getMessage()); + Logger.LogBackgroundAction(experimentName, experimentId, "Exception: " + e.getMessage()); return null; } - Logger.LogExperimentAction(experimentName, experimentId, "Completed successfully!"); + Logger.LogBackgroundAction(experimentName, experimentId, "Completed successfully!"); return returnError; } @@ -358,40 +358,40 @@ public class GalaxyService { 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..."); + // ATTENTION: Inside the Thread only LogBackgroundAction should be used, not LogUserAction! + Logger.LogBackgroundAction(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.LogBackgroundAction(experimentDAO.getName(), experimentDAO.getUuid(), "Sleep was disrupted: " + e.getMessage()); throw new InternalServerError(e.getMessage()); } - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Fetching status for experiment Id: " + experimentDAO.getUuid()); + Logger.LogBackgroundAction(experimentDAO.getName(), experimentDAO.getUuid(), "Fetching status for experiment Id: " + experimentDAO.getUuid()); String state = getWorkflowStatus(experimentDAO); - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "State is: " + state); + Logger.LogBackgroundAction(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."); + Logger.LogBackgroundAction(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()); + Logger.LogBackgroundAction(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()); + Logger.LogBackgroundAction(experimentDAO.getName(), experimentDAO.getUuid(), "Visible result are: " + jobResult.getId()); String result = getWorkflowResultBody(experimentDAO, jobResult.getId()); - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO: " + result); + Logger.LogBackgroundAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO: " + result); if (result == null) { experimentDAO.setStatus(ExperimentDAO.Status.error); } else { @@ -403,7 +403,7 @@ public class GalaxyService { } if (!resultFound) { // If there is no visible result - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "No visible result"); + Logger.LogBackgroundAction(experimentDAO.getName(), experimentDAO.getUuid(), "No visible result"); experimentDAO.setStatus(ExperimentDAO.Status.error); } @@ -413,16 +413,16 @@ public class GalaxyService { case "error": // Get the job result that failed workflowJobsResults = getWorkflowResults(experimentDAO); - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Error results are: " + workflowJobsResults.toString()); + Logger.LogBackgroundAction(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()); + Logger.LogBackgroundAction(experimentDAO.getName(), experimentDAO.getUuid(), "Failed job is: " + jobResult.getId()); String result = getWorkflowJobError(jobResult.getId(), experimentDAO); - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Job result: " + result); + Logger.LogBackgroundAction(experimentDAO.getName(), experimentDAO.getUuid(), "Job result: " + result); if (result == null) { experimentDAO.setStatus(ExperimentDAO.Status.error); } @@ -432,14 +432,14 @@ public class GalaxyService { } if (!failedJobFound) { // If there is no visible failed job - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "No failed result"); + Logger.LogBackgroundAction(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."); + Logger.LogBackgroundAction(experimentDAO.getName(), experimentDAO.getUuid(), "An unexpected error occurred."); experimentDAO.setStatus(ExperimentDAO.Status.error); experimentRepository.finishExperiment(experimentDAO, logger); break; @@ -447,7 +447,7 @@ public class GalaxyService { // If result exists return if (experimentDAO.getResult() != null) { - Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO exists: " + experimentDAO.getResult()); + Logger.LogBackgroundAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO exists: " + experimentDAO.getResult()); return; } } diff --git a/src/main/java/eu/hbp/mip/utils/Logger.java b/src/main/java/eu/hbp/mip/utils/Logger.java index 1e25d2c921f0338235bed01c2f2fcd55ab4cf94a..c21e2fdc9391be017fed2b470ff04e11d29a45fd 100644 --- a/src/main/java/eu/hbp/mip/utils/Logger.java +++ b/src/main/java/eu/hbp/mip/utils/Logger.java @@ -22,8 +22,8 @@ public class Logger { + "Info -> " + actionInfo); } - // Used from Threads because threads can't get userName. - public static void LogExperimentAction(String experimentName, UUID experimentId, String actionInfo) { + // Deprecated, should be removed + public static void LogBackgroundAction(String experimentName, UUID experimentId, String actionInfo) { LOGGER.info(" Experiment -> " + experimentName + "(" + experimentId + ") ," + "Info -> " + actionInfo);