diff --git a/docker/config/application.tmpl b/docker/config/application.tmpl index 5cdf823f9e84c4fc923deab02e1bf53b284d7b6b..6174fb409d967a2c67b5013ecc435a72fd763929 100644 --- a/docker/config/application.tmpl +++ b/docker/config/application.tmpl @@ -78,7 +78,7 @@ endpoints: services: exareme: - miningExaremeUrl: {{ default .Env.EXAREME_URL "http://localhost:9090" }}/mining/query + queryExaremeUrl: {{ default .Env.EXAREME_URL "http://localhost:9090" }}/mining/query algorithmsUrl: {{ default .Env.EXAREME_URL "http://localhost:9090" }}/mining/algorithms.json galaxy: diff --git a/src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java b/src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java index 492358c59c14801df01548032d0722a1c929a5bb..b3ef3e672003d9c47e3d4fa72641cd8908792285 100644 --- a/src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java +++ b/src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java @@ -5,8 +5,8 @@ import com.github.jmchilton.blend4j.galaxy.GalaxyInstanceFactory; import com.github.jmchilton.blend4j.galaxy.WorkflowsClient; import com.github.jmchilton.blend4j.galaxy.beans.Workflow; import com.google.gson.Gson; -import eu.hbp.mip.controllers.retrofit.RetroFitGalaxyClients; -import eu.hbp.mip.controllers.retrofit.RetrofitClientInstance; +import eu.hbp.mip.controllers.galaxy.retrofit.RetroFitGalaxyClients; +import eu.hbp.mip.controllers.galaxy.retrofit.RetrofitClientInstance; import eu.hbp.mip.model.AlgorithmDTO; import eu.hbp.mip.model.galaxy.WorkflowDTO; import eu.hbp.mip.utils.HTTPUtil; diff --git a/src/main/java/eu/hbp/mip/controllers/ExperimentApi.java b/src/main/java/eu/hbp/mip/controllers/ExperimentApi.java index 093a6c72f0da2c628e94c86d8e6d3fb468d4b61e..5f8433b78b03fe9d9abaffd152edc760f238ca4f 100644 --- a/src/main/java/eu/hbp/mip/controllers/ExperimentApi.java +++ b/src/main/java/eu/hbp/mip/controllers/ExperimentApi.java @@ -8,8 +8,8 @@ import com.github.jmchilton.blend4j.galaxy.beans.WorkflowDetails; import com.github.jmchilton.blend4j.galaxy.beans.WorkflowInputDefinition; import com.google.common.collect.Lists; import com.google.gson.*; -import eu.hbp.mip.controllers.retrofit.RetroFitGalaxyClients; -import eu.hbp.mip.controllers.retrofit.RetrofitClientInstance; +import eu.hbp.mip.controllers.galaxy.retrofit.RetroFitGalaxyClients; +import eu.hbp.mip.controllers.galaxy.retrofit.RetrofitClientInstance; import eu.hbp.mip.model.*; import eu.hbp.mip.model.ExperimentExecutionDTO.AlgorithmExecutionDTO.AlgorithmExecutionParamDTO; import eu.hbp.mip.model.galaxy.ErrorResponse; @@ -35,8 +35,14 @@ import retrofit2.Response; import java.io.IOException; import java.util.*; +import static java.lang.Thread.sleep; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +/* + This api is creating experiments and running it's algorithm on the + exareme or galaxy clients. + */ + @RestController @RequestMapping(value = "/experiments", produces = {APPLICATION_JSON_VALUE}) @Api(value = "/experiments") @@ -47,8 +53,8 @@ public class ExperimentApi { private static final Gson gsonOnlyExposed = new GsonBuilder().serializeNulls() .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").excludeFieldsWithoutExposeAnnotation().create(); - @Value("#{'${services.exareme.miningExaremeUrl}'}") - public String exaremeUrl; + @Value("#{'${services.exareme.queryExaremeUrl}'}") + private String queryExaremeUrl; @Value("#{'${services.workflows.workflowUrl}'}") private String workflowUrl; @@ -71,6 +77,31 @@ public class ExperimentApi { @Autowired private ExperimentRepository experimentRepository; + @ApiOperation(value = "get an experiment", response = Experiment.class) + @RequestMapping(value = "/{uuid}", method = RequestMethod.GET) + public ResponseEntity<String> getExperiment( + @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { + + Experiment experiment; + UUID experimentUuid; + try { + experimentUuid = UUID.fromString(uuid); + } catch (IllegalArgumentException iae) { + UserActionLogging.LogAction("Get Experiment", "Invalid Experiment UUID."); + return ResponseEntity.badRequest().body("Invalid Experiment UUID"); + } + + experiment = experimentRepository.findOne(experimentUuid); + + if (experiment == null) { + return new ResponseEntity<>("Not found", HttpStatus.NOT_FOUND); + } + + UserActionLogging.LogAction("Get an experiment ", " uuid : " + uuid); + + return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); + } + @ApiOperation(value = "Create an experiment", response = Experiment.class) @RequestMapping(value = "/runAlgorithm", method = RequestMethod.POST) public ResponseEntity<String> runExperiment(@RequestBody ExperimentExecutionDTO experimentExecutionDTO) { @@ -84,9 +115,183 @@ public class ExperimentApi { } else { return runExaremeAlgorithm(experimentExecutionDTO); } + } + + @ApiOperation(value = "Mark an experiment as viewed", response = Experiment.class) + @RequestMapping(value = "/{uuid}/markAsViewed", method = RequestMethod.GET) + public ResponseEntity<String> markExperimentAsViewed( + @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { + + UserActionLogging.LogAction("Mark an experiment as viewed", " uuid : " + uuid); + + Experiment experiment; + UUID experimentUuid; + User user = userInfo.getUser(); + try { + experimentUuid = UUID.fromString(uuid); + } catch (IllegalArgumentException iae) { + //LOGGER.trace("Invalid UUID", iae); + //LOGGER.warn("An invalid Experiment UUID was received !"); + return ResponseEntity.badRequest().body("Invalid Experiment UUID"); + } + + experiment = experimentRepository.findOne(experimentUuid); + if (!experiment.getCreatedBy().getUsername().equals(user.getUsername())) + return new ResponseEntity<>("You're not the owner of this experiment", HttpStatus.BAD_REQUEST); + experiment.setResultsViewed(true); + experimentRepository.save(experiment); + + UserActionLogging.LogAction("Experiment updated (marked as viewed)", " "); + + return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); + } + + @ApiOperation(value = "Mark an experiment as shared", response = Experiment.class) + @RequestMapping(value = "/{uuid}/markAsShared", method = RequestMethod.GET) + public ResponseEntity<String> markExperimentAsShared( + @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { + + UserActionLogging.LogAction("Mark an experiment as shared", " uuid : " + uuid); + + return doMarkExperimentAsShared(uuid, true); + } + + @ApiOperation(value = "Mark an experiment as unshared", response = Experiment.class) + @RequestMapping(value = "/{uuid}/markAsUnshared", method = RequestMethod.GET) + public ResponseEntity<String> markExperimentAsUnshared( + @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { + UserActionLogging.LogAction("Mark an experiment as unshared", " uuid : " + uuid); + + return doMarkExperimentAsShared(uuid, false); + } + + @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List") + @RequestMapping(method = RequestMethod.GET, params = {"maxResultCount"}) + public ResponseEntity<String> listExperiments( + @ApiParam(value = "maxResultCount") @RequestParam int maxResultCount) { + + UserActionLogging.LogAction("List experiments", " maxResultCount : " + maxResultCount); + + return doListExperiments(false, null); + } + + @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List") + @RequestMapping(method = RequestMethod.GET, params = {"slug", "maxResultCount"}) + public ResponseEntity<String> listExperiments(@ApiParam(value = "slug") @RequestParam("slug") String modelSlug, + @ApiParam(value = "maxResultCount") @RequestParam("maxResultCount") int maxResultCount) { + + UserActionLogging.LogAction("List experiments", " modelSlug : " + modelSlug); + + if (maxResultCount <= 0 && (modelSlug == null || "".equals(modelSlug))) { + return new ResponseEntity<>("You must provide at least a slug or a limit of result", + HttpStatus.BAD_REQUEST); + } + + return doListExperiments(false, modelSlug); + } + + @ApiOperation(value = "list my experiments", response = Experiment.class, responseContainer = "List") + @RequestMapping(method = RequestMethod.GET, params = {"mine"}) + public ResponseEntity<String> listMyExperiments(@ApiParam(value = "mine") @RequestParam("mine") boolean mine) { + UserActionLogging.LogAction("List my experiments", " mine : " + mine); + + return doListExperiments(true, null); + } + + private ResponseEntity<String> doListExperiments(boolean mine, String modelSlug) { + User user = userInfo.getUser(); + + Iterable<Experiment> myExperiments = experimentRepository.findByCreatedBy(user); + List<Experiment> expList = Lists.newLinkedList(myExperiments); + if (!mine) { + Iterable<Experiment> sharedExperiments = experimentRepository.findByShared(true); + List<Experiment> sharedExpList = Lists.newLinkedList(sharedExperiments); + expList.addAll(sharedExpList); + } + + if (modelSlug != null && !"".equals(modelSlug)) { + for (Iterator<Experiment> it = expList.iterator(); it.hasNext(); ) { + Experiment e = it.next(); + e.setResult(null); + e.setAlgorithms(null); + e.setValidations(null); + if (!e.getModel().getSlug().equals(modelSlug)) { + it.remove(); + } + } + } + return new ResponseEntity<>(gsonOnlyExposed.toJson(expList), HttpStatus.OK); } + private ResponseEntity<String> doMarkExperimentAsShared(String uuid, boolean shared) { + Experiment experiment; + UUID experimentUuid; + User user = userInfo.getUser(); + try { + experimentUuid = UUID.fromString(uuid); + } catch (IllegalArgumentException iae) { + //LOGGER.trace("Invalid UUID", iae); + //LOGGER.warn("An invalid Experiment UUID was received !"); + return ResponseEntity.badRequest().body("Invalid Experiment UUID"); + } + + experiment = experimentRepository.findOne(experimentUuid); + + if (!experiment.getCreatedBy().getUsername().equals(user.getUsername())) + return new ResponseEntity<>("You're not the owner of this experiment", HttpStatus.BAD_REQUEST); + + experiment.setShared(shared); + experimentRepository.save(experiment); + + UserActionLogging.LogAction("Experiment updated (marked as shared)", ""); + + return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); + } + + /* ------------------------------- EXPERIMENT MODEL METHODS ----------------------------------------------------*/ + + public Experiment createExperiment(ExperimentExecutionDTO experimentExecutionDTO){ + User user = userInfo.getUser(); + + Experiment experiment = new Experiment(); + experiment.setUuid(UUID.randomUUID()); + experiment.setCreatedBy(user); + experiment.setAlgorithms(gson.toJson(experimentExecutionDTO.getAlgorithms())); + Model model = modelRepository.findOne(experimentExecutionDTO.getModel()); + experiment.setModel(model); + experiment.setName(experimentExecutionDTO.getName()); + experimentRepository.save(experiment); + + UserActionLogging.LogAction("Created an experiment", " id : " + experiment.getUuid()); + UserActionLogging.LogAction("Created an experiment", " algorithms : " + experiment.getAlgorithms()); + UserActionLogging.LogAction("Created an experiment", " model : " + experiment.getModel().getSlug()); + UserActionLogging.LogAction("Created an experiment", " name : " + experiment.getName()); + return experiment; + } + + private void saveExperiment(Experiment experiment) { + UserActionLogging.LogAction("Saved an experiment", " id : " + experiment.getUuid()); + UserActionLogging.LogAction("Saved an experiment", " algorithms : " + experiment.getAlgorithms()); + UserActionLogging.LogAction("Saved an experiment", " model : " + experiment.getModel().getSlug()); + UserActionLogging.LogAction("Saved an experiment", " name : " + experiment.getName()); + UserActionLogging.LogAction("Saved an experiment", " historyId : " + experiment.getWorkflowHistoryId()); + UserActionLogging.LogAction("Saved an experiment", " status : " + experiment.getWorkflowStatus()); + + experimentRepository.save(experiment); + + UserActionLogging.LogAction("Experiment saved", ""); + } + + private void finishExperiment(Experiment experiment) { + experiment.setFinished(new Date()); + experimentRepository.save(experiment); + + UserActionLogging.LogThreadAction("Experiment finished!", ""); + } + + /* -------------------------------------- EXAREME CALLS ---------------------------------------------------------*/ + /** * The runExaremeExperiment will POST the algorithm to the exareme client * @@ -102,11 +307,11 @@ public class ExperimentApi { String algorithmName = experimentExecutionDTO.getAlgorithms().get(0).getName(); // Get the parameters - List<AlgorithmExecutionParamDTO> algorithmParameters + List<ExperimentExecutionDTO.AlgorithmExecutionDTO.AlgorithmExecutionParamDTO> algorithmParameters = experimentExecutionDTO.getAlgorithms().get(0).getParameters(); String body = gson.toJson(algorithmParameters); - String url = exaremeUrl + "/" + algorithmName; + String url = queryExaremeUrl + "/" + algorithmName; UserActionLogging.LogAction("Run exareme algorithm", "url: " + url + ", body: " + body); ResponseEntity<String> response = new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); @@ -117,16 +322,16 @@ public class ExperimentApi { "Starting exareme execution thread"); new Thread(() -> { // ATTENTION: Inside the Thread only LogThreadAction should be used, not LogAction! - UserActionLogging.LogThreadAction("Thread, Run exareme algorithm", + UserActionLogging.LogThreadAction("Run exareme algorithm", "Thread started!"); try { - UserActionLogging.LogThreadAction("Thread, Run exareme algorithm", + UserActionLogging.LogThreadAction("Run exareme algorithm", "Thread started!"); StringBuilder results = new StringBuilder(); int code = HTTPUtil.sendPost(url, body, results); - UserActionLogging.LogThreadAction("Thread, Run exareme algorithm", + UserActionLogging.LogThreadAction("Run exareme algorithm", "Algorithm finished with code: " + code); // Results are stored in the experiment object @@ -134,24 +339,27 @@ public class ExperimentApi { experiment.setHasError(code >= 400); experiment.setHasServerError(code >= 500); } catch (Exception e) { - UserActionLogging.LogThreadAction("Thread, Run exareme algorithm", + UserActionLogging.LogThreadAction("Run exareme algorithm", "There was an exception: " + e.getMessage()); experiment.setHasError(true); experiment.setHasServerError(true); experiment.setResult(e.getMessage()); } - UserActionLogging.LogThreadAction("Thread, Run exareme algorithm", + UserActionLogging.LogThreadAction("Run exareme algorithm", "Finished the experiment: " + experiment.toString()); finishExperiment(experiment); - UserActionLogging.LogThreadAction("Thread, Run exareme algorithm", + UserActionLogging.LogThreadAction("Run exareme algorithm", "Finished!"); }).start(); return response; } + /* --------------------------------------- GALAXY CALLS ---------------------------------------------------------*/ + + /** * The runWorkflow will POST the algorithm to the galaxy client * @@ -247,159 +455,148 @@ public class ExperimentApi { } saveExperiment(experiment); + // Start the process of fetching the status + updateWorkflowExperiment(experiment); + UserActionLogging.LogAction("Run workflow", "Run workflow completed!"); return new ResponseEntity(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); } - @ApiOperation(value = "get an experiment", response = Experiment.class) - @RequestMapping(value = "/{uuid}", method = RequestMethod.GET) - public ResponseEntity<String> getExperiment( - @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { - Experiment experiment; - UUID experimentUuid; - try { - experimentUuid = UUID.fromString(uuid); - } catch (IllegalArgumentException iae) { - UserActionLogging.LogAction("Get Experiment", "Invalid Experiment UUID."); - return ResponseEntity.badRequest().body("Invalid Experiment UUID"); - } - - experiment = experimentRepository.findOne(experimentUuid); + /** + * This method creates a thread that will fetch the workflow result when it is ready + * + * @param experiment will be used to fetch it's workflow status, it should have the workflowHistoryId initialized + * and the result should not already be fetched + * @return nothing, just updates the experiment + */ + public void updateWorkflowExperiment(Experiment experiment) { if (experiment == null) { - return new ResponseEntity<>("Not found", HttpStatus.NOT_FOUND); - } - - UserActionLogging.LogAction("Get an experiment ", " uuid : " + uuid); - - return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); - } - - @ApiOperation(value = "get a workflow", response = Experiment.class) - @RequestMapping(value = "/workflow/{experimentId}", method = RequestMethod.GET) - public ResponseEntity<String> getWorkflowExperiment( - @ApiParam(value = "experimentId", required = true) @PathVariable("experimentId") String experimentId) { - UserActionLogging.LogAction("Get workflow experiment", " Experiment Id : " + experimentId); - - Experiment experiment; - UUID experimentUuid; - try { - experimentUuid = UUID.fromString(experimentId); - } catch (IllegalArgumentException iae) { - UserActionLogging.LogAction("Get workflow experiment", " Invalid Experiment Id"); - return ResponseEntity.badRequest().body("Invalid Experiment UUID"); + UserActionLogging.LogAction("Update workflow experiment", "The experiment does not exist."); + return; } - experiment = experimentRepository.findOne(experimentUuid); - if (experiment == null) { - UserActionLogging.LogAction("Get workflow experiment", "The experiment does not exist."); - return ResponseEntity.badRequest().body("The experiment does not exist."); - } + UserActionLogging.LogAction("Update workflow experiment", + " Experiment id : " + experiment.getUuid()); if (experiment.getWorkflowHistoryId() == null) { - UserActionLogging.LogAction("Get workflow experiment", "History Id does not exist."); - return ResponseEntity.badRequest().body("The experiment is not a workflow."); + UserActionLogging.LogAction("Update workflow experiment", "History Id does not exist."); + return; } - // If result already exists return - if (experiment.getResult() != null) { - UserActionLogging.LogAction("Get workflow experiment", - "Result exists: " + experiment.getResult()); - return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); - } - - // If result doesn't exist, fetch it - UserActionLogging.LogAction("Get workflow experiment", "Result is null."); - - String state = getWorkflowStatus(experiment.getWorkflowHistoryId()); - UserActionLogging.LogAction("Get workflow experiment", "State is: " + state); - - switch (state) { - case "running": - // Do nothing, when the experiment is created the status is set to running - UserActionLogging.LogAction("Get workflow experiment", "Result is still running."); - break; - - case "completed": - // Get only the job result that is visible - List<GalaxyWorkflowResult> workflowJobsResults = getWorkflowResults(experiment.getWorkflowHistoryId()); - UserActionLogging.LogAction("Get workflow experiment", - "Results are: " + workflowJobsResults.toString()); - - boolean resultFound = false; - for (GalaxyWorkflowResult jobResult : workflowJobsResults) { - if (jobResult.getVisible()) { - UserActionLogging.LogAction("Get workflow experiment", - "Visible result are: " + jobResult.getId()); + UserActionLogging.LogAction("Update workflow experiment", "Starting Thread..." ); + new Thread(() -> { + while(true) { + // ATTENTION: Inside the Thread only LogThreadAction should be used, not LogAction! + UserActionLogging.LogThreadAction("Update workflow experiment", "Thread is running..."); + + try { + sleep(2000); + } catch (InterruptedException e) { + UserActionLogging.LogThreadAction("Update workflow experiment", + "Sleep was disrupted: " + e.getMessage()); + } - String result = getWorkflowResultBody(experiment.getWorkflowHistoryId(), jobResult.getId()); + UserActionLogging.LogThreadAction("Update workflow experiment", + "Fetching status for experiment Id: " + experiment.getUuid()); + + String state = getWorkflowStatus(experiment.getWorkflowHistoryId()); + UserActionLogging.LogThreadAction("Update workflow experiment", "State is: " + state); + + switch (state) { + case "running": + // Do nothing, when the experiment is created the status is set to running + UserActionLogging.LogThreadAction("Update workflow experiment", + "Workflow is still running."); + break; + + case "completed": + // Get only the job result that is visible + List<GalaxyWorkflowResult> workflowJobsResults = getWorkflowResults(experiment.getWorkflowHistoryId()); + UserActionLogging.LogThreadAction("Update workflow experiment", + "Results are: " + workflowJobsResults.toString()); + + boolean resultFound = false; + for (GalaxyWorkflowResult jobResult : workflowJobsResults) { + if (jobResult.getVisible()) { + UserActionLogging.LogThreadAction("Update workflow experiment", + "Visible result are: " + jobResult.getId()); + + String result = getWorkflowResultBody(experiment.getWorkflowHistoryId(), jobResult.getId()); + + UserActionLogging.LogThreadAction("Update workflow experiment", "Result: " + result); + if (result == null) { + experiment.setHasError(true); + experiment.setHasServerError(true); + } + experiment.setResult(result); + experiment.setWorkflowStatus("completed"); + resultFound = true; + } + } - UserActionLogging.LogAction("Get workflow experiment", "Result: " + result); - if (result == null) { + if (!resultFound) { // If there is no visible result + UserActionLogging.LogThreadAction("Update workflow experiment", "No visible result"); + experiment.setResult(new ErrorResponse("The workflow has no visible result.", "500").toString()); experiment.setHasError(true); experiment.setHasServerError(true); } - experiment.setResult(result); - experiment.setWorkflowStatus("completed"); - resultFound = true; - } - } - - if (!resultFound) { // If there is no visible result - UserActionLogging.LogAction("Get workflow experiment", "No visible result"); - experiment.setResult(new ErrorResponse("The workflow has no visible result.", "500").toString()); - experiment.setHasError(true); - experiment.setHasServerError(true); - } - - finishExperiment(experiment); - break; - - case "error": - // Get the job result that failed - workflowJobsResults = getWorkflowResults(experiment.getWorkflowHistoryId()); - UserActionLogging.LogAction("Get workflow experiment", - "Error results are: " + workflowJobsResults.toString()); - - boolean failedJobFound = false; - for (GalaxyWorkflowResult jobResult : workflowJobsResults) { - if (jobResult.getState().equals("error")) { - UserActionLogging.LogAction("Get workflow experiment", - "Failed job is: " + jobResult.getId()); - String result = getWorkflowJobError(jobResult.getId()); + finishExperiment(experiment); + break; + + case "error": + // Get the job result that failed + workflowJobsResults = getWorkflowResults(experiment.getWorkflowHistoryId()); + UserActionLogging.LogThreadAction("Update workflow experiment", + "Error results are: " + workflowJobsResults.toString()); + + boolean failedJobFound = false; + for (GalaxyWorkflowResult jobResult : workflowJobsResults) { + if (jobResult.getState().equals("error")) { + UserActionLogging.LogThreadAction("Update workflow experiment", + "Failed job is: " + jobResult.getId()); + + String result = getWorkflowJobError(jobResult.getId()); + + UserActionLogging.LogThreadAction("Update workflow experiment", "Job result: " + result); + if (result == null) { + experiment.setHasError(true); + experiment.setHasServerError(true); + } + experiment.setResult(result); + experiment.setWorkflowStatus("error"); + failedJobFound = true; + } + } - UserActionLogging.LogAction("Get workflow experiment", "Job result: " + result); - if (result == null) { + if (!failedJobFound) { // If there is no visible failed job + UserActionLogging.LogThreadAction("Update workflow experiment", "No failed result"); + experiment.setResult(new ErrorResponse("The workflow has no failed result.", "500").toString()); experiment.setHasError(true); experiment.setHasServerError(true); } - experiment.setResult(result); - experiment.setWorkflowStatus("error"); - failedJobFound = true; - } + finishExperiment(experiment); + break; + + default: // InternalError or unexpected result + experiment.setResult(new ErrorResponse("An unexpected error occurred.", "500").toString()); + experiment.setHasError(true); + experiment.setHasServerError(true); + finishExperiment(experiment); + break; } - if (!failedJobFound) { // If there is no visible failed job - UserActionLogging.LogAction("Get workflow experiment", "No failed result"); - experiment.setResult(new ErrorResponse("The workflow has no failed result.", "500").toString()); - experiment.setHasError(true); - experiment.setHasServerError(true); + // If result exists return + if (experiment.getResult() != null) { + UserActionLogging.LogThreadAction("Update workflow experiment", + "Result exists: " + experiment.getResult()); + return; } - finishExperiment(experiment); - break; - - default: // InternalError or unexpected result - experiment.setResult(new ErrorResponse("An unexpected error occurred.", "500").toString()); - experiment.setHasError(true); - experiment.setHasServerError(true); - finishExperiment(experiment); - break; - } - - return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); + } + }).start(); } @@ -411,7 +608,8 @@ public class ExperimentApi { * "completed" -> When the workflow completed successfully */ public String getWorkflowStatus(String historyId) { - UserActionLogging.LogAction("Get workflow status", " History Id : " + historyId); + // ATTENTION: This function is used from a Thread. Only LogThreadAction should be used, not LogAction! + UserActionLogging.LogThreadAction("Get workflow status", " History Id : " + historyId); // Create the request client RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); @@ -421,15 +619,15 @@ public class ExperimentApi { try { Response<Object> response = call.execute(); if (response.code() >= 400) { - UserActionLogging.LogAction("Get workflow status", " Response code: " + UserActionLogging.LogThreadAction("Get workflow status", " Response code: " + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); return "internalError"; } result = new Gson().toJson(response.body()); - UserActionLogging.LogAction("Get workflow status", " Result: " + result); + UserActionLogging.LogThreadAction("Get workflow status", " Result: " + result); } catch (IOException e) { - UserActionLogging.LogAction("Get workflow status" + UserActionLogging.LogThreadAction("Get workflow status" , " An exception happened: " + e.getMessage()); return "internalError"; } @@ -439,12 +637,12 @@ public class ExperimentApi { JSONObject resultJson = new JSONObject(result); state = resultJson.getString("state"); } catch (JSONException e) { - UserActionLogging.LogAction("Get workflow status" + UserActionLogging.LogThreadAction("Get workflow status" , " An exception happened: " + e.getMessage()); return "internalError"; } - UserActionLogging.LogAction("Get workflow status", " Completed!"); + UserActionLogging.LogThreadAction("Get workflow status", " Completed!"); switch (state) { case "ok": return "completed"; @@ -465,7 +663,7 @@ public class ExperimentApi { * @return a List<GalaxyWorkflowResult> or null when an error occurred */ public List<GalaxyWorkflowResult> getWorkflowResults(String historyId) { - UserActionLogging.LogAction("Get workflow results", " historyId : " + historyId); + UserActionLogging.LogThreadAction("Get workflow results", " historyId : " + historyId); RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); Call<List<GalaxyWorkflowResult>> call = service.getWorkflowResultsFromGalaxy(historyId, galaxyApiKey); @@ -474,20 +672,20 @@ public class ExperimentApi { try { Response<List<GalaxyWorkflowResult>> response = call.execute(); if (response.code() >= 400) { - UserActionLogging.LogAction("Get workflow results", " Response code: " + UserActionLogging.LogThreadAction("Get workflow results", " Response code: " + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); return null; } getGalaxyWorkflowResultList = response.body(); - UserActionLogging.LogAction("Get workflow results", " Result: " + response.body()); + UserActionLogging.LogThreadAction("Get workflow results", " Result: " + response.body()); } catch (IOException e) { - UserActionLogging.LogAction("Get workflow results" + UserActionLogging.LogThreadAction("Get workflow results" , " An exception happened: " + e.getMessage()); return null; } - UserActionLogging.LogAction("Get workflow results", " Completed!"); + UserActionLogging.LogThreadAction("Get workflow results", " Completed!"); return getGalaxyWorkflowResultList; } @@ -498,7 +696,7 @@ public class ExperimentApi { * @return the result of the specific workflow job, null if there was an error */ public String getWorkflowResultBody(String historyId, String contentId) { - UserActionLogging.LogAction("Get workflow results Body", " historyId : " + historyId); + UserActionLogging.LogThreadAction("Get workflow results Body", " historyId : " + historyId); RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); Call<Object> call = @@ -508,20 +706,20 @@ public class ExperimentApi { try { Response<Object> response = call.execute(); if (response.code() >= 400) { - UserActionLogging.LogAction("Get workflow results Body", " Response code: " + UserActionLogging.LogThreadAction("Get workflow results Body", " Response code: " + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); return null; } resultJson = new Gson().toJson(response.body()); - UserActionLogging.LogAction("Get workflow results Body", " Result: " + resultJson); + UserActionLogging.LogThreadAction("Get workflow results Body", " Result: " + resultJson); } catch (IOException e) { - UserActionLogging.LogAction("Get workflow results Body", + UserActionLogging.LogThreadAction("Get workflow results Body", " An exception happened: " + e.getMessage()); return null; } - UserActionLogging.LogAction("Get workflow results Body", " Completed!"); + UserActionLogging.LogThreadAction("Get workflow results Body", " Completed!"); return resultJson; } @@ -531,7 +729,7 @@ public class ExperimentApi { * @return the error that was produced or null if an error occurred */ public String getWorkflowJobError(String jobId) { - UserActionLogging.LogAction("Get workflow job error", " jobId : " + jobId); + UserActionLogging.LogThreadAction("Get workflow job error", " jobId : " + jobId); RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); Call<Object> callError = service.getErrorMessageOfWorkflowFromGalaxy(jobId, galaxyApiKey); @@ -541,7 +739,7 @@ public class ExperimentApi { try { Response<Object> response = callError.execute(); if (response.code() >= 400) { - UserActionLogging.LogAction("Get workflow job error", "Response code: " + UserActionLogging.LogThreadAction("Get workflow job error", "Response code: " + response.code() + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); return null; } @@ -551,192 +749,22 @@ public class ExperimentApi { JsonElement jsonElement = new JsonParser().parse(jsonString); JsonObject rootObject = jsonElement.getAsJsonObject(); fullError = rootObject.get("stderr").getAsString(); - UserActionLogging.LogAction("Get workflow job error", "Error: " + fullError); + UserActionLogging.LogThreadAction("Get workflow job error", "Error: " + fullError); String[] arrOfStr = fullError.split("ValueError", 0); String specError = arrOfStr[arrOfStr.length - 1]; returnError = specError.substring(1); - UserActionLogging.LogAction("Get workflow job error", "Parsed Error: " + returnError); + UserActionLogging.LogThreadAction("Get workflow job error", "Parsed Error: " + returnError); } catch (IOException e) { - UserActionLogging.LogAction("Get workflow job error", "Exception: " + e.getMessage()); + UserActionLogging.LogThreadAction("Get workflow job error", "Exception: " + e.getMessage()); return null; } - UserActionLogging.LogAction("Get workflow job error", "Completed successfully!"); + UserActionLogging.LogThreadAction("Get workflow job error", "Completed successfully!"); return returnError; } - @ApiOperation(value = "Mark an experiment as viewed", response = Experiment.class) - @RequestMapping(value = "/{uuid}/markAsViewed", method = RequestMethod.GET) - public ResponseEntity<String> markExperimentAsViewed( - @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { - - UserActionLogging.LogAction("Mark an experiment as viewed", " uuid : " + uuid); - - Experiment experiment; - UUID experimentUuid; - User user = userInfo.getUser(); - try { - experimentUuid = UUID.fromString(uuid); - } catch (IllegalArgumentException iae) { - //LOGGER.trace("Invalid UUID", iae); - //LOGGER.warn("An invalid Experiment UUID was received !"); - return ResponseEntity.badRequest().body("Invalid Experiment UUID"); - } - - experiment = experimentRepository.findOne(experimentUuid); - if (!experiment.getCreatedBy().getUsername().equals(user.getUsername())) - return new ResponseEntity<>("You're not the owner of this experiment", HttpStatus.BAD_REQUEST); - experiment.setResultsViewed(true); - experimentRepository.save(experiment); - - UserActionLogging.LogAction("Experiment updated (marked as viewed)", " "); - - return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); - } - - @ApiOperation(value = "Mark an experiment as shared", response = Experiment.class) - @RequestMapping(value = "/{uuid}/markAsShared", method = RequestMethod.GET) - public ResponseEntity<String> markExperimentAsShared( - @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { - - UserActionLogging.LogAction("Mark an experiment as shared", " uuid : " + uuid); - - return doMarkExperimentAsShared(uuid, true); - } - - @ApiOperation(value = "Mark an experiment as unshared", response = Experiment.class) - @RequestMapping(value = "/{uuid}/markAsUnshared", method = RequestMethod.GET) - public ResponseEntity<String> markExperimentAsUnshared( - @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { - UserActionLogging.LogAction("Mark an experiment as unshared", " uuid : " + uuid); - - return doMarkExperimentAsShared(uuid, false); - } - - @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List") - @RequestMapping(method = RequestMethod.GET, params = {"maxResultCount"}) - public ResponseEntity<String> listExperiments( - @ApiParam(value = "maxResultCount") @RequestParam int maxResultCount) { - - UserActionLogging.LogAction("List experiments", " maxResultCount : " + maxResultCount); - - return doListExperiments(false, null); - } - - @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List") - @RequestMapping(method = RequestMethod.GET, params = {"slug", "maxResultCount"}) - public ResponseEntity<String> listExperiments(@ApiParam(value = "slug") @RequestParam("slug") String modelSlug, - @ApiParam(value = "maxResultCount") @RequestParam("maxResultCount") int maxResultCount) { - - UserActionLogging.LogAction("List experiments", " modelSlug : " + modelSlug); - - if (maxResultCount <= 0 && (modelSlug == null || "".equals(modelSlug))) { - return new ResponseEntity<>("You must provide at least a slug or a limit of result", - HttpStatus.BAD_REQUEST); - } - - return doListExperiments(false, modelSlug); - } - - @ApiOperation(value = "list my experiments", response = Experiment.class, responseContainer = "List") - @RequestMapping(method = RequestMethod.GET, params = {"mine"}) - public ResponseEntity<String> listMyExperiments(@ApiParam(value = "mine") @RequestParam("mine") boolean mine) { - UserActionLogging.LogAction("List my experiments", " mine : " + mine); - - return doListExperiments(true, null); - } - - private ResponseEntity<String> doListExperiments(boolean mine, String modelSlug) { - User user = userInfo.getUser(); - - Iterable<Experiment> myExperiments = experimentRepository.findByCreatedBy(user); - List<Experiment> expList = Lists.newLinkedList(myExperiments); - if (!mine) { - Iterable<Experiment> sharedExperiments = experimentRepository.findByShared(true); - List<Experiment> sharedExpList = Lists.newLinkedList(sharedExperiments); - expList.addAll(sharedExpList); - } - - if (modelSlug != null && !"".equals(modelSlug)) { - for (Iterator<Experiment> it = expList.iterator(); it.hasNext(); ) { - Experiment e = it.next(); - e.setResult(null); - e.setAlgorithms(null); - e.setValidations(null); - if (!e.getModel().getSlug().equals(modelSlug)) { - it.remove(); - } - } - } - - return new ResponseEntity<>(gsonOnlyExposed.toJson(expList), HttpStatus.OK); - } - - private ResponseEntity<String> doMarkExperimentAsShared(String uuid, boolean shared) { - Experiment experiment; - UUID experimentUuid; - User user = userInfo.getUser(); - try { - experimentUuid = UUID.fromString(uuid); - } catch (IllegalArgumentException iae) { - //LOGGER.trace("Invalid UUID", iae); - //LOGGER.warn("An invalid Experiment UUID was received !"); - return ResponseEntity.badRequest().body("Invalid Experiment UUID"); - } - - experiment = experimentRepository.findOne(experimentUuid); - - if (!experiment.getCreatedBy().getUsername().equals(user.getUsername())) - return new ResponseEntity<>("You're not the owner of this experiment", HttpStatus.BAD_REQUEST); - - experiment.setShared(shared); - experimentRepository.save(experiment); - - UserActionLogging.LogAction("Experiment updated (marked as shared)", ""); - - return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); - } - - private Experiment createExperiment(ExperimentExecutionDTO experimentExecutionDTO){ - User user = userInfo.getUser(); - - Experiment experiment = new Experiment(); - experiment.setUuid(UUID.randomUUID()); - experiment.setCreatedBy(user); - experiment.setAlgorithms(gson.toJson(experimentExecutionDTO.getAlgorithms())); - Model model = modelRepository.findOne(experimentExecutionDTO.getModel()); - experiment.setModel(model); - experiment.setName(experimentExecutionDTO.getName()); - experimentRepository.save(experiment); - - UserActionLogging.LogAction("Created an experiment", " id : " + experiment.getUuid()); - UserActionLogging.LogAction("Created an experiment", " algorithms : " + experiment.getAlgorithms()); - UserActionLogging.LogAction("Created an experiment", " model : " + experiment.getModel().getSlug()); - UserActionLogging.LogAction("Created an experiment", " name : " + experiment.getName()); - return experiment; - } - - private void saveExperiment(Experiment experiment) { - UserActionLogging.LogAction("Saved an experiment", " id : " + experiment.getUuid()); - UserActionLogging.LogAction("Saved an experiment", " algorithms : " + experiment.getAlgorithms()); - UserActionLogging.LogAction("Saved an experiment", " model : " + experiment.getModel().getSlug()); - UserActionLogging.LogAction("Saved an experiment", " name : " + experiment.getName()); - UserActionLogging.LogAction("Saved an experiment", " historyId : " + experiment.getWorkflowHistoryId()); - UserActionLogging.LogAction("Saved an experiment", " status : " + experiment.getWorkflowStatus()); - - experimentRepository.save(experiment); - - UserActionLogging.LogAction("Experiment saved", ""); - } - - private void finishExperiment(Experiment experiment) { - experiment.setFinished(new Date()); - experimentRepository.save(experiment); - - UserActionLogging.LogThreadAction("Experiment finished!", ""); - } } diff --git a/src/main/java/eu/hbp/mip/controllers/MiningApi.java b/src/main/java/eu/hbp/mip/controllers/MiningApi.java index 13272fc7355ed509e5b030429409a98b83ac55e1..be3b291d935d34843e344006a2007bba2b78c0c0 100644 --- a/src/main/java/eu/hbp/mip/controllers/MiningApi.java +++ b/src/main/java/eu/hbp/mip/controllers/MiningApi.java @@ -45,8 +45,8 @@ public class MiningApi { @Autowired private UserInfo userInfo; - @Value("#{'${services.exareme.miningExaremeUrl:http://localhost:9090/mining/query}'}") - public String miningExaremeQueryUrl; + @Value("#{'${services.exareme.queryExaremeUrl:http://localhost:9090/mining/query}'}") + public String queryExaremeUrl; @ApiOperation(value = "Create an histogram on Exareme", response = String.class) @RequestMapping(value = "/exareme", method = RequestMethod.POST) @@ -54,7 +54,7 @@ public class MiningApi { UserActionLogging.LogAction("Run an histogram", ""); String query = gson.toJson(queryList); - String url = miningExaremeQueryUrl + "/" + "HISTOGRAMS"; + String url = queryExaremeUrl + "/" + "HISTOGRAMS"; try { StringBuilder results = new StringBuilder(); @@ -72,7 +72,7 @@ public class MiningApi { UserActionLogging.LogAction("Run descriptive stats", ""); String query = gson.toJson(queryList); - String url = miningExaremeQueryUrl + "/" + "DESCRIPTIVE_STATS"; + String url = queryExaremeUrl + "/" + "DESCRIPTIVE_STATS"; try { StringBuilder results = new StringBuilder(); @@ -93,7 +93,7 @@ public class MiningApi { UserActionLogging.LogAction("Run algo", ""); String query = gson.toJson(queryList); - String url = miningExaremeQueryUrl + "/" + algorithmName; + String url = queryExaremeUrl + "/" + algorithmName; try { StringBuilder results = new StringBuilder(); diff --git a/src/main/java/eu/hbp/mip/controllers/retrofit/RetroFitGalaxyClients.java b/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java similarity index 96% rename from src/main/java/eu/hbp/mip/controllers/retrofit/RetroFitGalaxyClients.java rename to src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java index 6acd92f0aeff3dde2a40ece432a6dc10ef86ed7c..612dce6ca5b557f23deafdf873978c0f442eb1d9 100644 --- a/src/main/java/eu/hbp/mip/controllers/retrofit/RetroFitGalaxyClients.java +++ b/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java @@ -1,4 +1,4 @@ -package eu.hbp.mip.controllers.retrofit; +package eu.hbp.mip.controllers.galaxy.retrofit; import com.google.gson.JsonObject; import eu.hbp.mip.model.galaxy.GalaxyWorkflowResult; diff --git a/src/main/java/eu/hbp/mip/controllers/retrofit/RetrofitClientInstance.java b/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetrofitClientInstance.java similarity index 96% rename from src/main/java/eu/hbp/mip/controllers/retrofit/RetrofitClientInstance.java rename to src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetrofitClientInstance.java index 52c919270e32d1a99e7bea5b29190f7a565f563a..6aa218902ebd724518d56d8cca8b0c5e77aa2893 100644 --- a/src/main/java/eu/hbp/mip/controllers/retrofit/RetrofitClientInstance.java +++ b/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetrofitClientInstance.java @@ -1,4 +1,4 @@ -package eu.hbp.mip.controllers.retrofit; +package eu.hbp.mip.controllers.galaxy.retrofit; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; diff --git a/src/main/java/eu/hbp/mip/utils/UserActionLogging.java b/src/main/java/eu/hbp/mip/utils/UserActionLogging.java index 2c37ccb31cfbb7922da969c7062327c65cfe8912..f8009127a19580fa34b2f429a928fba936e7d8bb 100644 --- a/src/main/java/eu/hbp/mip/utils/UserActionLogging.java +++ b/src/main/java/eu/hbp/mip/utils/UserActionLogging.java @@ -17,8 +17,9 @@ public class UserActionLogging { + " info: " + actionIdInfo); } + // Used from Threads because LogAction won't wor. public static void LogThreadAction(String actionName, String actionIdInfo) { - LOGGER.info( "Called endpoint: " + actionName + " info: " + actionIdInfo); + LOGGER.info( "Thread -->" + actionName + " info: " + actionIdInfo); } }