diff --git a/Dockerfile b/Dockerfile index 458fbc8a353233f0bda3dbff9be8b421d7fbaf5b..866c01bf47a4cff2589e9298b166d5b374fbe62b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,17 +43,16 @@ WORKDIR /home/portal ENTRYPOINT ["/run.sh"] # 8080: Web service API, health checks on http://host:8080$CONTEXT_PATH/health -# 4089: Akka cluster -EXPOSE 4089 8080 +EXPOSE 8080 HEALTHCHECK --start-period=60s CMD curl -v --silent http://localhost:8080$CONTEXT_PATH/health 2>&1 | grep UP LABEL org.label-schema.build-date=$BUILD_DATE \ org.label-schema.name="hbpmip/portal-backend" \ - org.label-schema.description="Java backend for the MIP portal" \ + org.label-schema.description="Spring backend for the MIP portal" \ org.label-schema.url="https://mip.humanbrainproject.eu" \ org.label-schema.vcs-type="git" \ - org.label-schema.vcs-url="https://github.com/LREN-CHUV/portal-backend" \ + org.label-schema.vcs-url="https://github.com/HBPMedical/portal-backend" \ org.label-schema.vcs-ref=$VCS_REF \ org.label-schema.version="$VERSION" \ org.label-schema.vendor="LREN CHUV" \ diff --git a/build.sh b/build.sh index ef4f10565705b3eb3d0fae54b60de23671f356bf..6a18d98ecec05885651675049490ca44c990ec7f 100755 --- a/build.sh +++ b/build.sh @@ -26,7 +26,7 @@ else DOCKER="sudo docker" fi -IMAGE="hbpmip/portal-backend" +IMAGE="kfilippopolitis/portal-backend" VCS_REF=$(git describe --tags --dirty) VERSION=$(git describe --tags --dirty) diff --git a/docker/README.md b/docker/README.md index 3f3437aec65ab4cc28b6236bf31a305b79572ea5..9636ff324e43b29c67fa367165370bbbf5c3a5f7 100644 --- a/docker/README.md +++ b/docker/README.md @@ -7,69 +7,33 @@ To use this image, you need a running instance of PostgreSQL and to configure the software using the following environment variables. -### DATABASES - -* PORTAL_DB_URL: JDBC URL to connect to the portal database, default value is "jdbc:postgresql://172.22.0.1:5432/portal". -* PORTAL_DB_SCHEMA: Database schema, default value is "public". -* PORTAL_DB_USER: User to use when connecting to the portal database, default value is "postgres". -* PORTAL_DB_PASSWORD: Password to use when connecting to the portal database. - -* META_DB_URL: JDBC URL to connect to the metadata database, default value is "jdbc:postgresql://172.22.0.1:5432/meta". -* META_DB_SCHEMA: Database schema, default value is "public". -* META_DB_USER: User to use when connecting to the metadata database. -* META_DB_PASSWORD: Password to use when connecting to the metadata database. - -* FEATURES_DB_URL: JDBC URL to connect to the science database, default value is "jdbc:postgresql://172.22.0.1:5433/features". -* FEATURES_DB_SCHEMA: Database schema, default value is "public". -* 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". - - -### OAUTH2 LOGIN - -* AUTHENTICATION: "0" to disable authentication or "1" to enable authentication, default value is "1". -* CLIENT_ID: required when authentication is turned on, client ID for the [OpenID server of HBP](https://services.humanbrainproject.eu/oidc/). -* CLIENT_SECRET: required when authentication is turned on, client secret for the [OpenID server of HBP](https://services.humanbrainproject.eu/oidc/). -* TOKEN_URI: default to "https://services.humanbrainproject.eu/oidc/token". -* AUTH_URI: default to "https://services.humanbrainproject.eu/oidc/authorize". -* USER_INFO_URI: default to "https://services.humanbrainproject.eu/oidc/userinfo". -* REVOKE_TOKEN_URI "https://services.humanbrainproject.eu/oidc/slo". - - -### WEB FRONTEND - -* FRONTEND_LOGIN_URL: URL to redirect to when login is required. Default to "http://frontend/services/login/hbp". -* FRONTEND_AFTER_LOGIN_URL: URL to redirect after login. Default to "http://frontend/home". -* FRONTEND_AFTER_LOGOUT_URL: URL to redirect to after logout. Default to "http://frontend/services/login/hbp". - - -### LOGGING - +### LOG LEVELS ### * LOG_LEVEL: log level for the developer added logs. Default is "ERROR". * LOG_LEVEL_FRAMEWORK: log level for all the framework logs. Default is "ERROR". -### ENDPOINTS +### AUTHENTICATION ### +* AUTHENTICATION: true for production, false for development. -* EXAREME_URL: URL to Exareme server, default value is "http://hbps2.chuv.ch:9090". -* WORKFLOW_URL: URL to Workflow server -* JWT_SECRET: "secret" -### EMBEDDED SERVER CONFIGURATION +### DATABASE CONFIGURATION ### +* PORTAL_DB_URL: JDBC URL to connect to the portal database, default value is "jdbc:postgresql://127.0.0.1:5432/portal". +* PORTAL_DB_SCHEMA: Database schema, default value is "public". +* PORTAL_DB_USER: User to use when connecting to the portal database, default value is "postgres". +* PORTAL_DB_PASSWORD: Password to use when connecting to the portal database. -* CONTEXT_PATH: context path appended to all services running in this container. Default to "/services". -* SESSION_TIMEOUT: Timeout in milliseconds for session expiration. Default to 2592000. -### PROXY +### EXTERNAL SERVICES ### +* EXAREME_URL: URL to Exareme server. Default is "http://localhost:9090" . -* HTTP_PROXY_HOST: HTTP proxy host -* HTTP_PROXY_PORT: HTTP proxy port -* HTTPS_PROXY_HOST: HTTPS proxy host -* HTTPS_PROXY_PORT: HTTPS proxy port +* GALAXY_URL: URL to Workflow server. Default is "http://localhost:8090/" . +* GALAXY_API_KEY: The api key to authorize galaxy requests. +* GALAXY_USERNAME: The username of galaxy user to be able to embed the frame. +* GALAXY_PASSWORD: The password of galaxy user. -## ERROR REPORTING -* RELEASE_STAGE: Release stage used when reporting errors to Bugsnag. Values are dev, staging, production -* DATA_CENTER_LOCATION: Location of the datacenter, used when reporting errors to Bugsnag -* CONTAINER_ORCHESTRATION: Container orchestration system used to execute the Docker containers. Values are mesos, docker-compose, kubernetes +### KEYCLOAK ### +* KEYCLOAK_AUTH_URL: Keycloak authentication URL. +* KEYCLOAK_REALM: Keycloak realm user for authentication. +* KEYCLOAK_CLIENT_ID: The keycloak client id. +* KEYCLOAK_CLIENT_SECRET: The keycloak secret to be able to authenticate. \ No newline at end of file diff --git a/docker/config/application.tmpl b/docker/config/application.tmpl index 13fc6577970ede925089895265e8a3f6b0a409ae..ae10744aa2424e7421da83da173d6e662608e843 100644 --- a/docker/config/application.tmpl +++ b/docker/config/application.tmpl @@ -1,14 +1,27 @@ # Configuration template for the portal running inside a Docker container -# See http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +### LOG LEVELS ### +logging: + level: + root: {{ default .Env.LOG_LEVEL_FRAMEWORK "ERROR" }} + org: {{ default .Env.LOG_LEVEL_FRAMEWORK "ERROR" }} + eu: + hbp: {{ default .Env.LOG_LEVEL "INFO" }} + + +### AUTHENTICATION ### +authentication: + enabled: {{ default .Env.AUTHENTICATION "true" }} + + +### DATABASE CONFIGURATION ### spring: - portalDatasource: - url: {{ default .Env.PORTAL_DB_URL "jdbc:postgresql://172.22.0.1:5432/portal" }} + portal-datasource: + url: {{ default .Env.PORTAL_DB_URL "jdbc:postgresql://88.197.53.106:5432/portal" }} schema: {{ default .Env.PORTAL_DB_SCHEMA "public" }} username: {{ default .Env.PORTAL_DB_USER "postgres" }} password: {{ .Env.PORTAL_DB_PASSWORD }} driver-class-name: org.postgresql.Driver - data: jpa: repositories: @@ -16,60 +29,10 @@ spring: jpa: hibernate: dialect: org.hibernate.dialect.PostgreSQL9Dialect - # SPRING RESOURCES HANDLING - resources: - chain: - enabled: true # TODO: why is that enabled? Do we serve any resources from the backend? + ddl-auto: validate -# HBP OAUTH2 LOGIN -hbp: - authentication: - enabled: {{ default .Env.AUTHENTICATION "1" }} - client: - clientId: {{ default .Env.CLIENT_ID "996f97c5-a3ca-460e-b18b-00df3e2be89a" }} - clientSecret: {{ .Env.CLIENT_SECRET }} - accessTokenUri: {{ default .Env.TOKEN_URI "https://services.humanbrainproject.eu/oidc/token" }} - userAuthorizationUri: {{ default .Env.AUTH_URI "https://services.humanbrainproject.eu/oidc/authorize" }} - logoutUri: {{ .Env.LOGOUT_URI }} - tokenName: access_token - authenticationScheme: query - clientAuthenticationScheme: form - useCurrentUri: false - preEstablishedRedirectUri: {{ default .Env.FRONTEND_LOGIN_URL "http://frontend/services/login/hbp" }} - resource: - userInfoUri: {{ default .Env.USER_INFO_URI "https://services.humanbrainproject.eu/oidc/userinfo" }} - revokeTokenUri: {{ default .Env.REVOKE_TOKEN_URI "https://services.humanbrainproject.eu/oidc/slo" }} - sso: - login-path: - -# WEB FRONTEND -frontend: - loginUrl: {{ default .Env.FRONTEND_LOGIN_URL "http://frontend/services/login/hbp" }} - redirectAfterLogoutUrl: {{ default .Env.FRONTEND_AFTER_LOGOUT_URL (default .Env.LOGIN_URI "http://frontend/services/login/hbp") }} - redirectAfterLoginUrl: {{ default .Env.FRONTEND_AFTER_LOGIN_URL "http://frontend/home" }} - -logging: - level: - root: {{ default .Env.LOG_LEVEL_FRAMEWORK "ERROR" }} - eu: - hbp: {{ default .Env.LOG_LEVEL "INFO" }} - -# EMBEDDED SERVER CONFIGURATION -server: - contextPath: {{ default .Env.CONTEXT_PATH "/services" }} - port: 8080 - use-forward-headers: true - session: - timeout: {{ default .Env.SESSION_TIMEOUT "2592000" }} - -# ENDPOINTS -endpoints: - enabled: true - health: - enabled: true - endpoint: /health - sensitive: false +### EXTERNAL SERVICES ### services: exareme: queryExaremeUrl: {{ default .Env.EXAREME_URL "http://localhost:9090" }}/mining/query @@ -77,10 +40,43 @@ services: galaxy: galaxyUrl: {{ default .Env.GALAXY_URL "http://localhost:8090/" }} - galaxyContext: {{ default .Env.GALAXY_CONTEXT "nativeGalaxy/workflows/list" }} + galaxyContext: "nativeGalaxy/workflows/list" galaxyApiKey: {{ .Env.GALAXY_API_KEY }} galaxyUsername: {{ default .Env.GALAXY_USERNAME "admin" }} galaxyPassword: {{ default .Env.GALAXY_PASSWORD "password" }} - keycloak: - keycloakUrl: {{ .Env.KEYCLOAK_URL }} + +### KEYCLOAK ### +keycloak: + enabled: true + auth-server-url: {{ .Env.KEYCLOAK_AUTH_URL }} + realm: {{ .Env.KEYCLOAK_REALM }} + resource: {{ .Env.KEYCLOAK_CLIENT_ID }} + enable-basic-auth: true + credentials: + secret: {{ .Env.KEYCLOAK_CLIENT_SECRET }} + principal-attribute: "preferred_username" + ssl-required: none + +### EXTERNAL FILES ### +# Files are imported when building the docker image +files: + pathologies_json: "file:/opt/portal/api/pathologies.json" + disabledAlgorithms_json: "file:/opt/portal/api/disabledAlgorithms.json" + + +### EMBEDDED SERVER CONFIGURATION ### +server: + servlet: + contextPath: "/services" + port: 8080 + forward-headers-strategy: native + + +### ENDPOINTS ### +endpoints: + enabled: true + health: + enabled: true + endpoint: /health + sensitive: false \ No newline at end of file diff --git a/pom.xml b/pom.xml index 20a6f066122779eab771ca0d012dbcc4a8e8a208..d92ff1f2dd22cd477f702ec2486f675c117c39c6 100644 --- a/pom.xml +++ b/pom.xml @@ -14,27 +14,25 @@ <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> - <version>1.3.8.RELEASE</version> - <relativePath/> - + <version>2.3.5.RELEASE</version> </parent> <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <sonar.host.url>https://hbps1.chuv.ch/sonarqube/</sonar.host.url> - <sonar.projectName>MIP portal-backend</sonar.projectName> - <sonar.sources>src/main/java/</sonar.sources> <java.version>1.8</java.version> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <keycloak-spring.version>11.0.2</keycloak-spring.version> + <springfox-swagger.version>2.5.0</springfox-swagger.version> + <spring-context.version>5.2.10.RELEASE</spring-context.version> + <springfox-boot-starter.version>3.0.0</springfox-boot-starter.version> <asciidoctor.maven.plugin.version>1.5.5</asciidoctor.maven.plugin.version> <asciidoctorj.pdf.version>1.5.0-alpha.15</asciidoctorj.pdf.version> <asciidoctorj.version>1.5.5</asciidoctorj.version> - <spring-data-commons.version>1.12.3.RELEASE</spring-data-commons.version> <angularjs.version>1.5.7</angularjs.version> <jquery.version>3.0.0</jquery.version> <bootstrap.version>3.3.7</bootstrap.version> + <webjars-locator.version>0.36</webjars-locator.version> <h2.version>1.4.192</h2.version> <postgresql.version>42.2.1</postgresql.version> - <springfox-swagger.version>2.5.0</springfox-swagger.version> <gson.version>2.7</gson.version> <slugify.version>2.1.5</slugify.version> <maven-resources-plugin.version>3.0.1</maven-resources-plugin.version> @@ -42,15 +40,13 @@ <swagger2markup-maven-plugin.version>1.0.0</swagger2markup-maven-plugin.version> <maven-compiler-plugin.version>3.5.1</maven-compiler-plugin.version> <hibernate4-maven-plugin.version>1.1.1</hibernate4-maven-plugin.version> + <commons-dbcp.version>2.7.0</commons-dbcp.version> <flyway-core.version>4.2.0</flyway-core.version> <hibernate-jpa-2.1-api.version>1.0.0.Final</hibernate-jpa-2.1-api.version> - <hibernate.version>4.3.11.Final</hibernate.version> - <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> + <hibernate.version>5.4.10.Final</hibernate.version> + <hibernate-validator.version>6.1.0.Final</hibernate-validator.version> <aspectjweaver.version>1.8.9</aspectjweaver.version> <javax-inject.version>1</javax-inject.version> - <akka.version>2.5.22</akka.version> - <spring-context.version>4.3.4.RELEASE</spring-context.version> <protobuf-java.version>3.1.0</protobuf-java.version> </properties> @@ -66,32 +62,39 @@ </repositories> <dependencies> - <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-actuator</artifactId> - <version>${spring-boot-starter-actuator.version}</version> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> - <groupId>org.springframework.data</groupId> - <artifactId>spring-data-commons</artifactId> - <version>${spring-data-commons.version}</version> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-security</artifactId> + <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> - <groupId>org.springframework.security.oauth</groupId> - <artifactId>spring-security-oauth2</artifactId> + <groupId>org.springframework.data</groupId> + <artifactId>spring-data-commons</artifactId> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-spring-boot-starter</artifactId> + <version>${keycloak-spring.version}</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-spring-security-adapter</artifactId> + <version>${keycloak-spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> @@ -115,6 +118,7 @@ <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> + <version>${webjars-locator.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> @@ -131,6 +135,11 @@ <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-validator</artifactId> + <version>${hibernate-validator.version}</version> + </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> @@ -148,13 +157,8 @@ </dependency> <dependency> <groupId>io.springfox</groupId> - <artifactId>springfox-swagger2</artifactId> - <version>${springfox-swagger.version}</version> - </dependency> - <dependency> - <groupId>io.springfox</groupId> - <artifactId>springfox-swagger-ui</artifactId> - <version>${springfox-swagger.version}</version> + <artifactId>springfox-boot-starter</artifactId> + <version>${springfox-boot-starter.version}</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> @@ -169,11 +173,11 @@ <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> - <version>${spring-data-jpa.version}</version> </dependency> <dependency> - <groupId>commons-dbcp</groupId> - <artifactId>commons-dbcp</artifactId> + <groupId>org.apache.commons</groupId> + <artifactId>commons-dbcp2</artifactId> + <version>${commons-dbcp.version}</version> </dependency> <dependency> <groupId>org.flywaydb</groupId> @@ -185,16 +189,15 @@ <artifactId>aspectjweaver</artifactId> <version>${aspectjweaver.version}</version> </dependency> - <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>${javax-inject.version}</version> </dependency> <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-context</artifactId> - <version>${spring.version}</version> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + <version>${spring-context.version}</version> </dependency> <dependency> <groupId>com.google.protobuf</groupId> @@ -209,60 +212,70 @@ <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> - <version>2.4.0-b180830.0438</version> - </dependency> - - <dependency> - <groupId>com.auth0</groupId> - <artifactId>java-jwt</artifactId> - <version>3.8.3</version> + <version>3.0.0-M4</version> </dependency> - <!-- https://mvnrepository.com/artifact/com.github.jmchilton.blend4j/blend4j --> <dependency> <groupId>com.github.jmchilton.blend4j</groupId> <artifactId>blend4j</artifactId> <version>0.2.0</version> </dependency> - <dependency> <groupId>com.squareup.retrofit2</groupId> <artifactId>retrofit</artifactId> - <version>2.5.0</version> + <version>2.9.0</version> </dependency> - <!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson --> <dependency> <groupId>com.squareup.retrofit2</groupId> <artifactId>converter-gson</artifactId> - <version>2.4.0</version> + <version>2.9.0</version> </dependency> - <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/logging-interceptor --> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>logging-interceptor</artifactId> - <version>3.12.1</version> </dependency> - <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> - <version>3.8.3</version> + <version>3.11.0</version> + </dependency> + <dependency> + <groupId>com.google.code.svenson</groupId> + <artifactId>svenson</artifactId> + <version>1.5.8</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.16</version> + <scope>provided</scope> </dependency> + </dependencies> - <build> - <finalName>portal-backend</finalName> - <resources> + <build> + <finalName>portal-backend</finalName> + <resources> + <resource> + <directory>src/main/resources</directory> + <includes> + <include>**/*.xml</include> + <include>**/*.json</include> + <include>**/*.csv</include> + <include>**/*.sql</include> + <include>**/*.conf</include> + <include>**/*.yml</include> <!-- Only for development --> + </includes> + <filtering>true</filtering> + </resource> + + <!-- Used for development. Docker/config folder files added as resources --> <resource> - <directory>src/main/resources</directory> + <directory>config</directory> <includes> - <include>**/*.xml</include> - <include>**/*.json</include> - <include>**/*.csv</include> - <include>**/*.sql</include> - <include>**/*.conf</include> + <include>*.json</include> </includes> <filtering>true</filtering> </resource> diff --git a/src/main/java/eu/hbp/mip/MIPApplication.java b/src/main/java/eu/hbp/mip/MIPApplication.java index 9af69bdd9cdc04e555a24f8a0ca4e7b3882206ed..f4001f93c477307cf0d464f76e8b22b2905af198 100644 --- a/src/main/java/eu/hbp/mip/MIPApplication.java +++ b/src/main/java/eu/hbp/mip/MIPApplication.java @@ -7,17 +7,12 @@ package eu.hbp.mip; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @SpringBootApplication public class MIPApplication { - private static final Logger LOGGER = LoggerFactory.getLogger(MIPApplication.class); - public static void main(String[] args) { SpringApplication.run(MIPApplication.class, args); } - } diff --git a/src/main/java/eu/hbp/mip/configuration/CacheConfiguration.java b/src/main/java/eu/hbp/mip/configuration/CacheConfiguration.java deleted file mode 100644 index b7300fc257fcef4afd29421d8ccef64aeb0a11dd..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/configuration/CacheConfiguration.java +++ /dev/null @@ -1,13 +0,0 @@ -package eu.hbp.mip.configuration; - -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.annotation.Configuration; - -/** - * Created by mirco on 07.11.16. - */ - -@Configuration -@EnableCaching -public class CacheConfiguration { -} diff --git a/src/main/java/eu/hbp/mip/configuration/PortalErrorAttributes.java b/src/main/java/eu/hbp/mip/configuration/PortalErrorAttributes.java deleted file mode 100644 index 352b1d156558ef42b9862b644ed5668070899708..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/configuration/PortalErrorAttributes.java +++ /dev/null @@ -1,43 +0,0 @@ -package eu.hbp.mip.configuration; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.autoconfigure.web.DefaultErrorAttributes; -import org.springframework.stereotype.Component; -import org.springframework.web.context.request.RequestAttributes; - -import java.util.HashMap; -import java.util.Map; - -@Component -public class PortalErrorAttributes extends DefaultErrorAttributes { - - private static final Logger LOGGER = LoggerFactory.getLogger(PortalErrorAttributes.class); - - @Override - public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { - Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace); - - Throwable throwable = getError(requestAttributes); - StringBuilder sb = new StringBuilder("["); - for (String attr : requestAttributes.getAttributeNames(RequestAttributes.SCOPE_REQUEST)) { - Object v = requestAttributes.getAttribute(attr, RequestAttributes.SCOPE_REQUEST); - sb.append(attr).append(" = ").append(v).append('\n'); - } - sb.append("]"); - LOGGER.error("Reporting server error on request with attributes " + sb.toString(), throwable); - - if (throwable != null) { - - Throwable cause = throwable.getCause(); - if (cause != null) { - Map<String, Object> causeErrorAttributes = new HashMap<>(); - causeErrorAttributes.put("exception", cause.getClass().getName()); - causeErrorAttributes.put("message", cause.getMessage()); - errorAttributes.put("cause", causeErrorAttributes); - } - } - - return errorAttributes; - } -} diff --git a/src/main/java/eu/hbp/mip/configuration/SecurityConfiguration.java b/src/main/java/eu/hbp/mip/configuration/SecurityConfiguration.java deleted file mode 100644 index 4ea52570fd3bde8c8b21253fe202aa3fc61363d4..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/configuration/SecurityConfiguration.java +++ /dev/null @@ -1,343 +0,0 @@ -package eu.hbp.mip.configuration; - -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.utils.*; -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.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor; -import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties; -import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices; -import org.springframework.boot.context.embedded.FilterRegistrationBean; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.*; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.oauth2.client.OAuth2ClientContext; -import org.springframework.security.oauth2.client.OAuth2RestTemplate; -import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter; -import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter; -import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails; -import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; -import org.springframework.security.web.access.channel.ChannelProcessingFilter; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; -import org.springframework.security.web.authentication.logout.LogoutHandler; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; -import org.springframework.security.web.csrf.CsrfFilter; -import org.springframework.security.web.csrf.CsrfToken; -import org.springframework.security.web.csrf.CsrfTokenRepository; -import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.filter.OncePerRequestFilter; -import org.springframework.web.util.WebUtils; - -import javax.net.ssl.*; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.net.URI; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - - -// See https://spring.io/guides/tutorials/spring-boot-oauth2/ for reference about configuring OAuth2 login -// also http://cscarioni.blogspot.ch/2013/04/pro-spring-security-and-oauth-2.html - -@Configuration -@EnableOAuth2Client -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(SecurityConfiguration.class); - - @Autowired - private OAuth2ClientContext oauth2ClientContext; - - /** - * Enable HBP collab authentication (1) or disable it (0). Default is 1 - */ - @Value("#{'${hbp.authentication.enabled:1}'}") - private boolean authentication; - - /** - * Absolute URL to redirect to when login is required - */ - @Value("#{'${frontend.loginUrl:/login/hbp}'}") - private String loginUrl; - - /** - * Absolute URL to redirect to when logout is required - */ - @Value("#{'${hbp.client.logoutUri}'}") - private String logoutUri; - - /** - * Absolute URL to redirect to after successful login - */ - @Value("#{'${frontend.redirectAfterLoginUrl:http://frontend/home}'}") - private String frontendRedirectAfterLogin; - - /** - * Absolute URL to redirect to after logout has occurred - */ - @Value("#{'${frontend.redirectAfterLogoutUrl:/login/hbp}'}") - private String redirectAfterLogoutUrl; - - /** - * URL to revoke auth token - */ - @Value("#{'${hbp.resource.revokeTokenUri:https://services.humanbrainproject.eu/oidc/revoke}'}") - private String revokeTokenURI; - - @Override - protected void configure(HttpSecurity http) throws Exception { - disableCertificateValidation(); - // @formatter:off - http.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class); - - if (authentication) { - http.antMatcher("/**") - .authorizeRequests() - .antMatchers( - "/", "/login/**", "/health/**", "/info/**", "/metrics/**", "/trace/**", "/frontend/**", "/webjars/**", "/v2/api-docs", "/swagger-ui.html", "/swagger-resources/**" - ) - .permitAll() - .antMatchers("/galaxy*", "/galaxy/*").hasRole("Data Manager") - //.anyRequest().authenticated() - .anyRequest().hasRole("Researcher") - .and().exceptionHandling().authenticationEntryPoint(new CustomLoginUrlAuthenticationEntryPoint(loginUrl)) - .accessDeniedHandler(new CustomAccessDeniedHandler()) - .and().logout().addLogoutHandler(authLogoutHandler()).logoutSuccessUrl(redirectAfterLogoutUrl) - .and().logout().permitAll() - .and().csrf().ignoringAntMatchers("/logout").csrfTokenRepository(csrfTokenRepository()) - .and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class) - .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class); - } else { - http.antMatcher("/**") - .authorizeRequests() - .antMatchers("/**").permitAll().and().csrf().disable(); - } - } - - private Filter ssoFilter() { - OAuth2ClientAuthenticationProcessingFilter hbpFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/hbp"); - OAuth2RestTemplate hbpTemplate = new OAuth2RestTemplate(hbp(), oauth2ClientContext); - hbpFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler(frontendRedirectAfterLogin)); - hbpFilter.setRestTemplate(hbpTemplate); - hbpFilter.setTokenServices(new UserInfoTokenServices(hbpResource().getUserInfoUri(), hbp().getClientId())); - return hbpFilter; - } - - @Bean - public FilterRegistrationBean oauth2ClientFilterRegistration( - OAuth2ClientContextFilter filter) { - FilterRegistrationBean registration = new FilterRegistrationBean(); - registration.setFilter(filter); - registration.setOrder(-100); - return registration; - } - - @Bean(name = "hbp") - @ConfigurationProperties("hbp.client") - public BaseOAuth2ProtectedResourceDetails hbp() { - return new AuthorizationCodeResourceDetails(); - } - - @Bean(name = "hbpResource") - @ConfigurationProperties("hbp.resource") - public ResourceServerProperties hbpResource() { - return new ResourceServerProperties(); - } - - public boolean isAuthentication() { - return authentication; - } - - public String getFrontendRedirectAfterLogin() { - return frontendRedirectAfterLogin; - } - - private Filter csrfHeaderFilter() { - return new OncePerRequestFilter() { - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); - if (csrf != null) { - Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN"); - String token = csrf.getToken(); - if (cookie == null || token != null && !token.equals(cookie.getValue())) { - cookie = new Cookie("XSRF-TOKEN", token); - cookie.setPath("/"); - response.addCookie(cookie); - } - } - filterChain.doFilter(request, response); - } - }; - } - - private CsrfTokenRepository csrfTokenRepository() { - HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); - repository.setHeaderName("X-XSRF-TOKEN"); - return repository; - } - - private class CustomLogoutHandler implements LogoutHandler { - @Override - public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) { - - // Hackish way of accessing to this information... - final UserInfo userInfo = (UserInfo) httpServletRequest.getSession().getAttribute("userInfo"); - if (userInfo != null) { - userInfo.setFakeAuth(false); - } - - if (oauth2ClientContext == null || oauth2ClientContext.getAccessToken() == null) { - return; - } - - String idToken = oauth2ClientContext.getAccessToken().getAdditionalInformation().get("id_token").toString(); - - StringBuilder query = new StringBuilder(); - query.append("{"); - query.append("\"token\":"); - query.append("\"").append(idToken).append("\""); - query.append("}"); - - try { - int responseCode = HTTPUtil.sendPost(revokeTokenURI, query.toString(), new StringBuilder()); - if (responseCode != 200) { - LOGGER.warn("Cannot send request to OIDC server for revocation ! "); - } else { - LOGGER.info("Should be logged out"); - } - } catch (IOException e) { - LOGGER.warn("Cannot notify logout to OIDC server !"); - LOGGER.trace("Cannot notify logout", e); - } - - } - } - - @Bean - public AuthoritiesExtractor keycloakAuthoritiesExtractor() { - return new KeycloakAuthoritiesExtractor(); - } - - - public class KeycloakAuthoritiesExtractor - implements AuthoritiesExtractor { - - @Override - public List<GrantedAuthority> extractAuthorities - (Map<String, Object> map) { - return AuthorityUtils - .commaSeparatedStringToAuthorityList(asAuthorities(map)); - } - - private String asAuthorities(Map<String, Object> map) { - List<String> authorities = new ArrayList<>(); -// authorities.add("BAELDUNG_USER"); - List<LinkedHashMap<String, String>> authz; - authz = (List<LinkedHashMap<String, String>>) map.get("authorities"); - for (LinkedHashMap<String, String> entry : authz) { - authorities.add(entry.get("authority")); - } - return String.join(",", authorities); - } - } - - - private LogoutHandler authLogoutHandler() { - return (request, response, authentication) -> { - logout(); - }; - } - - - public void logout() { - // POSTã™ã‚‹ãƒªã‚¯ã‚¨ã‚¹ãƒˆãƒ‘ãƒ©ãƒ¡ãƒ¼ã‚¿ãƒ¼ã‚’ä½œæˆ - RestTemplate restTemplate = new RestTemplate(); - MultiValueMap<String, String> formParams = new LinkedMultiValueMap<>(); - formParams.add("client_id", hbp().getClientId()); - formParams.add("client_secret", hbp().getClientSecret()); - formParams.add("refresh_token", this.oauth2ClientContext.getAccessToken().getRefreshToken().getValue()); - // ãƒªã‚¯ã‚¨ã‚¹ãƒˆãƒ˜ãƒƒãƒ€ãƒ¼ã‚’ä½œæˆ - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE); - // ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’ä½œæˆ - RequestEntity<MultiValueMap<String, String>> requestEntity = - new RequestEntity<>(formParams, httpHeaders, HttpMethod.POST, - URI.create(logoutUri)); - // POSTリクエストé€ä¿¡ï¼ˆãƒã‚°ã‚¢ã‚¦ãƒˆå®Ÿè¡Œï¼‰ - - ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class); - } - - @Value("#{'${services.keycloak.keycloakUrl}'}") - private String keycloakUrl; - - // static { - // disableCertificateValidation(); - // } - - public void disableCertificateValidation() { - LOGGER.info("disabling certificate validation host : " + keycloakUrl); - // Create a trust manager that does not validate certificate chains - TrustManager[] trustAllCerts = new TrustManager[]{ - new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - - public void checkClientTrusted(X509Certificate[] certs, String authType) { - } - - public void checkServerTrusted(X509Certificate[] certs, String authType) { - } - }}; - - - // Ignore differences between given hostname and certificate hostname - HostnameVerifier hv = new HostnameVerifier() { - public boolean verify(String hostname, SSLSession session) { - - // System.out.println("Warning: URL Host: " + hostname + " vs. " - // + session.getPeerHost()); - if (hostname.equals(keycloakUrl) && session.getPeerHost().equals(keycloakUrl)) { - return true; - } else { - return false; - } - } - }; - - // Install the all-trusting trust manager - try { - SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(null, trustAllCerts, new SecureRandom()); - HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); - HttpsURLConnection.setDefaultHostnameVerifier(hv); - } catch (Exception e) { - } - - } - -} diff --git a/src/main/java/eu/hbp/mip/configuration/WebConfiguration.java b/src/main/java/eu/hbp/mip/configurations/APIMetadataConfiguration.java similarity index 61% rename from src/main/java/eu/hbp/mip/configuration/WebConfiguration.java rename to src/main/java/eu/hbp/mip/configurations/APIMetadataConfiguration.java index a5b514dfb815c9df88c0475b7c3ce24df1f06803..7b9eab4563d9c71af0a0eac7d6bae42d798df93b 100644 --- a/src/main/java/eu/hbp/mip/configuration/WebConfiguration.java +++ b/src/main/java/eu/hbp/mip/configurations/APIMetadataConfiguration.java @@ -1,31 +1,18 @@ -package eu.hbp.mip.configuration; +package eu.hbp.mip.configurations; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; -import org.springframework.data.web.config.EnableSpringDataWebSupport; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger.web.UiConfiguration; import springfox.documentation.swagger2.annotations.EnableSwagger2; -/** - * Created by mirco on 11.07.16. - */ - @Configuration @EnableSwagger2 -@EnableSpringDataWebSupport -public class WebConfiguration { - - @Bean - public UiConfiguration swaggerUiConfig() { - return UiConfiguration.DEFAULT; - } +public class APIMetadataConfiguration { @Bean public Docket swaggerDocumentation() { @@ -40,10 +27,8 @@ public class WebConfiguration { private ApiInfo metadata() { return new ApiInfoBuilder() .title("Medical Informatics Platform API") - .description("Serve the MIP Frontend") - .version("1.0") - .contact(new Contact("Mirco Nasuti", "https://www.unil.ch/lren/en/home.html", "mirco.nasuti@chuv.ch")) + .description("Serving the MIP Frontend") + .contact(new Contact("Kostas Filippopolitis", "https://github.com/KFilippopolitis", "kostasfilippop@gmail.com")) .build(); } - } diff --git a/src/main/java/eu/hbp/mip/configurations/GalaxyAuthentication.java b/src/main/java/eu/hbp/mip/configurations/GalaxyAuthentication.java new file mode 100644 index 0000000000000000000000000000000000000000..e8a5df4bc7311cc86683c546f27de0208a850d20 --- /dev/null +++ b/src/main/java/eu/hbp/mip/configurations/GalaxyAuthentication.java @@ -0,0 +1,54 @@ +package eu.hbp.mip.configurations; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import eu.hbp.mip.services.ActiveUserService; +import eu.hbp.mip.utils.Logger; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Base64; + +@RestController +public class GalaxyAuthentication { + + private final ActiveUserService activeUserService; + + @Value("#{'${services.galaxy.galaxyUsername:admin}'}") + private String galaxyUsername; + + @Value("#{'${services.galaxy.galaxyPassword:password}'}") + private String galaxyPassword; + + @Value("#{'${services.galaxy.galaxpathoyContext:nativeGalaxy}'}") + private String galaxyContext; + + public GalaxyAuthentication(ActiveUserService activeUserService) { + this.activeUserService = activeUserService; + } + + /** + * Get Galaxy Reverse Proxy basic access token. + * + * @return Return a @{@link ResponseEntity} with the token. + */ + @RequestMapping(path = "/galaxy", method = RequestMethod.GET, produces = "application/json") + @PreAuthorize("hasRole('WORKFLOW_ADMIN')") + @ResponseStatus(value = HttpStatus.OK) + public ResponseEntity getGalaxyConfiguration() { + Logger logger = new Logger(activeUserService.getActiveUser().getUsername(), "(GET) /user/galaxy"); + String stringEncoded = Base64.getEncoder().encodeToString((galaxyUsername + ":" + galaxyPassword).getBytes()); + JsonObject object = new JsonObject(); + object.addProperty("authorization", stringEncoded); + object.addProperty("context", galaxyContext); + logger.LogUserAction("Successfully Loaded galaxy information."); + + return ResponseEntity.ok(new Gson().toJson(object)); + } +} diff --git a/src/main/java/eu/hbp/mip/configuration/PersistenceConfiguration.java b/src/main/java/eu/hbp/mip/configurations/PersistenceConfiguration.java similarity index 62% rename from src/main/java/eu/hbp/mip/configuration/PersistenceConfiguration.java rename to src/main/java/eu/hbp/mip/configurations/PersistenceConfiguration.java index c8024e1bffa90604da6d13712bc07cbac815b3d7..181bc639c05ea4b3987459cf36a62664db6812cb 100644 --- a/src/main/java/eu/hbp/mip/configuration/PersistenceConfiguration.java +++ b/src/main/java/eu/hbp/mip/configurations/PersistenceConfiguration.java @@ -1,10 +1,12 @@ -package eu.hbp.mip.configuration; +package eu.hbp.mip.configurations; import org.flywaydb.core.Flyway; -import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.orm.jpa.EntityScan; -import org.springframework.context.annotation.*; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.context.annotation.Primary; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -18,25 +20,24 @@ import javax.sql.DataSource; @Configuration @EnableJpaRepositories("eu.hbp.mip.repositories") -@EntityScan(basePackages = "eu.hbp.mip.model") public class PersistenceConfiguration { @Primary - @Bean(name = "portalDatasource") - @ConfigurationProperties(prefix = "spring.portalDatasource") + @Bean(name = "portal-datasource") + @ConfigurationProperties(prefix = "spring.portal-datasource") public DataSource portalDataSource() { return DataSourceBuilder.create().build(); } - @Bean(name = "entityManagerFactory") @DependsOn("flyway") public LocalContainerEntityManagerFactoryBean entityManagerFactory() { - LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); - em.setDataSource(portalDataSource()); + LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean(); + emfb.setDataSource(portalDataSource()); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); - em.setJpaVendorAdapter(vendorAdapter); - return em; + emfb.setJpaVendorAdapter(vendorAdapter); + emfb.setPackagesToScan("eu.hbp.mip.models.DAOs"); + return emfb; } @Bean(name = "flyway", initMethod = "migrate") diff --git a/src/main/java/eu/hbp/mip/configurations/SecurityConfiguration.java b/src/main/java/eu/hbp/mip/configurations/SecurityConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..9f583da4ef31205007e7467c63cfaf95645a5f28 --- /dev/null +++ b/src/main/java/eu/hbp/mip/configurations/SecurityConfiguration.java @@ -0,0 +1,126 @@ +package eu.hbp.mip.configurations; + +import eu.hbp.mip.utils.CORSFilter; +import org.keycloak.adapters.KeycloakConfigResolver; +import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; +import org.keycloak.adapters.springsecurity.KeycloakConfiguration; +import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; +import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; +import org.springframework.security.core.session.SessionRegistryImpl; +import org.springframework.security.web.access.channel.ChannelProcessingFilter; +import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; +import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; +import org.springframework.security.web.csrf.CsrfFilter; +import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.security.web.csrf.CsrfTokenRepository; +import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.filter.OncePerRequestFilter; +import org.springframework.web.util.WebUtils; + +import javax.servlet.*; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +@Controller +@KeycloakConfiguration +public class SecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter { + + // Upon logout, redirect to login page url + private static final String logoutRedirectURL = "/sso/login"; + + @Value("#{'${authentication.enabled}'}") + private boolean authenticationEnabled; + + public SecurityConfiguration(HttpServletRequest request) { + this.request = request; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + super.configure(http); + + if (authenticationEnabled) { + http.authorizeRequests() + .antMatchers( + "/sso/login", + "/v2/api-docs", "/swagger-ui/**", "/swagger-resources/**" // Swagger URLs + ).permitAll() + .antMatchers("/galaxy*", "/galaxy/*").hasRole("WORKFLOW_ADMIN") + .antMatchers("/**").authenticated() + .and().csrf().ignoringAntMatchers("/logout").csrfTokenRepository(csrfTokenRepository()) + .and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class); + } else { + http.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class); + http.antMatcher("/**") + .authorizeRequests() + .antMatchers("/**").permitAll() + .and().csrf().disable(); + } + } + + private Filter csrfHeaderFilter() { + return new OncePerRequestFilter() { + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); + if (csrf != null) { + Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN"); + String token = csrf.getToken(); + if (cookie == null || token != null && !token.equals(cookie.getValue())) { + cookie = new Cookie("XSRF-TOKEN", token); + cookie.setPath("/"); + response.addCookie(cookie); + } + } + filterChain.doFilter(request, response); + } + }; + } + + private CsrfTokenRepository csrfTokenRepository() { + HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); + repository.setHeaderName("X-XSRF-TOKEN"); + return repository; + } + + private final HttpServletRequest request; + + @GetMapping(value = "/logout") + public String logout() throws ServletException { + request.logout(); + return String.format("redirect:%s", logoutRedirectURL); + } + + @Bean + public KeycloakConfigResolver KeycloakConfigResolver() { + return new KeycloakSpringBootConfigResolver(); + } + + @Override + protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { + return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) { + SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper(); + grantedAuthorityMapper.setConvertToUpperCase(true); + + KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); + keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(grantedAuthorityMapper); + auth.authenticationProvider(keycloakAuthenticationProvider); + } + +} diff --git a/src/main/java/eu/hbp/mip/controllers/ActiveUserAPI.java b/src/main/java/eu/hbp/mip/controllers/ActiveUserAPI.java new file mode 100644 index 0000000000000000000000000000000000000000..aca62c4b6c2771e45ffa60a9cbc09040b1a3248a --- /dev/null +++ b/src/main/java/eu/hbp/mip/controllers/ActiveUserAPI.java @@ -0,0 +1,46 @@ +package eu.hbp.mip.controllers; + +import eu.hbp.mip.models.DAOs.UserDAO; +import eu.hbp.mip.services.ActiveUserService; +import eu.hbp.mip.utils.Logger; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +@RestController +@RequestMapping(value = "/activeUser", produces = {APPLICATION_JSON_VALUE}) +@Api(value = "/activeUser") +public class ActiveUserAPI { + + private final ActiveUserService activeUserService; + + public ActiveUserAPI(ActiveUserService activeUserService) { + this.activeUserService = activeUserService; + } + + @ApiOperation(value = "Get the active user", response = UserDAO.class) + @RequestMapping(method = RequestMethod.GET) + public ResponseEntity<UserDAO> getTheActiveUser(HttpServletResponse response) { + Logger logger = new Logger(activeUserService.getActiveUser().getUsername(), "(GET) /activeUser"); + logger.LogUserAction("Loading the details of the activeUser"); + + return ResponseEntity.ok(activeUserService.getActiveUser()); + } + + @ApiOperation(value = "The active user agrees to the NDA", response = UserDAO.class) + @RequestMapping(value = "/agreeNDA", method = RequestMethod.POST) + public ResponseEntity<UserDAO> activeUserServiceAgreesToNDA(@RequestBody(required = false) UserDAO userDAO) { + Logger logger = new Logger(activeUserService.getActiveUser().getUsername(), "(GET) /activeUser/agreeNDA"); + logger.LogUserAction("The user agreed to the NDA"); + + return ResponseEntity.ok(activeUserService.agreeToNDA()); + } +} diff --git a/src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java b/src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java similarity index 64% rename from src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java rename to src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java index 8310973a308ec810853519552dc48855f494e4d7..48500bb10470059f1fe7d37079dfb391ef395b31 100644 --- a/src/main/java/eu/hbp/mip/controllers/AlgorithmsApi.java +++ b/src/main/java/eu/hbp/mip/controllers/AlgorithmsAPI.java @@ -8,15 +8,14 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import eu.hbp.mip.controllers.galaxy.retrofit.RetroFitGalaxyClients; import eu.hbp.mip.controllers.galaxy.retrofit.RetrofitClientInstance; -import eu.hbp.mip.model.AlgorithmDTO; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.model.galaxy.WorkflowDTO; +import eu.hbp.mip.models.DTOs.AlgorithmDTO; +import eu.hbp.mip.models.galaxy.WorkflowDTO; +import eu.hbp.mip.services.ActiveUserService; import eu.hbp.mip.utils.CustomResourceLoader; import eu.hbp.mip.utils.HTTPUtil; -import eu.hbp.mip.utils.Logging; +import eu.hbp.mip.utils.Logger; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; @@ -31,19 +30,17 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -import static eu.hbp.mip.utils.ErrorMessages.disabledAlgorithmsCouldNotBeLoaded; import static eu.hbp.mip.utils.InputStreamConverter.convertInputStreamToString; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RestController @RequestMapping(value = "/algorithms", produces = {APPLICATION_JSON_VALUE}) @Api(value = "/algorithms") -public class AlgorithmsApi { +public class AlgorithmsAPI { private static final Gson gson = new Gson(); - @Autowired - private UserInfo userInfo; + private final ActiveUserService activeUserService; @Value("#{'${services.exareme.algorithmsUrl}'}") private String exaremeAlgorithmsUrl; @@ -54,36 +51,43 @@ public class AlgorithmsApi { @Value("#{'${services.galaxy.galaxyApiKey}'}") private String galaxyApiKey; + @Value("#{'${files.disabledAlgorithms_json}'}") + private String disabledAlgorithmsFilePath; + + public AlgorithmsAPI(ActiveUserService activeUserService, CustomResourceLoader resourceLoader) { + this.activeUserService = activeUserService; + this.resourceLoader = resourceLoader; + } + @ApiOperation(value = "List all algorithms", response = String.class) @RequestMapping(method = RequestMethod.GET) public ResponseEntity<List<AlgorithmDTO>> getAlgorithms() { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "Executing..."); + Logger logger = new Logger(activeUserService.getActiveUser().getUsername(), "(GET) /algorithms"); + + logger.LogUserAction("Executing..."); - LinkedList<AlgorithmDTO> exaremeAlgorithms = getExaremeAlgorithms(); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "Loaded " + exaremeAlgorithms.size() + " exareme algorithms"); - LinkedList<AlgorithmDTO> galaxyAlgorithms = getGalaxyWorkflows(); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "Loaded " + galaxyAlgorithms.size() + " galaxy algorithms"); + LinkedList<AlgorithmDTO> exaremeAlgorithms = getExaremeAlgorithms(logger); + logger.LogUserAction("Loaded " + exaremeAlgorithms.size() + " exareme algorithms"); + LinkedList<AlgorithmDTO> galaxyAlgorithms = getGalaxyWorkflows(logger); + logger.LogUserAction("Loaded " + galaxyAlgorithms.size() + " galaxy algorithms"); LinkedList<AlgorithmDTO> algorithms = new LinkedList<>(); if (exaremeAlgorithms != null) { algorithms.addAll(exaremeAlgorithms); } else { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", - "Getting exareme algorithms failed and returned null"); + logger.LogUserAction("Getting exareme algorithms failed and returned null"); } if (galaxyAlgorithms != null) { algorithms.addAll(galaxyAlgorithms); } else { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", - "Getting galaxy workflows failed and returned null"); + logger.LogUserAction("Getting galaxy workflows failed and returned null"); } List<String> disabledAlgorithms = new ArrayList<>(); try { disabledAlgorithms = getDisabledAlgorithms(); } catch (IOException e) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", - disabledAlgorithmsCouldNotBeLoaded); + logger.LogUserAction("The disabled algorithms could not be loaded."); } // Remove any disabled algorithm @@ -93,8 +97,7 @@ public class AlgorithmsApi { allowedAlgorithms.add(algorithm); } } - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", - "Successfully listed " + allowedAlgorithms.size() + " algorithms"); + logger.LogUserAction("Successfully listed " + allowedAlgorithms.size() + " algorithms"); return ResponseEntity.ok(allowedAlgorithms); } @@ -103,8 +106,8 @@ public class AlgorithmsApi { * * @return a list of AlgorithmDTOs or null if something fails */ - public LinkedList<AlgorithmDTO> getExaremeAlgorithms() { - LinkedList<AlgorithmDTO> algorithms = new LinkedList<>(); + public LinkedList<AlgorithmDTO> getExaremeAlgorithms(Logger logger) { + LinkedList<AlgorithmDTO> algorithms; // Get exareme algorithms try { StringBuilder response = new StringBuilder(); @@ -116,12 +119,11 @@ public class AlgorithmsApi { }.getType() ); } catch (IOException e) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "An exception occurred: " + e.getMessage()); + logger.LogUserAction("An exception occurred: " + e.getMessage()); return null; } - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", - "Completed, returned " + algorithms.size() + " algorithms."); + logger.LogUserAction("Completed, returned " + algorithms.size() + " algorithms."); return algorithms; } @@ -130,8 +132,7 @@ public class AlgorithmsApi { * * @return a list of AlgorithmDTOs or null if something fails */ - public LinkedList<AlgorithmDTO> getGalaxyWorkflows() { - + public LinkedList<AlgorithmDTO> getGalaxyWorkflows(Logger logger) { List<Workflow> workflowList; try { // Get all the workflows with the galaxy client @@ -140,8 +141,7 @@ public class AlgorithmsApi { workflowList = new ArrayList<>(workflowsClient.getWorkflows()); } catch (Exception e) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "Error when calling list galaxy workflows: " + e.getMessage()); - + logger.LogUserAction("Error when calling list galaxy workflows: " + e.getMessage()); return null; } @@ -160,33 +160,31 @@ public class AlgorithmsApi { } else { // Something unexpected happened String msgErr = gson.toJson(response.errorBody()); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "Error Response: " + msgErr); + logger.LogUserAction("Error Response: " + msgErr); return null; } } catch (Exception e) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "An exception occurred: " + e.getMessage()); + logger.LogUserAction("An exception occurred: " + e.getMessage()); return null; } } - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "Workflows fetched: " + workflows.size()); + logger.LogUserAction("Workflows fetched: " + workflows.size()); // Convert the workflows to algorithms LinkedList<AlgorithmDTO> algorithms = new LinkedList<>(); for (WorkflowDTO workflow : workflows) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "Converting workflow: " + workflow); + logger.LogUserAction("Converting workflow: " + workflow); algorithms.add(workflow.convertToAlgorithmDTO()); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", - "Converted algorithm: " + algorithms.get(algorithms.size() - 1)); + logger.LogUserAction("Converted algorithm: " + algorithms.get(algorithms.size() - 1)); } - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /algorithms", "Completed!"); + logger.LogUserAction("Completed!"); return algorithms; } - @Autowired - private CustomResourceLoader resourceLoader; + private final CustomResourceLoader resourceLoader; /** * Fetches the disabled algorithms from a .json file @@ -196,13 +194,12 @@ public class AlgorithmsApi { */ List<String> getDisabledAlgorithms() throws IOException { - Resource resource = resourceLoader.getResource("file:/opt/portal/api/disabledAlgorithms.json"); + Resource resource = resourceLoader.getResource(disabledAlgorithmsFilePath); - List<String> response = gson.fromJson(convertInputStreamToString( + return gson.fromJson(convertInputStreamToString( resource.getInputStream()), new TypeToken<List<String>>() { }.getType() ); - return response; } } diff --git a/src/main/java/eu/hbp/mip/controllers/ArticlesApi.java b/src/main/java/eu/hbp/mip/controllers/ArticlesApi.java deleted file mode 100644 index d4eb46e9f3d072255e23be8a37a4e956add16873..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/ArticlesApi.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.controllers; - - -import com.github.slugify.Slugify; -import eu.hbp.mip.model.Article; -import eu.hbp.mip.model.User; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.repositories.ArticleRepository; -import eu.hbp.mip.utils.Logging; -import io.swagger.annotations.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; -import java.io.IOException; -import java.util.Date; -import java.util.Iterator; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - -@RestController -@RequestMapping(value = "/articles", produces = {APPLICATION_JSON_VALUE}) -@Api(value = "/articles", description = "the articles API") -public class ArticlesApi { - - @Autowired - private UserInfo userInfo; - - @Autowired - private ArticleRepository articleRepository; - - @ApiOperation(value = "Get articles", response = Article.class, responseContainer = "List") - @RequestMapping(method = RequestMethod.GET) - public ResponseEntity<Iterable> getArticles( - @ApiParam(value = "Only ask own articles") @RequestParam(value = "own", required = false) Boolean own, - @ApiParam(value = "Only ask results matching status", allowableValues = "draft, published") @RequestParam(value = "status", required = false) String status - ) { - User user = userInfo.getUser(); - Iterable<Article> articles; - Logging.LogUserAction(user.getUsername(), "(GET) /articles", "Loading articles..."); - - if (own != null && own) { - articles = articleRepository.findByCreatedBy(user); - } else { - articles = articleRepository.findByStatusOrCreatedBy("published", user); - } - int articlesSize = 0; - if (status != null) { - for (Iterator<Article> i = articles.iterator(); i.hasNext(); ) { - Article a = i.next(); - if (!status.equals(a.getStatus())) { - i.remove(); - } - articlesSize++; - } - } - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /articles", "Successfully Loaded " + articlesSize + " articles"); - - return ResponseEntity.ok(articles); - } - - - @ApiOperation(value = "Create an article") - @ApiResponses(value = {@ApiResponse(code = 201, message = "Article created")}) - @RequestMapping(method = RequestMethod.POST) - public ResponseEntity<Void> addAnArticle( - @RequestBody @ApiParam(value = "Article to create", required = true) @Valid Article article - ) { - - User user = userInfo.getUser(); - Logging.LogUserAction(user.getUsername(), "(POST) /articles", "Creating article..."); - - article.setCreatedAt(new Date()); - if ("published".equals(article.getStatus())) { - article.setPublishedAt(new Date()); - } - article.setCreatedBy(user); - - long count = 1; - for (int i = 1; count > 0; i++) { - count = articleRepository.countByTitle(article.getTitle()); - - if (count > 0) { - String title = article.getTitle(); - if (i > 1) { - title = title.substring(0, title.length() - 4); - } - article.setTitle(title + " (" + i + ")"); - } - } - - String slug; - try { - slug = new Slugify().slugify(article.getTitle()); - } catch (IOException e) { - slug = ""; - //LOGGER.trace("Cannot slugify title", e); - } - - boolean alreadyExists = true; - for (int i = 1; alreadyExists; i++) { - alreadyExists = articleRepository.exists(slug); - if (alreadyExists) { - if (i > 1) { - slug = slug.substring(0, slug.length() - 2); - } - slug += "-" + i; - } - article.setSlug(slug); - } - articleRepository.save(article); - - Logging.LogUserAction(user.getUsername(), "(POST) /articles", "Successfully created article with id : " + article.getSlug()); - return new ResponseEntity<>(HttpStatus.CREATED); - } - - - @ApiOperation(value = "Get an article", response = Article.class) - @RequestMapping(value = "/{slug}", method = RequestMethod.GET) - public ResponseEntity<Article> getAnArticle( - @ApiParam(value = "slug", required = true) @PathVariable("slug") String slug - ) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /articles/{slug}", "Loading article with id : " + slug); - - User user = userInfo.getUser(); - Article article; - article = articleRepository.findOne(slug); - - if (article == null) { - //LOGGER.warn("Cannot find article : " + slug); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /articles/{slug}", "Article not found"); - return ResponseEntity.badRequest().body(null); - } - - if (!"published".equals(article.getStatus()) && !article.getCreatedBy().getUsername().equals(user.getUsername())) { - return new ResponseEntity<>(HttpStatus.FORBIDDEN); - } - - Logging.LogUserAction(user.getUsername(), "(GET) /articles/{slug}", "Successfully Loaded article with id : " + slug); - - return ResponseEntity.ok(article); - } - - - @ApiOperation(value = "Update an article") - @ApiResponses(value = {@ApiResponse(code = 204, message = "Article updated")}) - @RequestMapping(value = "/{slug}", method = RequestMethod.PUT) - public ResponseEntity<Void> updateAnArticle( - @ApiParam(value = "slug", required = true) @PathVariable("slug") String slug, - @RequestBody @ApiParam(value = "Article to update", required = true) @Valid Article article - ) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(PUT) /articles/{slug}", "Updating article with id : " + slug); - - User user = userInfo.getUser(); - - String author = articleRepository.findOne(slug).getCreatedBy().getUsername(); - - if (!user.getUsername().equals(author)) { - return new ResponseEntity<>(HttpStatus.FORBIDDEN); - } - - String oldTitle = articleRepository.findOne(slug).getTitle(); - - String newTitle = article.getTitle(); - - if (!newTitle.equals(oldTitle)) { - long count = 1; - for (int i = 1; count > 0 && !newTitle.equals(oldTitle); i++) { - newTitle = article.getTitle(); - count = articleRepository.countByTitle(newTitle); - if (count > 0 && !newTitle.equals(oldTitle)) { - if (i > 1) { - newTitle = newTitle.substring(0, newTitle.length() - 4); - } - article.setTitle(newTitle + " (" + i + ")"); - } - } - } - - articleRepository.save(article); - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(PUT) /articles/{slug}", "Successfully pdated article with id : " + slug); - - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - -} diff --git a/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java b/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java new file mode 100644 index 0000000000000000000000000000000000000000..e5d0b04c54b0fd8652f5d284cb8690eaf14d3acf --- /dev/null +++ b/src/main/java/eu/hbp/mip/controllers/ExperimentAPI.java @@ -0,0 +1,109 @@ +package eu.hbp.mip.controllers; + + +import eu.hbp.mip.models.DTOs.ExperimentDTO; +import eu.hbp.mip.services.ActiveUserService; +import eu.hbp.mip.services.ExperimentService; +import eu.hbp.mip.utils.JsonConverters; +import eu.hbp.mip.utils.Logger; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +/* + This api is creating experiments and running it's algorithm on the + exareme or galaxy clients. + */ + +@RestController +@RequestMapping(value = "/experiments", produces = {APPLICATION_JSON_VALUE}) +@Api(value = "/experiments") +public class ExperimentAPI { + + private final ExperimentService experimentService; + private final ActiveUserService activeUserService; + public ExperimentAPI( + ExperimentService experimentService, + ActiveUserService activeUserService + ) { + this.experimentService = experimentService; + this.activeUserService = activeUserService; + } + + @ApiOperation(value = "Get experiments", response = Map.class, responseContainer = "List") + @RequestMapping(method = RequestMethod.GET) + public ResponseEntity<String> getExperiments(Authentication authentication, + @RequestParam(name = "name", required = false) String name, + @RequestParam(name = "algorithm", required = false) String algorithm, + @RequestParam(name = "shared", required = false) Boolean shared, + @RequestParam(name = "viewed", required = false) Boolean viewed, + @RequestParam(name = "includeShared", required = false, defaultValue = "true") boolean includeShared, + @RequestParam(name = "orderBy", required = false, defaultValue = "created") String orderBy, + @RequestParam(name = "descending", required = false, defaultValue = "true") Boolean descending, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size + ) { + Map experiments = experimentService.getExperiments(authentication, + name, + algorithm, + shared, + viewed, + includeShared, + page, + size, + orderBy, + descending, + new Logger(activeUserService.getActiveUser().getUsername(),"(GET) /experiments")); + return new ResponseEntity(experiments, HttpStatus.OK); + } + + + @ApiOperation(value = "Get an experiment", response = ExperimentDTO.class) + @RequestMapping(value = "/{uuid}", method = RequestMethod.GET) + public ResponseEntity<String> getExperiment(Authentication authentication, + @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { + ExperimentDTO experimentDTO = experimentService.getExperiment(authentication, uuid, new Logger(activeUserService.getActiveUser().getUsername(),"(GET) /experiments/{uuid}")); + return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.OK); + } + + + @ApiOperation(value = "Create an experiment", response = ExperimentDTO.class) + @RequestMapping(method = RequestMethod.POST) + public ResponseEntity<String> createExperiment(Authentication authentication, @RequestBody ExperimentDTO experimentDTO) { + experimentDTO = experimentService.createExperiment(authentication, experimentDTO, new Logger(activeUserService.getActiveUser().getUsername(),"(POST) /experiments")); + return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.CREATED); + } + + + @ApiOperation(value = "Update an experiment", response = ExperimentDTO.class) + @RequestMapping(value = "/{uuid}", method = RequestMethod.PATCH) + public ResponseEntity<String> updateExperiment(@RequestBody ExperimentDTO experimentDTO, @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { + experimentDTO = experimentService.updateExperiment(uuid, experimentDTO, new Logger(activeUserService.getActiveUser().getUsername(),"(PATCH) /experiments/{uuid}")); + return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.OK); + } + + + @ApiOperation(value = "Delete an experiment", response = boolean.class) + @RequestMapping(value = "/{uuid}", method = RequestMethod.DELETE) + public ResponseEntity<String> deleteExperiment( + @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { + experimentService.deleteExperiment(uuid, new Logger(activeUserService.getActiveUser().getUsername(), "(DELETE) /experiments/{uuid}")); + return new ResponseEntity<>(HttpStatus.OK); + } + + + @ApiOperation(value = "Create a transient experiment", response = ExperimentDTO.class) + @RequestMapping(value = "/transient", method = RequestMethod.POST) + public ResponseEntity<String> createTransientExperiment(Authentication authentication, @RequestBody ExperimentDTO experimentDTO) { + experimentDTO = experimentService.createTransientExperiment(authentication, experimentDTO, new Logger(activeUserService.getActiveUser().getUsername(), "(POST) /experiments/transient")); + return new ResponseEntity<>(JsonConverters.convertObjectToJsonString(experimentDTO), HttpStatus.OK); + } +} \ No newline at end of file diff --git a/src/main/java/eu/hbp/mip/controllers/ExperimentApi.java b/src/main/java/eu/hbp/mip/controllers/ExperimentApi.java deleted file mode 100644 index a54b93df5facaeaa98c7ad35eef44793ad91e899..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/ExperimentApi.java +++ /dev/null @@ -1,833 +0,0 @@ -package eu.hbp.mip.controllers; - -import com.github.jmchilton.blend4j.galaxy.GalaxyInstance; -import com.github.jmchilton.blend4j.galaxy.GalaxyInstanceFactory; -import com.github.jmchilton.blend4j.galaxy.WorkflowsClient; -import com.github.jmchilton.blend4j.galaxy.beans.Workflow; -import com.github.jmchilton.blend4j.galaxy.beans.WorkflowDetails; -import com.github.jmchilton.blend4j.galaxy.beans.WorkflowInputDefinition; -import com.google.common.collect.Lists; -import com.google.gson.*; -import eu.hbp.mip.controllers.galaxy.retrofit.RetroFitGalaxyClients; -import eu.hbp.mip.controllers.galaxy.retrofit.RetrofitClientInstance; -import eu.hbp.mip.model.*; -import eu.hbp.mip.model.ExperimentExecutionDTO.AlgorithmExecutionDTO.AlgorithmExecutionParamDTO; -import eu.hbp.mip.model.galaxy.ErrorResponse; -import eu.hbp.mip.model.galaxy.GalaxyWorkflowResult; -import eu.hbp.mip.model.galaxy.PostWorkflowToGalaxyDtoResponse; -import eu.hbp.mip.repositories.ExperimentRepository; -import eu.hbp.mip.repositories.ModelRepository; -import eu.hbp.mip.utils.ClaimUtils; -import eu.hbp.mip.utils.HTTPUtil; -import eu.hbp.mip.utils.Logging; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import org.codehaus.jettison.json.JSONException; -import org.codehaus.jettison.json.JSONObject; -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.security.core.Authentication; -import org.springframework.web.bind.annotation.*; -import retrofit2.Call; -import retrofit2.Response; - -import java.io.IOException; -import java.util.*; - -import static java.lang.Thread.sleep; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - -/* - This api is creating experiments and running it's algorithm on the - exareme or galaxy clients. - */ - -@RestController -@RequestMapping(value = "/experiments", produces = {APPLICATION_JSON_VALUE}) -@Api(value = "/experiments") -public class ExperimentApi { - - private static final Gson gson = new Gson(); - - @Autowired - private UserInfo userInfo; - - private static final Gson gsonOnlyExposed = new GsonBuilder().serializeNulls() - .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").excludeFieldsWithoutExposeAnnotation().create(); - - @Value("#{'${services.exareme.queryExaremeUrl}'}") - private String queryExaremeUrl; - - @Value("#{'${services.workflows.workflowUrl}'}") - private String workflowUrl; - - @Value("#{'${services.workflows.jwtSecret}'}") - private String jwtSecret; - - @Value("#{'${services.galaxy.galaxyUrl}'}") - private String galaxyUrl; - - @Value("#{'${services.galaxy.galaxyApiKey}'}") - private String galaxyApiKey; - - // Enable HBP collab authentication (1) or disable it (0). Default is 1 - @Value("#{'${hbp.authentication.enabled:1}'}") - private boolean authenticationIsEnabled; - - @Autowired - private ModelRepository modelRepository; - - @Autowired - private ExperimentRepository experimentRepository; - - @ApiOperation(value = "get an experiment", response = Experiment.class) - @RequestMapping(value = "/{uuid}", method = RequestMethod.GET) - public ResponseEntity<String> getExperiment( - @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { - - Experiment experiment; - UUID experimentUuid; - User user = userInfo.getUser(); - - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{uuid}", "Loading Experiment with uuid : " + uuid); - - try { - experimentUuid = UUID.fromString(uuid); - } catch (IllegalArgumentException iae) { - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{uuid}", "Invalid Experiment UUID."); - return ResponseEntity.badRequest().body("Invalid Experiment UUID"); - } - - experiment = experimentRepository.findOne(experimentUuid); - - if (experiment == null) { - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{uuid}", "Experiment Not found."); - return new ResponseEntity<>("Not found", HttpStatus.NOT_FOUND); - } - - if (!experiment.isShared() && !experiment.getCreatedBy().getUsername().equals(user.getUsername())) { - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{uuid}", "Accessing Experiment is unauthorized."); - return new ResponseEntity<>("You don't have access to the experiment.", HttpStatus.UNAUTHORIZED); - } - - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{uuid}", "Experiment was Loaded with uuid : " + uuid + "."); - - return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); - } - - - @ApiOperation(value = "Create an experiment", response = Experiment.class) - @RequestMapping(value = "/runAlgorithm", method = RequestMethod.POST) - public ResponseEntity<String> runExperiment(Authentication authentication, @RequestBody ExperimentExecutionDTO experimentExecutionDTO) { - User user = userInfo.getUser(); - // Get the type and name of algorithm - String algorithmType = experimentExecutionDTO.getAlgorithms().get(0).getType(); - String algorithmName = experimentExecutionDTO.getAlgorithms().get(0).getName(); - - StringBuilder parametersLogMessage = new StringBuilder(", Parameters:\n"); - for (ExperimentExecutionDTO.AlgorithmExecutionDTO.AlgorithmExecutionParamDTO params : experimentExecutionDTO.getAlgorithms().get(0).getParameters()) { - parametersLogMessage - .append(" ") - .append(params.getLabel()) - .append(" -> ") - .append(params.getValue()) - .append("\n"); - } - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Executing " + algorithmName + parametersLogMessage); - - if (authenticationIsEnabled) { - // Getting the dataset from the experiment parameters - String experimentDatasets = null; - for (ExperimentExecutionDTO.AlgorithmExecutionDTO.AlgorithmExecutionParamDTO parameter : experimentExecutionDTO.getAlgorithms().get(0).getParameters()) { - if (parameter.getLabel().equals("dataset")) { - experimentDatasets = parameter.getValue(); - break; - } - } - - if (experimentDatasets == null || experimentDatasets.equals("")) { - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", - "A dataset should be specified to run an algorithm."); - return ResponseEntity.badRequest().body("Please provide at least one dataset to run the algorithm."); - } - - // --- Validating proper access rights on the datasets --- - if (!ClaimUtils.userHasDatasetsAuthorization(user.getUsername(), authentication.getAuthorities(), experimentDatasets)) { - return ResponseEntity.badRequest().body("You are not authorized to use these datasets."); - } - } - - // Run with the appropriate engine - if (algorithmType.equals("workflow")) { - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Algorithm runs on Galaxy."); - return runGalaxyWorkflow(experimentExecutionDTO); - } else { - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Algorithm runs on Exareme."); - return runExaremeAlgorithm(experimentExecutionDTO); - } - } - - @ApiOperation(value = "Mark an experiment as viewed", response = Experiment.class) - @RequestMapping(value = "/{uuid}/markAsViewed", method = RequestMethod.GET) - public ResponseEntity<String> markExperimentAsViewed( - @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { - - Experiment experiment; - UUID experimentUuid; - User user = userInfo.getUser(); - - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{uuid}/markAsViewed", "Marking as viewed the experiment with uuid : " + uuid + "."); - - try { - experimentUuid = UUID.fromString(uuid); - } catch (IllegalArgumentException iae) { - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{uuid}/markAsViewed", "Invalid Experiment UUID" + uuid + "."); - return ResponseEntity.badRequest().body("Invalid Experiment UUID"); - } - - experiment = experimentRepository.findOne(experimentUuid); - if (!experiment.getCreatedBy().getUsername().equals(user.getUsername())) { - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{uuid}/markAsViewed", "You're not the owner of this experiment"); - return new ResponseEntity<>("You're not the owner of this experiment", HttpStatus.UNAUTHORIZED); - } - experiment.setResultsViewed(true); - experimentRepository.save(experiment); - - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{uuid}/markAsViewed", "Experiment with uuid: " + uuid + " was marked as viewed."); - - return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); - } - - @ApiOperation(value = "Mark an experiment as shared", response = Experiment.class) - @RequestMapping(value = "/{uuid}/markAsShared", method = RequestMethod.GET) - public ResponseEntity<String> markExperimentAsShared( - @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /experiments/{uuid}/markAsShared", "Marking as shared the experiment with uuid : " + uuid + "."); - - return doMarkExperimentAsShared(uuid, true); - } - - @ApiOperation(value = "Mark an experiment as unshared", response = Experiment.class) - @RequestMapping(value = "/{uuid}/markAsUnshared", method = RequestMethod.GET) - public ResponseEntity<String> markExperimentAsUnshared( - @ApiParam(value = "uuid", required = true) @PathVariable("uuid") String uuid) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /experiments/{uuid}/markAs/Unshared", "Marking as unshared the experiment with uuid : " + uuid + "."); - - return doMarkExperimentAsShared(uuid, false); - } - - @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List") - @RequestMapping(method = RequestMethod.GET, params = {"maxResultCount"}) - public ResponseEntity<String> listExperiments( - @ApiParam(value = "maxResultCount") @RequestParam int maxResultCount) { - User user = userInfo.getUser(); - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{maxResultCount}", "Listing experiments with a maximum amount of : " + maxResultCount + "."); - - List<Experiment> expList = doListExperiments(false, null); - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{maxResultCount}", "Successfully listed experiments."); - - return new ResponseEntity<>(gsonOnlyExposed.toJson(expList), HttpStatus.OK); - } - - @ApiOperation(value = "list experiments", response = Experiment.class, responseContainer = "List") - @RequestMapping(method = RequestMethod.GET, params = {"slug", "maxResultCount"}) - public ResponseEntity<String> listExperiments(@ApiParam(value = "slug") @RequestParam("slug") String modelSlug, - @ApiParam(value = "maxResultCount") @RequestParam("maxResultCount") int maxResultCount) { - User user = userInfo.getUser(); - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{slug}/{maxResultCount}", "Listing experiments with a maximum amount of :" + maxResultCount + "with modelSlug : " + modelSlug + "."); - - if (maxResultCount <= 0 || modelSlug == null || "".equals(modelSlug)) { - return new ResponseEntity<>("You must provide at least a slug or a limit of result", - HttpStatus.BAD_REQUEST); - } - - List<Experiment> expList = doListExperiments(false, null); - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{slug}/{maxResultCount}", "Successfully listed my experiments."); - return new ResponseEntity<>(gsonOnlyExposed.toJson(expList), HttpStatus.OK); - } - - @ApiOperation(value = "list my experiments", response = Experiment.class, responseContainer = "List") - @RequestMapping(method = RequestMethod.GET, params = {"mine"}) - public ResponseEntity<String> listMyExperiments(Authentication authentication, @ApiParam(value = "mine") @RequestParam("mine") boolean mine) { - User user = userInfo.getUser(); - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{mine}", "Listing my experiments."); - List<Experiment> expList = doListExperiments(true, null); - Logging.LogUserAction(user.getUsername(), "(GET) /experiments/{mine}", "Successfully listed my experiments."); - return new ResponseEntity<>(gsonOnlyExposed.toJson(expList), HttpStatus.OK); - } - - private List<Experiment> doListExperiments(boolean mine, String modelSlug) { - User user = userInfo.getUser(); - - Iterable<Experiment> myExperiments = experimentRepository.findByCreatedBy(user); - List<Experiment> expList = Lists.newLinkedList(myExperiments); - if (!mine) { - Iterable<Experiment> sharedExperiments = experimentRepository.findByShared(true); - List<Experiment> sharedExpList = Lists.newLinkedList(sharedExperiments); - expList.addAll(sharedExpList); - } - - if (modelSlug != null && !"".equals(modelSlug)) { - for (Iterator<Experiment> it = expList.iterator(); it.hasNext(); ) { - Experiment e = it.next(); - e.setResult(null); - e.setAlgorithms(null); - e.setValidations(null); - if (!e.getModel().getSlug().equals(modelSlug)) { - it.remove(); - } - } - } - return expList; - } - - private ResponseEntity<String> doMarkExperimentAsShared(String uuid, boolean shared) { - Experiment experiment; - UUID experimentUuid; - User user = userInfo.getUser(); - - try { - experimentUuid = UUID.fromString(uuid); - } catch (IllegalArgumentException iae) { - //LOGGER.trace("Invalid UUID", iae); - //LOGGER.warn("An invalid Experiment UUID was received !"); - Logging.LogUserAction(user.getUsername(), "List my experiments", "Listing my experiments."); - return ResponseEntity.badRequest().body("Invalid Experiment UUID"); - } - - experiment = experimentRepository.findOne(experimentUuid); - - if (!experiment.getCreatedBy().getUsername().equals(user.getUsername())) - return new ResponseEntity<>("You're not the owner of this experiment", HttpStatus.UNAUTHORIZED); - - experiment.setShared(shared); - experimentRepository.save(experiment); - - Logging.LogUserAction(user.getUsername(), "Experiment updated (marked as shared)", ""); - - return new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); - } - - /* ------------------------------- EXPERIMENT MODEL METHODS ----------------------------------------------------*/ - - public Experiment createExperiment(ExperimentExecutionDTO experimentExecutionDTO) { - User user = userInfo.getUser(); - - Experiment experiment = new Experiment(); - experiment.setUuid(UUID.randomUUID()); - experiment.setCreatedBy(user); - experiment.setAlgorithms(gson.toJson(experimentExecutionDTO.getAlgorithms())); - Model model = modelRepository.findOne(experimentExecutionDTO.getModel()); - experiment.setModel(model); - experiment.setName(experimentExecutionDTO.getName()); - experimentRepository.save(experiment); - - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " id : " + experiment.getUuid()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " algorithms : " + experiment.getAlgorithms()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " model : " + experiment.getModel().getSlug()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " name : " + experiment.getName()); - return experiment; - } - - private void saveExperiment(Experiment experiment) { - User user = userInfo.getUser(); - - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " id : " + experiment.getUuid()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " algorithms : " + experiment.getAlgorithms()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " model : " + experiment.getModel().getSlug()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " name : " + experiment.getName()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " historyId : " + experiment.getWorkflowHistoryId()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", " status : " + experiment.getWorkflowStatus()); - - experimentRepository.save(experiment); - - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Saved experiment"); - } - - private void finishExperiment(Experiment experiment) { - experiment.setFinished(new Date()); - experimentRepository.save(experiment); - } - - /* -------------------------------------- EXAREME CALLS ---------------------------------------------------------*/ - - /** - * The runExaremeExperiment will POST the algorithm to the exareme client - * - * @param experimentExecutionDTO is the request with the experiment information - * @return the response to be returned - */ - public ResponseEntity<String> runExaremeAlgorithm(ExperimentExecutionDTO experimentExecutionDTO) { - User user = userInfo.getUser(); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Running the algorithm..."); - - Experiment experiment = createExperiment(experimentExecutionDTO); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Created experiment with uuid :" + experiment.getUuid()); - - // Run the 1st algorithm from the list - String algorithmName = experimentExecutionDTO.getAlgorithms().get(0).getName(); - - // Get the parameters - List<ExperimentExecutionDTO.AlgorithmExecutionDTO.AlgorithmExecutionParamDTO> algorithmParameters - = experimentExecutionDTO.getAlgorithms().get(0).getParameters(); - - String body = gson.toJson(algorithmParameters); - String url = queryExaremeUrl + "/" + algorithmName; - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "url: " + url + ", body: " + body); - - ResponseEntity<String> response = new ResponseEntity<>(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", - "Completed, returning: " + experiment.toString()); - - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", - "Starting exareme execution thread"); - new Thread(() -> { - // ATTENTION: Inside the Thread only LogExperimentAction should be used, not LogUserAction! - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Thread named :" + Thread.currentThread().getName() + " with id :" + Thread.currentThread().getId() + " started!"); - - try { - StringBuilder results = new StringBuilder(); - int code = HTTPUtil.sendPost(url, body, results); - - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Algorithm finished with code: " + code); - - // Results are stored in the experiment object - experiment.setResult("[" + results.toString() + "]"); - experiment.setHasError(code >= 400); - experiment.setHasServerError(code >= 500); - } catch (Exception e) { - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "There was an exception: " + e.getMessage()); - - experiment.setHasError(true); - experiment.setHasServerError(true); - experiment.setResult(e.getMessage()); - } - - finishExperiment(experiment); - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Finished the experiment: " + experiment.toString()); - }).start(); - - return response; - } - - /* --------------------------------------- GALAXY CALLS ---------------------------------------------------------*/ - - - /** - * The runWorkflow will POST the algorithm to the galaxy client - * - * @param experimentExecutionDTO is the request with the experiment information - * @return the response to be returned - */ - public ResponseEntity<String> runGalaxyWorkflow(ExperimentExecutionDTO experimentExecutionDTO) { - User user = userInfo.getUser(); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Running a workflow..."); - - Experiment experiment = createExperiment(experimentExecutionDTO); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Created experiment with uuid :" + experiment.getUuid()); - - - // Run the 1st algorithm from the list - String workflowId = experimentExecutionDTO.getAlgorithms().get(0).getName(); - - // Get the parameters - List<AlgorithmExecutionParamDTO> algorithmParameters - = experimentExecutionDTO.getAlgorithms().get(0).getParameters(); - - // Convert the parameters to workflow parameters - HashMap<String, String> algorithmParamsIncludingEmpty = new HashMap<>(); - if (algorithmParameters != null) { - for (AlgorithmExecutionParamDTO param : algorithmParameters) { - algorithmParamsIncludingEmpty.put(param.getName(), param.getValue()); - } - } - - // Get all the algorithm parameters because the frontend provides only the non-null - final GalaxyInstance instance = GalaxyInstanceFactory.get(galaxyUrl, galaxyApiKey); - final WorkflowsClient workflowsClient = instance.getWorkflowsClient(); - Workflow workflow = null; - for (Workflow curWorkflow : workflowsClient.getWorkflows()) { - if (curWorkflow.getId().equals(workflowId)) { - workflow = curWorkflow; - break; - } - } - if (workflow == null) { - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", - "Could not find algorithm code: " + workflowId); - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(new ErrorResponse("Could not find galaxy algorithm.").toString()); - } - final WorkflowDetails workflowDetails = workflowsClient.showWorkflow(workflow.getId()); - for (Map.Entry<String, WorkflowInputDefinition> workflowParameter : workflowDetails.getInputs().entrySet()) { - if (!(algorithmParamsIncludingEmpty.containsKey(workflowParameter.getValue().getUuid()))) { - algorithmParamsIncludingEmpty.put(workflowParameter.getValue().getUuid(), ""); - } - } - - // Create the body of the request - HashMap<String, HashMap<String, String>> requestBody = new HashMap<>(); - requestBody.put("inputs", algorithmParamsIncludingEmpty); - JsonObject requestBodyJson = new JsonParser().parse(gson.toJson(requestBody)).getAsJsonObject(); - - // Create the request client - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Running Galaxy workflow with id: " + workflow.getId()); - - // Call Galaxy to run the workflow - Call<PostWorkflowToGalaxyDtoResponse> call = service.postWorkflowToGalaxy(workflow.getId(), galaxyApiKey, requestBodyJson); - try { - Response<PostWorkflowToGalaxyDtoResponse> response = call.execute(); - - if (response.code() == 200) { // Call succeeded - String responseBody = gson.toJson(response.body()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Response: " + responseBody); - - String historyId = (String) new JSONObject(responseBody).get("history_id"); - experiment.setWorkflowHistoryId(historyId); - experiment.setWorkflowStatus("running"); - experiment.setHasError(false); - experiment.setHasServerError(response.code() >= 500); - - } else { // Something unexpected happened - String msgErr = gson.toJson(response.errorBody()); - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Error Response: " + msgErr); - - // Values are read from streams. - JSONObject jObjectError = new JSONObject(msgErr); - String errMsg = jObjectError.get("err_msg").toString(); - - experiment.setResult("[" + new ErrorResponse(errMsg).toString() + "]"); - experiment.setHasError(response.code() >= 400); - experiment.setHasServerError(response.code() >= 500); - } - - } catch (Exception e) { - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "An exception occurred: " + e.getMessage()); - experiment.setHasError(true); - experiment.setHasServerError(true); - experiment.setResult(e.getMessage()); - } - saveExperiment(experiment); - - // Start the process of fetching the status - updateWorkflowExperiment(experiment); - - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Run workflow completed!"); - - return new ResponseEntity(gsonOnlyExposed.toJson(experiment.jsonify()), HttpStatus.OK); - } - - - /** - * This method creates a thread that will fetch the workflow result when it is ready - * - * @param experiment will be used to fetch it's workflow status, it should have the workflowHistoryId initialized - * and the result should not already be fetched - * @return nothing, just updates the experiment - */ - public void updateWorkflowExperiment(Experiment experiment) { - User user = userInfo.getUser(); - - if (experiment == null) { - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "The experiment does not exist."); - return; - } - - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", - " Experiment id : " + experiment.getUuid()); - if (experiment.getWorkflowHistoryId() == null) { - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "History Id does not exist."); - return; - } - - Logging.LogUserAction(user.getUsername(), "(POST) /experiments/runAlgorithm", "Starting Thread..."); - new Thread(() -> { - while (true) { - // ATTENTION: Inside the Thread only LogExperimentAction should be used, not LogExperimentAction! - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Thread is running..."); - - try { - sleep(2000); - } catch (InterruptedException e) { - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Sleep was disrupted: " + e.getMessage()); - } - - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Fetching status for experiment Id: " + experiment.getUuid()); - - String state = getWorkflowStatus(experiment); - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "State is: " + state); - - switch (state) { - case "running": - // Do nothing, when the experiment is created the status is set to running - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Workflow is still running."); - break; - - case "completed": - // Get only the job result that is visible - List<GalaxyWorkflowResult> workflowJobsResults = getWorkflowResults(experiment); - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Results are: " + workflowJobsResults.toString()); - - boolean resultFound = false; - for (GalaxyWorkflowResult jobResult : workflowJobsResults) { - if (jobResult.getVisible()) { - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Visible result are: " + jobResult.getId()); - - String result = getWorkflowResultBody(experiment, jobResult.getId()); - - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Result: " + result); - if (result == null) { - experiment.setHasError(true); - experiment.setHasServerError(true); - } - experiment.setResult(result); - experiment.setWorkflowStatus("completed"); - resultFound = true; - } - } - - if (!resultFound) { // If there is no visible result - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "No visible result"); - experiment.setResult("[" + new ErrorResponse("The workflow has no visible result.").toString() + "]"); - experiment.setHasError(true); - experiment.setHasServerError(true); - } - - finishExperiment(experiment); - break; - - case "error": - // Get the job result that failed - workflowJobsResults = getWorkflowResults(experiment); - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Error results are: " + workflowJobsResults.toString()); - - boolean failedJobFound = false; - for (GalaxyWorkflowResult jobResult : workflowJobsResults) { - if (jobResult.getState().equals("error")) { - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Failed job is: " + jobResult.getId()); - - String result = getWorkflowJobError(jobResult.getId(), experiment); - - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Job result: " + result); - if (result == null) { - experiment.setHasError(true); - experiment.setHasServerError(true); - } - experiment.setResult("[" + result + "]"); - experiment.setWorkflowStatus("error"); - failedJobFound = true; - } - } - - if (!failedJobFound) { // If there is no visible failed job - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "No failed result"); - experiment.setResult("[" + new ErrorResponse("The workflow has no failed result.").toString() + "]"); - experiment.setHasError(true); - experiment.setHasServerError(true); - } - finishExperiment(experiment); - break; - - default: // InternalError or unexpected result - experiment.setResult("[" + new ErrorResponse("An unexpected error occurred.").toString() + "]"); - experiment.setHasError(true); - experiment.setHasServerError(true); - finishExperiment(experiment); - break; - } - - // If result exists return - if (experiment.getResult() != null) { - Logging.LogExperimentAction(experiment.getName(), experiment.getUuid(), "Result exists: " + experiment.getResult()); - return; - } - } - }).start(); - } - - - /** - * @param experiment The experiment of the workflow - * @return "running" -> When the workflow is still running - * "internalError" -> When an exception or a bad request occurred - * "error" -> When the workflow produced an error - * "completed" -> When the workflow completed successfully - */ - public String getWorkflowStatus(Experiment experiment) { - String historyId = experiment.getWorkflowHistoryId(); - String experimentName = experiment.getName(); - UUID experimentId = experiment.getUuid(); - - // ATTENTION: This function is used from a Thread. Only LogExperimentAction should be used, not LogUserAction! - Logging.LogExperimentAction(experimentName, experimentId, " History Id : " + historyId); - - // Create the request client - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - Call<Object> call = service.getWorkflowStatusFromGalaxy(historyId, galaxyApiKey); - - String result = null; - try { - Response<Object> response = call.execute(); - if (response.code() >= 400) { - Logging.LogExperimentAction(experimentName, experimentId, " Response code: " - + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); - return "internalError"; - } - result = new Gson().toJson(response.body()); - Logging.LogExperimentAction(experimentName, experimentId, " Result: " + result); - - } catch (IOException e) { - Logging.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); - return "internalError"; - } - - String state = null; - try { - JSONObject resultJson = new JSONObject(result); - state = resultJson.getString("state"); - } catch (JSONException e) { - Logging.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); - return "internalError"; - } - - Logging.LogExperimentAction(experimentName, experimentId, " Completed!"); - switch (state) { - case "ok": - return "completed"; - case "error": - return "error"; - case "running": - case "new": - case "waiting": - case "queued": - return "running"; - default: - return "internalError"; - } - } - - /** - * @param experiment The experiment of the workflow - * @return a List<GalaxyWorkflowResult> or null when an error occurred - */ - public List<GalaxyWorkflowResult> getWorkflowResults(Experiment experiment) { - - String historyId = experiment.getWorkflowHistoryId(); - String experimentName = experiment.getName(); - UUID experimentId = experiment.getUuid(); - Logging.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); - - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - Call<List<GalaxyWorkflowResult>> call = service.getWorkflowResultsFromGalaxy(historyId, galaxyApiKey); - - List<GalaxyWorkflowResult> getGalaxyWorkflowResultList = null; - try { - Response<List<GalaxyWorkflowResult>> response = call.execute(); - if (response.code() >= 400) { - Logging.LogExperimentAction(experimentName, experimentId, " Response code: " - + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); - return null; - } - getGalaxyWorkflowResultList = response.body(); - Logging.LogExperimentAction(experimentName, experimentId, " Result: " + response.body()); - - } catch (IOException e) { - Logging.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); - return null; - } - - Logging.LogExperimentAction(experimentName, experimentId, " Completed!"); - return getGalaxyWorkflowResultList; - - } - - /** - * @param experiment The experiment of the workflow - * @param contentId the id of the job result that we want - * @return the result of the specific workflow job, null if there was an error - */ - public String getWorkflowResultBody(Experiment experiment, String contentId) { - - String historyId = experiment.getWorkflowHistoryId(); - String experimentName = experiment.getName(); - UUID experimentId = experiment.getUuid(); - - Logging.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); - - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - Call<Object> call = - service.getWorkflowResultsBodyFromGalaxy(historyId, contentId, galaxyApiKey); - - String resultJson = null; - try { - Response<Object> response = call.execute(); - if (response.code() >= 400) { - Logging.LogExperimentAction(experimentName, experimentId, " Response code: " - + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); - return null; - } - resultJson = new Gson().toJson(response.body()); - Logging.LogExperimentAction(experimentName, experimentId, " Result: " + resultJson); - - } catch (IOException e) { - Logging.LogExperimentAction(experimentName, experimentId, - " An exception happened: " + e.getMessage()); - return null; - } - - Logging.LogExperimentAction(experimentName, experimentId, " Completed!"); - return resultJson; - } - - - /** - * @param jobId the id of the workflow job that failed - * @return the error that was produced or null if an error occurred - */ - public String getWorkflowJobError(String jobId, Experiment experiment) { - String experimentName = experiment.getName(); - UUID experimentId = experiment.getUuid(); - - Logging.LogExperimentAction(experimentName, experimentId, " jobId : " + jobId); - RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); - Call<Object> callError = service.getErrorMessageOfWorkflowFromGalaxy(jobId, galaxyApiKey); - - String fullError = null; - String returnError = null; - try { - Response<Object> response = callError.execute(); - if (response.code() >= 400) { - Logging.LogExperimentAction(experimentName, experimentId, "Response code: " - + response.code() + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); - return null; - } - - // Parsing the stderr of the job that failed - String jsonString = new Gson().toJson(response.body()); - JsonElement jsonElement = new JsonParser().parse(jsonString); - JsonObject rootObject = jsonElement.getAsJsonObject(); - fullError = rootObject.get("stderr").getAsString(); - Logging.LogExperimentAction(experimentName, experimentId, "Error: " + fullError); - - String[] arrOfStr = fullError.split("ValueError", 0); - String specError = arrOfStr[arrOfStr.length - 1]; - returnError = specError.substring(1); - Logging.LogExperimentAction(experimentName, experimentId, "Parsed Error: " + returnError); - - } catch (IOException e) { - Logging.LogExperimentAction(experimentName, experimentId, "Exception: " + e.getMessage()); - return null; - } - - Logging.LogExperimentAction(experimentName, experimentId, "Completed successfully!"); - - return returnError; - } - - -} diff --git a/src/main/java/eu/hbp/mip/controllers/FilesAPI.java b/src/main/java/eu/hbp/mip/controllers/FilesAPI.java deleted file mode 100644 index 69e7f3ba94702ee9b5465920d3234ca4dcac0248..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/FilesAPI.java +++ /dev/null @@ -1,47 +0,0 @@ -package eu.hbp.mip.controllers; - -import eu.hbp.mip.model.User; -import eu.hbp.mip.model.UserInfo; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; -import eu.hbp.mip.utils.Logging; - -/** - * Created by mirco on 08.05.17. - */ - -@RestController -@RequestMapping(value = "/protected") -@Api(value = "/protected", description = "the protected files API") -public class FilesAPI { - - - @Autowired - private UserInfo userInfo; - - @ApiOperation(value = "Get protected files") - @RequestMapping(value = "/{filename:.+}", method = RequestMethod.GET) - public ResponseEntity<Void> getProtectedFile( - @ApiParam(value = "filename", required = true) @PathVariable("filename") String filename - ) { - User user = userInfo.getUser(); - Logging.LogUserAction(user.getUsername(), "(GET) /protected/{filename:.+}", "Loading protected file with filename : " + filename); - - String filepath = "/protected/" + filename; - Logging.LogUserAction(user.getUsername(), "(GET) /protected/{filename:.+}" + filepath, "Downloaded protected file"); - - HttpHeaders headers = new HttpHeaders(); - headers.add("X-Accel-Redirect", filepath); - - return new ResponseEntity<>(headers, HttpStatus.OK); - } -} diff --git a/src/main/java/eu/hbp/mip/controllers/MiningApi.java b/src/main/java/eu/hbp/mip/controllers/MiningApi.java deleted file mode 100644 index 6a198cc0d4571c58b1ff424e590bc418893a39f1..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/MiningApi.java +++ /dev/null @@ -1,110 +0,0 @@ -package eu.hbp.mip.controllers; - -import eu.hbp.mip.utils.HTTPUtil; - -import com.google.gson.Gson; - -import eu.hbp.mip.model.UserInfo; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; - -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.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import eu.hbp.mip.utils.Logging; - - -import java.util.*; -import java.io.IOException; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - -/** - * Created by mirco on 06.01.17. - */ -@RestController -@RequestMapping(value = "/mining", produces = {APPLICATION_JSON_VALUE}) -@Api(value = "/mining", description = "the mining API") -public class MiningApi { - - private static final Gson gson = new Gson(); - - @Autowired - private UserInfo userInfo; - - @Value("#{'${services.exareme.queryExaremeUrl:http://localhost:9090/mining/query}'}") - public String queryExaremeUrl; - - @ApiOperation(value = "Create a histogram on Exareme", response = String.class) - @RequestMapping(value = "/histograms", method = RequestMethod.POST) - public ResponseEntity runExaremeHistograms(@RequestBody List<HashMap<String, String>> queryList) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /mining/histogram", "Executing histogram..."); - - String query = gson.toJson(queryList); - String url = queryExaremeUrl + "/" + "MULTIPLE_HISTOGRAMS"; - - try { - StringBuilder results = new StringBuilder(); - int code = HTTPUtil.sendPost(url, query, results); - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /mining/histogram", "Executed histogram with result :" + results.toString()); - return ResponseEntity.ok(gson.toJson(results.toString())); - } catch (IOException e) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /mining/histogram", "Histogram algorithm was not found"); - return new ResponseEntity<>("Not found", HttpStatus.NOT_FOUND); - } - } - - @ApiOperation(value = "Create a descriptive statistic on Exareme", response = String.class) - @RequestMapping(value = "/descriptive_stats", method = RequestMethod.POST) - public ResponseEntity runExaremeDescriptiveStats(@RequestBody List<HashMap<String, String>> queryList) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /experiments/descriptive_stats", "Executing Exareme descriptive stats..."); - - String query = gson.toJson(queryList); - String url = queryExaremeUrl + "/" + "DESCRIPTIVE_STATS"; - - try { - StringBuilder results = new StringBuilder(); - int code = HTTPUtil.sendPost(url, query, results); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /experiments/descriptive_stats", "Executed descriptive stats with result : " + results.toString()); - return ResponseEntity.ok(gson.toJson(results.toString())); - } catch (IOException e) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /experiments/descriptive_stats", "Descriptive stats algorithm was not found"); - return new ResponseEntity<>("Not found", HttpStatus.NOT_FOUND); - } - } - - @ApiOperation(value = "Create a descriptive statistic on Exareme", response = String.class) - @RequestMapping(value = "/descriptive_stats_v2", method = RequestMethod.POST) - public ResponseEntity runExaremeDescriptiveStatsV2(@RequestBody List<HashMap<String, String>> queryList) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /experiments/descriptive_stats_v2", "Executing an Exareme descriptive stats v2"); - - String query = gson.toJson(queryList); - String url = queryExaremeUrl + "/" + "DESCRIPTIVE_STATS_v2"; - - try { - StringBuilder results = new StringBuilder(); - int code = HTTPUtil.sendPost(url, query, results); - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /experiments/descriptive_stats_v2", "Successfully executed descriptive stats v2 with results : " + results.toString()); - return ResponseEntity.ok(gson.toJson(results.toString())); - } catch (IOException e) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /experiments/descriptive_stats_v2", "Descriptive stats v2 algorithm was not found"); - return new ResponseEntity<>("Not found", HttpStatus.NOT_FOUND); - } - } - - @ApiOperation(value = "Check if a formula is valid", response = String.class) - @RequestMapping(value = "/checkFormula", method = RequestMethod.POST) - public ResponseEntity checkFormulaValidity(String formula) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /experiments/checkFormula", "Executing checkFormula ..."); - - return ResponseEntity.ok(""); - } -} diff --git a/src/main/java/eu/hbp/mip/controllers/ModelsApi.java b/src/main/java/eu/hbp/mip/controllers/ModelsApi.java deleted file mode 100644 index 6f013ee336815bbb25514b37cdb764fe7710e8fd..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/ModelsApi.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.controllers; - -import com.github.slugify.Slugify; -import eu.hbp.mip.model.Model; -import eu.hbp.mip.model.User; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.model.Variable; -import eu.hbp.mip.repositories.*; -import io.swagger.annotations.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import eu.hbp.mip.utils.Logging; - -import java.io.IOException; -import java.util.*; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - -@RestController -@RequestMapping(value = "/models", produces = {APPLICATION_JSON_VALUE}) -@Api(value = "/models", description = "the models API") -public class ModelsApi { - - - @Autowired - private UserInfo userInfo; - - @Autowired - private DatasetRepository datasetRepository; - - @Autowired - private ModelRepository modelRepository; - - @Autowired - private QueryRepository queryRepository; - - @Autowired - private ConfigRepository configRepository; - - @Autowired - private VariableRepository variableRepository; - - @ApiOperation(value = "get models", response = Model.class, responseContainer = "List") - @RequestMapping(method = RequestMethod.GET) - public ResponseEntity<List> getModels( - @ApiParam(value = "Only ask own models") @RequestParam(value = "own", required = false) Boolean own, - @ApiParam(value = "Only ask published models") @RequestParam(value = "valid", required = false) Boolean valid - ) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /models", "Loading models ..."); - - User user = userInfo.getUser(); - - Iterable<Model> models; - if (own != null && own) { - models = modelRepository.findByCreatedByOrderByCreatedAt(user); - } else { - models = modelRepository.findByValidOrCreatedByOrderByCreatedAt(true, user); - } - - if (valid != null && models != null) { - for (Iterator<Model> i = models.iterator(); i.hasNext(); ) { - Model m = i.next(); - if (valid != m.getValid()) { - i.remove(); - } - } - } - - List<Object> modelsList = new LinkedList<>(); - models = models != null ? models : new LinkedList<>(); - for (Model m : models) { - m.setDataset(datasetRepository.findOne(m.getDataset().getCode())); - modelsList.add(m); - } - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /models", "Successfully loaded " + modelsList.size() + " models."); - - return ResponseEntity.ok(modelsList); - } - - - @ApiOperation(value = "Create a model", response = Model.class) - @ApiResponses(value = {@ApiResponse(code = 201, message = "Model created")}) - @RequestMapping(method = RequestMethod.POST) - public ResponseEntity<Model> addAModel( - @RequestBody @ApiParam(value = "Model to create", required = true) Model model - ) { - User user = userInfo.getUser(); - Logging.LogUserAction(user.getUsername(), "(POST) /models", "Creating a model"); - - model.setTitle(model.getConfig().getTitle().get("text")); - model.setCreatedBy(user); - model.setCreatedAt(new Date()); - if (model.getValid() == null) { - model.setValid(false); - } - - ensureTitleUniqueness(model); - ensureSlugUniqueness(model); - - Map<String, String> map = new HashMap<>(model.getConfig().getTitle()); - map.put("text", model.getTitle()); - model.getConfig().setTitle(map); - - saveVariables(model.getQuery().getVariables()); - saveVariables(model.getQuery().getCovariables()); - saveVariables(model.getQuery().getGrouping()); - saveVariables(model.getQuery().getTrainingDatasets()); - - configRepository.save(model.getConfig()); - queryRepository.save(model.getQuery()); - if (model.getDataset() != null) { - datasetRepository.save(model.getDataset()); - } - modelRepository.save(model); - - Logging.LogUserAction(user.getUsername(), "(POST) /models", "Created model with id : " + model.getSlug() + ", model.config and model.query"); - - return ResponseEntity.status(HttpStatus.CREATED).body(model); - } - - private void saveVariables(@RequestBody @ApiParam(value = "Model to create", required = true) List<Variable> variables) { - for (Variable var : variables) { - variableRepository.save(var); - } - } - - private void ensureSlugUniqueness(@RequestBody @ApiParam(value = "Model to create", required = true) Model model) { - String slug = createSlug(model.getTitle()); - boolean slugExists = true; - for (int i = 1; slugExists; i++) { - slugExists = modelRepository.exists(slug); - if (slugExists) { - if (i > 1) { - slug = slug.substring(0, slug.length() - 2); - } - slug += "-" + i; - } - model.setSlug(slug); - } - } - - private String createSlug(@RequestBody @ApiParam(value = "Model to create", required = true) String title) { - String slug; - try { - slug = new Slugify().slugify(title); - } catch (IOException e) { - slug = ""; // Should never happen - //LOGGER.trace("Cannot slugify title", e); - } - return slug; - } - - private void ensureTitleUniqueness(@RequestBody @ApiParam(value = "Model to create", required = true) Model model) { - boolean titleExists = true; - for (int i = 1; titleExists; i++) { - String title = model.getTitle(); - titleExists = modelRepository.countByTitle(title) > 0; - if (titleExists) { - if (i > 1) { - title = title.substring(0, title.length() - 4); - } - model.setTitle(title + " (" + i + ")"); - } - } - } - - @ApiOperation(value = "Get a model", response = Model.class) - @RequestMapping(value = "/{slug}", method = RequestMethod.GET) - public ResponseEntity<Model> getAModel( - @ApiParam(value = "slug", required = true) @PathVariable("slug") String slug - ) { - - User user = userInfo.getUser(); - - Logging.LogUserAction(user.getUsername(), "(GET) /models/{slug}", "Loading model with id : " + slug); - - Model model = modelRepository.findOne(slug); - if (model == null) { - //LOGGER.warn("Cannot find model : " + slug); - Logging.LogUserAction(user.getUsername(), "(GET) /models/{slug}", "Model was not found"); - return ResponseEntity.badRequest().body(null); - } - - if (!model.getValid() && !model.getCreatedBy().getUsername().equals(user.getUsername())) { - Logging.LogUserAction(user.getUsername(), "(GET) /models/{slug}", "You are not authorized to retrieve models. "); - return new ResponseEntity<>(HttpStatus.FORBIDDEN); - } - - List<String> yAxisVars = configRepository.findOne(model.getConfig().getId()).getyAxisVariables(); - Collection<String> yAxisVarsColl = new LinkedHashSet<>(yAxisVars); - model.getConfig().setyAxisVariables(new LinkedList<>(yAxisVarsColl)); - - Logging.LogUserAction(user.getUsername(), "(GET) /models/{slug}", "Loaded model with id : " + slug); - return ResponseEntity.ok(model); - } - - - @ApiOperation(value = "Update a model", response = Void.class) - @ApiResponses(value = {@ApiResponse(code = 204, message = "Model updated")}) - @RequestMapping(value = "/{slug}", method = RequestMethod.PUT) - public ResponseEntity<Void> updateAModel( - @ApiParam(value = "slug", required = true) @PathVariable("slug") String slug, - @RequestBody @ApiParam(value = "Model to update", required = true) Model model - ) { - User user = userInfo.getUser(); - Logging.LogUserAction(user.getUsername(), "(PUT) /models/{slug}", "Updating model with id : " + slug); - Model oldModel = modelRepository.findOne(slug); - - if (!user.getUsername().equals(oldModel.getCreatedBy().getUsername())) { - return new ResponseEntity<>(HttpStatus.FORBIDDEN); - } - - model.setTitle(model.getConfig().getTitle().get("text")); - - String oldTitle = oldModel.getTitle(); - String newTitle = model.getTitle(); - - // If title has been updated, ensure it is unique - if (!newTitle.equals(oldTitle)) { - boolean newTitleExists = true; - for (int i = 1; newTitleExists && !newTitle.equals(oldTitle); i++) { - newTitle = model.getTitle(); - newTitleExists = modelRepository.countByTitle(newTitle) > 0; - if (newTitleExists && !newTitle.equals(oldTitle)) { - if (i > 1) { - newTitle = newTitle.substring(0, newTitle.length() - 4); - } - model.setTitle(newTitle + " (" + i + ")"); - } - } - } - - Map<String, String> map = new HashMap<>(model.getConfig().getTitle()); - map.put("text", model.getTitle()); - model.getConfig().setTitle(map); - - saveVariables(model.getQuery().getVariables()); - saveVariables(model.getQuery().getCovariables()); - saveVariables(model.getQuery().getGrouping()); - saveVariables(model.getQuery().getTrainingDatasets()); - - configRepository.save(model.getConfig()); - queryRepository.save(model.getQuery()); - datasetRepository.save(model.getDataset()); - modelRepository.save(model); - - Logging.LogUserAction(user.getUsername(), "(PUT) /models/{slug}", "Updated model and saved/updated model.config and model.query"); - - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - -} diff --git a/src/main/java/eu/hbp/mip/controllers/PathologiesApi.java b/src/main/java/eu/hbp/mip/controllers/PathologiesAPI.java similarity index 58% rename from src/main/java/eu/hbp/mip/controllers/PathologiesApi.java rename to src/main/java/eu/hbp/mip/controllers/PathologiesAPI.java index 77916981465827ae4e0806366663a16c7ad1e70b..5e9a9d34452f81ff5293bccaf3a5a5aca0624057 100644 --- a/src/main/java/eu/hbp/mip/controllers/PathologiesApi.java +++ b/src/main/java/eu/hbp/mip/controllers/PathologiesAPI.java @@ -1,19 +1,15 @@ -/** - * Created by mirco on 04.12.15. - */ - package eu.hbp.mip.controllers; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import eu.hbp.mip.model.PathologyDTO; -import eu.hbp.mip.model.UserInfo; +import eu.hbp.mip.models.DTOs.PathologyDTO; +import eu.hbp.mip.services.ActiveUserService; import eu.hbp.mip.utils.ClaimUtils; import eu.hbp.mip.utils.CustomResourceLoader; +import eu.hbp.mip.utils.Exceptions.BadRequestException; import eu.hbp.mip.utils.InputStreamConverter; -import eu.hbp.mip.utils.Logging; +import eu.hbp.mip.utils.Logger; import io.swagger.annotations.Api; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; @@ -25,49 +21,55 @@ import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.util.List; -import static eu.hbp.mip.utils.ErrorMessages.pathologiesCouldNotBeLoaded; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RestController @RequestMapping(value = "/pathologies", produces = {APPLICATION_JSON_VALUE}) @Api(value = "/pathologies") -public class PathologiesApi { +public class PathologiesAPI { private static final Gson gson = new Gson(); - @Autowired - private UserInfo userInfo; // Enable HBP collab authentication (1) or disable it (0). Default is 1 - @Value("#{'${hbp.authentication.enabled:1}'}") + @Value("#{'${authentication.enabled}'}") private boolean authenticationIsEnabled; - @Autowired - private CustomResourceLoader resourceLoader; + @Value("#{'${files.pathologies_json}'}") + private String pathologiesFilePath; + + private final ActiveUserService activeUserService; + + private final CustomResourceLoader resourceLoader; + + public PathologiesAPI(ActiveUserService activeUserService, CustomResourceLoader resourceLoader) { + this.activeUserService = activeUserService; + this.resourceLoader = resourceLoader; + } @RequestMapping(name = "/pathologies", method = RequestMethod.GET) public ResponseEntity<String> getPathologies(Authentication authentication) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /pathologies", "Loading pathologies ..."); + Logger logger = new Logger(activeUserService.getActiveUser().getUsername(), "(GET) /pathologies"); + logger.LogUserAction("Loading pathologies ..."); // Load pathologies from file - Resource resource = resourceLoader.getResource("file:/opt/portal/api/pathologies.json"); + Resource resource = resourceLoader.getResource(pathologiesFilePath); List<PathologyDTO> allPathologies; try { allPathologies = gson.fromJson(InputStreamConverter.convertInputStreamToString(resource.getInputStream()), new TypeToken<List<PathologyDTO>>() { }.getType()); } catch (IOException e) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /pathologies", "Unable to load pathologies"); - return ResponseEntity.badRequest().body(pathologiesCouldNotBeLoaded); + logger.LogUserAction("Unable to load pathologies"); + throw new BadRequestException("The pathologies could not be loaded."); } // If authentication is disabled return everything if (!authenticationIsEnabled) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /pathologies", "Successfully loaded " + allPathologies.size() + " pathologies"); + logger.LogUserAction("Successfully loaded " + allPathologies.size() + " pathologies"); return ResponseEntity.ok().body(gson.toJson(allPathologies)); } - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /pathologies", "Successfully loaded all authorized pathologies"); - return ResponseEntity.ok().body(ClaimUtils.getAuthorizedPathologies( - userInfo.getUser().getUsername(), authentication.getAuthorities(), allPathologies)); + logger.LogUserAction("Successfully loaded all authorized pathologies"); + return ResponseEntity.ok().body(ClaimUtils.getAuthorizedPathologies(logger, authentication, allPathologies)); } } diff --git a/src/main/java/eu/hbp/mip/controllers/SecurityApi.java b/src/main/java/eu/hbp/mip/controllers/SecurityApi.java deleted file mode 100644 index 4e412aea08da5612f47d60baafd4bac791f2fc6e..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/SecurityApi.java +++ /dev/null @@ -1,120 +0,0 @@ -package eu.hbp.mip.controllers; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import eu.hbp.mip.configuration.SecurityConfiguration; -import eu.hbp.mip.model.User; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.repositories.UserRepository; -import eu.hbp.mip.utils.Logging; -import io.swagger.annotations.ApiParam; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.security.Principal; -import java.util.Base64; - -@RestController -public class SecurityApi { - - private static final Gson gson = new Gson(); - - @Autowired - private UserInfo userInfo; - - @Autowired - private UserRepository userRepository; - - @Autowired - private SecurityConfiguration securityConfiguration; - - @RequestMapping(path = "/user", method = RequestMethod.GET) - public Object user(Principal principal, HttpServletResponse response) { - ObjectMapper mapper = new ObjectMapper(); - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /user", "Loading user : " + userInfo.getUser().getUsername()); - try { - String userJSON = mapper.writeValueAsString(userInfo.getUser()); - Cookie cookie = new Cookie("user", URLEncoder.encode(userJSON, "UTF-8")); - cookie.setSecure(true); - cookie.setPath("/"); - response.addCookie(cookie); - } catch (JsonProcessingException | UnsupportedEncodingException e) { - //LOGGER.trace("Cannot read user json", e); - } - - if (!securityConfiguration.isAuthentication()) { - if (userInfo.isFakeAuth()) { - response.setStatus(401); - } - String principalJson = "{\"principal\": \"anonymous\", \"name\": \"anonymous\", \"userAuthentication\": {" - + "\"details\": {\"preferred_username\": \"anonymous\"}}}"; - return new Gson().fromJson(principalJson, Object.class); - } - - return principal; - } - - @RequestMapping(path = "/user", method = RequestMethod.POST) - public ResponseEntity<Void> postUser( - @ApiParam(value = "Has the user agreed on the NDA") @RequestParam(value = "agreeNDA") Boolean agreeNDA) { - User user = userInfo.getUser(); - if (user != null) { - user.setAgreeNDA(agreeNDA); - userRepository.save(user); - } - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(POST) /user", "User has agreed on the NDA"); - - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - @RequestMapping(path = "/login/hbp", method = RequestMethod.GET) - @ConditionalOnExpression("${hbp.authentication.enabled:0}") - public void noLogin(HttpServletResponse httpServletResponse) throws IOException { - userInfo.setFakeAuth(true); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /user/login/hbp", "Unathorized login."); - - httpServletResponse.sendRedirect(securityConfiguration.getFrontendRedirectAfterLogin()); - } - - @Value("#{'${services.galaxy.galaxyUsername:admin}'}") - private String galaxyUsername; - - @Value("#{'${services.galaxy.galaxyPassword:password}'}") - private String galaxyPassword; - - @Value("#{'${services.galaxy.galaxyContext:nativeGalaxy}'}") - private String galaxyContext; - - /** - * Get Galaxy Reverse Proxy basic access token. - * - * @return Return a @{@link ResponseEntity} with the token. - */ - - @RequestMapping(path = "/galaxy", method = RequestMethod.GET, produces = "application/json") - @PreAuthorize("hasRole('Data Manager')") - @ResponseStatus(value = HttpStatus.OK) - public ResponseEntity getGalaxyConfiguration() { - String stringEncoded = Base64.getEncoder().encodeToString((galaxyUsername + ":" + galaxyPassword).getBytes()); - JsonObject object = new JsonObject(); - object.addProperty("authorization", stringEncoded); - object.addProperty("context", galaxyContext); - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /user/galaxy", "Successfully Loaded galaxy information."); - - return ResponseEntity.ok(gson.toJson(object)); - } -} diff --git a/src/main/java/eu/hbp/mip/controllers/StatsApi.java b/src/main/java/eu/hbp/mip/controllers/StatsApi.java deleted file mode 100644 index 8bd109e535b7c29b5dac96b68b2ba59329ca6a59..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/StatsApi.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Created by mirco on 18.01.16. - */ - -package eu.hbp.mip.controllers; - -import eu.hbp.mip.model.GeneralStats; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.repositories.ArticleRepository; -import eu.hbp.mip.repositories.UserRepository; -import eu.hbp.mip.utils.Logging; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.beans.factory.annotation.Autowired; -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 static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - -@RestController -@RequestMapping(value = "/stats", produces = {APPLICATION_JSON_VALUE}) -@Api(value = "/stats", description = "the stats API") -public class StatsApi { - @Autowired - private UserRepository userRepository; - - @Autowired - private UserInfo userInfo; - - @Autowired - private ArticleRepository articleRepository; - - - @ApiOperation(value = "Get general statistics", response = GeneralStats.class) - @RequestMapping(method = RequestMethod.GET) - public ResponseEntity<GeneralStats> getGeneralStatistics() { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /stats", "Loading general statistics"); - - GeneralStats stats = new GeneralStats(); - - stats.setUsers(userRepository.count()); - stats.setArticles(articleRepository.count()); - - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /stats", "Loaded " + userRepository.count() + " user statistics and " + articleRepository.count() + " artcle statistics."); - return ResponseEntity.ok(stats); - } - -} diff --git a/src/main/java/eu/hbp/mip/controllers/UsersApi.java b/src/main/java/eu/hbp/mip/controllers/UsersApi.java deleted file mode 100644 index b791a7858e216d8ce0f8cd36610763c5c123e66a..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/controllers/UsersApi.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Created by mirco on 14.01.16. - */ - -package eu.hbp.mip.controllers; - -import eu.hbp.mip.model.User; -import eu.hbp.mip.model.UserInfo; -import eu.hbp.mip.repositories.UserRepository; -import eu.hbp.mip.utils.Logging; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - -@RestController -@RequestMapping(value = "/users", produces = {APPLICATION_JSON_VALUE}) -@Api(value = "/users", description = "the users API") -public class UsersApi { - - @Autowired - private UserRepository userRepository; - - @Autowired - private UserInfo userInfo; - - @ApiOperation(value = "Get a user", response = User.class) - @RequestMapping(value = "/{username}", method = RequestMethod.GET) - public ResponseEntity<User> getAUser( - @ApiParam(value = "username", required = true) @PathVariable("username") String username - ) { - Logging.LogUserAction(userInfo.getUser().getUsername(), "(GET) /users/{username}", "Loaded a user with username : " + userInfo.getUser().getUsername()); - - return ResponseEntity.ok(userRepository.findOne(username)); - } -} diff --git a/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java b/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java index 612dce6ca5b557f23deafdf873978c0f442eb1d9..609163e8920ad3443e908c36aea6143ba69533c1 100644 --- a/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java +++ b/src/main/java/eu/hbp/mip/controllers/galaxy/retrofit/RetroFitGalaxyClients.java @@ -1,9 +1,9 @@ package eu.hbp.mip.controllers.galaxy.retrofit; import com.google.gson.JsonObject; -import eu.hbp.mip.model.galaxy.GalaxyWorkflowResult; -import eu.hbp.mip.model.galaxy.PostWorkflowToGalaxyDtoResponse; -import eu.hbp.mip.model.galaxy.WorkflowDTO; +import eu.hbp.mip.models.galaxy.GalaxyWorkflowResult; +import eu.hbp.mip.models.galaxy.PostWorkflowToGalaxyDtoResponse; +import eu.hbp.mip.models.galaxy.WorkflowDTO; import retrofit2.Call; import retrofit2.http.*; diff --git a/src/main/java/eu/hbp/mip/model/AlgorithmDTO.java b/src/main/java/eu/hbp/mip/model/AlgorithmDTO.java deleted file mode 100644 index ed0ef2a15606ef09f139bad65c90c3cf436c2474..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/AlgorithmDTO.java +++ /dev/null @@ -1,220 +0,0 @@ -package eu.hbp.mip.model; - -import com.google.gson.annotations.SerializedName; - -import java.util.List; - -public class AlgorithmDTO { - - 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 getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public List<AlgorithmParamDTO> getParameters() { - return parameters; - } - - public void setParameters(List<AlgorithmParamDTO> parameters) { - this.parameters = parameters; - } - - @SerializedName("name") - private String name; - - @SerializedName("desc") - private String desc; - - @SerializedName("label") - private String label; - - @SerializedName("type") - private String type; - - @SerializedName("parameters") - private List<AlgorithmParamDTO> parameters; - - public static class AlgorithmParamDTO { - @SerializedName("name") - private String name; - - @SerializedName("desc") - private String desc; - - @SerializedName("label") - private String label; - - @SerializedName("type") - private String type; - - @SerializedName("columnValuesSQLType") - private String columnValuesSQLType; - - @SerializedName("columnValuesIsCategorical") - private String columnValuesIsCategorical; - - @SerializedName("value") - private String value; - - @SerializedName("defaultValue") - private String defaultValue; - - @SerializedName("valueType") - private String valueType; - - @SerializedName("valueNotBlank") - private String valueNotBlank; - - @SerializedName("valueMultiple") - private String valueMultiple; - - @SerializedName("valueMin") - private String valueMin; - - @SerializedName("valueMax") - private String valueMax; - - @SerializedName("valueEnumerations") - private List<String> valueEnumerations; - - 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 getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getColumnValuesSQLType() { - return columnValuesSQLType; - } - - public void setColumnValuesSQLType(String columnValuesSQLType) { - this.columnValuesSQLType = columnValuesSQLType; - } - - public String getColumnValuesIsCategorical() { - return columnValuesIsCategorical; - } - - public void setColumnValuesIsCategorical(String columnValuesIsCategorical) { - this.columnValuesIsCategorical = columnValuesIsCategorical; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getDefaultValue() { - return defaultValue; - } - - public void setDefaultValue(String defaultValue) { - this.defaultValue = defaultValue; - } - - public String getValueType() { - return valueType; - } - - public void setValueType(String valueType) { - this.valueType = valueType; - } - - public String getValueNotBlank() { - return valueNotBlank; - } - - public void setValueNotBlank(String valueNotBlank) { - this.valueNotBlank = valueNotBlank; - } - - public String getValueMultiple() { - return valueMultiple; - } - - public void setValueMultiple(String valueMultiple) { - this.valueMultiple = valueMultiple; - } - - public String getValueMin() { - return valueMin; - } - - public void setValueMin(String valueMin) { - this.valueMin = valueMin; - } - - public String getValueMax() { - return valueMax; - } - - public void setValueMax(String valueMax) { - this.valueMax = valueMax; - } - - public List<String> getValueEnumerations() { - return valueEnumerations; - } - - public void setValueEnumerations(List<String> valueEnumerations) { - this.valueEnumerations = valueEnumerations; - } - } - -} diff --git a/src/main/java/eu/hbp/mip/model/Article.java b/src/main/java/eu/hbp/mip/model/Article.java deleted file mode 100644 index 95c7cbbae0701558b249dec7a5cf0b9a07bd3e92..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Article.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import org.springframework.validation.annotation.Validated; - -import javax.persistence.*; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -@Entity -@Table(name = "`article`") -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -@Validated -public class Article { - - @Id - private String slug = null; - - @NotNull - @Size(min = 1, max = 255) - private String title; - - private String status = null; - - @Column(columnDefinition = "text", name = "abstract") - private String abstractText = null; - - @Column(columnDefinition = "text") - private String content = null; - - private Date publishedAt = null; - - private Date createdAt = null; - - private Date updatedAt = null; - - @ManyToOne - @JoinColumn(name = "createdby_username") - private User createdBy = null; - - @ManyToOne - @JoinColumn(name = "updatedby_username") - private User updatedBy = null; - - @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST) - private List<Tag> tags = new LinkedList<>(); - - - public Article() { - /* - * Empty constructor is needed by Hibernate - */ - title = ""; - } - - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - - public String getSlug() { - return slug; - } - - public void setSlug(String slug) { - this.slug = slug; - } - - - @JsonProperty("abstract") - public String getAbstract() { - return abstractText; - } - - public void setAbstract(String abstractText) { - this.abstractText = abstractText; - } - - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - - public Date getPublishedAt() { - return publishedAt; - } - - public void setPublishedAt(Date publishedAt) { - this.publishedAt = publishedAt; - } - - - public Date getCreatedAt() { - return createdAt; - } - - public void setCreatedAt(Date createdAt) { - this.createdAt = createdAt; - } - - - public Date getUpdatedAt() { - return updatedAt; - } - - public void setUpdatedAt(Date updatedAt) { - this.updatedAt = updatedAt; - } - - - public User getCreatedBy() { - return createdBy; - } - - public void setCreatedBy(User createdBy) { - this.createdBy = createdBy; - } - - - public User getUpdatedBy() { - return updatedBy; - } - - public void setUpdatedBy(User updatedBy) { - this.updatedBy = updatedBy; - } - - - public List<Tag> getTags() { - return tags; - } - - public void setTags(List<Tag> tags) { - this.tags = tags; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/Config.java b/src/main/java/eu/hbp/mip/model/Config.java deleted file mode 100644 index 2362194b2b8338d7ab7a0b781c7891e88acfd293..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Config.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Created by mirco on 25.02.16. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import io.swagger.annotations.ApiModel; - -import javax.persistence.*; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -@Entity -@Table(name = "`config`") -@ApiModel -@JsonIgnoreProperties(value = {"id"}) -public class Config { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) - private Long id = null; - - private String type = null; - - private Integer height = null; - - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "config_yAxisVariables", joinColumns = @JoinColumn(name = "config_id")) - private List<String> yAxisVariables = new LinkedList<>(); - - private String xAxisVariable = null; - - private Boolean hasXAxis = null; - - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "config_title", joinColumns = @JoinColumn(name = "config_id")) - private Map<String, String> title = new HashMap<>(); - - - public Config() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - - public Integer getHeight() { - return height; - } - - public void setHeight(Integer height) { - this.height = height; - } - - - public List<String> getyAxisVariables() { - return yAxisVariables; - } - - public void setyAxisVariables(List<String> yAxisVariables) { - this.yAxisVariables = yAxisVariables; - } - - - public String getxAxisVariable() { - return xAxisVariable; - } - - public void setxAxisVariable(String xAxisVariable) { - this.xAxisVariable = xAxisVariable; - } - - - public Boolean getHasXAxis() { - return hasXAxis; - } - - public void setHasXAxis(Boolean hasXAxis) { - this.hasXAxis = hasXAxis; - } - - - public Map<String, String> getTitle() { - return title; - } - - public void setTitle(Map<String, String> title) { - this.title = title; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/Dataset.java b/src/main/java/eu/hbp/mip/model/Dataset.java deleted file mode 100644 index d920571d9526dca8d29316d8d56578dc3d0b3b9b..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Dataset.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; - -import javax.persistence.*; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; - -// TODO: deprecate - -@Entity -@Table(name = "`dataset`") -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Dataset { - - @Id - private String code = null; - - private Date date = null; - - // Aka covariables - @ElementCollection - @CollectionTable(name = "dataset_header", joinColumns = @JoinColumn(name = "dataset_code")) - private List<String> header = new LinkedList<>(); - - @ElementCollection - @CollectionTable(name = "dataset_grouping", joinColumns = @JoinColumn(name = "dataset_code")) - private List<String> grouping = new LinkedList<>(); - - @ElementCollection - @CollectionTable(name = "dataset_variable", joinColumns = @JoinColumn(name = "dataset_code")) - private List<String> variable = new LinkedList<>(); - - // TODO: - @Transient - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - private Object data = null; - - - public Dataset() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - - public List<String> getHeader() { - return header; - } - - public void setHeader(List<String> header) { - this.header = header; - } - - - public List<String> getGrouping() { - return grouping; - } - - public void setGrouping(List<String> grouping) { - this.grouping = grouping; - } - - - public List<String> getVariable() { - return variable; - } - - public void setVariable(List<String> variable) { - this.variable = variable; - } - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } -} diff --git a/src/main/java/eu/hbp/mip/model/DatasetDescription.java b/src/main/java/eu/hbp/mip/model/DatasetDescription.java deleted file mode 100644 index c77c50aeab3a4256ecadf78aa2f25f89a05a0b92..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/DatasetDescription.java +++ /dev/null @@ -1,46 +0,0 @@ -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.annotations.ApiModel; - -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -public class DatasetDescription { - - private String code; - private String label; - private String description; - private String anonymisationLevel; - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getAnonymisationLevel() { - return anonymisationLevel; - } - - public void setAnonymisationLevel(String anonymisationLevel) { - this.anonymisationLevel = anonymisationLevel; - } -} diff --git a/src/main/java/eu/hbp/mip/model/Experiment.java b/src/main/java/eu/hbp/mip/model/Experiment.java deleted file mode 100644 index c40d91d3441ce131e45e5dbda0934c4a3ab0c30b..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Experiment.java +++ /dev/null @@ -1,232 +0,0 @@ -package eu.hbp.mip.model; - -import com.google.gson.*; -import com.google.gson.annotations.Expose; -import org.hibernate.annotations.Cascade; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.persistence.*; -import java.util.*; - -/** - * Created by habfast on 21/04/16. - */ -@Entity -@Table(name = "`experiment`") -public class Experiment { - - private static final Gson gson = new Gson(); - - @Id - @Column(columnDefinition = "uuid") - @org.hibernate.annotations.Type(type = "pg-uuid") - @Expose - private UUID uuid; - - @Column(columnDefinition = "TEXT") - @Expose - private String name; - - @Expose - @ManyToOne - @JoinColumn(name = "createdby_username") - private User createdBy; - - @ManyToOne - @Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE) - @Expose - private Model model; - - @Column(columnDefinition = "TEXT") - @Expose - private String algorithms; - - @Column(columnDefinition = "TEXT") - private String validations; - - @Column(columnDefinition = "TEXT") - @Expose - private String workflowHistoryId; - - @Column(columnDefinition = "TEXT") - @Expose - private String workflowStatus; - - @Column(columnDefinition = "TEXT") - @Expose - private String result; - - @Expose - private Date created = new Date(); - - @Expose - private Date finished; - - @Expose - private boolean hasError = false; - - @Expose - private boolean hasServerError = false; - - @Expose - private boolean shared = false; - - // whether or not the experiment's result have been resultsViewed by its owner - @Expose - private boolean resultsViewed = false; - - public Experiment() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - public JsonObject jsonify() { - JsonObject exp = gson.toJsonTree(this).getAsJsonObject(); - JsonParser parser = new JsonParser(); - - if (this.algorithms != null) { - exp.remove("algorithms"); - JsonArray jsonAlgorithms = parser.parse(this.algorithms).getAsJsonArray(); - exp.add("algorithms", jsonAlgorithms); - } - - if (this.validations != null) { - exp.remove("validations"); - JsonArray jsonValidations = parser.parse(this.validations).getAsJsonArray(); - exp.add("validations", jsonValidations); - } - - if (this.result != null && !this.hasServerError) { - exp.remove("result"); - - JsonElement jsonResult = parser.parse(this.result); - exp.add("result", jsonResult); - - } - - return exp; - } - - public String getValidations() { - return validations; - } - - public void setValidations(String validations) { - this.validations = validations; - } - - public String getAlgorithms() { - return algorithms; - } - - public void setAlgorithms(String algorithms) { - this.algorithms = algorithms; - } - - public Model getModel() { - return model; - } - - public void setModel(Model model) { - this.model = model; - } - - public boolean isHasError() { - return hasError; - } - - public void setHasError(boolean hasError) { - this.hasError = hasError; - } - - public String getWorkflowHistoryId() { - return workflowHistoryId; - } - - public void setWorkflowHistoryId(String workflowHistoryId) { - this.workflowHistoryId = workflowHistoryId; - } - - public String getWorkflowStatus() { - return workflowStatus; - } - - public void setWorkflowStatus(String workflowStatus) { - this.workflowStatus = workflowStatus; - } - - public String getResult() { - return result; - } - - public void setResult(String result) { - this.result = result; - } - - public Date getFinished() { - return finished; - } - - public void setFinished(Date finished) { - this.finished = finished; - } - - public Date getCreated() { - return created; - } - - public void setCreated(Date created) { - this.created = created; - } - - public UUID getUuid() { - return uuid; - } - - public void setUuid(UUID uuid) { - this.uuid = uuid; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public User getCreatedBy() { - return createdBy; - } - - public void setCreatedBy(User createdBy) { - this.createdBy = createdBy; - } - - public boolean isResultsViewed() { - return resultsViewed; - } - - public void setResultsViewed(boolean resultsViewed) { - this.resultsViewed = resultsViewed; - } - - public boolean isHasServerError() { - return hasServerError; - } - - public void setHasServerError(boolean hasServerError) { - this.hasServerError = hasServerError; - } - - public boolean isShared() { - return shared; - } - - public void setShared(boolean shared) { - this.shared = shared; - } -} diff --git a/src/main/java/eu/hbp/mip/model/ExperimentExecutionDTO.java b/src/main/java/eu/hbp/mip/model/ExperimentExecutionDTO.java deleted file mode 100644 index a68cd9121d852503bc01eb6b2f0d23dd8af525dd..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/ExperimentExecutionDTO.java +++ /dev/null @@ -1,106 +0,0 @@ -package eu.hbp.mip.model; - -import java.util.List; - -public class ExperimentExecutionDTO { - - private String name; - private String model; - private List<AlgorithmExecutionDTO> algorithms; - - public String getModel() { - return model; - } - - public void setModel(String model) { - this.model = model; - } - - public List<AlgorithmExecutionDTO> getAlgorithms() { - return algorithms; - } - - public void setAlgorithms(List<AlgorithmExecutionDTO> algorithms) { - this.algorithms = algorithms; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public static class AlgorithmExecutionDTO { - - private String name; - private String label; - private String type; - - private List<AlgorithmExecutionParamDTO> parameters; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public List<AlgorithmExecutionDTO.AlgorithmExecutionParamDTO> getParameters() { - return parameters; - } - - public void setParameters(List<AlgorithmExecutionDTO.AlgorithmExecutionParamDTO> parameters) { - this.parameters = parameters; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public static class AlgorithmExecutionParamDTO { - - private String name; - private String label; - private String value; - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - } - } -} diff --git a/src/main/java/eu/hbp/mip/model/GeneralStats.java b/src/main/java/eu/hbp/mip/model/GeneralStats.java deleted file mode 100644 index 4253ae7dd859ed63a47ffba68a9bcafc5646302c..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/GeneralStats.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Created by mirco on 03.02.16. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.annotations.ApiModel; - -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -public class GeneralStats { - - private Long users = null; - private Long articles = null; - - - public GeneralStats() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - public Long getUsers() { - return users; - } - - public void setUsers(Long users) { - this.users = users; - } - - - public Long getArticles() { - return articles; - } - - public void setArticles(Long articles) { - this.articles = articles; - } -} diff --git a/src/main/java/eu/hbp/mip/model/Group.java b/src/main/java/eu/hbp/mip/model/Group.java deleted file mode 100644 index abb195a932669d28785b407ad3738ab8087cffe7..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Group.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.annotations.ApiModel; - -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name = "`group`") -@ApiModel -@JsonIgnoreProperties(value = {"parent"}) -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Group { - - @Id - private String code = null; - - - public Group() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - public String getCode() { - return code; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/Mining.java b/src/main/java/eu/hbp/mip/model/Mining.java deleted file mode 100644 index 46cfd6c3ec64b0a7e552cd4f6e210a24a746fc1e..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Mining.java +++ /dev/null @@ -1,64 +0,0 @@ -package eu.hbp.mip.model; - -import com.google.gson.*; - -import java.util.Date; - -public class Mining { - - private static final Gson gson = new Gson(); - - private final String jobId; - private final String node; - private final String function; - private final String shape; - private final Date timestamp; - private final String data; - - public Mining(String jobId, String node, String function, String shape, Date timestamp, String data) { - this.jobId = jobId; - this.node = node; - this.function = function; - this.shape = shape; - this.timestamp = timestamp; - this.data = data; - } - - public String getJobId() { - return jobId; - } - - public String getNode() { - return node; - } - - public String getFunction() { - return function; - } - - public String getShape() { - return shape; - } - - public Date getTimestamp() { - return timestamp; - } - - public String getData() { - return data; - } - - public JsonObject jsonify() { - JsonObject exp = gson.toJsonTree(this).getAsJsonObject(); - JsonParser parser = new JsonParser(); - - if (this.data != null) { - exp.remove("data"); - JsonElement jsonResult = parser.parse(this.data); - exp.add("data", jsonResult); - } - - return exp; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/MiningQuery.java b/src/main/java/eu/hbp/mip/model/MiningQuery.java deleted file mode 100644 index 171c55032eee4b3c5f63d636c137d6ae41bfe051..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/MiningQuery.java +++ /dev/null @@ -1,96 +0,0 @@ -package eu.hbp.mip.model; - -import com.google.gson.Gson; - -import java.util.LinkedList; -import java.util.List; - -/** - * Created by mirco on 06.01.17. - */ -public class MiningQuery { - - private List<Variable> variables; - private List<Variable> covariables; - private List<Variable> grouping; - private List<Variable> datasets; - private String filters; - private ExperimentExecutionDTO.AlgorithmExecutionDTO algorithm; - - public MiningQuery() { - this.variables = new LinkedList<>(); - this.covariables = new LinkedList<>(); - this.grouping = new LinkedList<>(); - this.datasets = new LinkedList<>(); - this.filters = ""; - } - - public List<Variable> getVariables() { - return variables; - } - - public void setVariables(List<Variable> variables) { - this.variables = variables; - } - - public void addVariable(Variable variable) { - this.variables.add(variable); - } - - public List<Variable> getCovariables() { - return covariables; - } - - public void setCovariables(List<Variable> covariables) { - this.covariables = covariables; - } - - public void addCovariable(Variable variable) { - this.covariables.add(variable); - } - - public List<Variable> getGrouping() { - return grouping; - } - - public void setGrouping(List<Variable> grouping) { - this.grouping = grouping; - } - - public List<Variable> getDatasets() { - return datasets; - } - - public void setDataset(List<Variable> datasets) { - this.datasets = datasets; - } - - public void addDataset(Variable variable) { - this.datasets.add(variable); - } - - public void addGrouping(Variable variable) { - this.grouping.add(variable); - } - - public String getFilters() { - return filters; - } - - public void setFilters(String filters) { - this.filters = filters; - } - - public ExperimentExecutionDTO.AlgorithmExecutionDTO getAlgorithm() { - return algorithm; - } - - public void setAlgorithm(ExperimentExecutionDTO.AlgorithmExecutionDTO algorithm) { - this.algorithm = algorithm; - } - - @Override - public String toString() { - return new Gson().toJson(this); - } -} diff --git a/src/main/java/eu/hbp/mip/model/Model.java b/src/main/java/eu/hbp/mip/model/Model.java deleted file mode 100644 index b1590803720c5a0c38538667ef48c940d644399c..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Model.java +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.google.gson.annotations.Expose; -import io.swagger.annotations.ApiModel; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; - -import javax.persistence.*; -import java.util.Date; - -@Entity -@Table(name = "`model`") -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Model { - - @Id - @Expose - private String slug = null; - - @Expose - private String title = null; - - private String description = null; - - private Boolean valid = null; - - private Date createdAt = null; - - private Date updatedAt = null; - - @ManyToOne - @Cascade(CascadeType.SAVE_UPDATE) - private eu.hbp.mip.model.Query query = null; - - @ManyToOne - @Cascade(CascadeType.SAVE_UPDATE) - private Dataset dataset = null; - - @ManyToOne - @Cascade(CascadeType.SAVE_UPDATE) - private Config config = null; - - @ManyToOne - @JoinColumn(name = "createdby_username") - private User createdBy = null; - - @ManyToOne - @JoinColumn(name = "updatedby_username") - private User updatedBy = null; - - - public Model() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - - public String getSlug() { - return slug; - } - - public void setSlug(String slug) { - this.slug = slug; - } - - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - - public eu.hbp.mip.model.Query getQuery() { - return query; - } - - public void setQuery(eu.hbp.mip.model.Query query) { - this.query = query; - } - - - public Dataset getDataset() { - return dataset; - } - - public void setDataset(Dataset dataset) { - this.dataset = dataset; - } - - - public Boolean getValid() { - return valid; - } - - public void setValid(Boolean valid) { - this.valid = valid; - } - - - public Config getConfig() { - return config; - } - - public void setConfig(Config config) { - this.config = config; - } - - - public Date getCreatedAt() { - return createdAt; - } - - public void setCreatedAt(Date createdAt) { - this.createdAt = createdAt; - } - - - public Date getUpdatedAt() { - return updatedAt; - } - - public void setUpdatedAt(Date updatedAt) { - this.updatedAt = updatedAt; - } - - - public User getCreatedBy() { - return createdBy; - } - - public void setCreatedBy(User createdBy) { - this.createdBy = createdBy; - } - - - public User getUpdatedBy() { - return updatedBy; - } - - public void setUpdatedBy(User updatedBy) { - this.updatedBy = updatedBy; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/PathologyDTO.java b/src/main/java/eu/hbp/mip/model/PathologyDTO.java deleted file mode 100644 index c58238b623e18aa5f7942d9e4816f905ce48f3f8..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/PathologyDTO.java +++ /dev/null @@ -1,85 +0,0 @@ -package eu.hbp.mip.model; - -import com.google.gson.annotations.SerializedName; - -import java.util.List; - -public class PathologyDTO { - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public Object getMetadataHierarchy() { - return metadataHierarchy; - } - - public void setMetadataHierarchy(Object metadataHierarchy) { - this.metadataHierarchy = metadataHierarchy; - } - - public List<PathologyDatasetDTO> getDatasets() { - return datasets; - } - - public void setDatasets(List<PathologyDatasetDTO> datasets) { - this.datasets = datasets; - } - - @SerializedName("code") - private String code; - - @SerializedName("label") - private String label; - - @SerializedName("metadataHierarchy") - private Object metadataHierarchy; - - @SerializedName("datasets") - private List<PathologyDatasetDTO> datasets; - - public static class PathologyDatasetDTO { - @SerializedName("code") - private String code; - - @SerializedName("label") - private String label; - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String toString() { - return code; - } - } - - public String toString() { - return code; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/Query.java b/src/main/java/eu/hbp/mip/model/Query.java deleted file mode 100644 index 8e4d78dcbb1534052e9108aa9cf6d35be6ffa26e..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Query.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; - -import javax.persistence.*; -import java.util.LinkedList; -import java.util.List; - -@Entity -@ApiModel -@Table(name = "`query`") -@JsonIgnoreProperties(value = {"id"}) -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Query { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) - private Long id = null; - - @ManyToMany - @JoinTable(name = "query_variable", joinColumns = { - @JoinColumn(name = "id", nullable = false, updatable = false)}, - inverseJoinColumns = {@JoinColumn(name = "code", - nullable = false, updatable = false)}) - private List<Variable> variables = new LinkedList<>(); - - @ManyToMany - @JoinTable(name = "query_covariable", joinColumns = { - @JoinColumn(name = "id", nullable = false, updatable = false)}, - inverseJoinColumns = {@JoinColumn(name = "code", - nullable = false, updatable = false)}) - private List<Variable> covariables = new LinkedList<>(); - - @ManyToMany - @JoinTable(name = "query_grouping", joinColumns = { - @JoinColumn(name = "id", nullable = false, updatable = false)}, - inverseJoinColumns = {@JoinColumn(name = "code", - nullable = false, updatable = false)}) - private List<Variable> grouping = new LinkedList<>(); - - @ManyToMany - @JoinTable(name = "query_training_datasets", joinColumns = { - @JoinColumn(name = "id", nullable = false, updatable = false)}, - inverseJoinColumns = {@JoinColumn(name = "code", - nullable = false, updatable = false)}) - private List<Variable> trainingDatasets = new LinkedList<>(); - - @ManyToMany - @JoinTable(name = "query_testing_datasets", joinColumns = { - @JoinColumn(name = "id", nullable = false, updatable = false)}, - inverseJoinColumns = {@JoinColumn(name = "code", - nullable = false, updatable = false)}) - private List<Variable> testingDatasets = new LinkedList<>(); - - @ManyToMany - @JoinTable(name = "query_validation_datasets", joinColumns = { - @JoinColumn(name = "id", nullable = false, updatable = false)}, - inverseJoinColumns = {@JoinColumn(name = "code", - nullable = false, updatable = false)}) - private List<Variable> validationDatasets = new LinkedList<>(); - - @Column(columnDefinition = "text") - private String filters = ""; - - @Column(columnDefinition = "text") - private String pathology = ""; - - - public Query() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - - @JsonProperty("variables") - public List<Variable> getVariables() { - return variables; - } - - public void setVariables(List<Variable> variables) { - this.variables = variables; - } - - - @JsonProperty("coVariables") - public List<Variable> getCovariables() { - return covariables; - } - - public void setCovariables(List<Variable> covariables) { - this.covariables = covariables; - } - - - @JsonProperty("groupings") - public List<Variable> getGrouping() { - return grouping; - } - - public void setGrouping(List<Variable> grouping) { - this.grouping = grouping; - } - - @JsonProperty("trainingDatasets") - public List<Variable> getTrainingDatasets() { - return trainingDatasets; - } - - public void setTrainingDatasets(List<Variable> trainingDatasets) { - this.trainingDatasets = trainingDatasets; - } - - @JsonProperty("testingDatasets") - public List<Variable> getTestingDatasets() { - return testingDatasets; - } - - public void setTestingDatasets(List<Variable> testingDatasets) { - this.testingDatasets = testingDatasets; - } - - @JsonProperty("validationDatasets") - public List<Variable> getValidationDatasets() { - return validationDatasets; - } - - public void setValidationDatasets(List<Variable> validationDatasets) { - this.validationDatasets = validationDatasets; - } - - public String getFilters() { - return filters; - } - - public void setFilters(String filters) { - this.filters = filters; - } - - public String getPathology() { - return pathology; - } - - public void setPathology(String pathology) { - this.pathology = pathology; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/Tag.java b/src/main/java/eu/hbp/mip/model/Tag.java deleted file mode 100644 index 693c9865602ace72de50d067e3dd5e3eaac97526..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Tag.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.annotations.ApiModel; - -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name = "`tag`") -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Tag { - - @Id - private String name = null; - - - public Tag() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/User.java b/src/main/java/eu/hbp/mip/model/User.java deleted file mode 100644 index 64fee4b670e6285a0e06ada431975fd5c17cf50e..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/User.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.google.gson.annotations.Expose; -import io.swagger.annotations.ApiModel; - -import javax.persistence.*; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -@Entity -@Table(name = "`user`") -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonIgnoreProperties(value = {"appsVotes"}) -public class User { - - @Id - @Expose - private String username = null; - - @Expose - private String fullname = null; - - @Expose - private String firstname = null; - - @Expose - private String lastname = null; - - @Expose - private String picture = null; - - @Expose - private String web = null; - - @Expose - private String phone = null; - - @Expose - private String birthday = null; - - @Expose - private String gender = null; - - @Expose - private String city = null; - - @Expose - private String country = null; - - @Expose - private String password = null; - - @Expose - private String email = null; - - @Expose - private String apikey = null; - - @Expose - private String team = null; - - @Expose - private Boolean isActive = null; - - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "user_languages", joinColumns = @JoinColumn(name = "user_username")) - @Expose - private List<String> languages = new LinkedList<>(); - - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_username")) - @Expose - private List<String> roles = new LinkedList<>(); - - private Boolean agreeNDA = null; - - - public User() { - /* - * Empty constructor is needed by Hibernate - */ - } - - - /** - * Create a user using OpenID user profile - * - * @param userInfo info from OpenID UserInfo endpoint - */ - public User(String userInfo) { - - Pattern p; - Matcher m; - - p = Pattern.compile("preferred_username=([\\w- ]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.username = m.group(1); - } - - p = Pattern.compile("name=([\\w ]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.fullname = m.group(1); - } - - p = Pattern.compile("given_name=([\\w ]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.firstname = m.group(1); - } - - p = Pattern.compile("family_name=([\\w ]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.lastname = m.group(1); - } - - p = Pattern.compile("email=([\\w.]+@[\\w.]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.email = m.group(1); - } - - p = Pattern.compile("title=([\\w ]+)"); - m = p.matcher(userInfo); - if (m.find()) { - if ("Mr".equals(m.group(1))) { - this.gender = "Male"; - } else { - this.gender = "Female"; - } - } - - p = Pattern.compile("contractor=([\\w ]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.team = m.group(1); - } - - p = Pattern.compile("picture=([-a-zA-Z0-9+&@#/%=~_|.: ]+)"); - m = p.matcher(userInfo); - if (m.find()) { - this.picture = m.group(1); - } - - if (this.picture == null || this.picture.isEmpty()) { - this.picture = "images/users/default_user.png"; - } - - } - - - public String getFullname() { - return fullname; - } - - public void setFullname(String fullname) { - this.fullname = fullname; - } - - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - - public String getFirstname() { - return firstname; - } - - public void setFirstname(String firstname) { - this.firstname = firstname; - } - - - public String getLastname() { - return lastname; - } - - public void setLastname(String lastname) { - this.lastname = lastname; - } - - - public String getPicture() { - return picture; - } - - public void setPicture(String picture) { - this.picture = picture; - } - - - public String getWeb() { - return web; - } - - public void setWeb(String web) { - this.web = web; - } - - - public String getPhone() { - return phone; - } - - public void setPhone(String phone) { - this.phone = phone; - } - - - public String getBirthday() { - return birthday; - } - - public void setBirthday(String birthday) { - this.birthday = birthday; - } - - - public String getGender() { - return gender; - } - - public void setGender(String gender) { - this.gender = gender; - } - - - public String getCity() { - return city; - } - - public void setCity(String city) { - this.city = city; - } - - - public String getCountry() { - return country; - } - - public void setCountry(String country) { - this.country = country; - } - - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - - public String getApikey() { - return apikey; - } - - public void setApikey(String apikey) { - this.apikey = apikey; - } - - - public String getTeam() { - return team; - } - - public void setTeam(String team) { - this.team = team; - } - - - public Boolean getIsActive() { - return isActive; - } - - public void setIsActive(Boolean isActive) { - this.isActive = isActive; - } - - - public List<String> getLanguages() { - return languages; - } - - public void setLanguages(List<String> languages) { - this.languages = languages; - } - - - public List<String> getRoles() { - return roles; - } - - public void setRoles(List<String> roles) { - this.roles = roles; - } - - - public Boolean getAgreeNDA() { - return agreeNDA; - } - - public void setAgreeNDA(Boolean agreeNDA) { - this.agreeNDA = agreeNDA; - } -} diff --git a/src/main/java/eu/hbp/mip/model/UserInfo.java b/src/main/java/eu/hbp/mip/model/UserInfo.java deleted file mode 100644 index 71eee3573b485d690c810b42c1344cc2170fb9f5..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/UserInfo.java +++ /dev/null @@ -1,84 +0,0 @@ -package eu.hbp.mip.model; - -import eu.hbp.mip.repositories.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Scope; -import org.springframework.context.annotation.ScopedProxyMode; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.stereotype.Component; - -import javax.inject.Named; - -@Component -@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) -@Named("userInfo") -public class UserInfo { - - @Autowired - private UserRepository userRepository; - - /** - * Enable HBP collab authentication (1) or disable it (0). Default is 1 - */ - @Value("#{'${hbp.authentication.enabled:1}'}") - private boolean authentication; - - private User user; - - /** - * Set to true if using no-auth mode and user has clicked on the login button - */ - private boolean fakeAuth = false; - - /** - * returns the user for the current session. - * <p> - * the "synchronized" keyword is there to avoid a bug that the transaction is supposed to protect me from. - * To test if your solution to removing it works, do the following: - * - clean DB from scratch - * - restart DB and backend (no session or anything like that) - * - log in using the front end - * - check you have no 500 error in the network logs. - * - * @return the user for the current session - */ - public User getUser() { - if (user == null) { - - if (!authentication) { - user = new User(); - user.setUsername("anonymous"); - user.setFullname("anonymous"); - user.setEmail("anonymous@anonymous.com"); - user.setPicture("images/users/default_user.png"); - } else { - user = new User(getUserInfos()); - } - User foundUser = userRepository.findOne(user.getUsername()); - if (foundUser != null) { - user.setAgreeNDA(foundUser.getAgreeNDA()); - } - userRepository.save(user); - } - - return user; - } - - public boolean isFakeAuth() { - return fakeAuth; - } - - public void setFakeAuth(boolean fakeAuth) { - this.fakeAuth = fakeAuth; - } - - private String getUserInfos() { - OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication(); - Authentication userAuthentication = oAuth2Authentication.getUserAuthentication(); - return userAuthentication.getDetails().toString(); - } - -} diff --git a/src/main/java/eu/hbp/mip/model/Value.java b/src/main/java/eu/hbp/mip/model/Value.java deleted file mode 100644 index 784452e591ffc8eb1f62ff5cc0c7f82694c78a3c..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Value.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.annotations.ApiModel; - -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name = "`value`") -@ApiModel -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Value { - - @Id - private String code = null; - - private String label = null; - - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - -} diff --git a/src/main/java/eu/hbp/mip/model/Variable.java b/src/main/java/eu/hbp/mip/model/Variable.java deleted file mode 100644 index 596be8d775673af068235dabed39323a4440de49..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/model/Variable.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Created by mirco on 04.12.15. - */ - -package eu.hbp.mip.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.google.gson.annotations.Expose; -import io.swagger.annotations.ApiModel; - -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import java.util.List; - -@Entity -@Table(name = "`variable`") -@ApiModel -@JsonIgnoreProperties(value = {"queries"}) -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Variable { - - @Id - @Expose - private String code = null; - - /** - * Empty constructor is needed by Hibernate - */ - public Variable() { - } - - public Variable(String code) { - this.code = code; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public static String stringFromVariables(List<Variable> variables, String operator) { - StringBuilder sb = new StringBuilder(); - int i = 0; - for (Variable s : variables) { - i++; - sb.append(s.getCode()); - if (i < variables.size()) { - sb.append(operator); - } - } - return sb.toString(); - } - -} diff --git a/src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java b/src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java new file mode 100644 index 0000000000000000000000000000000000000000..585bd8bd6694275d341fe1aea19f82f3105d97ea --- /dev/null +++ b/src/main/java/eu/hbp/mip/models/DAOs/ExperimentDAO.java @@ -0,0 +1,116 @@ +package eu.hbp.mip.models.DAOs; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.google.gson.Gson; +import com.google.gson.annotations.Expose; +import eu.hbp.mip.models.DTOs.AlgorithmDTO; +import eu.hbp.mip.models.DTOs.ExperimentDTO; +import eu.hbp.mip.utils.JsonConverters; +import io.swagger.annotations.ApiModel; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.*; +import java.util.*; + +/** + * Created by habfast on 21/04/16. + */ +@Entity +@Getter +@Setter +@Table(name = "`experiment`") +@ApiModel +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ExperimentDAO { + + private static final Gson gson = new Gson(); + + @Expose + @Id + @Column(columnDefinition = "uuid", updatable = false) + @org.hibernate.annotations.Type(type = "pg-uuid") + private UUID uuid; + + @Expose + @Column(columnDefinition = "TEXT") + private String name; + + @Expose + @ManyToOne + @JoinColumn(name = "created_by_username",columnDefinition = "CHARACTER VARYING") + private UserDAO createdBy; + + @Expose + @Column(name="workflow_history_id", columnDefinition = "TEXT") + private String workflowHistoryId; + + @Expose + @Column(columnDefinition = "TEXT") + @Enumerated(EnumType.STRING) + private Status status; + + @Expose + @Column(columnDefinition = "TEXT") + private String result; + + @Expose + @Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE") + private Date finished; + + @Expose + @Column(columnDefinition = "TEXT") + private String algorithm; + + @Expose + @Column(columnDefinition = "TEXT") + private String algorithmId; + + @Expose + @Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE") + private Date created = new Date(); + + @Expose + @Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE") + private Date updated; + + @Expose + @Column(columnDefinition = "BOOLEAN") + private boolean shared = false; + + // whether or not the experiment's result have been viewed by its owner + @Expose + @Column(columnDefinition = "BOOLEAN") + private boolean viewed = false; + + public enum Status { + error, + pending, + success + } + + public ExperimentDAO() { + /* + * Empty constructor is needed by Hibernate + */ + } + + public ExperimentDTO convertToDTO(boolean includeResult) + { + ExperimentDTO experimentDTO = new ExperimentDTO(); + experimentDTO.setAlgorithm(JsonConverters.convertJsonStringToObject(this.algorithm, AlgorithmDTO.class)); + experimentDTO.setCreated(this.created); + experimentDTO.setUpdated(this.updated); + experimentDTO.setFinished(this.finished); + experimentDTO.setCreatedBy(this.createdBy.getUsername()); + experimentDTO.setName(this.name); + if(includeResult){ + experimentDTO.setResult(JsonConverters.convertJsonStringToObject(String.valueOf(this.result), new ArrayList<>().getClass())); + } + experimentDTO.setStatus(this.status); + experimentDTO.setShared(this.shared); + experimentDTO.setUuid(this.uuid); + experimentDTO.setViewed(this.viewed); + return experimentDTO; + } +} diff --git a/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java b/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java new file mode 100644 index 0000000000000000000000000000000000000000..9279b3793c44c449302c083b823da674d7e4d46f --- /dev/null +++ b/src/main/java/eu/hbp/mip/models/DAOs/UserDAO.java @@ -0,0 +1,53 @@ +/* + * Created by mirco on 04.12.15. + */ + +package eu.hbp.mip.models.DAOs; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.google.gson.annotations.Expose; +import io.swagger.annotations.ApiModel; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Getter +@Setter +@Table(name = "`user`") +@ApiModel +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UserDAO { + + @Id + @Expose + private String username; + + @Expose + private String subjectId; + + @Expose + private String fullname; + + @Expose + private String email; + + @Expose + private Boolean agreeNDA; + + public UserDAO() { + // Empty constructor is needed by Hibernate + } + + public UserDAO(String username, String fullname, String email, String subjectId) { + this.username = username; + this.fullname = fullname; + this.email = email; + this.agreeNDA = false; + this.subjectId = subjectId; + + } +} diff --git a/src/main/java/eu/hbp/mip/models/DTOs/AlgorithmDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/AlgorithmDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..52db979d5ddd7b043572be8fc9255c45fa0e9c98 --- /dev/null +++ b/src/main/java/eu/hbp/mip/models/DTOs/AlgorithmDTO.java @@ -0,0 +1,73 @@ +package eu.hbp.mip.models.DTOs; + +import com.google.gson.annotations.SerializedName; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class AlgorithmDTO { + + @SerializedName("name") + private String name; + + @SerializedName("desc") + private String desc; + + @SerializedName("label") + private String label; + + @SerializedName("type") + private String type; + + @SerializedName("parameters") + private List<AlgorithmParamDTO> parameters; + + @Getter + @Setter + public static class AlgorithmParamDTO { + @SerializedName("name") + private String name; + + @SerializedName("desc") + private String desc; + + @SerializedName("label") + private String label; + + @SerializedName("type") + private String type; + + @SerializedName("columnValuesSQLType") + private String columnValuesSQLType; + + @SerializedName("columnValuesIsCategorical") + private String columnValuesIsCategorical; + + @SerializedName("value") + private String value; + + @SerializedName("defaultValue") + private String defaultValue; + + @SerializedName("valueType") + private String valueType; + + @SerializedName("valueNotBlank") + private String valueNotBlank; + + @SerializedName("valueMultiple") + private String valueMultiple; + + @SerializedName("valueMin") + private String valueMin; + + @SerializedName("valueMax") + private String valueMax; + + @SerializedName("valueEnumerations") + private List<String> valueEnumerations; + } +} diff --git a/src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..e64c6f75e7d7a4d7aafa8ba93d38f9d3edf6bf19 --- /dev/null +++ b/src/main/java/eu/hbp/mip/models/DTOs/ExperimentDTO.java @@ -0,0 +1,31 @@ +package eu.hbp.mip.models.DTOs; + +import com.fasterxml.jackson.annotation.JsonInclude; +import eu.hbp.mip.models.DAOs.ExperimentDAO; +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +@Getter +@Setter +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ExperimentDTO { + + private UUID uuid; + private String name; + private String createdBy; + private Date created; + private Date updated; + private Date finished; + private Boolean shared; + private Boolean viewed; + private List<Object> result; + private ExperimentDAO.Status status; + private AlgorithmDTO algorithm; + + public ExperimentDTO() { + } +} diff --git a/src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java b/src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..aa78ef8b0e315a2f71261dc1fed480cb8617ccb2 --- /dev/null +++ b/src/main/java/eu/hbp/mip/models/DTOs/PathologyDTO.java @@ -0,0 +1,42 @@ +package eu.hbp.mip.models.DTOs; + +import com.google.gson.annotations.SerializedName; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class PathologyDTO { + + @SerializedName("code") + private String code; + + @SerializedName("label") + private String label; + + @SerializedName("metadataHierarchy") + private Object metadataHierarchy; + + @SerializedName("datasets") + private List<PathologyDatasetDTO> datasets; + + @Getter + @Setter + public static class PathologyDatasetDTO { + @SerializedName("code") + private String code; + + @SerializedName("label") + private String label; + + public String toString() { + return code; + } + } + + public String toString() { + return code; + } +} diff --git a/src/main/java/eu/hbp/mip/model/galaxy/ErrorResponse.java b/src/main/java/eu/hbp/mip/models/galaxy/ErrorResponse.java similarity index 96% rename from src/main/java/eu/hbp/mip/model/galaxy/ErrorResponse.java rename to src/main/java/eu/hbp/mip/models/galaxy/ErrorResponse.java index 77a171358b54561e3492dcb317acd835aeaa645f..2703e742541faf9f715ed19485076d397697059e 100644 --- a/src/main/java/eu/hbp/mip/model/galaxy/ErrorResponse.java +++ b/src/main/java/eu/hbp/mip/models/galaxy/ErrorResponse.java @@ -3,7 +3,7 @@ * Copyright (c) 2019. MIT License */ -package eu.hbp.mip.model.galaxy; +package eu.hbp.mip.models.galaxy; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/eu/hbp/mip/model/galaxy/GalaxyWorkflowResult.java b/src/main/java/eu/hbp/mip/models/galaxy/GalaxyWorkflowResult.java similarity index 99% rename from src/main/java/eu/hbp/mip/model/galaxy/GalaxyWorkflowResult.java rename to src/main/java/eu/hbp/mip/models/galaxy/GalaxyWorkflowResult.java index 089a6a626ed1e0d38306c911b515edd3fa8fa5f0..ca7d98fe51e55cd60914893283f2c30b6fcf90be 100644 --- a/src/main/java/eu/hbp/mip/model/galaxy/GalaxyWorkflowResult.java +++ b/src/main/java/eu/hbp/mip/models/galaxy/GalaxyWorkflowResult.java @@ -3,7 +3,7 @@ * Copyright (c) 2019. MIT License */ -package eu.hbp.mip.model.galaxy; +package eu.hbp.mip.models.galaxy; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/eu/hbp/mip/model/galaxy/PostWorkflowToGalaxyDtoResponse.java b/src/main/java/eu/hbp/mip/models/galaxy/PostWorkflowToGalaxyDtoResponse.java similarity index 98% rename from src/main/java/eu/hbp/mip/model/galaxy/PostWorkflowToGalaxyDtoResponse.java rename to src/main/java/eu/hbp/mip/models/galaxy/PostWorkflowToGalaxyDtoResponse.java index edefd63266a8d1678bf82d057882e4eccab112cc..96d8aa8efa089599093fed13ac8e0d0a4be81f42 100644 --- a/src/main/java/eu/hbp/mip/model/galaxy/PostWorkflowToGalaxyDtoResponse.java +++ b/src/main/java/eu/hbp/mip/models/galaxy/PostWorkflowToGalaxyDtoResponse.java @@ -3,7 +3,7 @@ * Copyright (c) 2019. MIT License */ -package eu.hbp.mip.model.galaxy; +package eu.hbp.mip.models.galaxy; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/eu/hbp/mip/model/galaxy/WorkflowDTO.java b/src/main/java/eu/hbp/mip/models/galaxy/WorkflowDTO.java similarity index 95% rename from src/main/java/eu/hbp/mip/model/galaxy/WorkflowDTO.java rename to src/main/java/eu/hbp/mip/models/galaxy/WorkflowDTO.java index fa0cb4b336ef2f8276db39c1a03097f51a5c8ea7..496ee2dfebf50324b1443774cc48edd4e32c2de0 100644 --- a/src/main/java/eu/hbp/mip/model/galaxy/WorkflowDTO.java +++ b/src/main/java/eu/hbp/mip/models/galaxy/WorkflowDTO.java @@ -1,8 +1,8 @@ -package eu.hbp.mip.model.galaxy; +package eu.hbp.mip.models.galaxy; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; -import eu.hbp.mip.model.AlgorithmDTO; +import eu.hbp.mip.models.DTOs.AlgorithmDTO; import java.util.*; diff --git a/src/main/java/eu/hbp/mip/repositories/ArticleRepository.java b/src/main/java/eu/hbp/mip/repositories/ArticleRepository.java deleted file mode 100644 index 1a93186ff064bf5833246d82b2cb0d35bf838312..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/repositories/ArticleRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package eu.hbp.mip.repositories; - -import eu.hbp.mip.model.Article; -import eu.hbp.mip.model.User; -import org.springframework.data.repository.CrudRepository; - -/** - * Created by mirco on 11.07.16. - */ - -public interface ArticleRepository extends CrudRepository<Article, String> { - Long countByTitle(String title); - - Iterable<Article> findByCreatedBy(User user); - - Iterable<Article> findByStatusOrCreatedBy(String status, User user); -} diff --git a/src/main/java/eu/hbp/mip/repositories/ConfigRepository.java b/src/main/java/eu/hbp/mip/repositories/ConfigRepository.java deleted file mode 100644 index deb286150c0ba9c7833b4dfa66a61d3890c011c4..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/repositories/ConfigRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package eu.hbp.mip.repositories; - -import eu.hbp.mip.model.Config; -import org.springframework.data.repository.CrudRepository; - -/** - * Created by mirco on 11.07.16. - */ - -public interface ConfigRepository extends CrudRepository<Config, Long> { -} diff --git a/src/main/java/eu/hbp/mip/repositories/DatasetRepository.java b/src/main/java/eu/hbp/mip/repositories/DatasetRepository.java deleted file mode 100644 index 7c6da1e9745b8a144296d51a5d85434111213b96..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/repositories/DatasetRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package eu.hbp.mip.repositories; - -import eu.hbp.mip.model.Dataset; -import org.springframework.data.repository.CrudRepository; - -/** - * Created by mirco on 11.07.16. - */ - -public interface DatasetRepository extends CrudRepository<Dataset, String> { -} diff --git a/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java b/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java index 2f6ae857d49018c5d9a3cb429f17cf3d2b80d313..9ac54cada906b78ad5ab5ac41d77d05562bedc4e 100644 --- a/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java +++ b/src/main/java/eu/hbp/mip/repositories/ExperimentRepository.java @@ -1,17 +1,17 @@ package eu.hbp.mip.repositories; -import eu.hbp.mip.model.Experiment; -import eu.hbp.mip.model.User; +import eu.hbp.mip.models.DAOs.ExperimentDAO; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; +import java.util.Optional; import java.util.UUID; /** * Created by mirco on 11.07.16. */ -public interface ExperimentRepository extends CrudRepository<Experiment, UUID> { - Iterable<Experiment> findByCreatedBy(User user); - - Iterable<Experiment> findByShared(Boolean shared); +public interface ExperimentRepository extends CrudRepository<ExperimentDAO, UUID>, JpaSpecificationExecutor<ExperimentDAO> +{ + ExperimentDAO findByUuid(UUID experimentUuid); } diff --git a/src/main/java/eu/hbp/mip/repositories/ModelRepository.java b/src/main/java/eu/hbp/mip/repositories/ModelRepository.java deleted file mode 100644 index c25b1e5bb6c4a5e888851b08ae3f0a801d5a4553..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/repositories/ModelRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package eu.hbp.mip.repositories; - -import eu.hbp.mip.model.Model; -import eu.hbp.mip.model.User; -import org.springframework.data.repository.CrudRepository; - -/** - * Created by mirco on 11.07.16. - */ - -public interface ModelRepository extends CrudRepository<Model, String> { - Long countByTitle(String Title); - - Iterable<Model> findByCreatedByOrderByCreatedAt(User user); - - Iterable<Model> findByValidOrCreatedByOrderByCreatedAt(Boolean valid, User user); -} diff --git a/src/main/java/eu/hbp/mip/repositories/QueryRepository.java b/src/main/java/eu/hbp/mip/repositories/QueryRepository.java deleted file mode 100644 index f0b95d39c4c3a480fe2bec20ce75e46361889e71..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/repositories/QueryRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package eu.hbp.mip.repositories; - -import eu.hbp.mip.model.Query; -import org.springframework.data.repository.CrudRepository; - -/** - * Created by mirco on 11.07.16. - */ - -public interface QueryRepository extends CrudRepository<Query, Long> { -} diff --git a/src/main/java/eu/hbp/mip/repositories/TagRepository.java b/src/main/java/eu/hbp/mip/repositories/TagRepository.java deleted file mode 100644 index 4edb4090e0336ac034daf245d5ca3bb084a6f5ae..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/repositories/TagRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package eu.hbp.mip.repositories; - -import eu.hbp.mip.model.Tag; -import org.springframework.data.repository.CrudRepository; - -/** - * Created by mirco on 11.07.16. - */ - -public interface TagRepository extends CrudRepository<Tag, String> { -} diff --git a/src/main/java/eu/hbp/mip/repositories/UserRepository.java b/src/main/java/eu/hbp/mip/repositories/UserRepository.java index 3a0db7ee31cf9c56cdd68397d641f4a71e8c37a2..99ae0b1dcfc237e875e7ba458175ae8441ec8c8e 100644 --- a/src/main/java/eu/hbp/mip/repositories/UserRepository.java +++ b/src/main/java/eu/hbp/mip/repositories/UserRepository.java @@ -1,12 +1,13 @@ package eu.hbp.mip.repositories; -import eu.hbp.mip.model.User; +import eu.hbp.mip.models.DAOs.UserDAO; import org.springframework.data.repository.CrudRepository; /** * Created by mirco on 11.07.16. */ -public interface UserRepository extends CrudRepository<User, String> { +public interface UserRepository extends CrudRepository<UserDAO, String> { + UserDAO findByUsername(String username); } diff --git a/src/main/java/eu/hbp/mip/repositories/ValueRepository.java b/src/main/java/eu/hbp/mip/repositories/ValueRepository.java deleted file mode 100644 index b41574d6082542ec1539f8e14203e61eb27e0614..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/repositories/ValueRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package eu.hbp.mip.repositories; - -import eu.hbp.mip.model.Value; -import org.springframework.data.repository.CrudRepository; - -/** - * Created by mirco on 11.07.16. - */ - -public interface ValueRepository extends CrudRepository<Value, String> { -} diff --git a/src/main/java/eu/hbp/mip/repositories/VariableRepository.java b/src/main/java/eu/hbp/mip/repositories/VariableRepository.java deleted file mode 100644 index 3ded949436f345143bb9e60a51bc0ee2ab20019b..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/repositories/VariableRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package eu.hbp.mip.repositories; - -import eu.hbp.mip.model.Variable; -import org.springframework.data.repository.CrudRepository; - -/** - * Created by mirco on 13.09.16. - */ -public interface VariableRepository extends CrudRepository<Variable, String> { -} diff --git a/src/main/java/eu/hbp/mip/services/ActiveUserService.java b/src/main/java/eu/hbp/mip/services/ActiveUserService.java new file mode 100644 index 0000000000000000000000000000000000000000..bc3c8ced7fc3a573a8fe67bd87abaf1dcf19246c --- /dev/null +++ b/src/main/java/eu/hbp/mip/services/ActiveUserService.java @@ -0,0 +1,85 @@ +package eu.hbp.mip.services; + +import eu.hbp.mip.models.DAOs.UserDAO; +import eu.hbp.mip.repositories.UserRepository; +import org.keycloak.KeycloakPrincipal; +import org.keycloak.representations.IDToken; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +import javax.inject.Named; +import java.util.Objects; + +@Component +@Named("ActiveUserService") +@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) +public class ActiveUserService { + + @Value("#{'${authentication.enabled}'}") + private boolean authenticationIsEnabled; + + private UserDAO user; + + private final UserRepository userRepository; + + public ActiveUserService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + /** + * Fetches the details of the active user. + * If the user doesn't exist, it's created on the fly from the auth token. + * + * @return the userDAO + */ + public UserDAO getActiveUser() { + + // User already loaded + if (user != null) + return user; + + // If Authentication is OFF, create anonymous user with accepted NDA + if (!authenticationIsEnabled) { + user = new UserDAO("anonymous", "anonymous", "anonymous@anonymous.com", "anonymousId"); + user.setAgreeNDA(true); + userRepository.save(user); + return user; + } + + // If authentication is ON get user info from Token + KeycloakPrincipal keycloakPrincipal = + (KeycloakPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + IDToken idToken = keycloakPrincipal.getKeycloakSecurityContext().getIdToken(); + user = new UserDAO(idToken.getPreferredUsername(), idToken.getName(), idToken.getEmail(), idToken.getId()); + + UserDAO userInDatabase = userRepository.findByUsername(user.getUsername()); + if (userInDatabase == null) { + userRepository.save(user); + return user; + } + + if (!Objects.equals(user.getEmail(),userInDatabase.getEmail()) + || !Objects.equals(user.getFullname(),userInDatabase.getFullname()) + ) { + userInDatabase.setFullname(user.getFullname()); + userInDatabase.setEmail(user.getEmail()); + } + + user = userInDatabase; + userRepository.save(user); + return user; + } + + public UserDAO agreeToNDA() { + // Fetch the active user + getActiveUser(); + + user.setAgreeNDA(true); + userRepository.save(user); + + return user; + } +} diff --git a/src/main/java/eu/hbp/mip/services/ExperimentService.java b/src/main/java/eu/hbp/mip/services/ExperimentService.java new file mode 100644 index 0000000000000000000000000000000000000000..45345c8a5b33d5826c149cd384a5b17c0d3b7a78 --- /dev/null +++ b/src/main/java/eu/hbp/mip/services/ExperimentService.java @@ -0,0 +1,1008 @@ +package eu.hbp.mip.services; + +import com.github.jmchilton.blend4j.galaxy.GalaxyInstance; +import com.github.jmchilton.blend4j.galaxy.GalaxyInstanceFactory; +import com.github.jmchilton.blend4j.galaxy.WorkflowsClient; +import com.github.jmchilton.blend4j.galaxy.beans.Workflow; +import com.github.jmchilton.blend4j.galaxy.beans.WorkflowDetails; +import com.github.jmchilton.blend4j.galaxy.beans.WorkflowInputDefinition; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.internal.LinkedTreeMap; +import eu.hbp.mip.controllers.galaxy.retrofit.RetroFitGalaxyClients; +import eu.hbp.mip.controllers.galaxy.retrofit.RetrofitClientInstance; +import eu.hbp.mip.models.DAOs.ExperimentDAO; +import eu.hbp.mip.models.DAOs.UserDAO; +import eu.hbp.mip.models.DTOs.AlgorithmDTO; +import eu.hbp.mip.models.DTOs.ExperimentDTO; +import eu.hbp.mip.models.galaxy.GalaxyWorkflowResult; +import eu.hbp.mip.models.galaxy.PostWorkflowToGalaxyDtoResponse; +import eu.hbp.mip.repositories.ExperimentRepository; +import eu.hbp.mip.services.Specifications.ExperimentSpecifications; +import eu.hbp.mip.utils.ClaimUtils; +import eu.hbp.mip.utils.Exceptions.*; +import eu.hbp.mip.utils.HTTPUtil; +import eu.hbp.mip.utils.JsonConverters; +import eu.hbp.mip.utils.Logger; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; +import retrofit2.Call; +import retrofit2.Response; + +import java.io.IOException; +import java.util.*; + +import static java.lang.Thread.sleep; + +@Service +public class ExperimentService { + + + @Value("#{'${services.exareme.queryExaremeUrl}'}") + private String queryExaremeUrl; + + @Value("#{'${services.galaxy.galaxyUrl}'}") + private String galaxyUrl; + + @Value("#{'${services.galaxy.galaxyApiKey}'}") + private String galaxyApiKey; + + @Value("#{'${authentication.enabled}'}") + private boolean authenticationIsEnabled; + + private static final Gson gson = new Gson(); + + private final ActiveUserService activeUserService; + private final ExperimentRepository experimentRepository; + + public ExperimentService(ActiveUserService activeUserService, ExperimentRepository experimentRepository) { + this.activeUserService = activeUserService; + this.experimentRepository = experimentRepository; + } + + /** + * The getExperiments will retrieve the experiments from database according to the filters. + * + * @param name is optional, in case it is required to filter the experiments by name + * @param algorithm is optional, in case it is required to filter the experiments by algorithm name + * @param shared is optional, in case it is required to filter the experiments by shared + * @param viewed is optional, in case it is required to filter the experiments by viewed + * @param includeShared is optional, in case it is required to retrieve the experiment that is shared + * @param page is the page that is required to be retrieve + * @param size is the size of each page + * @param orderBy is the column that is required to ordered by + * @param descending is a boolean to determine if the experiments will be order by descending or ascending + * @param logger contains username and the endpoint. + * @return a list of mapped experiments + */ + + public Map getExperiments(Authentication authentication, String name, String algorithm, Boolean shared, Boolean viewed, boolean includeShared, int page, int size, String orderBy, Boolean descending, Logger logger) { + + UserDAO user = activeUserService.getActiveUser(); + logger.LogUserAction("Listing my experiments."); + if (size > 50) + throw new BadRequestException("Invalid size input, max size is 50."); + Specification<ExperimentDAO> spec; + if(!authenticationIsEnabled || ClaimUtils.validateAccessRightsOnExperiments(authentication, logger)) + { + spec = Specification + .where(new ExperimentSpecifications.ExperimentWithName(name)) + .and(new ExperimentSpecifications.ExperimentWithAlgorithm(algorithm)) + .and(new ExperimentSpecifications.ExperimentWithShared(shared)) + .and(new ExperimentSpecifications.ExperimentWithViewed(viewed)) + .and(new ExperimentSpecifications.ExperimentOrderBy(orderBy, descending)); + } + else { + spec = Specification + .where(new ExperimentSpecifications.MyExperiment(user.getUsername())) + .or(new ExperimentSpecifications.SharedExperiment(includeShared)) + .and(new ExperimentSpecifications.ExperimentWithAlgorithm(algorithm)) + .and(new ExperimentSpecifications.ExperimentWithShared(shared)) + .and(new ExperimentSpecifications.ExperimentWithViewed(viewed)) + .and(new ExperimentSpecifications.ExperimentWithName(name)) + .and(new ExperimentSpecifications.ExperimentOrderBy(orderBy, descending)); + } + Pageable paging = PageRequest.of(page, size); + Page<ExperimentDAO> pageExperiments = experimentRepository.findAll(spec, paging); + List<ExperimentDAO> experimentDAOs = pageExperiments.getContent(); + + if (experimentDAOs.isEmpty()) + throw new NoContent("No experiment found with the filters provided."); + + List<ExperimentDTO> experimentDTOs = new ArrayList<>(); + experimentDAOs.forEach(experimentDAO -> experimentDTOs.add(experimentDAO.convertToDTO(false))); + + Map<String, Object> response = new HashMap<>(); + response.put("experiments", experimentDTOs); + response.put("currentPage", pageExperiments.getNumber()); + response.put("totalExperiments", pageExperiments.getTotalElements()); + response.put("totalPages", pageExperiments.getTotalPages()); + + return response; + } + + /** + * The getExperiment will retrieve the experiment from database according to the input uuid + * + * @param uuid is the id of the experiment to be retrieved + * @param logger contains username and the endpoint. + * @return the experiment information that was retrieved from the database + */ + public ExperimentDTO getExperiment(Authentication authentication, String uuid, Logger logger) { + + ExperimentDAO experimentDAO; + UserDAO user = activeUserService.getActiveUser(); + + logger.LogUserAction("Loading Experiment with uuid : " + uuid); + + experimentDAO = loadExperiment(uuid, logger); + if ( + !experimentDAO.isShared() + && !experimentDAO.getCreatedBy().getUsername().equals(user.getUsername()) + && authenticationIsEnabled + && ClaimUtils.validateAccessRightsOnExperiments(authentication, logger) + ) { + logger.LogUserAction("Accessing Experiment is unauthorized."); + throw new UnauthorizedException("You don't have access to the experiment."); + } + ExperimentDTO experimentDTO = experimentDAO.convertToDTO(true); + logger.LogUserAction("Experiment was Loaded with uuid : " + uuid + "."); + + return experimentDTO; + } + + /** + * The createExperiment will create and save an experiment in the database. + * + * @param authentication is the role of the user + * @param experimentDTO is the experiment information + * @param logger contains username and the endpoint. + * @return the experiment information which was created + */ + public ExperimentDTO createExperiment(Authentication authentication, ExperimentDTO experimentDTO, Logger logger) { + + //Checking if check (POST) /experiments has proper input. + checkPostExperimentProperInput(experimentDTO, logger); + + // Get the type and name of algorithm + String algorithmType = experimentDTO.getAlgorithm().getType(); + + if(algorithmType == null){ + logger.LogUserAction("Please provide algorithm type."); + throw new BadRequestException("Please provide algorithm type."); + } + + algorithmParametersLogging(experimentDTO, logger); + + if (authenticationIsEnabled) { + String experimentDatasets = getDatasetFromExperimentParameters(experimentDTO, logger); + ClaimUtils.validateAccessRightsOnDatasets(authentication, experimentDatasets, logger); + } + + // Run with the appropriate engine + if (algorithmType.equals("workflow")) { + logger.LogUserAction("Algorithm runs on Galaxy."); + return runGalaxyWorkflow(experimentDTO, logger); + } else { + logger.LogUserAction("Algorithm runs on Exareme."); + return createExaremeExperiment(experimentDTO, logger); + } + } + + /** + * The createTransientExperiment will run synchronous a transient experiment into exareme and provide results + * + * @param authentication is the role of the user + * @param experimentDTO is the experiment information + * @param logger contains username and the endpoint. + * @return the experiment information which was created + */ + public ExperimentDTO createTransientExperiment(Authentication authentication, ExperimentDTO experimentDTO, Logger logger) { + + //Checking if check (POST) /experiments has proper input. + checkPostExperimentProperInput(experimentDTO, logger); + + // Get the type and name of algorithm + String algorithmType = experimentDTO.getAlgorithm().getType(); + + if(algorithmType.equals("workflow")){ + logger.LogUserAction("You can not run workflow algorithms transiently."); + throw new BadRequestException("You can not run workflow algorithms transiently."); + } + + // Get the parameters + List<AlgorithmDTO.AlgorithmParamDTO> algorithmParameters + = experimentDTO.getAlgorithm().getParameters(); + + // Get the type and name of algorithm + String algorithmName = experimentDTO.getAlgorithm().getName(); + + algorithmParametersLogging(experimentDTO, logger); + + if (authenticationIsEnabled) { + String experimentDatasets = getDatasetFromExperimentParameters(experimentDTO, logger); + ClaimUtils.validateAccessRightsOnDatasets(authentication, experimentDatasets, logger); + } + + String body = gson.toJson(algorithmParameters); + String url = queryExaremeUrl + "/" + algorithmName; + logger.LogUserAction("url: " + url + ", body: " + body); + + logger.LogUserAction("Completed, returning: " + experimentDTO.toString()); + + // Results are stored in the experiment object + ExaremeResult exaremeResult = runExaremeExperiment(url, body, experimentDTO); + + logger.LogUserAction("Experiment with uuid: " + experimentDTO.getUuid() + "gave response code: " + exaremeResult.getCode() + " and result: " + exaremeResult.getResults()); + + experimentDTO.setResult((exaremeResult.getCode() >= 400) ? null : exaremeResult.getResults()); + experimentDTO.setStatus((exaremeResult.getCode() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); + + return experimentDTO; + } + + /** + * The updateExperiment will update the experiment's properties + * + * @param uuid is the id of the experiment to be updated + * @param experimentDTO is the experiment information to be updated + * @param logger contains username and the endpoint. + */ + public ExperimentDTO updateExperiment(String uuid, ExperimentDTO experimentDTO, Logger logger) { + ExperimentDAO experimentDAO; + UserDAO user = activeUserService.getActiveUser(); + logger.LogUserAction("Updating experiment with uuid : " + uuid + "."); + + experimentDAO = loadExperiment(uuid, logger); + + //Verify (PATCH) /experiments non editable fields. + verifyPatchExperimentNonEditableFields(experimentDTO, logger); + + if (!experimentDAO.getCreatedBy().getUsername().equals(user.getUsername())) + throw new UnauthorizedException("You don't have access to the experiment."); + + if (experimentDTO.getName() != null && experimentDTO.getName().length() != 0) + experimentDAO.setName(experimentDTO.getName()); + + if (experimentDTO.getShared() != null) + experimentDAO.setShared(experimentDTO.getShared()); + + if (experimentDTO.getViewed() != null) + experimentDAO.setViewed(experimentDTO.getViewed()); + + experimentDAO.setUpdated(new Date()); + + try { + experimentRepository.save(experimentDAO); + } catch (Exception e) { + logger.LogUserAction("Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); + throw new InternalServerError(e.getMessage()); + } + + logger.LogUserAction("Updated experiment with uuid : " + uuid + "."); + + experimentDTO = experimentDAO.convertToDTO(true); + return experimentDTO; + } + + /** + * The deleteExperiment will delete an experiment from the database + * + * @param uuid is the id of the experiment to be deleted + * @param logger contains username and the endpoint. + */ + public void deleteExperiment(String uuid, Logger logger) { + ExperimentDAO experimentDAO; + UserDAO user = activeUserService.getActiveUser(); + logger.LogUserAction("Deleting experiment with uuid : " + uuid + "."); + + experimentDAO = loadExperiment(uuid, logger); + + if (!experimentDAO.getCreatedBy().getUsername().equals(user.getUsername())) + throw new UnauthorizedException("You don't have access to the experiment."); + + try { + experimentRepository.delete(experimentDAO); + } catch (Exception e) { + logger.LogUserAction("Attempted to delete an experiment to database but an error ocurred : " + e.getMessage() + "."); + throw new InternalServerError(e.getMessage()); + } + + logger.LogUserAction("Deleted experiment with uuid : " + uuid + "."); + } + + // /* ------------------------------- PRIVATE METHODS ----------------------------------------------------*/ + + private void checkPostExperimentProperInput(ExperimentDTO experimentDTO, Logger logger) { + + boolean properInput = + experimentDTO.getShared() == null + && experimentDTO.getViewed() == null + && experimentDTO.getCreated() == null + && experimentDTO.getCreatedBy() == null + && experimentDTO.getResult() == null + && experimentDTO.getStatus() == null + && experimentDTO.getUuid() == null; + + if (!properInput) { + logger.LogUserAction( "Invalid input."); + throw new BadRequestException("Please provide proper input."); + } + } + + private void verifyPatchExperimentNonEditableFields(ExperimentDTO experimentDTO, Logger logger) { + if (experimentDTO.getUuid() != null ) { + logger.LogUserAction( "Uuid is not editable."); + throw new BadRequestException("Uuid is not editable."); + } + + if (experimentDTO.getAlgorithm() != null ) { + logger.LogUserAction( "Algorithm is not editable."); + throw new BadRequestException("Algorithm is not editable."); + } + + if (experimentDTO.getCreated() != null) { + logger.LogUserAction( "Created is not editable."); + throw new BadRequestException("Created is not editable."); + } + + if (experimentDTO.getCreatedBy() != null) { + logger.LogUserAction( "CreatedBy is not editable."); + throw new BadRequestException("CreatedBy is not editable."); + } + + if (experimentDTO.getUpdated() != null) { + logger.LogUserAction( "Updated is not editable."); + throw new BadRequestException("Updated is not editable."); + } + + if (experimentDTO.getFinished() != null) { + logger.LogUserAction( "Finished is not editable."); + throw new BadRequestException("Finished is not editable."); + } + + if (experimentDTO.getResult() != null) { + logger.LogUserAction( "Result is not editable."); + throw new BadRequestException("Result is not editable."); + } + + if (experimentDTO.getStatus() != null) { + logger.LogUserAction( "Status is not editable."); + throw new BadRequestException("Status is not editable."); + } + } + + private void algorithmParametersLogging(ExperimentDTO experimentDTO, Logger logger) { + String algorithmName = experimentDTO.getAlgorithm().getName(); + StringBuilder parametersLogMessage = new StringBuilder(", Parameters:\n"); + experimentDTO.getAlgorithm().getParameters().forEach( + params -> parametersLogMessage + .append(" ") + .append(params.getLabel()) + .append(" -> ") + .append(params.getValue()) + .append("\n")); + logger.LogUserAction("Executing " + algorithmName + parametersLogMessage); + } + + /** + * The getDatasetFromExperimentParameters will retrieve the dataset from the experiment parameters + * + * @param experimentDTO is the experiment information + * @param logger contains username and the endpoint. + * @return the dataset from the experiment + */ + private String getDatasetFromExperimentParameters(ExperimentDTO experimentDTO, Logger logger) { + + String experimentDatasets = null; + for (AlgorithmDTO.AlgorithmParamDTO parameter : experimentDTO.getAlgorithm().getParameters()) { + if (parameter.getLabel().equals("dataset")) { + experimentDatasets = parameter.getValue(); + break; + } + } + + if (experimentDatasets == null || experimentDatasets.equals("")) { + logger.LogUserAction("A dataset should be specified to run an algorithm."); + throw new BadRequestException("Please provide at least one dataset to run the algorithm."); + } + return experimentDatasets; + } + + /** + * The loadExperiment access the database and load the information of a specific experiment + * + * @param uuid is the id of the experiment to be retrieved + * @return the experiment information that was retrieved from database + */ + private ExperimentDAO loadExperiment(String uuid, Logger logger) { + UUID experimentUuid; + ExperimentDAO experimentDAO; + + try { + experimentUuid = UUID.fromString(uuid); + } catch (Exception e) { + logger.LogUserAction( e.getMessage()); + throw new BadRequestException(e.getMessage()); + } + + experimentDAO = experimentRepository.findByUuid(experimentUuid); + if (experimentDAO == null) { + logger.LogUserAction( "Experiment with uuid : " + uuid + "was not found."); + throw new ExperimentNotFoundException("Experiment with uuid : " + uuid + " was not found."); + } + + return experimentDAO; + } + + /** + * The createExperimentInTheDatabase will insert a new experiment in the database according to the given experiment information + * + * @param experimentDTO is the experiment information to inserted in the database + * @return the experiment information that was inserted into the database + * @Note In the database there will be stored Algorithm Details that is the whole information about the algorithm + * and an Algorithm column that is required for the filtering with algorithm name in the GET /experiments. + */ + private ExperimentDAO createExperimentInTheDatabase(ExperimentDTO experimentDTO, Logger logger) { + UserDAO user = activeUserService.getActiveUser(); + + ExperimentDAO experimentDAO = new ExperimentDAO(); + experimentDAO.setUuid(UUID.randomUUID()); + experimentDAO.setCreatedBy(user); + experimentDAO.setAlgorithm(JsonConverters.convertObjectToJsonString(experimentDTO.getAlgorithm())); + experimentDAO.setAlgorithmId(experimentDTO.getAlgorithm().getName()); + experimentDAO.setName(experimentDTO.getName()); + experimentDAO.setStatus(ExperimentDAO.Status.pending); + + try { + experimentRepository.save(experimentDAO); + } catch (Exception e) { + logger.LogUserAction("Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); + throw new InternalServerError(e.getMessage()); + } + + logger.LogUserAction(" id : " + experimentDAO.getUuid()); + logger.LogUserAction(" algorithm : " + experimentDAO.getAlgorithm()); + logger.LogUserAction(" name : " + experimentDAO.getName()); + return experimentDAO; + } + + private void saveExperiment(ExperimentDAO experimentDAO, Logger logger) { + + logger.LogUserAction(" id : " + experimentDAO.getUuid()); + logger.LogUserAction(" algorithm : " + experimentDAO.getAlgorithm()); + logger.LogUserAction(" name : " + experimentDAO.getName()); + logger.LogUserAction(" historyId : " + experimentDAO.getWorkflowHistoryId()); + logger.LogUserAction(" status : " + experimentDAO.getStatus()); + + try { + experimentRepository.save(experimentDAO); + } catch (Exception e) { + logger.LogUserAction("Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); + throw new InternalServerError(e.getMessage()); + } + + logger.LogUserAction("Saved experiment"); + } + + private void finishExperiment(ExperimentDAO experimentDAO, Logger logger) { + experimentDAO.setFinished(new Date()); + + try { + experimentRepository.save(experimentDAO); + } catch (Exception e) { + logger.LogUserAction( "Attempted to save changes to database but an error ocurred : " + e.getMessage() + "."); + throw new InternalServerError(e.getMessage()); + } + } + + private String formattingGalaxyResult(String result) { + List<LinkedTreeMap<String,Object>> jsonObject = JsonConverters.convertJsonStringToObject(result, new ArrayList<ArrayList<Object>>().getClass()); + LinkedTreeMap<String,Object> firstResult = jsonObject.get(0); + jsonObject = (List<LinkedTreeMap<String, Object>>) firstResult.get("result"); + List<LinkedTreeMap<String,Object>> finalJsonObject = new ArrayList<>(); + finalJsonObject.add(jsonObject.get(0)); + return JsonConverters.convertObjectToJsonString(finalJsonObject); + } + + /** + * The runExaremeExperiment will run to exareme the experiment + * + * @param url is the url that contain the results of the experiment + * @param body is the parameters of the algorithm + * @param experimentDTO is the experiment information to be executed in the exareme + * @return the result of exareme as well as the http status that was retrieved + */ + public ExaremeResult runExaremeExperiment(String url, String body, ExperimentDTO experimentDTO) { + + StringBuilder results = new StringBuilder(); + int code; + try { + code = HTTPUtil.sendPost(url, body, results); + } catch (Exception e) { + throw new InternalServerError("Error occurred : " + e.getMessage()); + } + + // Results are stored in the experiment object + ExperimentDTO experimentDTOWithOnlyResult = JsonConverters.convertJsonStringToObject(String.valueOf(results), ExperimentDTO.class); + List<Object> resultDTOS = experimentDTOWithOnlyResult.getResult(); + + return new ExaremeResult(code, resultDTOS); + } + + /* -------------------------------------- EXAREME CALLS ---------------------------------------------------------*/ + + /** + * The createExaremeExperiment will POST the algorithm to the exareme client + * + * @param experimentDTO is the request with the experiment information + * @param logger contains username and the endpoint. + * @return the experiment information that was retrieved from exareme + */ + public ExperimentDTO createExaremeExperiment(ExperimentDTO experimentDTO, Logger logger) { + + logger.LogUserAction("Running the algorithm..."); + + ExperimentDAO experimentDAO = createExperimentInTheDatabase(experimentDTO, logger); + logger.LogUserAction("Created experiment with uuid :" + experimentDAO.getUuid()); + + // Run the 1st algorithm from the list + String algorithmName = experimentDTO.getAlgorithm().getName(); + + // Get the parameters + List<AlgorithmDTO.AlgorithmParamDTO> algorithmParameters + = experimentDTO.getAlgorithm().getParameters(); + + String body = gson.toJson(algorithmParameters); + String url = queryExaremeUrl + "/" + algorithmName; + logger.LogUserAction("url: " + url + ", body: " + body); + + logger.LogUserAction("Completed, returning: " + experimentDTO.toString()); + + logger.LogUserAction("Starting exareme execution thread"); + ExperimentDTO finalExperimentDTO = experimentDTO; + new Thread(() -> { + + // ATTENTION: Inside the Thread only LogExperimentAction should be used, not LogUserAction! + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Thread named :" + Thread.currentThread().getName() + " with id :" + Thread.currentThread().getId() + " started!"); + + try { + // Results are stored in the experiment object + ExaremeResult exaremeResult = runExaremeExperiment(url, body, finalExperimentDTO); + + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Experiment with uuid: " + experimentDAO.getUuid() + "gave response code: " + exaremeResult.getCode() + " and result: " + exaremeResult.getResults()); + + experimentDAO.setResult((exaremeResult.getCode() >= 400) ? null : JsonConverters.convertObjectToJsonString(exaremeResult.getResults())); + experimentDAO.setStatus((exaremeResult.getCode() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); + } catch (Exception e) { + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "There was an exception: " + e.getMessage()); + + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + + finishExperiment(experimentDAO, logger); + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Finished the experiment: " + experimentDAO.toString()); + }).start(); + experimentDTO = experimentDAO.convertToDTO(true); + return experimentDTO; + } + + /* --------------------------------------- GALAXY CALLS ---------------------------------------------------------*/ + + + /** + * The runWorkflow will POST the algorithm to the galaxy client + * + * @param experimentDTO is the request with the experiment information + * @return the response to be returned + */ + public ExperimentDTO runGalaxyWorkflow(ExperimentDTO experimentDTO, Logger logger) { + logger.LogUserAction("Running a workflow..."); + + ExperimentDAO experimentDAO = createExperimentInTheDatabase(experimentDTO, logger); + logger.LogUserAction("Created experiment with uuid :" + experimentDAO.getUuid()); + + + // Run the 1st algorithm from the list + String workflowId = experimentDTO.getAlgorithm().getName(); + + // Get the parameters + List<AlgorithmDTO.AlgorithmParamDTO> algorithmParameters + = experimentDTO.getAlgorithm().getParameters(); + + // Convert the parameters to workflow parameters + HashMap<String, String> algorithmParamsIncludingEmpty = new HashMap<>(); + if (algorithmParameters != null) { + for (AlgorithmDTO.AlgorithmParamDTO param : algorithmParameters) { + algorithmParamsIncludingEmpty.put(param.getName(), param.getValue()); + } + } + + // Get all the algorithm parameters because the frontend provides only the non-null + final GalaxyInstance instance = GalaxyInstanceFactory.get(galaxyUrl, galaxyApiKey); + final WorkflowsClient workflowsClient = instance.getWorkflowsClient(); + Workflow workflow = null; + for (Workflow curWorkflow : workflowsClient.getWorkflows()) { + if (curWorkflow.getId().equals(workflowId)) { + workflow = curWorkflow; + break; + } + } + if (workflow == null) { + logger.LogUserAction("Could not find algorithm code: " + workflowId); + throw new BadRequestException("Could not find galaxy algorithm."); + } + final WorkflowDetails workflowDetails = workflowsClient.showWorkflow(workflow.getId()); + for (Map.Entry<String, WorkflowInputDefinition> workflowParameter : workflowDetails.getInputs().entrySet()) { + if (!(algorithmParamsIncludingEmpty.containsKey(workflowParameter.getValue().getUuid()))) { + algorithmParamsIncludingEmpty.put(workflowParameter.getValue().getUuid(), ""); + } + } + + // Create the body of the request + HashMap<String, HashMap<String, String>> requestBody = new HashMap<>(); + requestBody.put("inputs", algorithmParamsIncludingEmpty); + JsonObject requestBodyJson = new JsonParser().parse(gson.toJson(requestBody)).getAsJsonObject(); + + // Create the request client + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + logger.LogUserAction("Running Galaxy workflow with id: " + workflow.getId()); + + // Call Galaxy to run the workflow + Call<PostWorkflowToGalaxyDtoResponse> call = service.postWorkflowToGalaxy(workflow.getId(), galaxyApiKey, requestBodyJson); + try { + Response<PostWorkflowToGalaxyDtoResponse> response = call.execute(); + + if (response.code() == 200) { // Call succeeded + String responseBody = gson.toJson(response.body()); + logger.LogUserAction("Response: " + responseBody); + + String historyId = (String) new JSONObject(responseBody).get("history_id"); + experimentDAO.setWorkflowHistoryId(historyId); + experimentDAO.setStatus(ExperimentDAO.Status.success); + + } else { // Something unexpected happened + String msgErr = gson.toJson(response.errorBody()); + logger.LogUserAction("Error Response: " + msgErr); + experimentDTO.setStatus((response.code() >= 400) ? ExperimentDAO.Status.error : ExperimentDAO.Status.success); + } + + } catch (Exception e) { + logger.LogUserAction("An exception occurred: " + e.getMessage()); + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + saveExperiment(experimentDAO, logger); + + // Start the process of fetching the status + updateWorkflowExperiment(experimentDAO, logger); + + logger.LogUserAction("Run workflow completed!"); + + experimentDTO = experimentDAO.convertToDTO(true); + return experimentDTO; + } + + + /** + * This method creates a thread that will fetch the workflow result when it is ready + * + * @param experimentDAO will be used to fetch it's workflow status, it should have the workflowHistoryId initialized + * and the result should not already be fetched + */ + public void updateWorkflowExperiment(ExperimentDAO experimentDAO, Logger logger) { + + if (experimentDAO == null) { + logger.LogUserAction("The experiment does not exist."); + return; + } + + logger.LogUserAction(" Experiment id : " + experimentDAO.getUuid()); + if (experimentDAO.getWorkflowHistoryId() == null) { + logger.LogUserAction("History Id does not exist."); + return; + } + + logger.LogUserAction("Starting Thread..."); + new Thread(() -> { + while (true) { + // ATTENTION: Inside the Thread only LogExperimentAction should be used, not LogExperimentAction! + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Thread is running..."); + + try { + sleep(2000); + } catch (InterruptedException e) { + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Sleep was disrupted: " + e.getMessage()); + } + + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Fetching status for experiment Id: " + experimentDAO.getUuid()); + + String state = getWorkflowStatus(experimentDAO); + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "State is: " + state); + + switch (state) { + case "pending": + // Do nothing, when the experiment is created the status is set to running + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Workflow is still running."); + break; + + case "success": + // Get only the job result that is visible + List<GalaxyWorkflowResult> workflowJobsResults = getWorkflowResults(experimentDAO); + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Results are: " + workflowJobsResults.toString()); + + boolean resultFound = false; + for (GalaxyWorkflowResult jobResult : workflowJobsResults) { + if (jobResult.getVisible()) { + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Visible result are: " + jobResult.getId()); + + String result = getWorkflowResultBody(experimentDAO, jobResult.getId()); + + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO: " + result); + if (result == null) { + experimentDAO.setStatus(ExperimentDAO.Status.error); + } else { + experimentDAO.setResult(result); + experimentDAO.setStatus(ExperimentDAO.Status.success); + resultFound = true; + } + } + } + + if (!resultFound) { // If there is no visible result + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "No visible result"); + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + + finishExperiment(experimentDAO, logger); + break; + + case "error": + // Get the job result that failed + workflowJobsResults = getWorkflowResults(experimentDAO); + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Error results are: " + workflowJobsResults.toString()); + + boolean failedJobFound = false; + for (GalaxyWorkflowResult jobResult : workflowJobsResults) { + if (jobResult.getState().equals("error")) { + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Failed job is: " + jobResult.getId()); + + String result = getWorkflowJobError(jobResult.getId(), experimentDAO); + + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "Job result: " + result); + if (result == null) { + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + experimentDAO.setStatus(ExperimentDAO.Status.error); + failedJobFound = true; + } + } + + if (!failedJobFound) { // If there is no visible failed job + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "No failed result"); + experimentDAO.setStatus(ExperimentDAO.Status.error); + } + finishExperiment(experimentDAO, logger); + break; + + default: // InternalError or unexpected result + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "An unexpected error occurred."); + experimentDAO.setStatus(ExperimentDAO.Status.error); + finishExperiment(experimentDAO, logger); + break; + } + + // If result exists return + if (experimentDAO.getResult() != null) { + Logger.LogExperimentAction(experimentDAO.getName(), experimentDAO.getUuid(), "ResultDTO exists: " + experimentDAO.getResult()); + return; + } + } + }).start(); + } + + + /** + * @param experimentDAO The experiment of the workflow + * @return "pending" -> When the workflow is still running + * "internalError" -> When an exception or a bad request occurred + * "error" -> When the workflow produced an error + * "success" -> When the workflow completed successfully + */ + public String getWorkflowStatus(ExperimentDAO experimentDAO) { + String historyId = experimentDAO.getWorkflowHistoryId(); + String experimentName = experimentDAO.getName(); + UUID experimentId = experimentDAO.getUuid(); + + // ATTENTION: This function is used from a Thread. Only LogExperimentAction should be used, not LogUserAction! + Logger.LogExperimentAction(experimentName, experimentId, " History Id : " + historyId); + + // Create the request client + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + Call<Object> call = service.getWorkflowStatusFromGalaxy(historyId, galaxyApiKey); + + String result; + try { + Response<Object> response = call.execute(); + if (response.code() >= 400) { + Logger.LogExperimentAction(experimentName, experimentId, " Response code: " + + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); + return "internalError"; + } + result = new Gson().toJson(response.body()); + Logger.LogExperimentAction(experimentName, experimentId, " ResultDTO: " + result); + + } catch (IOException e) { + Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); + return "internalError"; + } + + String state; + try { + JSONObject resultJson = new JSONObject(result); + state = resultJson.getString("state"); + } catch (JSONException e) { + Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); + return "internalError"; + } + + Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); + switch (state) { + case "ok": + return "success"; + case "error": + return "error"; + case "pending": + case "new": + case "waiting": + case "queued": + return "pending"; + default: + return "internalError"; + } + } + + /** + * @param experimentDAO The experiment of the workflow + * @return a List<GalaxyWorkflowResult> or null when an error occurred + */ + public List<GalaxyWorkflowResult> getWorkflowResults(ExperimentDAO experimentDAO) { + + String historyId = experimentDAO.getWorkflowHistoryId(); + String experimentName = experimentDAO.getName(); + UUID experimentId = experimentDAO.getUuid(); + Logger.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); + + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + Call<List<GalaxyWorkflowResult>> call = service.getWorkflowResultsFromGalaxy(historyId, galaxyApiKey); + + List<GalaxyWorkflowResult> getGalaxyWorkflowResultList; + try { + Response<List<GalaxyWorkflowResult>> response = call.execute(); + if (response.code() >= 400) { + Logger.LogExperimentAction(experimentName, experimentId, " Response code: " + + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); + return null; + } + getGalaxyWorkflowResultList = response.body(); + Logger.LogExperimentAction(experimentName, experimentId, " ResultDTO: " + response.body()); + + } catch (IOException e) { + Logger.LogExperimentAction(experimentName, experimentId, " An exception happened: " + e.getMessage()); + return null; + } + + Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); + return getGalaxyWorkflowResultList; + + } + + /** + * @param experimentDAO The experiment of the workflow + * @param contentId the id of the job result that we want + * @return the result of the specific workflow job, null if there was an error + */ + public String getWorkflowResultBody(ExperimentDAO experimentDAO, String contentId) { + + String historyId = experimentDAO.getWorkflowHistoryId(); + String experimentName = experimentDAO.getName(); + UUID experimentId = experimentDAO.getUuid(); + + Logger.LogExperimentAction(experimentName, experimentId, " historyId : " + historyId); + + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + Call<Object> call = + service.getWorkflowResultsBodyFromGalaxy(historyId, contentId, galaxyApiKey); + + String resultJson; + try { + Response<Object> response = call.execute(); + if (response.code() >= 400) { + Logger.LogExperimentAction(experimentName, experimentId, " Response code: " + + response.code() + "" + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); + return null; + } + resultJson = new Gson().toJson(response.body()); + Logger.LogExperimentAction(experimentName, experimentId, " ResultDTO: " + resultJson); + + } catch (IOException e) { + Logger.LogExperimentAction(experimentName, experimentId, + " An exception happened: " + e.getMessage()); + return null; + } + + Logger.LogExperimentAction(experimentName, experimentId, " Completed!"); + return formattingGalaxyResult(resultJson); + } + + + /** + * @param jobId the id of the workflow job that failed + * @return the error that was produced or null if an error occurred + */ + public String getWorkflowJobError(String jobId, ExperimentDAO experimentDAO) { + String experimentName = experimentDAO.getName(); + UUID experimentId = experimentDAO.getUuid(); + + Logger.LogExperimentAction(experimentName, experimentId, " jobId : " + jobId); + RetroFitGalaxyClients service = RetrofitClientInstance.getRetrofitInstance().create(RetroFitGalaxyClients.class); + Call<Object> callError = service.getErrorMessageOfWorkflowFromGalaxy(jobId, galaxyApiKey); + + String fullError; + String returnError; + try { + Response<Object> response = callError.execute(); + if (response.code() >= 400) { + Logger.LogExperimentAction(experimentName, experimentId, "Response code: " + + response.code() + " with body: " + (response.errorBody() != null ? response.errorBody().string() : " ")); + return null; + } + + // Parsing the stderr of the job that failed + String jsonString = new Gson().toJson(response.body()); + JsonElement jsonElement = new JsonParser().parse(jsonString); + JsonObject rootObject = jsonElement.getAsJsonObject(); + fullError = rootObject.get("stderr").getAsString(); + Logger.LogExperimentAction(experimentName, experimentId, "Error: " + fullError); + + String[] arrOfStr = fullError.split("ValueError", 0); + String specError = arrOfStr[arrOfStr.length - 1]; + returnError = specError.substring(1); + Logger.LogExperimentAction(experimentName, experimentId, "Parsed Error: " + returnError); + + } catch (IOException e) { + Logger.LogExperimentAction(experimentName, experimentId, "Exception: " + e.getMessage()); + return null; + } + + Logger.LogExperimentAction(experimentName, experimentId, "Completed successfully!"); + + return returnError; + } + + static class ExaremeResult { + private final int code; + private final List<Object> results; + + public ExaremeResult(int code, List<Object> results) { + this.code = code; + this.results = results; + } + + public int getCode() { + return code; + } + + public List<Object> getResults() { + return results; + } + } +} diff --git a/src/main/java/eu/hbp/mip/services/Specifications/ExperimentSpecifications.java b/src/main/java/eu/hbp/mip/services/Specifications/ExperimentSpecifications.java new file mode 100644 index 0000000000000000000000000000000000000000..c1e6a13acae08d9ac2c516884773b5bf9b4c71b2 --- /dev/null +++ b/src/main/java/eu/hbp/mip/services/Specifications/ExperimentSpecifications.java @@ -0,0 +1,158 @@ +package eu.hbp.mip.services.Specifications; + +import eu.hbp.mip.models.DAOs.ExperimentDAO; +import eu.hbp.mip.models.DAOs.UserDAO; +import eu.hbp.mip.utils.Exceptions.BadRequestException; +import org.springframework.data.jpa.domain.Specification; + +import javax.persistence.criteria.*; +import java.util.ArrayList; +import java.util.List; + +public class ExperimentSpecifications { + public static class ExperimentWithName implements Specification<ExperimentDAO> { + + private String name; + private String regExp; + + public ExperimentWithName(String name) { + this.name = name; + this.regExp = name; + } + + public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { + if (name == null) { + return cb.isTrue(cb.literal(true)); + } else { + regExp = (name.contains("%") ? name : name + "%"); + } + + return cb.like(cb.lower(root.get("name")), this.regExp.toLowerCase()); + } + } + + public static class ExperimentWithAlgorithm implements Specification<ExperimentDAO> { + + private String algorithm; + + public ExperimentWithAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { + if (algorithm == null) { + return cb.isTrue(cb.literal(true)); + } + + return cb.equal(cb.lower(root.get("algorithm")), this.algorithm.toLowerCase()); + } + } + + public static class ExperimentWithViewed implements Specification<ExperimentDAO> { + + private Boolean viewed; + + public ExperimentWithViewed(Boolean viewed) { + this.viewed = viewed; + } + + public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> query, CriteriaBuilder cb) { + if (viewed == null) { + return cb.isTrue(cb.literal(true)); // always true = no filtering + } + return cb.equal(root.get("viewed"), this.viewed); + } + } + + public static class ExperimentWithShared implements Specification<ExperimentDAO> { + + private Boolean shared; + + public ExperimentWithShared(Boolean shared) { + this.shared = shared; + } + + public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { + if (shared == null) { + return cb.isTrue(cb.literal(true)); + } + return cb.equal(root.get("shared"), this.shared); + } + } + + public static class MyExperiment implements Specification<ExperimentDAO> { + + private String username; + + public MyExperiment(String username) { + this.username = username; + } + + public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { + if (username == null) { + return cb.isTrue(cb.literal(true)); + } + Join<ExperimentDAO, UserDAO> experimentDAOUserDAOJoin = root.join("createdBy"); + return cb.equal(experimentDAOUserDAOJoin.get("username"), username); + } + } + + public static class SharedExperiment implements Specification<ExperimentDAO> { + + private boolean shared; + + public SharedExperiment(boolean shared) { + this.shared = shared; + } + + public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { + if (shared == false) { + return cb.isTrue(cb.literal(false)); + } + return cb.equal(root.get("shared"), shared); + } + } + + public static class ExperimentOrderBy implements Specification<ExperimentDAO> { + + private String orderBy; + private Boolean descending; + + public ExperimentOrderBy(String orderBy, Boolean descending) { + if (properColumnToBeOrderedBy(orderBy)) + this.orderBy = orderBy; + else + throw new BadRequestException("Please provide proper column to order by."); + if (descending == null) + this.descending = true; + else + this.descending = descending; + } + + public Predicate toPredicate(Root<ExperimentDAO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { + if (descending) { + criteriaQuery.orderBy(cb.desc(root.get(orderBy))); + } else { + criteriaQuery.orderBy(cb.asc(root.get(orderBy))); + } + return cb.isTrue(cb.literal(true)); + } + + } + + public static boolean properColumnToBeOrderedBy(String column) { + { + List<String> properColumns = new ArrayList<>(); + properColumns.add("uuid"); + properColumns.add("name"); + properColumns.add("created_by_username"); + properColumns.add("algorithm"); + properColumns.add("created"); + properColumns.add("status"); + properColumns.add("shared"); + properColumns.add("viewed"); + return properColumns.contains(column); + } + } +} + diff --git a/src/main/java/eu/hbp/mip/utils/CORSFilter.java b/src/main/java/eu/hbp/mip/utils/CORSFilter.java index 7ed1ecf38d84fedddb5acb4750db327fbb9e5079..7d77b9022ef0855f0f5d6decf84601d0a00f75b0 100644 --- a/src/main/java/eu/hbp/mip/utils/CORSFilter.java +++ b/src/main/java/eu/hbp/mip/utils/CORSFilter.java @@ -1,32 +1,25 @@ package eu.hbp.mip.utils; + import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; + /** - * Created by mirco on 12.02.16. + * CORS Filter used only for development. + * + * Allows requests from all possible origins. */ 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", "*"); - response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT"); + response.setHeader("Access-Control-Allow-Methods", "GET,POST,PATCH,DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "*"); response.setHeader("Access-Control-Request-Headers", "*"); chain.doFilter(req, res); } - - @Override - public void init(FilterConfig filterConfig) { - /* Nothing to do */ - } - - @Override - public void destroy() { - /* Nothing to do */ - } -} +} \ No newline at end of file diff --git a/src/main/java/eu/hbp/mip/utils/ClaimUtils.java b/src/main/java/eu/hbp/mip/utils/ClaimUtils.java index e71d3f19083d03ae0067176b2fccfe4f06175915..f5676b52c130f0b4be1c79d939567f74b752c0db 100644 --- a/src/main/java/eu/hbp/mip/utils/ClaimUtils.java +++ b/src/main/java/eu/hbp/mip/utils/ClaimUtils.java @@ -1,13 +1,14 @@ package eu.hbp.mip.utils; import com.google.gson.Gson; -import eu.hbp.mip.model.PathologyDTO; -import org.springframework.security.core.GrantedAuthority; +import eu.hbp.mip.models.DTOs.PathologyDTO; +import eu.hbp.mip.utils.Exceptions.InternalServerError; +import eu.hbp.mip.utils.Exceptions.UnauthorizedException; +import org.keycloak.KeycloakPrincipal; +import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; +import org.springframework.security.core.Authentication; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; public class ClaimUtils { @@ -15,68 +16,68 @@ public class ClaimUtils { private static final Gson gson = new Gson(); public static String allDatasetsAllowedClaim() { - return "dataset_all"; + return "research_dataset_all"; + } + + public static String allExperimentsAllowedClaim() { + return "research_experiment_all"; } public static String getDatasetClaim(String datasetCode) { - return "dataset_" + datasetCode.toLowerCase(); + return "research_dataset_" + datasetCode.toLowerCase(); } - public static boolean userHasDatasetsAuthorization(String username, Collection<? extends GrantedAuthority> authorities, - String experimentDatasets) { + public static void validateAccessRightsOnDatasets(Authentication authentication, + String experimentDatasets, Logger logger) { - List<String> userClaims = Arrays.asList(authorities.toString().toLowerCase() - .replaceAll("[\\s+\\]\\[]", "").split(",")); - Logging.LogUserAction(username, "(POST) /experiments/runAlgorithm", userClaims.toString()); + ArrayList<String> authorities = getKeycloakAuthorities(authentication, logger); // Don't check for dataset claims if "super" claim exists allowing everything - if (!userClaims.contains(ClaimUtils.allDatasetsAllowedClaim())) { + if (!hasRoleAccess(authorities, ClaimUtils.allDatasetsAllowedClaim(), logger)) { for (String dataset : experimentDatasets.split(",")) { String datasetRole = ClaimUtils.getDatasetClaim(dataset); - if (!userClaims.contains(datasetRole.toLowerCase())) { - Logging.LogUserAction(username, "(POST) /experiments/runAlgorithm", - "You are not allowed to use dataset: " + dataset); - return false; + if (!hasRoleAccess(authorities, datasetRole, logger)) { + logger.LogUserAction("You are not allowed to use dataset: " + dataset); + throw new UnauthorizedException("You are not authorized to use these datasets."); } } - Logging.LogUserAction(username, "(POST) /experiments/runAlgorithm", - "User is authorized to use the datasets: " + experimentDatasets); + logger.LogUserAction("User is authorized to use the datasets: " + experimentDatasets); } - return true; } - public static String getAuthorizedPathologies(String username, Collection<? extends GrantedAuthority> authorities, + public static boolean validateAccessRightsOnExperiments(Authentication authentication, Logger logger) { + + ArrayList<String> authorities = getKeycloakAuthorities(authentication, logger); + + // Check for experiment_all claims + return hasRoleAccess(authorities, ClaimUtils.allExperimentsAllowedClaim(), logger); + } + + public static String getAuthorizedPathologies(Logger logger, Authentication authentication, List<PathologyDTO> allPathologies) { // --- Providing only the allowed pathologies/datasets to the user --- - Logging.LogUserAction(username, - "(GET) /pathologies", "Filter out the unauthorised datasets."); + logger.LogUserAction("Filter out the unauthorised datasets."); - List<String> userClaims = Arrays.asList(authorities.toString().toLowerCase() - .replaceAll("[\\s+\\]\\[]", "").split(",")); - - Logging.LogUserAction(username, - "(GET) /pathologies", "User Claims: " + userClaims); + ArrayList<String> authorities = getKeycloakAuthorities(authentication, logger); // If the "dataset_all" claim exists then return everything - if (userClaims.contains(ClaimUtils.allDatasetsAllowedClaim())) { + if (hasRoleAccess(authorities, ClaimUtils.allDatasetsAllowedClaim(), logger)) { return gson.toJson(allPathologies); } List<PathologyDTO> userPathologies = new ArrayList<>(); for (PathologyDTO curPathology : allPathologies) { - List<PathologyDTO.PathologyDatasetDTO> userPathologyDatasets = new ArrayList<PathologyDTO.PathologyDatasetDTO>(); + List<PathologyDTO.PathologyDatasetDTO> userPathologyDatasets = new ArrayList<>(); for (PathologyDTO.PathologyDatasetDTO dataset : curPathology.getDatasets()) { - if (userClaims.contains(ClaimUtils.getDatasetClaim(dataset.getCode()))) { - Logging.LogUserAction(username, "(GET) /pathologies", - "Added dataset: " + dataset.getCode()); + if (hasRoleAccess(authorities, ClaimUtils.getDatasetClaim(dataset.getCode()), logger)) { + logger.LogUserAction("Added dataset: " + dataset.getCode()); userPathologyDatasets.add(dataset); } } if (userPathologyDatasets.size() > 0) { - Logging.LogUserAction(username, "(GET) /pathologies", - "Added pathology '" + curPathology.getLabel() + logger.LogUserAction("Added pathology '" + curPathology.getLabel() + "' with datasets: '" + userPathologyDatasets + "'"); PathologyDTO userPathology = new PathologyDTO(); @@ -91,4 +92,24 @@ public class ClaimUtils { return gson.toJson(userPathologies); } + private static boolean hasRoleAccess(ArrayList<String> authorities, String role, Logger logger) + { + List<String> userClaims = Arrays.asList(authorities.toString().toLowerCase() + .replaceAll("[\\s+\\]\\[]", "").split(",")); + + logger.LogUserAction("User Claims: " + userClaims); + return userClaims.contains(role.toLowerCase()); + } + + private static ArrayList<String> getKeycloakAuthorities(Authentication authentication, Logger logger){ + KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) authentication; + KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal) token.getPrincipal(); + if(keycloakPrincipal.getKeycloakSecurityContext().getIdToken().getOtherClaims().get("authorities") == null) + { + logger.LogUserAction("Your user has no roles."); + throw new InternalServerError("Your user has no roles."); + } + + return (ArrayList<String>)keycloakPrincipal.getKeycloakSecurityContext().getIdToken().getOtherClaims().get("authorities"); + } } diff --git a/src/main/java/eu/hbp/mip/utils/ControllerExceptionHandler.java b/src/main/java/eu/hbp/mip/utils/ControllerExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..7f644fb7fec4eec89a653236da29be79e3a2f80c --- /dev/null +++ b/src/main/java/eu/hbp/mip/utils/ControllerExceptionHandler.java @@ -0,0 +1,89 @@ +package eu.hbp.mip.utils; + +import eu.hbp.mip.utils.Exceptions.*; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import java.util.Date; + +@ControllerAdvice +public class ControllerExceptionHandler extends ResponseEntityExceptionHandler { + + @ExceptionHandler(ExperimentNotFoundException.class) + public ResponseEntity<Object> handleExperimentNotFoundException(ExperimentNotFoundException ex, WebRequest request) { + + ErrorMessage message = new ErrorMessage( + HttpStatus.NOT_FOUND.value(), + new Date(), + ex.getMessage(), + request.getDescription(false)); + + return new ResponseEntity<>(message, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(BadRequestException.class) + public ResponseEntity<Object> handleBadRequestException(BadRequestException ex, WebRequest request) { + + ErrorMessage message = new ErrorMessage( + HttpStatus.BAD_REQUEST.value(), + new Date(), + ex.getMessage(), + request.getDescription(false)); + + return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(UnauthorizedException.class) + public ResponseEntity<Object> handleUnauthorizedException(UnauthorizedException ex, WebRequest request) { + + ErrorMessage message = new ErrorMessage( + HttpStatus.UNAUTHORIZED.value(), + new Date(), + ex.getMessage(), + request.getDescription(false)); + + return new ResponseEntity<>(message, HttpStatus.UNAUTHORIZED); + } + + @ExceptionHandler(IllegalArgumentException.class) + public Object handleIllegalArgumentException(IllegalArgumentException ex, WebRequest request) { + return null; + } + + @ExceptionHandler(InternalServerError.class) + public ResponseEntity<ErrorMessage> handleInternalServerError(InternalServerError er, WebRequest request) { + ErrorMessage message = new ErrorMessage( + HttpStatus.INTERNAL_SERVER_ERROR.value(), + new Date(), + er.getMessage(), + request.getDescription(false)); + + return new ResponseEntity<>(message, HttpStatus.INTERNAL_SERVER_ERROR); + } + + @ExceptionHandler(NoContent.class) + public ResponseEntity<ErrorMessage> handleNoContent(NoContent nc, WebRequest request) { + ErrorMessage message = new ErrorMessage( + HttpStatus.NO_CONTENT.value(), + new Date(), + nc.getMessage(), + request.getDescription(false)); + + return new ResponseEntity<>(message, HttpStatus.NO_CONTENT); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity<ErrorMessage> globalExceptionHandler(Exception ex, WebRequest request) { + ErrorMessage message = new ErrorMessage( + HttpStatus.INTERNAL_SERVER_ERROR.value(), + new Date(), + ex.getMessage(), + request.getDescription(false)); + + return new ResponseEntity<>(message, HttpStatus.INTERNAL_SERVER_ERROR); + } +} diff --git a/src/main/java/eu/hbp/mip/utils/CustomAccessDeniedHandler.java b/src/main/java/eu/hbp/mip/utils/CustomAccessDeniedHandler.java deleted file mode 100644 index 783e4a3ff68ab3384a798d9fc70f68f29c114bd6..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/utils/CustomAccessDeniedHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package eu.hbp.mip.utils; - -import org.codehaus.jettison.json.JSONException; -import org.codehaus.jettison.json.JSONObject; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.web.access.AccessDeniedHandler; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.sql.Timestamp; - -public class CustomAccessDeniedHandler implements AccessDeniedHandler { - @Override - public void handle(HttpServletRequest request, HttpServletResponse response, - AccessDeniedException accessDeniedException) throws IOException, ServletException { - response.setContentType("application/json;charset=UTF-8"); - response.setStatus(403); - try { - response.getWriter().write(new JSONObject() - .put("timestamp", new Timestamp(System.currentTimeMillis())) - .put("status", 403) - .put("error", "Forbidden") - .put("message", "Access Denied. Please contact the system administrator to request access.") - .put("path", request.getServletPath()) - .toString()); - } catch (JSONException e) { - response.getWriter().write(""); - e.printStackTrace(); - } - } -} diff --git a/src/main/java/eu/hbp/mip/utils/CustomLoginUrlAuthenticationEntryPoint.java b/src/main/java/eu/hbp/mip/utils/CustomLoginUrlAuthenticationEntryPoint.java deleted file mode 100644 index 45870c7778280ff60c8ccca2908105ee677a6f7a..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/utils/CustomLoginUrlAuthenticationEntryPoint.java +++ /dev/null @@ -1,21 +0,0 @@ -package eu.hbp.mip.utils; - -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -public class CustomLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { - - public CustomLoginUrlAuthenticationEntryPoint(String url) { - super(url); - } - - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - } -} diff --git a/src/main/java/eu/hbp/mip/utils/ErrorMessage.java b/src/main/java/eu/hbp/mip/utils/ErrorMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..ef15c71ae041b277e51c487afb03d17d11556aa8 --- /dev/null +++ b/src/main/java/eu/hbp/mip/utils/ErrorMessage.java @@ -0,0 +1,34 @@ +package eu.hbp.mip.utils; + + +import java.util.Date; + +public class ErrorMessage { + private int statusCode; + private Date timestamp; + private String message; + private String description; + + public ErrorMessage(int statusCode, Date timestamp, String message, String description) { + this.statusCode = statusCode; + this.timestamp = timestamp; + this.message = message; + this.description = description; + } + + public int getStatusCode() { + return statusCode; + } + + public Date getTimestamp() { + return timestamp; + } + + public String getMessage() { + return message; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/eu/hbp/mip/utils/ErrorMessages.java b/src/main/java/eu/hbp/mip/utils/ErrorMessages.java deleted file mode 100644 index 9f672f81b8bb57c559015a52bc65e44a0da7bd72..0000000000000000000000000000000000000000 --- a/src/main/java/eu/hbp/mip/utils/ErrorMessages.java +++ /dev/null @@ -1,7 +0,0 @@ -package eu.hbp.mip.utils; - -public class ErrorMessages { - - public static String pathologiesCouldNotBeLoaded = "The pathologies could not be loaded."; - public static String disabledAlgorithmsCouldNotBeLoaded = "The disabled algorithms could not be loaded."; -} diff --git a/src/main/java/eu/hbp/mip/utils/Exceptions/BadRequestException.java b/src/main/java/eu/hbp/mip/utils/Exceptions/BadRequestException.java new file mode 100644 index 0000000000000000000000000000000000000000..6684cae281a0487aa5d39e78693b6c9f5bd04098 --- /dev/null +++ b/src/main/java/eu/hbp/mip/utils/Exceptions/BadRequestException.java @@ -0,0 +1,8 @@ +package eu.hbp.mip.utils.Exceptions; + +public class BadRequestException extends RuntimeException { + + public BadRequestException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/src/main/java/eu/hbp/mip/utils/Exceptions/ExperimentNotFoundException.java b/src/main/java/eu/hbp/mip/utils/Exceptions/ExperimentNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..b8e05d7e667769537de9d540f436902dca6edc4e --- /dev/null +++ b/src/main/java/eu/hbp/mip/utils/Exceptions/ExperimentNotFoundException.java @@ -0,0 +1,8 @@ +package eu.hbp.mip.utils.Exceptions; + +public class ExperimentNotFoundException extends RuntimeException { + + public ExperimentNotFoundException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/src/main/java/eu/hbp/mip/utils/Exceptions/InternalServerError.java b/src/main/java/eu/hbp/mip/utils/Exceptions/InternalServerError.java new file mode 100644 index 0000000000000000000000000000000000000000..19bc88eed27b6e0e4ab36a05136f043be65725ec --- /dev/null +++ b/src/main/java/eu/hbp/mip/utils/Exceptions/InternalServerError.java @@ -0,0 +1,8 @@ +package eu.hbp.mip.utils.Exceptions; + +public class InternalServerError extends RuntimeException { + + public InternalServerError(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/src/main/java/eu/hbp/mip/utils/Exceptions/NoContent.java b/src/main/java/eu/hbp/mip/utils/Exceptions/NoContent.java new file mode 100644 index 0000000000000000000000000000000000000000..9bb67d8114e71545b8a00a8eb0bcdb0f7285b714 --- /dev/null +++ b/src/main/java/eu/hbp/mip/utils/Exceptions/NoContent.java @@ -0,0 +1,8 @@ +package eu.hbp.mip.utils.Exceptions; + +public class NoContent extends RuntimeException { + + public NoContent(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/src/main/java/eu/hbp/mip/utils/Exceptions/UnauthorizedException.java b/src/main/java/eu/hbp/mip/utils/Exceptions/UnauthorizedException.java new file mode 100644 index 0000000000000000000000000000000000000000..379911daeabe7227497f3d5bb622e54f6ccffb87 --- /dev/null +++ b/src/main/java/eu/hbp/mip/utils/Exceptions/UnauthorizedException.java @@ -0,0 +1,8 @@ +package eu.hbp.mip.utils.Exceptions; + +public class UnauthorizedException extends RuntimeException { + + public UnauthorizedException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/src/main/java/eu/hbp/mip/utils/JsonConverters.java b/src/main/java/eu/hbp/mip/utils/JsonConverters.java new file mode 100644 index 0000000000000000000000000000000000000000..74d01b851f44877fffe0e146d8f678ee3fb95dfb --- /dev/null +++ b/src/main/java/eu/hbp/mip/utils/JsonConverters.java @@ -0,0 +1,27 @@ +package eu.hbp.mip.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; + +import java.lang.reflect.Type; + +public class JsonConverters { + private static final Gson gson = new Gson(); + + public static String convertObjectToJsonString(Object object) { + ObjectMapper mapper = new ObjectMapper(); + //Converting the Object to JSONString + try { + return mapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + return e.getMessage(); + } + } + + public static <T> T convertJsonStringToObject(String jsonString, Type typeOfT) { + if(jsonString == null || jsonString.isEmpty()) + return null; + return gson.fromJson(jsonString, typeOfT); + } +} diff --git a/src/main/java/eu/hbp/mip/utils/Logging.java b/src/main/java/eu/hbp/mip/utils/Logger.java similarity index 53% rename from src/main/java/eu/hbp/mip/utils/Logging.java rename to src/main/java/eu/hbp/mip/utils/Logger.java index 9b75de636fc7c1721fca6dba59e2ce38cced1a7d..1e25d2c921f0338235bed01c2f2fcd55ab4cf94a 100644 --- a/src/main/java/eu/hbp/mip/utils/Logging.java +++ b/src/main/java/eu/hbp/mip/utils/Logger.java @@ -1,16 +1,23 @@ package eu.hbp.mip.utils; -import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.UUID; -public class Logging { - private static final Logger LOGGER = LoggerFactory.getLogger(Logging.class); +public class Logger { - public static void LogUserAction(String userName, String endpoint, String actionInfo) { - LOGGER.info(" User -> " + userName + " ," + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(Logger.class); + private String username; + private String endpoint; + + public Logger(String username, String endpoint){ + this.username = username; + this.endpoint = endpoint; + } + + public void LogUserAction(String actionInfo) { + LOGGER.info(" User -> " + username + " ," + "Endpoint -> " + endpoint + " ," + "Info -> " + actionInfo); } diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf deleted file mode 100644 index e2abfd5ae7f2a4e0e3ceb4abc888cdb065dbc79f..0000000000000000000000000000000000000000 --- a/src/main/resources/application.conf +++ /dev/null @@ -1,20 +0,0 @@ -app { - # Name of the application - name = "Portal backend" - # Type of the application - type = "Spring" - clusterSystemName = ${clustering.cluster.name} -} - -clustering { - ip = "127.0.0.1" - ip = ${?CLUSTER_IP} - port = 4489 - port = ${?CLUSTER_PORT} -} - -akka { - cluster { - roles = ["portal"] - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..345fc4bfa1955560e8cc33b2fb7cf62bb3698f12 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,81 @@ +# Configuration for development purposes + +### LOG LEVELS ### +logging: + level: + root: "ERROR" + org: "ERROR" + eu: + hbp: "DEBUG" + + +### AUTHENTICATION ### +authentication: + enabled: false + + +### DATABASE CONFIGURATION ### +spring: + portal-datasource: + url: "jdbc:postgresql://127.0.0.1:5433/portal" + schema: "public" + username: "portal" + password: "portalpwd" + driver-class-name: org.postgresql.Driver + data: + jpa: + repositories: + bootstrap-mode: default + jpa: + hibernate: + dialect: org.hibernate.dialect.PostgreSQL9Dialect + ddl-auto: validate + + +### EXTERNAL SERVICES ### +services: + exareme: + queryExaremeUrl: "http://127.0.0.1:9090/mining/query" + algorithmsUrl: "http://127.0.0.1:9090/mining/algorithms.json" + galaxy: + galaxyUrl: "http://127.0.0.1:8090" + galaxyContext: "nativeGalaxy/workflows/list" + galaxyApiKey: "d14a4cc5eebf805eb2ff261374ed08a2" + galaxyUsername: "admin" + galaxyPassword: "password" + + +### KEYCLOAK ### +keycloak: + enabled: true + auth-server-url: "https://iam.humanbrainproject.eu/auth" + realm: "MIP" + resource: "mipfedqa" + enable-basic-auth: true + credentials: + secret: "dae83a6b-c769-4186-8383-f0984c6edf05" + principal-attribute: "preferred_username" + + +### EXTERNAL FILES ### +# Files are loaded from the resources +files: + pathologies_json: "classPath:/pathologies.json" + disabledAlgorithms_json: "classPath:/disabledAlgorithms.json" + + +### EMBEDDED SERVER CONFIGURATION ### +server: + servlet: + contextPath: "/services" + port: 8080 + forward-headers-strategy: native + + +### ENDPOINTS ### +endpoints: + enabled: true + health: + enabled: true + endpoint: "/health" + sensitive: false \ No newline at end of file diff --git a/src/main/resources/db/migration/V7_0__NewDatabaseStructure.sql b/src/main/resources/db/migration/V7_0__NewDatabaseStructure.sql new file mode 100644 index 0000000000000000000000000000000000000000..c1732c9e94860337218e6af917b1b523980a3d63 --- /dev/null +++ b/src/main/resources/db/migration/V7_0__NewDatabaseStructure.sql @@ -0,0 +1,84 @@ +UPDATE experiment +SET algorithms = + ( + SELECT SUBSTR(algorithms, 2, LENGTH(algorithms) - 2) + ); + +UPDATE experiment +SET workflowstatus = 'error' +WHERE workflowstatus IS NULL AND haserror; + +UPDATE experiment +SET workflowstatus = 'success' +WHERE workflowstatus IS NULL AND NOT haserror; + +UPDATE experiment +SET workflowstatus = 'success' +WHERE workflowstatus = 'completed'; + +UPDATE experiment +SET workflowstatus = 'pending' +WHERE workflowstatus = 'running'; + +ALTER TABLE experiment +DROP COLUMN haserror, +DROP COLUMN hasservererror, +DROP COLUMN validations, +DROP COLUMN model_slug; + +ALTER TABLE experiment +RENAME algorithms TO algorithm; +ALTER TABLE experiment +ALTER COLUMN algorithm TYPE json USING algorithm::json; +ALTER TABLE experiment +RENAME createdby_username TO created_by_username; +ALTER TABLE experiment +RENAME workflowhistoryid TO workflow_history_id; +ALTER TABLE experiment +RENAME resultsviewed TO viewed; +ALTER TABLE experiment +RENAME workflowstatus TO status; + +ALTER TABLE experiment +ADD COLUMN algorithmId text; + +UPDATE experiment +SET algorithmId = (algorithm ->> 'name'); + +ALTER TABLE experiment +ALTER COLUMN algorithm TYPE text; +ALTER TABLE experiment +ADD COLUMN updated timestamp without time zone; + +ALTER TABLE "user" +DROP COLUMN birthday, +DROP COLUMN city, +DROP COLUMN country, +DROP COLUMN firstname, +DROP COLUMN gender, +DROP COLUMN isactive, +DROP COLUMN lastname, +DROP COLUMN password, +DROP COLUMN phone, +DROP COLUMN picture, +DROP COLUMN team, +DROP COLUMN web, +DROP COLUMN apikey; + +ALTER TABLE "user" +ADD COLUMN subjectID text; + +DROP TABLE "config_title", "config_yaxisvariables"; +DROP TABLE "dataset_variable", "dataset_grouping", "dataset_data", "dataset_header"; +DROP TABLE "query_variable", "query_grouping", "query_filter", "query_covariable"; +DROP TABLE "article_tag", "tag","article"; +DROP TABLE "variable_value"; +DROP TABLE "query_training_datasets", "query_validation_datasets", "query_testing_datasets"; +DROP TABLE "variable", "value"; +DROP TABLE "group_group", "group"; +DROP TABLE "model"; +DROP TABLE "query"; +DROP TABLE "dataset"; +DROP TABLE "config"; +DROP TABLE "vote", "app"; +DROP TABLE "user_roles", "user_languages"; diff --git a/src/main/resources/kamon.conf b/src/main/resources/kamon.conf deleted file mode 100644 index face394cba2325ea855db49c88219256c610a333..0000000000000000000000000000000000000000 --- a/src/main/resources/kamon.conf +++ /dev/null @@ -1,75 +0,0 @@ -kamon { - enabled = no - enabled = ${?KAMON_ENABLED} - - environment { - service = "portal-backend" - service = ${?KAMON_SERVICE_NAME} - } - - zipkin = { - enabled = no - enabled = ${?ZIPKIN_ENABLED} - host = "zipkin" - host = ${?ZIPKIN_IP} - port = 9411 - port = ${?ZIPKIN_PORT} - } - - prometheus = { - enabled = no - enabled = ${?PROMETHEUS_ENABLED} - host = "prometheus" - host = ${?PROMETHEUS_IP} - port = 9090 - port = ${?PROMETHEUS_PORT} - } - - util.filters { - "akka.tracked-actor" { - includes = ["**"] - } - - "akka.tracked-dispatcher" { - includes = ["**"] - } - - "akka.traced-actor" { - includes = ["**"] - excludes = [ - ${clustering.cluster.name}"/system/IO**", - ${clustering.cluster.name}"/user/Stream**", - ${clustering.cluster.name}"/system/transports**", - ${clustering.cluster.name}"/system/cluster**", - ${clustering.cluster.name}"/system/remote**", - ${clustering.cluster.name}"/system/endpointmanager/**", - ${clustering.cluster.name}"/system/sharding/UserActor/**"] - } - - } - - akka-http { - add-http-status-code-as-metric-tag = true - } - - akka { - ask-pattern-timeout-warning = lightweight - } - - trace { - join-remote-parents-with-same-span-id = yes - sampler = "always" - } - - system-metrics { - host { - enabled = no - enabled = ${?SIGAR_SYSTEM_METRICS} - } - jvm { - enabled = no - enabled = ${?JVM_SYSTEM_METRICS} - } - } - -}