From c9c43887e853d0122bce16a4f67d4d1b984a668c Mon Sep 17 00:00:00 2001
From: Ludovic Claude <ludovic.claude54@gmail.com>
Date: Thu, 15 Mar 2018 18:45:41 +0100
Subject: [PATCH] Update woken-messages to 2.5.2, /datasets return
 [{code,label}] from Woken

---
 docker/README.md                              |  1 -
 docker/config/application.tmpl                |  1 -
 docker/run.sh                                 |  2 +-
 pom.xml                                       |  2 +-
 .../hbp/mip/akka/WokenClientController.java   | 45 +++++++----------
 .../eu/hbp/mip/controllers/DatasetsApi.java   | 49 +++++++++++++++----
 .../eu/hbp/mip/controllers/MethodsApi.java    |  2 +-
 7 files changed, 60 insertions(+), 42 deletions(-)

diff --git a/docker/README.md b/docker/README.md
index 33262bdde..419dd0798 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -24,7 +24,6 @@ To use this image, you need a running instance of PostgreSQL and to configure th
 * FEATURES_DB_USER: User to use when connecting to the science database, default value is "postgres".
 * FEATURES_DB_PASSWORD: Password to use when connecting to the science database.
 * FEATURES_DB_MAIN_TABLE: Table that contains the scientific data to use, default value is "features".
-* DATASETS (temporary hack): list of datasets available in the features table
 
 
 ### OAUTH2 LOGIN
diff --git a/docker/config/application.tmpl b/docker/config/application.tmpl
index 3be9dac65..16a901f6b 100644
--- a/docker/config/application.tmpl
+++ b/docker/config/application.tmpl
@@ -21,7 +21,6 @@ spring:
       username: {{ default .Env.FEATURES_DB_USER "postgres" }}
       password: {{ .Env.FEATURES_DB_PASSWORD }}
       driver-class-name: org.postgresql.Driver
-      datasets: {{ .Env.DATASETS }}
   jpa:
     hibernate:
       dialect: org.hibernate.dialect.PostgreSQL9Dialect
diff --git a/docker/run.sh b/docker/run.sh
index 2b1ca22d1..a89331926 100755
--- a/docker/run.sh
+++ b/docker/run.sh
@@ -10,4 +10,4 @@ fi
 if [ ! -z "$FEATURES_DB_SERVER" ]; then
   OPTS="$OPTS -wait tcp://$FEATURES_DB_SERVER -timeout 60s"
 fi
-dockerize $OPTS java -jar /usr/share/jars/portal-backend.jar
+dockerize $OPTS java ${JAVA_OPTS} -jar /usr/share/jars/portal-backend.jar
diff --git a/pom.xml b/pom.xml
index 3f71142f1..d39be85f1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,7 +47,7 @@
         <spring-data-jpa.version>1.10.11.RELEASE</spring-data-jpa.version>
         <spring-boot-starter-actuator.version>1.4.7.RELEASE</spring-boot-starter-actuator.version>
         <aspectjweaver.version>1.8.9</aspectjweaver.version>
-        <woken-messages.version>2.4.9</woken-messages.version>
+        <woken-messages.version>2.5.2</woken-messages.version>
         <javax-inject.version>1</javax-inject.version>
         <akka.version>2.5.9</akka.version>
         <spring-context.version>4.3.4.RELEASE</spring-context.version>
diff --git a/src/main/java/eu/hbp/mip/akka/WokenClientController.java b/src/main/java/eu/hbp/mip/akka/WokenClientController.java
index 3cc463857..2504d6468 100644
--- a/src/main/java/eu/hbp/mip/akka/WokenClientController.java
+++ b/src/main/java/eu/hbp/mip/akka/WokenClientController.java
@@ -31,7 +31,7 @@ import java.util.function.Function;
  */
 public abstract class WokenClientController {
 
-    private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
+    protected final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
 
     @Autowired
     private ActorSystem actorSystem;
@@ -44,6 +44,7 @@ public abstract class WokenClientController {
 
     private ActorRef wokenClient;
 
+    @SuppressWarnings("unused")
     @PostConstruct
     public void initClusterClient() {
         LOGGER.info("Start Woken client " + wokenReceptionistPath);
@@ -56,7 +57,8 @@ public abstract class WokenClientController {
         return Collections.singleton(ActorPaths.fromString(wokenReceptionistPath));
     }
 
-    protected <A, B> ResponseEntity askWoken(A message, int waitInSeconds, Function<B, ResponseEntity> handleResponse) {
+    @SuppressWarnings("unchecked")
+    protected <A, B> B askWoken(A message, int waitInSeconds) throws Exception {
         LOGGER.info("Akka is trying to reach remote " + wokenPath);
 
         ClusterClient.Send queryMessage = new ClusterClient.Send(wokenPath, message, true);
@@ -64,35 +66,29 @@ public abstract class WokenClientController {
 
         Future<Object> future = Patterns.ask(wokenClient, queryMessage, timeout);
 
-        B result;
+        return (B) Await.result(future, timeout.duration());
+    }
+
+    protected <A, B> ResponseEntity requestWoken(A message, int waitInSeconds, Function<B, ResponseEntity> handleResponse) {
         try {
-            result = (B) Await.result(future, timeout.duration());
+            B result = askWoken(message, waitInSeconds);
+            return handleResponse.apply(result);
         } catch (Exception e) {
-            LOGGER.error("Cannot receive algorithm result from woken: " + e.getMessage(), e);
-            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build();
+            final String msg = "Cannot receive result from woken: " + e.getMessage();
+            LOGGER.error(msg, e);
+            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(msg);
         }
-
-        return handleResponse.apply(result);
     }
 
-
     protected <A extends Query> ResponseEntity askWokenQuery(A query, int waitInSeconds, Function<QueryResult, ResponseEntity> handleResponse) {
-        LOGGER.info("Akka is trying to reach remote " + wokenPath);
-
-        ClusterClient.Send queryMessage = new ClusterClient.Send(wokenPath, query, true);
-        Timeout timeout = new Timeout(Duration.create(waitInSeconds, "seconds"));
-
-        Future<Object> future = Patterns.ask(wokenClient, queryMessage, timeout);
-
-        QueryResult result;
         try {
-            result = (QueryResult) Await.result(future, timeout.duration());
+            QueryResult result = askWoken(query, waitInSeconds);
+            return handleResponse.apply(result);
         } catch (Exception e) {
-            LOGGER.error("Cannot receive algorithm result from woken: " + e.getMessage(), e);
-            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build();
+            final String msg = "Cannot receive algorithm result from woken: " + e.getMessage();
+            LOGGER.error(msg, e);
+            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(msg);
         }
-
-        return handleResponse.apply(result);
     }
 
     protected <A extends Query> Future<Object> sendWokenQuery(A query, int timeout) {
@@ -103,11 +99,6 @@ public abstract class WokenClientController {
         return Patterns.ask(wokenClient, queryMessage, timeout);
     }
 
-    protected ActorRef createActor(String actorBeanName, String actorName) {
-        return actorSystem.actorOf(SpringExtension.SPRING_EXTENSION_PROVIDER.get(actorSystem)
-                .props(actorBeanName), actorName);
-    }
-
     protected ExecutionContext getExecutor() {
         return actorSystem.dispatcher();
     }
diff --git a/src/main/java/eu/hbp/mip/controllers/DatasetsApi.java b/src/main/java/eu/hbp/mip/controllers/DatasetsApi.java
index 052486a5e..f4f67edd9 100644
--- a/src/main/java/eu/hbp/mip/controllers/DatasetsApi.java
+++ b/src/main/java/eu/hbp/mip/controllers/DatasetsApi.java
@@ -5,7 +5,12 @@
 package eu.hbp.mip.controllers;
 
 
+import ch.chuv.lren.woken.messages.datasets.DatasetsQuery;
+import ch.chuv.lren.woken.messages.datasets.DatasetsResponse;
 import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import eu.hbp.mip.akka.WokenClientController;
 import eu.hbp.mip.model.Dataset;
 import eu.hbp.mip.model.Variable;
 import eu.hbp.mip.repositories.VariableRepository;
@@ -13,21 +18,25 @@ import io.swagger.annotations.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
+import scala.Option;
 
 import javax.annotation.PostConstruct;
 
+import java.util.Set;
+import java.util.stream.Stream;
+
 import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
 
 
 @RestController
 @RequestMapping(value = "/datasets", produces = {APPLICATION_JSON_VALUE})
 @Api(value = "/datasets", description = "the datasets API")
-public class DatasetsApi {
+public class DatasetsApi extends WokenClientController {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(DatasetsApi.class);
     private static final Gson gson = new Gson();
@@ -35,15 +44,15 @@ public class DatasetsApi {
     @Autowired
     private VariableRepository variableRepository;
 
-    @Value("#{'${spring.featuresDatasource.datasets:adni,ppmi,edsd}'}")
-    private String datasets;
-
     @PostConstruct
-    public void init() {
-        for (String dataset: datasets.split(",")) {
-            Variable v = variableRepository.findOne(dataset);
+    public void init() throws Exception {
+        // Pre-fill the local variable repository with the list of datasets, interpreted here as variables
+        // (a bit like a categorical variable can be split into a set of variables (a.k.a one hot encoding in Data science) )
+        for (ch.chuv.lren.woken.messages.datasets.Dataset dataset: fetchDatasets()) {
+            final String code = dataset.dataset().code();
+            Variable v = variableRepository.findOne(code);
             if (v == null) {
-                v = new Variable(dataset);
+                v = new Variable(code);
                 variableRepository.save(v);
             }
         }
@@ -55,7 +64,27 @@ public class DatasetsApi {
     )  {
         LOGGER.info("Get dataset list");
 
-        return ResponseEntity.ok(datasets.split(","));
+        try {
+            JsonArray datasets = new JsonArray();
+            Stream<JsonObject> values = fetchDatasets().stream().map(d -> {
+                JsonObject jsObject = new JsonObject();
+                jsObject.addProperty("code", d.dataset().code());
+                jsObject.addProperty("label", d.label());
+                datasets.add(jsObject);
+                return jsObject;
+            });
+
+            return ResponseEntity.ok(datasets);
+        } catch (Exception e) {
+            final String msg = "Cannot receive datasets from woken: " + e.getMessage();
+            LOGGER.error(msg, e);
+            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(msg);
+        }
+
     }
 
+    private Set<ch.chuv.lren.woken.messages.datasets.Dataset> fetchDatasets() throws Exception {
+        DatasetsResponse result = askWoken(new DatasetsQuery(Option.empty()), 30);
+        return scala.collection.JavaConversions.setAsJavaSet(result.datasets());
+    }
 }
diff --git a/src/main/java/eu/hbp/mip/controllers/MethodsApi.java b/src/main/java/eu/hbp/mip/controllers/MethodsApi.java
index f25187d58..5e7f36b2d 100644
--- a/src/main/java/eu/hbp/mip/controllers/MethodsApi.java
+++ b/src/main/java/eu/hbp/mip/controllers/MethodsApi.java
@@ -35,7 +35,7 @@ public class MethodsApi extends WokenClientController {
     public ResponseEntity listAvailableMethodsAndValidations() {
         LOGGER.info("List available methods and validations");
 
-        return askWoken(MethodsQuery$.MODULE$, 10, r -> {
+        return requestWoken(MethodsQuery$.MODULE$, 10, r -> {
             MethodsResponse result = (MethodsResponse) r;
 
             // >> Temporary : should return result.methods() in the future
-- 
GitLab