diff --git a/config/application.yml b/config/application.yml index aba6d24c8361d21d4e4a899afb617ef8dbd0595a..6f752d822bf63ecaf3bfb238dd920f177f05e2f3 100644 --- a/config/application.yml +++ b/config/application.yml @@ -40,7 +40,8 @@ server: timeout: 2592000 workflow: - miningUrl: http://mip.humanbrainproject.eu/services/mining - exaremeListAlgoUrl: http://hbps2.chuv.ch:9090/mining/algorithms - exaremeQueryUrl: http://hbps2.chuv.ch:9090/mining/query + experimentUrl: http://dockerhost:8087/experiment + listMethodsUrl: http://dockerhost:8087/list-methods + miningMipUrl: http://dockerhost:8087/mining + miningExaremeUrl: http://hbps2.chuv.ch:9090/mining/query diff --git a/pom.xml b/pom.xml index 7c627835778704f3a3d84b2fd11a293946d1c09d..af7c98035d8d7f354bf6730240deef5b94d9d464 100644 --- a/pom.xml +++ b/pom.xml @@ -25,25 +25,6 @@ <relativePath /> <!-- lookup parent from repository --> </parent> <profiles> - <profile> - <id>test</id> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <java.version>1.8</java.version> - <connection.driver_class>org.h2.Driver</connection.driver_class> - <connection.url>jdbc:h2:mem:test</connection.url> - <connection.username>root</connection.username> - <connection.password>root</connection.password> - <hibernate.dialect>org.hibernate.dialect.H2Dialect</hibernate.dialect> - <schema.deploy>true</schema.deploy> - <frontend.redirect>http://frontend/#/home</frontend.redirect> - <workflow.experimentUrl>http://hbps1.chuv.ch:8087/experiment</workflow.experimentUrl> - <workflow.listMethodsUrl>http://hbps1.chuv.ch:8087/list-methods</workflow.listMethodsUrl> - <flyway.url>${connection.url}</flyway.url> - <flyway.user>${connection.username}</flyway.user> - <flyway.password>${connection.password}</flyway.password> - </properties> - </profile> <profile> <id>prod</id> <properties> @@ -55,9 +36,7 @@ <connection.password>iaezXODVLb1e70I</connection.password> <hibernate.dialect>org.hibernate.dialect.PostgreSQL82Dialect</hibernate.dialect> <schema.deploy>false</schema.deploy> - <frontend.redirect>https://mip.humanbrainproject.eu/#/home</frontend.redirect> - <workflow.experimentUrl>http://hbps1.chuv.ch:8087/experiment</workflow.experimentUrl> - <workflow.listMethodsUrl>http://hbps1.chuv.ch:8087/list-methods</workflow.listMethodsUrl> + <frontend.redirect>https://mip.humanbrainproject.eu/home</frontend.redirect> <flyway.url>${connection.url}</flyway.url> <flyway.user>${connection.username}</flyway.user> <flyway.password>${connection.password}</flyway.password> @@ -75,8 +54,6 @@ <hibernate.dialect>org.hibernate.dialect.PostgreSQL82Dialect</hibernate.dialect> <schema.deploy>false</schema.deploy> <frontend.redirect>http://frontend/home</frontend.redirect> - <workflow.experimentUrl>http://hbps1.chuv.ch:8087/experiment</workflow.experimentUrl> - <workflow.listMethodsUrl>http://hbps1.chuv.ch:8087/list-methods</workflow.listMethodsUrl> <flyway.url>${connection.url}</flyway.url> <flyway.user>${connection.username}</flyway.user> <flyway.password>${connection.password}</flyway.password> @@ -94,8 +71,6 @@ <hibernate.dialect>org.hibernate.dialect.PostgreSQL82Dialect</hibernate.dialect> <schema.deploy>false</schema.deploy> <frontend.redirect>http://hbps1.chuv.ch/home</frontend.redirect> - <workflow.experimentUrl>http://hbps1.chuv.ch:8087/experiment</workflow.experimentUrl> - <workflow.listMethodsUrl>http://hbps1.chuv.ch:8087/list-methods</workflow.listMethodsUrl> <flyway.url>${connection.url}</flyway.url> <flyway.user>${connection.username}</flyway.user> <flyway.password>${connection.password}</flyway.password> @@ -194,12 +169,10 @@ <resources> <resource> <directory>src/main/resources</directory> - <includes><include>**/*.csv</include></includes> - <excludes><exclude>**/*.xml</exclude></excludes> - </resource> - <resource> - <directory>src/main/resources</directory> - <includes><include>**/*.xml</include></includes> + <includes> + <include>**/*.xml</include> + <include>**/*.json</include> + </includes> <excludes><exclude>**/*.csv</exclude></excludes> <filtering>true</filtering> </resource> diff --git a/src/main/java/org/hbp/mip/controllers/ExperimentApi.java b/src/main/java/org/hbp/mip/controllers/ExperimentApi.java index e71ee947f6a46583f375c52e680f9c865afffd49..868b7ed860f08eb63d1bb88a572355d00f30c486 100644 --- a/src/main/java/org/hbp/mip/controllers/ExperimentApi.java +++ b/src/main/java/org/hbp/mip/controllers/ExperimentApi.java @@ -1,13 +1,10 @@ package org.hbp.mip.controllers; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; +import com.google.gson.*; import io.swagger.annotations.*; import org.hbp.mip.MIPApplication; -import org.hbp.mip.model.Experiment; -import org.hbp.mip.model.Model; -import org.hbp.mip.model.User; +import org.hbp.mip.model.*; +import org.hbp.mip.utils.HTTPUtil; import org.hbp.mip.utils.HibernateUtil; import org.hibernate.Query; import org.hibernate.Session; @@ -20,11 +17,11 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.io.*; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.ProtocolException; -import java.net.URL; -import java.util.*; +import java.net.*; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @@ -37,19 +34,23 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @javax.annotation.Generated(value = "class io.swagger.codegen.languages.SpringMVCServerCodegen", date = "2016-01-07T07:38:20.227Z") public class ExperimentApi { + private static final String EXAREME_ALGO_JSON_FILE="data/exareme_algorithms.json"; + private static final Gson gson = new GsonBuilder() .serializeNulls() .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") .excludeFieldsWithoutExposeAnnotation() .create(); - @Value("#{'${workflow.experimentUrl:http://hbps1.chuv.ch:8087/experiment}'}") + @Value("#{'${workflow.experimentUrl:http://dockerhost:8087/experiment}'}") private String experimentUrl; - - @Value("#{'${workflow.listMethodsUrl:http://hbps1.chuv.ch:8087/list-methods}'}") + @Value("#{'${workflow.listMethodsUrl:http://dockerhost:8087/list-methods}'}") private String listMethodsUrl; + @Value("#{'${workflow.miningExaremeUrl:http://hbps2.chuv.ch:9090/mining/query}'}") + private String miningExaremeQueryUrl; + @Autowired MIPApplication mipApplication; @@ -155,12 +156,117 @@ public class ExperimentApi { } try { - sendPost(experiment); + if(isExaremeAlgo(experiment)) + { + sendExaremePost(experiment); + } + else + { + sendPost(experiment); + } } catch (MalformedURLException mue) {} // ignore return new ResponseEntity<>(gson.toJson(experiment), HttpStatus.OK); } + private void sendExaremePost(Experiment experiment) { + + Model model = experiment.getModel(); + String algoCode = "WP_LINEAR_REGRESSION"; + + LinkedList<ExaremeQueryElement> queryElements = new LinkedList<>(); + for (Variable var : model.getQuery().getVariables()) + { + ExaremeQueryElement el = new ExaremeQueryElement(); + el.setName("variable"); + el.setDesc(""); + el.setValue(var.getCode()); + queryElements.add(el); + } + for (Variable var : model.getQuery().getCovariables()) + { + ExaremeQueryElement el = new ExaremeQueryElement(); + el.setName("covariables"); + el.setDesc(""); + el.setValue(var.getCode()); + queryElements.add(el); + } + for (Variable var : model.getQuery().getGrouping()) + { + ExaremeQueryElement el = new ExaremeQueryElement(); + el.setName("groupings"); + el.setDesc(""); + el.setValue(var.getCode()); + queryElements.add(el); + } + + ExaremeQueryElement tableEl = new ExaremeQueryElement(); + tableEl.setName("showtable"); + tableEl.setDesc(""); + tableEl.setValue("TotalResults"); + queryElements.add(tableEl); + + ExaremeQueryElement formatEl = new ExaremeQueryElement(); + formatEl.setName("format"); + formatEl.setDesc(""); + formatEl.setValue("True"); + queryElements.add(formatEl); + + String jsonQuery = new Gson().toJson(queryElements); + + new Thread() { + public void run() { + try { + String url = miningExaremeQueryUrl + "/" + algoCode; + StringBuilder results = new StringBuilder(); + int code = HTTPUtil.sendPost(url, jsonQuery, results); + + experiment.setResult(results.toString().replace("\0", "")); + experiment.setHasError(code >= 400); + experiment.setHasServerError(code >= 500); + + if(!isJSONValid(experiment.getResult())) + { + experiment.setResult("Unsupported variables !"); + } + } catch (Exception e) { + experiment.setHasError(true); + experiment.setHasServerError(true); + experiment.setResult(e.getMessage()); + } + + experiment.setFinished(new Date()); + + try { + Session session = HibernateUtil.getSessionFactory().openSession(); + Transaction transaction = session.beginTransaction(); + session.update(experiment); + transaction.commit(); + session.close(); + } catch (DataException e) { + throw e; + } + + } + }.start(); + } + + public boolean isJSONValid(String test) { + try { + new JsonParser().parse(test); + } catch (JsonParseException jpe) + { + return false; + } + return true; + } + + private boolean isExaremeAlgo(Experiment experiment) { + JsonArray algorithms = new JsonParser().parse(experiment.getAlgorithms()).getAsJsonArray(); + String algoCode = algorithms.get(0).getAsJsonObject().get("code").getAsString(); + return algoCode.equals("glm_exareme"); + } + @ApiOperation(value = "get an experiment", response = Experiment.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") }) @RequestMapping(value = "/{uuid}", method = RequestMethod.GET) @@ -371,22 +477,22 @@ public class ExperimentApi { @RequestMapping(path = "/methods", method = RequestMethod.GET) public ResponseEntity<String> listAvailableMethodsAndValidations() throws Exception { - URL obj = new URL(listMethodsUrl); - HttpURLConnection con = (HttpURLConnection) obj.openConnection(); - con.setRequestMethod("GET"); + StringBuilder response = new StringBuilder(); - int respCode = con.getResponseCode(); + int code = HTTPUtil.sendGet(listMethodsUrl, response); + if (code < 200 || code > 299) { + return new ResponseEntity<>(response.toString(), HttpStatus.valueOf(code)); + } - BufferedReader in = new BufferedReader(new InputStreamReader(respCode == 200 ? con.getInputStream() : con.getErrorStream())); + JsonObject catalog = new JsonParser().parse(response.toString()).getAsJsonObject(); - String inputLine; - StringBuilder response = new StringBuilder(); + InputStream is = ExperimentApi.class.getClassLoader().getResourceAsStream(EXAREME_ALGO_JSON_FILE); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + JsonObject exaremeAlgo = new JsonParser().parse(br).getAsJsonObject(); - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); + catalog.get("algorithms").getAsJsonArray().add(exaremeAlgo); - return new ResponseEntity<>(response.toString(), HttpStatus.valueOf(respCode)); + return new ResponseEntity<>(new Gson().toJson(catalog), HttpStatus.valueOf(code)); } } diff --git a/src/main/java/org/hbp/mip/controllers/MiningApi.java b/src/main/java/org/hbp/mip/controllers/MiningApi.java deleted file mode 100644 index 2fc2882d7ee1a9e401c02b879dcb598a1dcb9407..0000000000000000000000000000000000000000 --- a/src/main/java/org/hbp/mip/controllers/MiningApi.java +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Created by mirco on 02.03.16. - */ - -package org.hbp.mip.controllers; - -import com.google.gson.JsonParser; -import io.swagger.annotations.*; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.UnknownHostException; - -@RestController -@RequestMapping(value = "/mining") -@Api(value = "/mining", description = "Forward mining API") -public class MiningApi { - - @Value("#{'${workflow.miningUrl:http://localhost:8087/mining}'}") - private String miningUrl; - - @Value("#{'${workflow.exaremeListAlgoUrl:http://localhost:9090/mining/algorithms}'}") - private String exaremeListAlgoUrl; - - @Value("#{'${workflow.exaremeQueryUrl:http://localhost:9090/mining/query}'}") - private String exaremeQueryUrl; - - @ApiOperation(value = "Send a request to the workflow for data mining", response = String.class) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") }) - @RequestMapping(method = RequestMethod.POST) - public ResponseEntity<String> postMining( - @RequestBody @ApiParam(value = "Query for the data mining", required = true) String query - ) throws Exception { - try { - StringBuilder results = new StringBuilder(); - int code = sendPost(miningUrl, query, results); - - return new ResponseEntity<>(results.toString(), HttpStatus.valueOf(code)); - } - catch(UnknownHostException uhe) { - uhe.printStackTrace(); - return new ResponseEntity<>(HttpStatus.BAD_GATEWAY); - } - } - - @ApiOperation(value = "Send a request to the Exareme service to list available algorithms", response = String.class) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") }) - @RequestMapping(path = "/exareme/algorithms", method = RequestMethod.GET) - public ResponseEntity<String> getExaremeAlgoList( - ) throws Exception { - try { - StringBuilder results = new StringBuilder(); - int code = sendGet(exaremeListAlgoUrl, results); - - return new ResponseEntity<>(results.toString(), HttpStatus.valueOf(code)); - } - catch(UnknownHostException uhe) { - uhe.printStackTrace(); - return new ResponseEntity<>(HttpStatus.BAD_GATEWAY); - } - } - - @ApiOperation(value = "Send a request to the Exareme service to run an algorithm", response = String.class) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") }) - @RequestMapping(path = "/exareme/query/{algo}", method = RequestMethod.POST) - public ResponseEntity<String> postExaremeQuery( - @ApiParam(value = "algo", required = true) @PathVariable("algo") String algo, - @RequestBody(required = false) @ApiParam(value = "Query for the data mining") String query - ) throws Exception { - try { - - /* Launch computation */ - - String url = exaremeQueryUrl+"/"+algo+"/?format=true"; - StringBuilder results = new StringBuilder(); - int code = sendPost(url, query, results); - if (code < 200 || code > 299) - { - return new ResponseEntity<>(results.toString(), HttpStatus.valueOf(code)); - } - - JsonParser parser = new JsonParser(); - String key = parser.parse(results.toString()).getAsJsonObject().get("queryKey").getAsString(); - - /* Wait for result */ - - url = exaremeQueryUrl+"/"+key+"/status"; - double progress = 0; - - while (progress < 100) { - Thread.sleep(200); - results = new StringBuilder(); - code = sendPost(url, query, results); - if (code < 200 || code > 299) - { - return new ResponseEntity<>(results.toString(), HttpStatus.valueOf(code)); - } - progress = parser.parse(results.toString()).getAsJsonObject().get("status").getAsDouble(); - } - - /* Get result */ - - url = exaremeQueryUrl+"/"+key+"/result"; - results = new StringBuilder(); - code = sendPost(url, query, results); - - return new ResponseEntity<>(results.toString(), HttpStatus.valueOf(code)); - } - catch(UnknownHostException uhe) { - uhe.printStackTrace(); - return new ResponseEntity<>(HttpStatus.BAD_GATEWAY); - } - } - - private static int sendGet(String url, StringBuilder resp) throws Exception { - return sendHTTP(url, "", resp, "GET"); - } - - private static int sendPost(String url, String query, StringBuilder resp) throws Exception { - return sendHTTP(url, query, resp, "POST"); - } - - private static int sendHTTP(String url, String query, StringBuilder resp, String httpVerb) throws Exception { - - URL obj = new URL(url); - HttpURLConnection con = (HttpURLConnection) obj.openConnection(); - - if(!httpVerb.equals("GET")) { - con.setRequestMethod(httpVerb); - if(query != null && query.length() > 0) - { - con.addRequestProperty("Content-Type", "application/json"); - con.setRequestProperty("Content-Length", Integer.toString(query.length())); - - con.setDoOutput(true); - DataOutputStream wr = new DataOutputStream(con.getOutputStream()); - wr.write(query.getBytes("UTF8")); - wr.flush(); - wr.close(); - } - } - - int respCode = con.getResponseCode(); - - BufferedReader in; - if(respCode == 200) { - in = new BufferedReader(new InputStreamReader(con.getInputStream())); - } - else - { - in = new BufferedReader(new InputStreamReader(con.getErrorStream())); - } - String inputLine; - StringBuilder response = new StringBuilder(); - - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - resp.append(response.toString()); - - return respCode; - } - -} diff --git a/src/main/java/org/hbp/mip/model/ExaremeQueryElement.java b/src/main/java/org/hbp/mip/model/ExaremeQueryElement.java new file mode 100644 index 0000000000000000000000000000000000000000..dba6d6269da25986a0d39028d927f61563b39ae8 --- /dev/null +++ b/src/main/java/org/hbp/mip/model/ExaremeQueryElement.java @@ -0,0 +1,43 @@ +package org.hbp.mip.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.annotations.ApiModel; + +/** + * Created by mirco on 20.06.16. + */ + +@ApiModel +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ExaremeQueryElement { + + private String name; + + private String desc; + + private String value; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/src/main/java/org/hbp/mip/utils/HTTPUtil.java b/src/main/java/org/hbp/mip/utils/HTTPUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..92beffaf45e7f48e8c71d51e36414fb78ce827ae --- /dev/null +++ b/src/main/java/org/hbp/mip/utils/HTTPUtil.java @@ -0,0 +1,63 @@ +package org.hbp.mip.utils; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * Created by mirco on 20.06.16. + */ +public class HTTPUtil { + + public static int sendGet(String url, StringBuilder resp) throws Exception { + return sendHTTP(url, "", resp, "GET"); + } + + public static int sendPost(String url, String query, StringBuilder resp) throws Exception { + return sendHTTP(url, query, resp, "POST"); + } + + public static int sendHTTP(String url, String query, StringBuilder resp, String httpVerb) throws Exception { + + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + + if(!httpVerb.equals("GET")) { + con.setRequestMethod(httpVerb); + if(query != null && query.length() > 0) + { + con.addRequestProperty("Content-Type", "application/json"); + con.setRequestProperty("Content-Length", Integer.toString(query.length())); + + con.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(con.getOutputStream()); + wr.write(query.getBytes("UTF8")); + wr.flush(); + wr.close(); + } + } + + int respCode = con.getResponseCode(); + + BufferedReader in; + if(respCode == 200) { + in = new BufferedReader(new InputStreamReader(con.getInputStream())); + } + else + { + in = new BufferedReader(new InputStreamReader(con.getErrorStream())); + } + String inputLine; + StringBuilder response = new StringBuilder(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + resp.append(response.toString()); + + return respCode; + } +} diff --git a/src/main/resources/data/exareme_algorithms.json b/src/main/resources/data/exareme_algorithms.json new file mode 100644 index 0000000000000000000000000000000000000000..3fc6a34713fd110758b4c59032254cf292439775 --- /dev/null +++ b/src/main/resources/data/exareme_algorithms.json @@ -0,0 +1,14 @@ +{ + "code": "glm_exareme", + "label": "GLM (exareme)", + "type": ["statistics"], + "environment": "Exareme", + "description": "Linear Regression using Exareme services", + "constraints": { + "variable": { + "real": true, + "binominal": false, + "polynominal": false + } + } +} \ No newline at end of file