diff --git a/pom.xml b/pom.xml
index af7c98035d8d7f354bf6730240deef5b94d9d464..a9cb39f28e7cf809c411420afed6756ec9965b9e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,13 +11,6 @@
     <name>backend-services</name>
     <description>Medical Informatics Platform : backend restful services</description>
 
-	<distributionManagement>
-	    <repository>
-	        <id>central</id>
-	        <name>8a59c6752bef-releases</name>
-	        <url>http://hbps1.chuv.ch/artifactory/libs-release-local</url>
-	    </repository>
-	</distributionManagement>
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
@@ -165,6 +158,33 @@
         </dependency>
     </dependencies>
 
+
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>jcenter-snapshots</id>
+            <name>jcenter</name>
+            <url>http://oss.jfrog.org/artifactory/oss-snapshot-local/</url>
+        </pluginRepository>
+        <pluginRepository>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <id>jcenter-releases</id>
+            <name>jcenter</name>
+            <url>http://jcenter.bintray.com</url>
+        </pluginRepository>
+    </pluginRepositories>
+
+    <properties>
+        <asciidoctor.maven.plugin.version>1.5.3</asciidoctor.maven.plugin.version>
+        <asciidoctorj.pdf.version>1.5.0-alpha.11</asciidoctorj.pdf.version>
+        <asciidoctorj.version>1.5.4</asciidoctorj.version>
+        <sonar.host.url>http://dockerhost:9000</sonar.host.url>
+        <sonar.projectName>MIP Backend</sonar.projectName>
+        <sonar.sources>src/main/java/</sonar.sources>
+    </properties>
+
     <build>
         <resources>
             <resource>
@@ -172,8 +192,8 @@
                 <includes>
                     <include>**/*.xml</include>
                     <include>**/*.json</include>
+                    <include>**/*.csv</include>
                 </includes>
-                <excludes><exclude>**/*.csv</exclude></excludes>
                 <filtering>true</filtering>
             </resource>
         </resources>
@@ -182,7 +202,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-resources-plugin</artifactId>
-                <version>2.4</version>
+                <version>2.3</version>
                 <configuration>
                     <!-- specify UTF-8, ISO-8859-1 or any other file encoding -->
                     <encoding>UTF-8</encoding>
@@ -192,28 +212,19 @@
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
             </plugin>
-			<plugin>
-				<groupId>de.juplo</groupId>
-				<artifactId>hibernate-maven-plugin</artifactId>
-				<version>2.0.0</version>
-				<executions>
-					<execution>
-						<phase>compile</phase>
-						<goals>
-							<goal>create</goal>
-						</goals>
-					</execution>
-				</executions>
-				<configuration>
-					<export>false</export>
-					<show>true</show>
-					<format>true</format>
-				</configuration>
-			</plugin>
             <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
+                <groupId>de.juplo</groupId>
+                <artifactId>hibernate4-maven-plugin</artifactId>
+                <version>1.1.0</version>
+                <executions>
+                    <execution>
+                        <phase>compile</phase>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.5.1</version>
+                <version>3.1</version>
                 <configuration>
                     <source>1.8</source>
                     <target>1.8</target>
@@ -224,6 +235,43 @@
                 <artifactId>flyway-maven-plugin</artifactId>
                 <version>4.0.1</version>
             </plugin>
+            <plugin>
+                <groupId>io.github.swagger2markup</groupId>
+                <artifactId>swagger2markup-maven-plugin</artifactId>
+                <version>1.0.0</version>
+                <configuration>
+                    <swaggerInput>http://localhost:8080/services/v2/api-docs</swaggerInput>
+                    <outputFile>${project.build.directory}/asciidoc/api</outputFile>
+                    <config>
+                        <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>
+                    </config>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.asciidoctor</groupId>
+                <artifactId>asciidoctor-maven-plugin</artifactId>
+                <version>${asciidoctor.maven.plugin.version}</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.asciidoctor</groupId>
+                        <artifactId>asciidoctorj-pdf</artifactId>
+                        <version>${asciidoctorj.pdf.version}</version>
+                    </dependency>
+                </dependencies>
+                <configuration>
+                    <sourceDirectory>${project.build.directory}/asciidoc</sourceDirectory>
+                    <backend>pdf</backend>
+                    <attributes>
+                        <toc/>
+                        <idseparator>-</idseparator>
+                    </attributes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.sonarsource.scanner.maven</groupId>
+                <artifactId>sonar-maven-plugin</artifactId>
+                <version>3.0.1</version>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/src/main/java/org/hbp/mip/MIPApplication.java b/src/main/java/org/hbp/mip/MIPApplication.java
index 0c44fef61108fcd62b46653bdc996ceb42480967..f6d5aeb3d156eeac8afd31340c8bf1b190065e61 100644
--- a/src/main/java/org/hbp/mip/MIPApplication.java
+++ b/src/main/java/org/hbp/mip/MIPApplication.java
@@ -3,27 +3,13 @@
  * Based on gregturn code at : 'https://github.com/spring-guides/tut-spring-boot-oauth2'.
  */
 
-/*
- * Copyright 2012-2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 package org.hbp.mip;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiParam;
+import org.apache.log4j.Logger;
 import org.hbp.mip.model.User;
 import org.hbp.mip.utils.CORSFilter;
 import org.hbp.mip.utils.HibernateUtil;
@@ -92,6 +78,8 @@ import java.security.Principal;
 @Api(value = "/", description = "MIP API")
 public class MIPApplication extends WebSecurityConfigurerAdapter {
 
+    private static final Logger LOGGER = Logger.getLogger(MIPApplication.class);
+
     @Autowired
     OAuth2ClientContext oauth2ClientContext;
 
@@ -178,12 +166,11 @@ public class MIPApplication extends WebSecurityConfigurerAdapter {
         try {
             String userJSON = mapper.writeValueAsString(getUser());
             Cookie cookie = new Cookie("user", URLEncoder.encode(userJSON, "UTF-8"));
+            cookie.setSecure(true);
             cookie.setPath("/");
             response.addCookie(cookie);
-        } catch (JsonProcessingException e) {
-            e.printStackTrace();
-        } catch (UnsupportedEncodingException e) {
-            e.printStackTrace();
+        } catch (JsonProcessingException | UnsupportedEncodingException e) {
+            LOGGER.trace(e);
         }
         return principal;
     }
@@ -222,7 +209,7 @@ public class MIPApplication extends WebSecurityConfigurerAdapter {
         http.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class);
         http.antMatcher("/**")
                 .authorizeRequests()
-                .antMatchers("/", "/frontend/**", "/webjars/**").permitAll()
+                .antMatchers("/", "/frontend/**", "/webjars/**", "/v2/api-docs").permitAll()
                 .anyRequest().authenticated()
                 .and().exceptionHandling().authenticationEntryPoint(new CustomLoginUrlAuthenticationEntryPoint("/login/hbp"))
                 .and().logout().logoutSuccessUrl("/login/hbp").permitAll()
@@ -274,8 +261,7 @@ public class MIPApplication extends WebSecurityConfigurerAdapter {
     }
 
     private CsrfTokenRepository csrfTokenRepository() {
-        HttpSessionCsrfTokenRepository repository = httpSessionCsrfTokenRepository;
-        return repository;
+        return httpSessionCsrfTokenRepository;
     }
 
 }
diff --git a/src/main/java/org/hbp/mip/controllers/AppsApi.java b/src/main/java/org/hbp/mip/controllers/AppsApi.java
index aa0bd2357c08c99f8e121ccc85ecb71af9ef6f7c..b89ef31b4836ba1e52966ae8a002e341bdb13546 100644
--- a/src/main/java/org/hbp/mip/controllers/AppsApi.java
+++ b/src/main/java/org/hbp/mip/controllers/AppsApi.java
@@ -5,6 +5,7 @@
 package org.hbp.mip.controllers;
 
 import io.swagger.annotations.*;
+import org.apache.log4j.Logger;
 import org.hbp.mip.MIPApplication;
 import org.hbp.mip.model.App;
 import org.hbp.mip.model.User;
@@ -32,6 +33,8 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
 @Api(value = "/apps", description = "the apps API")
 public class AppsApi {
 
+    private static final Logger LOGGER = Logger.getLogger(AppsApi.class);
+
     @Autowired
     MIPApplication mipApplication;
 
@@ -106,6 +109,7 @@ public class AppsApi {
         }
         catch (ConstraintViolationException cve)
         {
+            LOGGER.trace(cve);
             if(session.getTransaction() != null)
             {
                 session.getTransaction().rollback();
@@ -114,6 +118,7 @@ public class AppsApi {
         }
         catch (NonUniqueObjectException nuoe)
         {
+            LOGGER.trace(nuoe);
             if(session.getTransaction() != null)
             {
                 session.getTransaction().rollback();
diff --git a/src/main/java/org/hbp/mip/controllers/ArticlesApi.java b/src/main/java/org/hbp/mip/controllers/ArticlesApi.java
index 8a0a15e52e478f36a86eb326239cfa3c7f0d7f88..99fe8334aef8fa27ba2fde647794b472b1cdb196 100644
--- a/src/main/java/org/hbp/mip/controllers/ArticlesApi.java
+++ b/src/main/java/org/hbp/mip/controllers/ArticlesApi.java
@@ -7,6 +7,7 @@ package org.hbp.mip.controllers;
 
 import com.github.slugify.Slugify;
 import io.swagger.annotations.*;
+import org.apache.log4j.Logger;
 import org.hbp.mip.MIPApplication;
 import org.hbp.mip.model.Article;
 import org.hbp.mip.model.User;
@@ -31,6 +32,8 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
 @Api(value = "/articles", description = "the articles API")
 public class ArticlesApi {
 
+    private static final Logger LOGGER = Logger.getLogger(ArticlesApi.class);
+
     @Autowired
     MIPApplication mipApplication;
 
@@ -57,11 +60,6 @@ public class ArticlesApi {
         else
         {
             queryString += " AND (status='published' or u.username= :username)";
-            if(team != null && team)
-            {
-                // TODO: decide if this is needed
-                //queryString += " AND u.team= :team";
-            }
         }
 
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
@@ -99,7 +97,7 @@ public class ArticlesApi {
         User user = mipApplication.getUser();
 
         article.setCreatedAt(new Date());
-        if (article.getStatus().equals("published")) {
+        if ("published".equals(article.getStatus())) {
             article.setPublishedAt(new Date());
         }
         article.setCreatedBy(user);
@@ -128,13 +126,7 @@ public class ArticlesApi {
                 }
             } while(count > 0);
 
-            Slugify slg = null;
-            try {
-                slg = new Slugify();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-            String slug = slg.slugify(article.getTitle());
+            String slug = new Slugify().slugify(article.getTitle());
 
             i = 0;
             do {
@@ -156,8 +148,9 @@ public class ArticlesApi {
 
             session.save(article);
             session.getTransaction().commit();
-        } catch (Exception e)
-        {
+        } catch (IOException e) {
+        LOGGER.trace(e);
+        } catch (Exception e) {
             if(session.getTransaction() != null)
             {
                 session.getTransaction().rollback();
@@ -191,7 +184,7 @@ public class ArticlesApi {
 
             session.getTransaction().commit();
 
-            if (!article.getStatus().equals("published") && !article.getCreatedBy().getUsername().equals(user.getUsername()))
+            if (!"published".equals(article.getStatus()) && !article.getCreatedBy().getUsername().equals(user.getUsername()))
             {
                 return new ResponseEntity<>(HttpStatus.FORBIDDEN);
             }
diff --git a/src/main/java/org/hbp/mip/controllers/ExperimentApi.java b/src/main/java/org/hbp/mip/controllers/ExperimentApi.java
index 868b7ed860f08eb63d1bb88a572355d00f30c486..5adbdaa35ffd233717ea958b54e6a3cdfc7f78a2 100644
--- a/src/main/java/org/hbp/mip/controllers/ExperimentApi.java
+++ b/src/main/java/org/hbp/mip/controllers/ExperimentApi.java
@@ -2,23 +2,28 @@ package org.hbp.mip.controllers;
 
 import com.google.gson.*;
 import io.swagger.annotations.*;
+import org.apache.log4j.Logger;
 import org.hbp.mip.MIPApplication;
-import org.hbp.mip.model.*;
+import org.hbp.mip.model.Experiment;
+import org.hbp.mip.model.Model;
+import org.hbp.mip.model.User;
 import org.hbp.mip.utils.HTTPUtil;
 import org.hbp.mip.utils.HibernateUtil;
+import org.hbp.mip.utils.JSONUtil;
 import org.hibernate.Query;
 import org.hibernate.Session;
 import org.hibernate.Transaction;
-import org.hibernate.exception.DataException;
 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.*;
 
-import java.io.*;
-import java.net.*;
-import java.util.Date;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
@@ -34,6 +39,8 @@ 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 Logger LOGGER = Logger.getLogger(ExperimentApi.class);
+
     private static final String EXAREME_ALGO_JSON_FILE="data/exareme_algorithms.json";
 
     private static final Gson gson = new GsonBuilder()
@@ -42,6 +49,8 @@ public class ExperimentApi {
             .excludeFieldsWithoutExposeAnnotation()
             .create();
 
+    private static final String EXAREME_LR_ALGO = "WP_LINEAR_REGRESSION";
+
     @Value("#{'${workflow.experimentUrl:http://dockerhost:8087/experiment}'}")
     private String experimentUrl;
 
@@ -54,72 +63,6 @@ public class ExperimentApi {
     @Autowired
     MIPApplication mipApplication;
 
-    private void sendPost(Experiment experiment) throws MalformedURLException {
-        URL obj = new URL(experimentUrl);
-
-        // this runs in the background. For future optimization: use a thread pool
-        new Thread() {
-            public void run() {
-                try {
-                    HttpURLConnection con = (HttpURLConnection) obj.openConnection();
-
-                    String query = experiment.computeQuery();
-                    System.out.println("Running experiment: " + query);
-
-                    // create query
-                    try {
-                        con.setRequestMethod("POST");
-                    } catch (ProtocolException pe) {} // ignore; won't happen
-                    con.addRequestProperty("Content-Type", "application/json");
-                    con.setRequestProperty("Content-Length", Integer.toString(query.length()));
-                    con.setFollowRedirects(true);
-                    con.setReadTimeout(3600000); // 1 hour: 60*60*1000 ms
-
-                    // write body of query
-                    con.setDoOutput(true);
-                    DataOutputStream wr = new DataOutputStream(con.getOutputStream());
-                    wr.write(query.getBytes("UTF8"));
-                    wr.flush();
-                    wr.close();
-
-                    // get response
-                    InputStream stream = con.getResponseCode() < 400 ? con.getInputStream() : con.getErrorStream();
-                    BufferedReader in = new BufferedReader(new InputStreamReader(stream));
-                    String inputLine;
-                    StringBuilder response = new StringBuilder();
-                    while ((inputLine = in.readLine()) != null) {
-                        response.append(inputLine + '\n');
-                    }
-                    in.close();
-
-                    // write to experiment
-                    experiment.setResult(response.toString().replace("\0", ""));
-                    experiment.setHasError(con.getResponseCode() >= 400);
-                    experiment.setHasServerError(con.getResponseCode() >= 500);
-
-                } catch (IOException ioe) {
-                    // write error to
-                    experiment.setHasError(true);
-                    experiment.setHasServerError(true);
-                    experiment.setResult(ioe.getMessage());
-                }
-
-                experiment.setFinished(new Date());
-
-                // finally
-                try {
-                    Session session = HibernateUtil.getSessionFactory().openSession();
-                    Transaction transaction = session.beginTransaction();
-                    session.update(experiment);
-                    transaction.commit();
-                    session.close();
-                } catch (DataException e) {
-                    throw e;
-                }
-
-            }
-        }.start();
-    }
 
     @ApiOperation(value = "Send a request to the workflow to run an experiment", response = Experiment.class)
     @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") })
@@ -149,8 +92,12 @@ public class ExperimentApi {
             transaction.commit();
 
         } catch (Exception e) {
-            transaction.rollback();
-            e.printStackTrace();
+            if(transaction != null)
+            {
+                transaction.rollback();
+            }
+            LOGGER.trace(e);
+            LOGGER.warn("Cannot create experiment to run ! This is probably caused by a bad request !");
             // 400 here probably
             return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
         }
@@ -158,125 +105,28 @@ public class ExperimentApi {
         try {
             if(isExaremeAlgo(experiment))
             {
-                sendExaremePost(experiment);
+                sendExaremeExperiment(experiment);
             }
             else
             {
-                sendPost(experiment);
+                sendExperiment(experiment);
             }
-        } catch (MalformedURLException mue) {} // ignore
+        } catch (MalformedURLException mue) { LOGGER.trace(mue.getMessage()); } // 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)
     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) {
+            LOGGER.trace(iae);
+            LOGGER.warn("An invalid Experiment UUID was received !");
             return ResponseEntity.badRequest().body("Invalid Experiment UUID");
         }
 
@@ -291,7 +141,10 @@ public class ExperimentApi {
             session.getTransaction().commit();
         } catch (Exception e) {
             // 404 here probably
-            session.getTransaction().rollback();
+            if(session.getTransaction() != null)
+            {
+                session.getTransaction().rollback();
+            }
             throw e;
         }
 
@@ -312,6 +165,8 @@ public class ExperimentApi {
         try {
             experimentUuid = UUID.fromString(uuid);
         } catch (IllegalArgumentException iae) {
+            LOGGER.trace(iae);
+            LOGGER.warn("An invalid Experiment UUID was received !");
             return ResponseEntity.badRequest().body("Invalid Experiment UUID");
         }
 
@@ -333,56 +188,16 @@ public class ExperimentApi {
             transaction.commit();
         } catch (Exception e) {
             // 404 here probably
-            transaction.rollback();
-            throw e;
-        }
-
-        if (experiment == null) {
-            return new ResponseEntity<>("Not found", HttpStatus.NOT_FOUND);
-        }
-        return new ResponseEntity<>(gson.toJson(experiment), HttpStatus.OK);
-    }
-
-    public ResponseEntity<String> doMarkExperimentAsShared(String uuid, boolean shared) {
-
-        Experiment experiment;
-        UUID experimentUuid;
-        User user = mipApplication.getUser();
-        try {
-            experimentUuid = UUID.fromString(uuid);
-        } catch (IllegalArgumentException iae) {
-            return ResponseEntity.badRequest().body("Invalid Experiment UUID");
-        }
-
-        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
-        Transaction transaction = null;
-        try {
-            transaction = session.beginTransaction();
-
-            Query hibernateQuery = session.createQuery("from Experiment as experiment where experiment.uuid = :uuid");
-            hibernateQuery.setParameter("uuid", experimentUuid);
-            experiment = (Experiment) hibernateQuery.uniqueResult();
-
-            if (!experiment.getCreatedBy().getUsername().equals(user.getUsername()))
-                return new ResponseEntity<>("You're not the owner of this experiment", HttpStatus.BAD_REQUEST);
-
-            experiment.setShared(shared);
-            session.update(experiment);
-
-            transaction.commit();
-        } catch (Exception e) {
-            // 404 here probably
-            transaction.rollback();
+            if(transaction != null)
+            {
+                transaction.rollback();
+            }
             throw e;
         }
 
-        if (experiment == null) {
-            return new ResponseEntity<>("Not found", HttpStatus.NOT_FOUND);
-        }
         return new ResponseEntity<>(gson.toJson(experiment), HttpStatus.OK);
     }
 
-
     @ApiOperation(value = "get an experiment", response = Experiment.class)
     @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") })
     @RequestMapping(value = "/{uuid}/markAsShared", method = RequestMethod.GET)
@@ -397,7 +212,55 @@ public class ExperimentApi {
         return doMarkExperimentAsShared(uuid, false);
     }
 
-    public ResponseEntity<String> doListExperiments(
+    @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List")
+    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") })
+    @RequestMapping(value = "/mine", method = RequestMethod.GET, params = {"maxResultCount"})
+    public ResponseEntity<String> listExperiments(
+            @ApiParam(value = "maxResultCount", required = false) @RequestParam int maxResultCount
+    ) {
+        return doListExperiments(true, maxResultCount, null);
+    }
+
+    @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List")
+    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") })
+    @RequestMapping(method = RequestMethod.GET, params = {"slug", "maxResultCount"})
+    public ResponseEntity<String> listExperiments(
+            @ApiParam(value = "slug", required = false) @RequestParam("slug") String modelSlug,
+            @ApiParam(value = "maxResultCount", required = false) @RequestParam("maxResultCount") int maxResultCount
+    ) {
+
+        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, maxResultCount, modelSlug);
+    }
+
+    @ApiOperation(value = "List available methods and validations", response = String.class)
+    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") })
+    @RequestMapping(path = "/methods", method = RequestMethod.GET)
+    public ResponseEntity<String> listAvailableMethodsAndValidations() throws IOException {
+
+        StringBuilder response = new StringBuilder();
+
+        int code = HTTPUtil.sendGet(listMethodsUrl, response);
+        if (code < 200 || code > 299) {
+            return new ResponseEntity<>(response.toString(), HttpStatus.valueOf(code));
+        }
+
+        JsonObject catalog = new JsonParser().parse(response.toString()).getAsJsonObject();
+
+        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();
+
+        catalog.get("algorithms").getAsJsonArray().add(exaremeAlgo);
+
+        return new ResponseEntity<>(new Gson().toJson(catalog), HttpStatus.valueOf(code));
+    }
+
+    private ResponseEntity<String> doListExperiments(
             boolean mine,
             int maxResultCount,
             String modelSlug
@@ -415,10 +278,11 @@ public class ExperimentApi {
 
             baseQuery += mine ? "e.createdBy = :user" : "(e.createdBy = :user OR e.shared is true)";
 
-            if (modelSlug == null || modelSlug.equals("")) {
+            if (modelSlug == null || "".equals(modelSlug)) {
                 hibernateQuery = session.createQuery(baseQuery);
             } else {
-                hibernateQuery = session.createQuery(baseQuery + " AND e.model.slug = :slug");
+                baseQuery += " AND e.model.slug = :slug";
+                hibernateQuery = session.createQuery(baseQuery);
                 hibernateQuery.setParameter("slug", modelSlug);
             }
             hibernateQuery.setParameter("user", user);
@@ -440,59 +304,125 @@ public class ExperimentApi {
             }
         } catch (Exception e) {
             // 404 here probably
+            LOGGER.trace(e);
             throw e;
         } finally {
-            session.getTransaction().rollback();
+            if(session.getTransaction() != null)
+            {
+                session.getTransaction().rollback();
+            }
         }
 
         return new ResponseEntity<>(gson.toJson(experiments), HttpStatus.OK);
     }
 
-    @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") })
-    @RequestMapping(value = "/mine", method = RequestMethod.GET, params = {"maxResultCount"})
-    public ResponseEntity<String> listExperiments(
-        @ApiParam(value = "maxResultCount", required = false) @RequestParam int maxResultCount
-    ) {
-        return doListExperiments(true, maxResultCount, null);
-    }
+    private ResponseEntity<String> doMarkExperimentAsShared(String uuid, boolean shared) {
+        Experiment experiment;
+        UUID experimentUuid;
+        User user = mipApplication.getUser();
+        try {
+            experimentUuid = UUID.fromString(uuid);
+        } catch (IllegalArgumentException iae) {
+            LOGGER.trace(iae);
+            LOGGER.warn("An invalid Experiment UUID was received !");
+            return ResponseEntity.badRequest().body("Invalid Experiment UUID");
+        }
 
-    @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List")
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") })
-    @RequestMapping(method = RequestMethod.GET, params = {"slug", "maxResultCount"})
-    public ResponseEntity<String> listExperiments(
-        @ApiParam(value = "slug", required = false) @RequestParam("slug") String modelSlug,
-        @ApiParam(value = "maxResultCount", required = false) @RequestParam("maxResultCount") int maxResultCount
-    ) {
+        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+        Transaction transaction = null;
+        try {
+            transaction = session.beginTransaction();
 
-        if (maxResultCount <= 0 && (modelSlug == null || modelSlug.equals(""))) {
-            return new ResponseEntity<>("You must provide at least a slug or a limit of result", HttpStatus.BAD_REQUEST);
+            Query hibernateQuery = session.createQuery("from Experiment as experiment where experiment.uuid = :uuid");
+            hibernateQuery.setParameter("uuid", experimentUuid);
+            experiment = (Experiment) hibernateQuery.uniqueResult();
+
+            if (!experiment.getCreatedBy().getUsername().equals(user.getUsername()))
+                return new ResponseEntity<>("You're not the owner of this experiment", HttpStatus.BAD_REQUEST);
+
+            experiment.setShared(shared);
+            session.update(experiment);
+
+            transaction.commit();
+        } catch (Exception e) {
+            // 404 here probably
+            if(transaction != null)
+            {
+                transaction.rollback();
+            }
+            throw e;
         }
 
-        return doListExperiments(false, maxResultCount, modelSlug);
+        return new ResponseEntity<>(gson.toJson(experiment), HttpStatus.OK);
     }
 
-    @ApiOperation(value = "List available methods and validations", response = String.class)
-    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success") })
-    @RequestMapping(path = "/methods", method = RequestMethod.GET)
-    public ResponseEntity<String> listAvailableMethodsAndValidations() throws Exception {
+    private void sendExperiment(Experiment experiment) throws MalformedURLException {
+        // this runs in the background. For future optimization: use a thread pool
+        new Thread() {
+            @Override
+            public void run() {
+                    String url = experimentUrl;
+                    String query = experiment.computeQuery();
 
-        StringBuilder response = new StringBuilder();
+                    // Results are stored in the experiment object
+                try {
+                    executeExperiment(url, query, experiment);
+                } catch (IOException e) {
+                    LOGGER.trace(e);
+                    LOGGER.warn("Experiment failed to run properly !");
+                    setExperimentError(e, experiment);
+                }
 
-        int code = HTTPUtil.sendGet(listMethodsUrl, response);
-        if (code < 200 || code > 299) {
-            return new ResponseEntity<>(response.toString(), HttpStatus.valueOf(code));
-        }
+                experiment.finish();
+            }
+        }.start();
+    }
 
-        JsonObject catalog = new JsonParser().parse(response.toString()).getAsJsonObject();
+    private void sendExaremeExperiment(Experiment experiment) {
+        // this runs in the background. For future optimization: use a thread pool
+        new Thread() {
+            @Override
+            public void run() {
+                String query = experiment.computeExaremeQuery();
+                String url = miningExaremeQueryUrl + "/" + EXAREME_LR_ALGO;
 
-        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();
+                // Results are stored in the experiment object
+                try {
+                    executeExperiment(url, query, experiment);
+                } catch (IOException e) {
+                    LOGGER.trace(e);
+                    LOGGER.warn("Exareme experiment failed to run properly !");
+                    setExperimentError(e, experiment);
+                }
 
-        catalog.get("algorithms").getAsJsonArray().add(exaremeAlgo);
+                if(!JSONUtil.isJSONValid(experiment.getResult()))
+                    {
+                        experiment.setResult("Unsupported variables !");
+                    }
 
-        return new ResponseEntity<>(new Gson().toJson(catalog), HttpStatus.valueOf(code));
+                experiment.finish();
+            }
+        }.start();
+    }
+
+    private static void executeExperiment(String url, String query, Experiment experiment) throws IOException {
+        StringBuilder results = new StringBuilder();
+        int code = HTTPUtil.sendPost(url, query, results);
+        experiment.setResult(results.toString().replace("\0", ""));
+        experiment.setHasError(code >= 400);
+        experiment.setHasServerError(code >= 500);
     }
+
+    private static void setExperimentError(IOException e, Experiment experiment) {
+        experiment.setHasError(true);
+        experiment.setHasServerError(true);
+        experiment.setResult(e.getMessage());
+    }
+
+    private static boolean isExaremeAlgo(Experiment experiment)  {
+        JsonArray algorithms = new JsonParser().parse(experiment.getAlgorithms()).getAsJsonArray();
+        String algoCode = algorithms.get(0).getAsJsonObject().get("code").getAsString();
+        return "glm_exareme".equals(algoCode);
+    }
+
 }
diff --git a/src/main/java/org/hbp/mip/controllers/ModelsApi.java b/src/main/java/org/hbp/mip/controllers/ModelsApi.java
index 7041bbe76420928f5a0785f4301fb5fb300f681f..21b102e1858a508f92bff344a4aded93006c10f2 100644
--- a/src/main/java/org/hbp/mip/controllers/ModelsApi.java
+++ b/src/main/java/org/hbp/mip/controllers/ModelsApi.java
@@ -6,6 +6,7 @@ package org.hbp.mip.controllers;
 
 import com.github.slugify.Slugify;
 import io.swagger.annotations.*;
+import org.apache.log4j.Logger;
 import org.hbp.mip.MIPApplication;
 import org.hbp.mip.model.*;
 import org.hbp.mip.utils.CSVUtil;
@@ -28,6 +29,8 @@ 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 ModelsApi {
 
+    private static final Logger LOGGER = Logger.getLogger(ModelsApi.class);
+
     @Autowired
     MIPApplication mipApplication;
 
@@ -57,11 +60,6 @@ public class ModelsApi {
         else
         {
             queryString += " AND (m.valid=true or u.username= :username)";
-            if(team != null && team)
-            {
-                // TODO: decide if this is needed
-                //queryString += " AND u.team= :team";
-            }
         }
 
         queryString += " ORDER BY m.createdAt DESC";
@@ -92,7 +90,7 @@ public class ModelsApi {
         }
 
         for(Model model:models){
-            String ds_code = model.getDataset().getCode();
+            String dsCode = model.getDataset().getCode();
 
             session = HibernateUtil.getSessionFactory().getCurrentSession();
             Dataset dataset = null;
@@ -100,7 +98,7 @@ public class ModelsApi {
                 session.beginTransaction();
                 dataset = (Dataset) session
                         .createQuery("from Dataset where code= :code")
-                        .setString("code", ds_code)
+                        .setString("code", dsCode)
                         .uniqueResult();
                 session.getTransaction().commit();
             } catch (Exception e)
@@ -160,13 +158,7 @@ public class ModelsApi {
                 }
             } while(count > 0);
 
-            Slugify slg = null;
-            try {
-                slg = new Slugify();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-            String slug = slg.slugify(model.getTitle());
+            String slug = new Slugify().slugify(model.getTitle());
 
             i = 0;
             do {
@@ -192,6 +184,8 @@ public class ModelsApi {
 
             session.save(model);
             session.getTransaction().commit();
+        } catch (IOException e) {
+            LOGGER.trace(e);
         } catch (Exception e)
         {
             if(session.getTransaction() != null)
@@ -215,7 +209,6 @@ public class ModelsApi {
 
         Session session = HibernateUtil.getSessionFactory().getCurrentSession();
         Model model = null;
-        Query query;
 
         try {
             session.beginTransaction();
@@ -260,45 +253,48 @@ public class ModelsApi {
                 }
             }
 
-            List<Variable> vars = new LinkedList<>();
-            for (Variable var : q.getVariables()) {
-                Variable v = new Variable();
-                v.setCode(var.getCode());
-                vars.add(v);
-            }
+            if(q != null) {
 
-            List<Variable> covs = new LinkedList<>();
-            for (Variable cov : q.getCovariables()) {
-                Variable v = new Variable();
-                v.setCode(cov.getCode());
-                covs.add(v);
-            }
+                List<Variable> vars = new LinkedList<>();
+                for (Variable var : q.getVariables()) {
+                    Variable v = new Variable();
+                    v.setCode(var.getCode());
+                    vars.add(v);
+                }
 
-            List<Variable> grps = new LinkedList<>();
-            for (Variable grp : q.getGrouping()) {
-                Variable v = new Variable();
-                v.setCode(grp.getCode());
-                grps.add(v);
-            }
+                List<Variable> covs = new LinkedList<>();
+                for (Variable cov : q.getCovariables()) {
+                    Variable v = new Variable();
+                    v.setCode(cov.getCode());
+                    covs.add(v);
+                }
 
-            List<Filter> fltrs = new LinkedList<>();
-            for (Filter fltr : q.getFilters()) {
-                Filter f = new Filter();
-                f.setId(fltr.getId());
-                f.setOperator(fltr.getOperator());
-                f.setValues(fltr.getValues());
-                f.setVariable(fltr.getVariable());
-                fltrs.add(f);
-            }
+                List<Variable> grps = new LinkedList<>();
+                for (Variable grp : q.getGrouping()) {
+                    Variable v = new Variable();
+                    v.setCode(grp.getCode());
+                    grps.add(v);
+                }
 
-            org.hbp.mip.model.Query myQuery = new org.hbp.mip.model.Query();
-            myQuery.setId(q.getId());
-            myQuery.setVariables(vars);
-            myQuery.setCovariables(covs);
-            myQuery.setGrouping(grps);
-            myQuery.setFilters(fltrs);
+                List<Filter> fltrs = new LinkedList<>();
+                for (Filter fltr : q.getFilters()) {
+                    Filter f = new Filter();
+                    f.setId(fltr.getId());
+                    f.setOperator(fltr.getOperator());
+                    f.setValues(fltr.getValues());
+                    f.setVariable(fltr.getVariable());
+                    fltrs.add(f);
+                }
 
-            model.setQuery(myQuery);
+                org.hbp.mip.model.Query myQuery = new org.hbp.mip.model.Query();
+                myQuery.setId(q.getId());
+                myQuery.setVariables(vars);
+                myQuery.setCovariables(covs);
+                myQuery.setGrouping(grps);
+                myQuery.setFilters(fltrs);
+
+                model.setQuery(myQuery);
+            }
 
             Dataset ds = CSVUtil.parseValues(DATA_FILE, model.getQuery());
             model.setDataset(ds);
@@ -380,41 +376,7 @@ public class ModelsApi {
         return new ResponseEntity<>(HttpStatus.NO_CONTENT);
     }
 
-    @ApiOperation(value = "Copy a model", response = Model.class)
-    @ApiResponses(value = { @ApiResponse(code = 201, message = "Model copied"), @ApiResponse(code = 404, message = "Not found") })
-    @RequestMapping(value = "/{slug}/copies", method = RequestMethod.POST)
-    public ResponseEntity<Model> copyAModel(
-            @ApiParam(value = "slug", required = true) @PathVariable("slug") String slug,
-            @RequestBody @ApiParam(value = "Model to update", required = true) Model model
-    )  {
-
-        User user = mipApplication.getUser();
-
-        String originalSlug = model.getSlug();
-        String copySlug;
-        do {
-            copySlug = originalSlug+" copy_"+randomStr(20);
-        } while (getAModel(copySlug) == null);
-        model.setSlug(copySlug);
-
-        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
-        try{
-            session.beginTransaction();
-            session.save(model);
-            session.getTransaction().commit();
-        } catch (Exception e)
-        {
-            if(session.getTransaction() != null)
-            {
-                session.getTransaction().rollback();
-                throw e;
-            }
-        }
-
-        return new ResponseEntity<>(HttpStatus.CREATED).ok(model);
-    }
-
-    private String randomStr(int length) {
+    private static String randomStr(int length) {
         char[] chars = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray();
         StringBuilder sb = new StringBuilder();
         Random random = new Random();
diff --git a/src/main/java/org/hbp/mip/model/App.java b/src/main/java/org/hbp/mip/model/App.java
index 38450ade304847675a0f02966eb79d0fef9e54b7..c328c36ca8330b538d66028cd085407959a4b5ca 100644
--- a/src/main/java/org/hbp/mip/model/App.java
+++ b/src/main/java/org/hbp/mip/model/App.java
@@ -44,6 +44,9 @@ public class App {
 
 
     public App() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/Article.java b/src/main/java/org/hbp/mip/model/Article.java
index 49e0fc8171d7d4ea26401312d708cc77c5689b34..b7821db0ca22566bb2aff06a847d566fff0a40e7 100644
--- a/src/main/java/org/hbp/mip/model/Article.java
+++ b/src/main/java/org/hbp/mip/model/Article.java
@@ -26,12 +26,12 @@ public class Article {
 
     @NotNull
     @Size(min = 1, max = 255)
-    private String title = null;
+    private String title;
 
     private String status = null;
 
-    @Column(columnDefinition = "text")
-    private String _abstract = null;
+    @Column(columnDefinition = "text", name = "abstract")
+    private String abstractText = null;
 
     @Column(columnDefinition = "text")
     private String content = null;
@@ -55,6 +55,10 @@ public class Article {
 
 
     public Article() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
+        title = "";
     }
 
 
@@ -87,11 +91,11 @@ public class Article {
 
     @JsonProperty("abstract")
     public String getAbstract() {
-        return _abstract;
+        return abstractText;
     }
 
-    public void setAbstract(String _abstract) {
-        this._abstract = _abstract;
+    public void setAbstract(String abstractText) {
+        this.abstractText = abstractText;
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/Config.java b/src/main/java/org/hbp/mip/model/Config.java
index 555d7cece4fc591d29792f9ffdcbb5e30a67c1a7..08bed89798cda8f97015ae62717a7a2300b7126d 100644
--- a/src/main/java/org/hbp/mip/model/Config.java
+++ b/src/main/java/org/hbp/mip/model/Config.java
@@ -41,6 +41,9 @@ public class Config {
 
 
     public Config() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/Dataset.java b/src/main/java/org/hbp/mip/model/Dataset.java
index 61b5a5316cebdd78d10b4bb63045bffeb4541c35..023cecf06d6738dc31f7cfde5edb2dccf2dbd09f 100644
--- a/src/main/java/org/hbp/mip/model/Dataset.java
+++ b/src/main/java/org/hbp/mip/model/Dataset.java
@@ -39,6 +39,9 @@ public class Dataset {
 
 
     public Dataset() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/Experiment.java b/src/main/java/org/hbp/mip/model/Experiment.java
index a569c9719231a54e50f66f4d1b71a7421b1fdd32..d87949be04dc8da5d7080d4e20ace726e22ff267 100644
--- a/src/main/java/org/hbp/mip/model/Experiment.java
+++ b/src/main/java/org/hbp/mip/model/Experiment.java
@@ -5,12 +5,19 @@ import com.google.gson.GsonBuilder;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
 import com.google.gson.annotations.Expose;
+import org.apache.log4j.Logger;
+import org.hbp.mip.utils.HibernateUtil;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
 import org.hibernate.annotations.*;
+import org.hibernate.exception.DataException;
 
 import javax.persistence.*;
 import javax.persistence.Entity;
 import javax.persistence.Table;
 import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.UUID;
 
 /**
@@ -20,6 +27,8 @@ import java.util.UUID;
 @Table(name = "`experiment`")
 public class Experiment {
 
+    private static final Logger LOGGER = Logger.getLogger(Experiment.class);
+
     private static final Gson gson = new GsonBuilder()
             .serializeNulls()
             .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
@@ -78,6 +87,9 @@ public class Experiment {
     private boolean resultsViewed = false;
 
     public Experiment() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
     public String computeQuery() {
@@ -91,6 +103,63 @@ public class Experiment {
         return outgoingQuery.toString();
     }
 
+    public String computeExaremeQuery() {
+        List<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);
+
+        return new Gson().toJson(queryElements);
+    }
+
+    public void finish() {
+        this.setFinished(new Date());
+
+        try {
+            Session session = HibernateUtil.getSessionFactory().openSession();
+            Transaction transaction = session.beginTransaction();
+            session.update(this);
+            transaction.commit();
+            session.close();
+        } catch (DataException e) {
+            LOGGER.trace(e);
+            throw e;
+        }
+    }
+
     public String getValidations() {
         return validations;
     }
diff --git a/src/main/java/org/hbp/mip/model/Filter.java b/src/main/java/org/hbp/mip/model/Filter.java
index c85bc140a47ab0bcef46c795ad9160a60edac1c1..27af1d69c9b26fd1475d1395f1e3a6432c86bf81 100644
--- a/src/main/java/org/hbp/mip/model/Filter.java
+++ b/src/main/java/org/hbp/mip/model/Filter.java
@@ -34,6 +34,9 @@ public class Filter {
 
 
     public Filter() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/GeneralStats.java b/src/main/java/org/hbp/mip/model/GeneralStats.java
index 94b3b62b28b5dea3b2d727c66042272401827858..b9366c013e3e2913a220e598cfe6c3264d231b6a 100644
--- a/src/main/java/org/hbp/mip/model/GeneralStats.java
+++ b/src/main/java/org/hbp/mip/model/GeneralStats.java
@@ -17,6 +17,9 @@ public class GeneralStats {
 
 
     public GeneralStats() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/Group.java b/src/main/java/org/hbp/mip/model/Group.java
index 066f3f94905128fdb961b1d473b0d878948814ad..32cf44f662107d113c214901ee77113d6e434d85 100644
--- a/src/main/java/org/hbp/mip/model/Group.java
+++ b/src/main/java/org/hbp/mip/model/Group.java
@@ -32,6 +32,9 @@ public class Group {
 
 
     public Group() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
@@ -70,15 +73,4 @@ public class Group {
         this.groups = groups;
     }
 
-
-    public Group clone()
-    {
-        Group g = new Group();
-        g.setCode(this.getCode());
-        g.setLabel(this.getLabel());
-        g.setParent(this.getParent());
-        g.setGroups(this.getGroups());
-        return g;
-    }
-
 }
diff --git a/src/main/java/org/hbp/mip/model/Model.java b/src/main/java/org/hbp/mip/model/Model.java
index 774b8e0cf75833d659a06a75a637c3d7e84b19cb..fb871152fe562a4fab41a0b7def52123cd26394b 100644
--- a/src/main/java/org/hbp/mip/model/Model.java
+++ b/src/main/java/org/hbp/mip/model/Model.java
@@ -59,6 +59,9 @@ public class Model {
 
 
     public Model() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/Query.java b/src/main/java/org/hbp/mip/model/Query.java
index ebcce263bb75713c521f0e34b25f1264038b3724..fddb0c7a7c68ffb5a79c733032d9a36c4564008b 100644
--- a/src/main/java/org/hbp/mip/model/Query.java
+++ b/src/main/java/org/hbp/mip/model/Query.java
@@ -52,6 +52,9 @@ public class Query {
 
 
     public Query() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/Tag.java b/src/main/java/org/hbp/mip/model/Tag.java
index e4c34e30bb9ca12ee306455e755018033ab928f7..6619bd75f57a66dfe66446e4f710b4d515663199 100644
--- a/src/main/java/org/hbp/mip/model/Tag.java
+++ b/src/main/java/org/hbp/mip/model/Tag.java
@@ -22,6 +22,9 @@ public class Tag {
 
 
     public Tag() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/User.java b/src/main/java/org/hbp/mip/model/User.java
index f013859e96b02d12adeada9cbadf250b4429d9e9..7d12a47f5265f9f4aebd58463b7dcde0c93140b1 100644
--- a/src/main/java/org/hbp/mip/model/User.java
+++ b/src/main/java/org/hbp/mip/model/User.java
@@ -88,6 +88,9 @@ public class User {
 
 
     public User() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
@@ -133,7 +136,7 @@ public class User {
         p = Pattern.compile("title=([\\w ]+)");
         m = p.matcher(userInfo);
         if (m.find()) {
-            if (m.group(1).equals("Mr")) {
+            if ("Mr".equals(m.group(1))) {
                 this.gender = "Male";
             } else {
                 this.gender = "Female";
diff --git a/src/main/java/org/hbp/mip/model/Variable.java b/src/main/java/org/hbp/mip/model/Variable.java
index e651105c6f525d13345daf6a6b7f04b56d4f4fbf..2bc6a37c8637930c0ea1466633250bfb467ac9b2 100644
--- a/src/main/java/org/hbp/mip/model/Variable.java
+++ b/src/main/java/org/hbp/mip/model/Variable.java
@@ -59,6 +59,9 @@ public class Variable {
 
 
     public Variable() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/model/Vote.java b/src/main/java/org/hbp/mip/model/Vote.java
index 91ce0b055d21cfd9dd65a9066d34dea1f9aa93db..b9981a8e92a96092b8c0fa8e4e833f70846dedfd 100644
--- a/src/main/java/org/hbp/mip/model/Vote.java
+++ b/src/main/java/org/hbp/mip/model/Vote.java
@@ -33,6 +33,9 @@ public class Vote {
 
 
     public Vote() {
+        /*
+        *  Empty constructor is needed by Hibernate
+        */
     }
 
 
diff --git a/src/main/java/org/hbp/mip/utils/CORSFilter.java b/src/main/java/org/hbp/mip/utils/CORSFilter.java
index 30bea8de4bc436b3a9aa685424e89d7f6f7c92ab..9feb2895dd7af50acfcb61e0e35810e3a71d2ebe 100644
--- a/src/main/java/org/hbp/mip/utils/CORSFilter.java
+++ b/src/main/java/org/hbp/mip/utils/CORSFilter.java
@@ -9,6 +9,7 @@ import java.io.IOException;
  */
 public class CORSFilter implements Filter {
 
+    @Override
     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
         HttpServletResponse response = (HttpServletResponse) res;
         response.setHeader("Access-Control-Allow-Origin", "*");
@@ -18,7 +19,13 @@ public class CORSFilter implements Filter {
         chain.doFilter(req, res);
     }
 
-    public void init(FilterConfig filterConfig) {}
+    @Override
+    public void init(FilterConfig filterConfig) {
+        /* Nothing to do */
+    }
 
-    public void destroy() {}
+    @Override
+    public void destroy() {
+        /* Nothing to do */
+    }
 }
diff --git a/src/main/java/org/hbp/mip/utils/CSVUtil.java b/src/main/java/org/hbp/mip/utils/CSVUtil.java
index 4ac7fd269d736166e12daf3fdd5716ad115a398a..b3f6850be795983ec8728624da7dfcf733369dfe 100644
--- a/src/main/java/org/hbp/mip/utils/CSVUtil.java
+++ b/src/main/java/org/hbp/mip/utils/CSVUtil.java
@@ -1,5 +1,6 @@
 package org.hbp.mip.utils;
 
+import org.apache.log4j.Logger;
 import org.hbp.mip.model.Dataset;
 import org.hbp.mip.model.Query;
 import org.hbp.mip.model.Variable;
@@ -19,14 +20,22 @@ import java.util.stream.Collectors;
  */
 public class CSVUtil {
 
+    private static final Logger LOGGER = Logger.getLogger(CSVUtil.class);
+
     private static final String SEPARATOR = ",";
 
+    private CSVUtil()
+    {
+        /* Hide implicit public constructor */
+        throw new IllegalAccessError("CSVUtil class");
+    }
+
     public static Dataset parseValues(String filename, Query query)
     {
         List<String[]> rows = getRows(filename);
 
         Dataset result = new Dataset();
-        String code = GenerateDSCode(query);
+        String code = generateDSCode(query);
         Date date = new Date();
         List<String> header = new LinkedList<>();
         List<String> grouping = new LinkedList<>();
@@ -140,7 +149,7 @@ public class CSVUtil {
                 data.put(c, ll);
             }
         } catch (IOException e) {
-            e.printStackTrace();
+            LOGGER.trace(e);
         }
         result.setCode(code);
         result.setDate(date);
@@ -155,7 +164,7 @@ public class CSVUtil {
     private static List<String[]> getRows(String filename) {
         List<String[]> rows = new LinkedList<>();
         try {
-            InputStream is = Dataset.class.getClassLoader().getResourceAsStream(filename);
+            InputStream is = CSVUtil.class.getClassLoader().getResourceAsStream(filename);
             InputStreamReader isr = new InputStreamReader(is);
             BufferedReader br = new BufferedReader(isr);
             String[] firstRow = br.readLine().split(SEPARATOR, -1);  // 1st row -> headers
@@ -167,7 +176,8 @@ public class CSVUtil {
             isr.close();
             is.close();
         } catch (IOException e) {
-            e.printStackTrace();
+            LOGGER.trace(e);
+            LOGGER.warn("A problem occured while trying to read a CSV file !");
         }
 
         return rows;
@@ -181,7 +191,7 @@ public class CSVUtil {
         return -1;
     }
 
-    private static String GenerateDSCode(Query query) {
+    private static String generateDSCode(Query query) {
         String prefix = "DS";
         String queryStr = Integer.toString(query.hashCode());
         String memId;
diff --git a/src/main/java/org/hbp/mip/utils/HTTPUtil.java b/src/main/java/org/hbp/mip/utils/HTTPUtil.java
index 92beffaf45e7f48e8c71d51e36414fb78ce827ae..0a524bb99d7fa8403af05fb94fdfec0c1e9d9a25 100644
--- a/src/main/java/org/hbp/mip/utils/HTTPUtil.java
+++ b/src/main/java/org/hbp/mip/utils/HTTPUtil.java
@@ -2,6 +2,7 @@ package org.hbp.mip.utils;
 
 import java.io.BufferedReader;
 import java.io.DataOutputStream;
+import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.URL;
@@ -11,20 +12,26 @@ import java.net.URL;
  */
 public class HTTPUtil {
 
-    public static int sendGet(String url, StringBuilder resp) throws Exception {
+    private HTTPUtil()
+    {
+        /* Hide implicit public constructor */
+        throw new IllegalAccessError("HTTPUtil class");
+    }
+
+    public static int sendGet(String url, StringBuilder resp) throws IOException {
         return sendHTTP(url, "", resp, "GET");
     }
 
-    public static int sendPost(String url, String query, StringBuilder resp) throws Exception {
+    public static int sendPost(String url, String query, StringBuilder resp) throws IOException {
         return sendHTTP(url, query, resp, "POST");
     }
 
-    public static int sendHTTP(String url, String query, StringBuilder resp, String httpVerb) throws Exception {
+    public static int sendHTTP(String url, String query, StringBuilder resp, String httpVerb) throws IOException {
 
         URL obj = new URL(url);
         HttpURLConnection con = (HttpURLConnection) obj.openConnection();
 
-        if(!httpVerb.equals("GET")) {
+        if(!"GET".equals(httpVerb)) {
             con.setRequestMethod(httpVerb);
             if(query != null && query.length() > 0)
             {
diff --git a/src/main/java/org/hbp/mip/utils/HibernateUtil.java b/src/main/java/org/hbp/mip/utils/HibernateUtil.java
index 3048e20b8f338a7ce22d047f9701ac89176d98b8..87cde9618993e4070518b70d2bf6e4d058d54760 100644
--- a/src/main/java/org/hbp/mip/utils/HibernateUtil.java
+++ b/src/main/java/org/hbp/mip/utils/HibernateUtil.java
@@ -4,15 +4,25 @@
 
 package org.hbp.mip.utils;
 
+import org.apache.log4j.Logger;
 import org.hibernate.SessionFactory;
 import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
 import org.hibernate.cfg.Configuration;
 import org.hibernate.service.ServiceRegistry;
 
 public class HibernateUtil {
+
+    private static final Logger LOGGER = Logger.getLogger(CSVUtil.class);
+
     private static ServiceRegistry serviceRegistry;
+
     private static SessionFactory sessionFactory = buildSessionFactory();
 
+    private HibernateUtil() {
+        /* Hide implicit public constructor */
+        throw new IllegalAccessError("HibernateUtil class");
+    }
+
     private static SessionFactory buildSessionFactory() {
         try {
             Configuration configuration = new Configuration();
@@ -21,8 +31,8 @@ public class HibernateUtil {
                     configuration.getProperties()).build();
             sessionFactory = configuration.buildSessionFactory(serviceRegistry);
             return sessionFactory;
-        } catch (Throwable ex) {
-            System.err.println("Initial SessionFactory creation failed." + ex);
+        } catch (RuntimeException ex) {
+            LOGGER.error("Initial SessionFactory creation failed." + ex);
             throw new ExceptionInInitializerError(ex);
         }
     }
diff --git a/src/main/java/org/hbp/mip/utils/JSONUtil.java b/src/main/java/org/hbp/mip/utils/JSONUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..938cfbb70a26974495782707d151089fad9b4d01
--- /dev/null
+++ b/src/main/java/org/hbp/mip/utils/JSONUtil.java
@@ -0,0 +1,30 @@
+package org.hbp.mip.utils;
+
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import org.apache.log4j.Logger;
+
+/**
+ * Created by mirco on 01.07.16.
+ */
+public class JSONUtil {
+
+    private static final Logger LOGGER = Logger.getLogger(JSONUtil.class);
+
+    private JSONUtil() {
+        /* Hide implicit public constructor */
+        throw new IllegalAccessError("JSONUtil class");
+    }
+
+    public static boolean isJSONValid(String test) {
+        try {
+            new JsonParser().parse(test);
+        } catch (JsonParseException jpe)
+        {
+            LOGGER.trace(jpe); // This is the normal behavior when the input string is not JSON-ified
+            return false;
+        }
+        return true;
+    }
+
+}