diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml deleted file mode 100644 index edf4861c..00000000 --- a/.github/workflows/build-docker.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Build UI docker - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - workflow_dispatch: -env: - IMAGE_NAME: record-manager - MAIN_BRANCH_NAME: master - -jobs: - build-and-publish: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Build docker image - run: cd src/main/webapp; docker build . --file Dockerfile --tag $IMAGE_NAME - - - name: Log in to the Container registry - run: echo "${{ github.token }}" | docker login docker.pkg.github.com -u ${{ github.actor }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=docker.pkg.github.com/${{ github.repository }}/$IMAGE_NAME - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - # Get branch name if merge to a branch - GIT_BRANCH_NAME=$(echo "${{ github.ref }}" | grep 'refs/heads/.*' | cut -d"/" -f 3) - # Get pull request id (e.g. "pr-123" from "/pulls/123") - PULL_REQUEST_ID=$(echo "${{ github.event.pull_request.number }}" | grep -v "^$" | sed 's/^/pr-/') - # Get tag id while strip "v" prefix (e.g. "1.2" from "v1.2") - TAG_ID=$(echo "${{ github.ref }}" | grep 'refs/tags/.*' | cut -d"/" -f 3 | sed -e 's/^v//') - # Version is either "git branch name"/"pull request id"/"tag id" - VERSION=${GIT_BRANCH_NAME:-${PULL_REQUEST_ID:-${TAG_ID}}} - # Use Docker `latest` tag convention - [ "$VERSION" == $MAIN_BRANCH_NAME ] && VERSION=latest - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $IMAGE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION diff --git a/.github/workflows/build-server-docker.yml b/.github/workflows/build-server-docker.yml deleted file mode 100644 index 813fa410..00000000 --- a/.github/workflows/build-server-docker.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Build server docker - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - workflow_dispatch: -env: - IMAGE_NAME: record-manager-server - MVN_PROFILE: production-docker - MAIN_BRANCH_NAME: master -jobs: - - build-and-publish: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Build application archive - run: mvn clean package -B -P $MVN_PROFILE - - - name: Build docker image - run: docker build . --file Dockerfile --tag $IMAGE_NAME - - - name: Log in to the Container registry - run: echo "${{ github.token }}" | docker login docker.pkg.github.com -u ${{ github.actor }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=docker.pkg.github.com/${{ github.repository }}/$IMAGE_NAME - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - # Get branch name if merge to a branch - GIT_BRANCH_NAME=$(echo "${{ github.ref }}" | grep 'refs/heads/.*' | cut -d"/" -f 3) - # Get pull request id (e.g. "pr-123" from "/pulls/123") - PULL_REQUEST_ID=$(echo "${{ github.event.pull_request.number }}" | grep -v "^$" | sed 's/^/pr-/') - # Get tag id while strip "v" prefix (e.g. "1.2" from "v1.2") - TAG_ID=$(echo "${{ github.ref }}" | grep 'refs/tags/.*' | cut -d"/" -f 3 | sed -e 's/^v//') - # Version is either "git branch name"/"pull request id"/"tag id" - VERSION=${GIT_BRANCH_NAME:-${PULL_REQUEST_ID:-${TAG_ID}}} - # Use Docker `latest` tag convention - [ "$VERSION" == $MAIN_BRANCH_NAME ] && VERSION=latest - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $IMAGE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION diff --git a/.github/workflows/protect-master.yml b/.github/workflows/protect-main.yml similarity index 75% rename from .github/workflows/protect-master.yml rename to .github/workflows/protect-main.yml index 42a920cc..ae1efc77 100644 --- a/.github/workflows/protect-master.yml +++ b/.github/workflows/protect-main.yml @@ -6,9 +6,9 @@ name: CI # events but only for the master branch on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: @@ -20,12 +20,12 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 - - # Runs a single command using the runners shell -# - name: Compile -# run: mvn compile + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' # Runs a set of commands using the runners shell -# - name: Test -# run: mvn test + - name: Test + run: mvn -B test diff --git a/Dockerfile b/Dockerfile index cecbb681..b29f1c35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,18 @@ -FROM tomcat:9.0-jdk8-slim +FROM maven:3-eclipse-temurin-17 as build -EXPOSE 8080 +WORKDIR /record-manager + +COPY pom.xml pom.xml + +RUN mvn -B de.qaware.maven:go-offline-maven-plugin:resolve-dependencies + +COPY src src -COPY /target/record-manager-0.*.war /usr/local/tomcat/webapps/record-manager.war +RUN mvn package -B -DskipTests=true + +FROM eclipse-temurin:17-jdk-alpine as runtime +COPY --from=build /record-manager/target/record-manager.jar record-manager.jar + +EXPOSE 8080 -CMD ["catalina.sh","run"] +ENTRYPOINT ["java","-jar","/record-manager.jar"] diff --git a/README.md b/README.md index cad9b1f8..35f45232 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,11 @@ # OFN Record Manager -Manager of records based on OFN (https://opendata.gov.cz/otevřené-formální-normy:start). +Manager of records based on OFN (https://data.gov.cz/ofn/). ## Required Technologies -- JDK 8 (preferably Oracle) +- JDK 17 - Apache Maven 3.5.x -- Apache Tomcat 9 or newer (required by Servlet API 4) ## System Architecture diff --git a/doc/development.md b/doc/development.md index 0877982b..026ff109 100644 --- a/doc/development.md +++ b/doc/development.md @@ -1,14 +1,14 @@ Development Notes -Frontend of the application can be developed separately from the backend. +Frontend of the application is developed separately. + The setup requires following steps: 1) configure the application according to [Setup Guide](setup.md) 2) configure `config.properties` to contain `security.sameSite=None` This is important if you are running the application over http so web browser would not block requests to the server due to CORS policy. 3) build the backend `mvn clean package` -4) deploy created web application archive (`./target/record-manager-*.war`) to a web server -5) run frontend `cd ./src/main/webapp; npm run dev` -6) frontend is by default accessible from `http://localhost:3000` +4) Run the created application archive (`./target/record-manager.jar`) +5) Checkout and run frontend -Alternatively to step 2, a browser plugin can be used to disable CORS policy. \ No newline at end of file +Alternatively to step 2, a browser plugin can be used to disable CORS policy. diff --git a/doc/setup.md b/doc/setup.md index ef4290b6..504cb5d3 100644 --- a/doc/setup.md +++ b/doc/setup.md @@ -4,37 +4,22 @@ ### System Requirements -- JDK 8 (newer or older versions are not supported at the moment) +- JDK 17 or later - Apache Maven 3.5.x or newer -### Setup - -#### Maven Profiles - -To build the application for **non**-development deployment, use Maven and select the `production` profile. - ### Application Configuration -Application has backend developed in Java and frontend developed in ReactJS frameworks. - -__Backend__ uses src/main/resources/config.properties to configure: +The application uses `src/main/resources/config.properties` to configure: * connection to internal triple store -* rest endpoint of Form service -* smtp configuration for sending emails +* REST endpoint of Form service +* SMTP configuration for sending emails * email templates for invitation, password change, and profile update scenarios -See comments in the configuration file for more information. In addition, supported record types are configured using query in src/main/resources/query/findFormTypes.rq. - -__Frontend__ uses src/main/resources/webapp/.env to configure: -* url of backend -* application title in browser -* internationalization settings - -See src/main/resources/webapp/.env.example for detailed description of options. +See comments in the configuration file for more information. In addition, supported record types are configured using query in `src/main/resources/query/findFormTypes.rq`. ### Building -Production war file can be produced by maven command: `mvn clean package -B -P production` +Application JAR file can be produced by maven command: `mvn clean package -B` ## Deployment @@ -47,25 +32,21 @@ Deployment requires 4 steps: ### System Requirements -- JDK 8 (newer or older versions are not supported at the moment) -- Apache Tomcat 8.5 or later (9.x is recommended) or any Servlet API 4-compatible application server +- JDK 17 - ### Record Manager RDF4J Repository +### Record Manager RDF4J Repository - Main repository of the application is configured by `repositoryUrl` parameter. +Main repository of the application is configured by `repositoryUrl` parameter. - ### Form service RDF4J Repository +### Form service RDF4J Repository - Repository dedicated to provide data to Form service is configured by `formGenRepositoryUrl`. Additionally, this repository can contain a configuration of generation of forms fom SGoV model. +Repository dedicated to provide data to Form service is configured by `formGenRepositoryUrl`. Additionally, this repository can contain a configuration of generation of forms fom SGoV model. - ### SGoV Model Repository +### SGoV Model Repository - This repository is query parameter of Form service call specified in `sgovRepositoryUrl`. +This repository is query parameter of Form service call specified in `sgovRepositoryUrl`. - ### SForms Service +### SForms Service - SForms service is configured in `formGenServiceUrl`, the call to the service should contain SGoV model repository as query parameter. Example call: - `formGenRepositoryUrl=`http://localhost:8080/s-pipes/service?_pId=transform&sgovRepositoryUrl=https%3A%2F%2Fgraphdb.onto.fel.cvut.cz%2Frepositories%2Fkodi-slovnik-gov-cz` - - - +SForms service is configured in `formGenServiceUrl`, the call to the service should contain SGoV model repository as query parameter. Example call: +`formGenRepositoryUrl=`http://localhost:8080/s-pipes/service?_pId=transform&sgovRepositoryUrl=https%3A%2F%2Fgraphdb.onto.fel.cvut.cz%2Frepositories%2Fkodi-slovnik-gov-cz` diff --git a/docker-compose.yml b/docker-compose.yml index 113b1e65..c84df613 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,8 @@ services: API_URL: "http://localhost:3000/ofn-record-manager" dm-record-manager-server: - image: 'ofn-record-manager-server:latest' + build: . + image: record-manager-server container_name: dm-record-manager-server ports: - '3000:8080' @@ -37,7 +38,7 @@ services: - ./scripts:/scripts dm-rdf4j: - image: 'eclipse/rdf4j-workbench:amd64-3.5.0' + image: 'eclipse/rdf4j-workbench:4.3.7' container_name: dm-rdf4j ports: - "8080:8080" diff --git a/pom.xml b/pom.xml index 76d7f95a..ee610c58 100644 --- a/pom.xml +++ b/pom.xml @@ -5,131 +5,52 @@ 4.0.0 - cz.cvut.kbss - kbss-project-parent - 0.0.8 + org.springframework.boot + spring-boot-starter-parent + 3.1.4 record-manager 0.2.1 OFN Record Manager - war - - - - - kbss - https://kbss.felk.cvut.cz/m2repo - - + jar UTF-8 - 1.8 - 1.8 - 1.8 + 17 + ${jdk.version} + ${jdk.version} - 0.19.2 - 1.9.7 - 5.0.7.RELEASE - 5.0.6.RELEASE - 2.12.1 - 4.12 - 1.10.19 - 1.2.2 - 1.2.0.Final + 1.1.3 + 1.9.20 + 4.11.0 + 1.5.5.Final - - - - kbss - KBSS Maven 2 Repository - http://kbss.felk.cvut.cz/m2repo - - warn - true - always - - - - - org.springframework - spring-core - ${org.springframework.version} - - - org.springframework - spring-context - ${org.springframework.version} - - - org.springframework - spring-context-support - ${org.springframework.version} - - - org.springframework - spring-web - ${org.springframework.version} - - - org.springframework - spring-webmvc - ${org.springframework.version} - - - org.springframework - spring-tx - ${org.springframework.version} - - - org.springframework - spring-aspects - ${org.springframework.version} - - - - - - org.springframework.security - spring-security-config - ${org.springframework.security.version} + org.springframework.boot + spring-boot-starter-web - org.springframework.security - spring-security-core - ${org.springframework.security.version} + org.springframework.boot + spring-boot-starter-security - org.springframework.security - spring-security-web - ${org.springframework.security.version} + org.springframework.boot + spring-boot-starter-mail - - javax.annotation - javax.annotation-api - 1.3.2 - provided - - - - - com.fasterxml.jackson.core - jackson-databind - ${com.fasterxml.jackson.version} + org.apache.httpcomponents.client5 + httpclient5 - javax.servlet - javax.servlet-api - 3.1.0 + jakarta.servlet + jakarta.servlet-api provided @@ -144,28 +65,26 @@ ontodriver-rdf4j ${cz.cvut.kbss.jopa.version} + + com.github.ledsoft + jopa-spring-transaction + 0.2.0 + org.slf4j slf4j-api - 1.7.25 - - - ch.qos.logback - logback-core - ${ch.qos.logback.version} ch.qos.logback logback-classic - ${ch.qos.logback.version} org.mapstruct - mapstruct-jdk8 + mapstruct ${org.mapstruct.version} @@ -175,49 +94,65 @@ commons-lang 2.6 + - junit - junit - ${junit.version} + org.hamcrest + hamcrest test - org.springframework - spring-test - ${org.springframework.version} + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine test org.mockito - mockito-all + mockito-core ${org.mockito.version} test - - javax.mail - javax.mail-api - 1.5.5 + org.springframework.boot + spring-boot-starter-test + test - com.sun.mail - javax.mail - 1.5.5 + org.springframework.security + spring-security-test + test + record-manager org.apache.maven.plugins - maven-war-plugin - 3.3.1 + maven-compiler-plugin + + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + - com.nickwongdev + org.springframework.boot + spring-boot-maven-plugin + + + dev.aspectj aspectj-maven-plugin - 1.12.6 + 1.13.1 ${jdk.version} ${jdk.version} @@ -227,10 +162,6 @@ cz.cvut.kbss.jopa jopa-impl - - org.springframework - spring-aspects - @@ -239,11 +170,6 @@ aspectjtools ${org.aspectj.version} - - org.aspectj - aspectjrt - ${org.aspectj.version} - @@ -264,17 +190,9 @@ - - org.apache.maven.plugins - maven-compiler-plugin - org.apache.maven.plugins maven-surefire-plugin - - - 0 - @@ -300,45 +218,11 @@ - - org.bsc.maven - maven-processor-plugin - 3.3.3 - - - - ${project.basedir}/src/main/generated-sources - - - - ${project.basedir}/src/main/generated-sources - - - org.mapstruct.ap.MappingProcessor - - - - - process - generate-sources - - process - - - - - - org.mapstruct - mapstruct-processor - ${org.mapstruct.version} - - - org.jacoco jacoco-maven-plugin - 0.7.5.201505241946 + 0.8.8 @@ -357,7 +241,6 @@ org.codehaus.mojo build-helper-maven-plugin - 1.10 add-source @@ -375,7 +258,6 @@ maven-clean-plugin - 3.0.0 @@ -388,7 +270,11 @@ org.apache.maven.plugins maven-resources-plugin - 3.2.0 + + + de.qaware.maven + go-offline-maven-plugin + 1.2.8 diff --git a/src/main/java/cz/cvut/kbss/study/RecordManagerApplication.java b/src/main/java/cz/cvut/kbss/study/RecordManagerApplication.java new file mode 100644 index 00000000..30871772 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/RecordManagerApplication.java @@ -0,0 +1,12 @@ +package cz.cvut.kbss.study; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RecordManagerApplication { + + public static void main(String[] args) { + SpringApplication.run(RecordManagerApplication.class, args); + } +} diff --git a/src/main/java/cz/cvut/kbss/study/config/AppConfig.java b/src/main/java/cz/cvut/kbss/study/config/AppConfig.java index a636b477..bb2a388c 100644 --- a/src/main/java/cz/cvut/kbss/study/config/AppConfig.java +++ b/src/main/java/cz/cvut/kbss/study/config/AppConfig.java @@ -1,9 +1,9 @@ package cz.cvut.kbss.study.config; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration -@Import({WebAppConfig.class, PersistenceConfig.class, ServiceConfig.class}) +@EnableAspectJAutoProxy(proxyTargetClass = true) public class AppConfig { } diff --git a/src/main/java/cz/cvut/kbss/study/config/DispatcherServletInitializer.java b/src/main/java/cz/cvut/kbss/study/config/DispatcherServletInitializer.java deleted file mode 100644 index c2721443..00000000 --- a/src/main/java/cz/cvut/kbss/study/config/DispatcherServletInitializer.java +++ /dev/null @@ -1,47 +0,0 @@ -package cz.cvut.kbss.study.config; - -import cz.cvut.kbss.study.security.SecurityConstants; -import org.springframework.web.context.request.RequestContextListener; -import org.springframework.web.filter.DelegatingFilterProxy; -import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; - -import javax.servlet.DispatcherType; -import javax.servlet.FilterRegistration; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import java.util.EnumSet; - -public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { - - @Override - protected Class[] getRootConfigClasses() { - return new Class[]{AppConfig.class}; - } - - @Override - protected Class[] getServletConfigClasses() { - return null; - } - - @Override - protected String[] getServletMappings() { - return new String[]{"/rest/*"}; - } - - @Override - public void onStartup(ServletContext servletContext) throws ServletException { - System.out.println("****** Application Context Initialization ******"); - - initSecurityFilter(servletContext); - servletContext.addListener(new RequestContextListener()); - servletContext.getSessionCookieConfig().setName(SecurityConstants.SESSION_COOKIE_NAME); - super.onStartup(servletContext); - } - - private void initSecurityFilter(ServletContext servletContext) { - FilterRegistration.Dynamic securityFilter = servletContext.addFilter("springSecurityFilterChain", - DelegatingFilterProxy.class); - final EnumSet es = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); - securityFilter.addMappingForUrlPatterns(es, true, "/*"); - } -} diff --git a/src/main/java/cz/cvut/kbss/study/config/PersistenceConfig.java b/src/main/java/cz/cvut/kbss/study/config/PersistenceConfig.java index 305adca6..6f4ead9e 100644 --- a/src/main/java/cz/cvut/kbss/study/config/PersistenceConfig.java +++ b/src/main/java/cz/cvut/kbss/study/config/PersistenceConfig.java @@ -1,9 +1,24 @@ package cz.cvut.kbss.study.config; -import org.springframework.context.annotation.ComponentScan; +import com.github.ledsoft.jopa.spring.transaction.DelegatingEntityManager; +import com.github.ledsoft.jopa.spring.transaction.JopaTransactionManager; +import cz.cvut.kbss.jopa.model.EntityManagerFactory; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration -@ComponentScan(basePackages = "cz.cvut.kbss.study.persistence") +@EnableTransactionManagement public class PersistenceConfig { + + @Bean + public DelegatingEntityManager entityManager() { + return new DelegatingEntityManager(); + } + + @Bean(name = "txManager") + public PlatformTransactionManager transactionManager(EntityManagerFactory emf, DelegatingEntityManager emProxy) { + return new JopaTransactionManager(emf, emProxy); + } } diff --git a/src/main/java/cz/cvut/kbss/study/config/RestConfig.java b/src/main/java/cz/cvut/kbss/study/config/RestConfig.java deleted file mode 100644 index 44353230..00000000 --- a/src/main/java/cz/cvut/kbss/study/config/RestConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package cz.cvut.kbss.study.config; - -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ComponentScan(basePackages = "cz.cvut.kbss.study.rest") -public class RestConfig { - - @Bean - public ObjectMapper objectMapper() { - final ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - return objectMapper; - } -} diff --git a/src/main/java/cz/cvut/kbss/study/config/SecurityConfig.java b/src/main/java/cz/cvut/kbss/study/config/SecurityConfig.java index c7292512..32e1dabf 100644 --- a/src/main/java/cz/cvut/kbss/study/config/SecurityConfig.java +++ b/src/main/java/cz/cvut/kbss/study/config/SecurityConfig.java @@ -2,20 +2,23 @@ import cz.cvut.kbss.study.security.CsrfHeaderFilter; import cz.cvut.kbss.study.security.SecurityConstants; +import cz.cvut.kbss.study.service.ConfigReader; +import cz.cvut.kbss.study.util.ConfigParam; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.csrf.CsrfFilter; import org.springframework.web.cors.CorsConfiguration; @@ -23,12 +26,12 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import java.util.Collections; +import java.util.List; @Configuration @EnableWebSecurity -@ComponentScan(basePackages = "cz.cvut.kbss.study.security") -@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) -public class SecurityConfig extends WebSecurityConfigurerAdapter { +@EnableMethodSecurity +public class SecurityConfig { private static final String[] COOKIES_TO_DESTROY = { SecurityConstants.SESSION_COOKIE_NAME, @@ -36,8 +39,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { SecurityConstants.CSRF_COOKIE_NAME }; - private final AuthenticationEntryPoint authenticationEntryPoint; - private final AuthenticationFailureHandler authenticationFailureHandler; private final AuthenticationSuccessHandler authenticationSuccessHandler; @@ -46,56 +47,52 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { private final AuthenticationProvider ontologyAuthenticationProvider; - public SecurityConfig(AuthenticationEntryPoint authenticationEntryPoint, - AuthenticationFailureHandler authenticationFailureHandler, + public SecurityConfig(AuthenticationFailureHandler authenticationFailureHandler, AuthenticationSuccessHandler authenticationSuccessHandler, LogoutSuccessHandler logoutSuccessHandler, AuthenticationProvider ontologyAuthenticationProvider) { - this.authenticationEntryPoint = authenticationEntryPoint; this.authenticationFailureHandler = authenticationFailureHandler; this.authenticationSuccessHandler = authenticationSuccessHandler; this.logoutSuccessHandler = logoutSuccessHandler; this.ontologyAuthenticationProvider = ontologyAuthenticationProvider; } - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.authenticationProvider(ontologyAuthenticationProvider); - } - @Bean - @Override - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); + public SecurityFilterChain filterChain(HttpSecurity http, ConfigReader config) throws Exception { + final AuthenticationManager authManager = buildAuthenticationManager(http); + http.authorizeHttpRequests((auth) -> auth.anyRequest().permitAll()) + .cors((auth) -> auth.configurationSource(corsConfigurationSource(config))) + .csrf(AbstractHttpConfigurer::disable) + .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class) + .exceptionHandling(ehc -> ehc.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) + .formLogin((form) -> form.loginProcessingUrl(SecurityConstants.SECURITY_CHECK_URI) + .successHandler(authenticationSuccessHandler) + .failureHandler(authenticationFailureHandler)) + .logout((auth) -> auth.logoutUrl(SecurityConstants.LOGOUT_URI) + .logoutSuccessHandler(logoutSuccessHandler) + .invalidateHttpSession(true).deleteCookies(COOKIES_TO_DESTROY)) + .authenticationManager(authManager); + return http.build(); } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().permitAll().and() - .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint) - .and().cors().configurationSource(corsConfigurationSource()) - .and() - .authenticationProvider(ontologyAuthenticationProvider) - .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class) - .csrf().disable() - .formLogin().successHandler(authenticationSuccessHandler) - .failureHandler(authenticationFailureHandler) - .loginProcessingUrl(SecurityConstants.SECURITY_CHECK_URI) - .usernameParameter(SecurityConstants.USERNAME_PARAM).passwordParameter(SecurityConstants.PASSWORD_PARAM) - .and() - .logout().invalidateHttpSession(true).deleteCookies(COOKIES_TO_DESTROY) - .logoutUrl(SecurityConstants.LOGOUT_URI).logoutSuccessHandler(logoutSuccessHandler) - .and().sessionManagement().maximumSessions(1); + private AuthenticationManager buildAuthenticationManager(HttpSecurity http) throws Exception { + final AuthenticationManagerBuilder ab = http.getSharedObject(AuthenticationManagerBuilder.class); + ab.authenticationProvider(ontologyAuthenticationProvider); + return ab.build(); } @Bean - CorsConfigurationSource corsConfigurationSource() { - // We're allowing all methods from all origins so that the application API is usable also by other clients - // than just the UI. - // This behavior can be restricted later. + CorsConfigurationSource corsConfigurationSource(ConfigReader config) { + // allowCredentials requires allowed origins to be configured (* is not supported) final CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues(); corsConfiguration.setAllowedMethods(Collections.singletonList("*")); - corsConfiguration.setAllowedOrigins(Collections.singletonList("*")); + if (!config.getConfig(ConfigParam.APP_CONTEXT, "").isBlank()) { + String appUrl = config.getConfig(ConfigParam.APP_CONTEXT); + appUrl = appUrl.substring(0, appUrl.lastIndexOf('/')); + corsConfiguration.setAllowedOrigins(List.of(appUrl)); + } else { + corsConfiguration.setAllowedOrigins(Collections.singletonList("*")); + } corsConfiguration.addExposedHeader(HttpHeaders.AUTHORIZATION); corsConfiguration.addExposedHeader(HttpHeaders.LOCATION); corsConfiguration.addExposedHeader(HttpHeaders.CONTENT_DISPOSITION); diff --git a/src/main/java/cz/cvut/kbss/study/config/ServiceConfig.java b/src/main/java/cz/cvut/kbss/study/config/ServiceConfig.java index 35150732..d5dec886 100644 --- a/src/main/java/cz/cvut/kbss/study/config/ServiceConfig.java +++ b/src/main/java/cz/cvut/kbss/study/config/ServiceConfig.java @@ -1,14 +1,23 @@ package cz.cvut.kbss.study.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.DefaultRedirectStrategy; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.ResourceHttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.client.RestTemplate; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + @Configuration -@ComponentScan(basePackages = "cz.cvut.kbss.study.service") public class ServiceConfig { @Bean @@ -17,7 +26,22 @@ public PasswordEncoder passwordEncoder() { } @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); + public RestTemplate restTemplate(ObjectMapper objectMapper) { + final RestTemplate restTemplate = new RestTemplate(); + + // HttpClient 5 default redirect strategy automatically follows POST redirects as well + final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + final HttpClient httpClient = HttpClientBuilder.create() + .setRedirectStrategy(new DefaultRedirectStrategy()) + .build(); + factory.setHttpClient(httpClient); + restTemplate.setRequestFactory(factory); + + final MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(); + jacksonConverter.setObjectMapper(objectMapper); + final StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8); + restTemplate.setMessageConverters( + Arrays.asList(stringConverter, jacksonConverter, new ResourceHttpMessageConverter())); + return restTemplate; } } diff --git a/src/main/java/cz/cvut/kbss/study/config/WebAppConfig.java b/src/main/java/cz/cvut/kbss/study/config/WebAppConfig.java index 59f02316..df53da8b 100644 --- a/src/main/java/cz/cvut/kbss/study/config/WebAppConfig.java +++ b/src/main/java/cz/cvut/kbss/study/config/WebAppConfig.java @@ -3,48 +3,56 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import cz.cvut.kbss.jopa.sessions.UnitOfWorkImpl; +import cz.cvut.kbss.study.rest.servlet.DiagnosticsContextFilter; import cz.cvut.kbss.study.util.Constants; +import cz.cvut.kbss.study.util.json.ManageableIgnoreMixin; +import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.ResourceHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.method.HandlerTypePredicate; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.support.StandardServletMultipartResolver; -import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; -import org.springframework.web.servlet.view.InternalResourceViewResolver; -import org.springframework.web.servlet.view.JstlView; +import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import java.nio.charset.Charset; -import java.util.List; +import java.nio.charset.StandardCharsets; @Configuration -@EnableWebMvc -@Import({RestConfig.class, SecurityConfig.class}) -public class WebAppConfig extends WebMvcConfigurerAdapter { +public class WebAppConfig implements WebMvcConfigurer { - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); - registry.addResourceHandler("/js/**").addResourceLocations("/js/"); - } - - @Override - public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { - configurer.enable(); + @Bean(name = "objectMapper") + @Primary + public ObjectMapper objectMapper() { + return createJsonObjectMapper(); } - @Bean - public InternalResourceViewResolver setupViewResolver() { - InternalResourceViewResolver resolver = new InternalResourceViewResolver(); - resolver.setViewClass(JstlView.class); - resolver.setPrefix("/WEB-INF/"); - resolver.setSuffix(".html"); - return resolver; + /** + * Creates an {@link ObjectMapper} for processing regular JSON. + *

+ * This method is public static so that it can be used by the test environment as well. + * + * @return {@code ObjectMapper} instance + */ + public static ObjectMapper createJsonObjectMapper() { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // Ignore UoW references injected into entities + objectMapper.addMixIn(UnitOfWorkImpl.class, ManageableIgnoreMixin.class); + // JSR 310 (Java 8 DateTime API) + objectMapper.registerModule(new JavaTimeModule()); + // Serialize datetime as ISO strings + objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false); + return objectMapper; } @Bean(name = "multipartResolver") @@ -52,17 +60,36 @@ public MultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); } - @Override - public void configureMessageConverters(List> converters) { + @Bean + public HttpMessageConverter stringMessageConverter() { + return new StringHttpMessageConverter(StandardCharsets.UTF_8); + } + + @Bean + public HttpMessageConverter jsonMessageConverter(ObjectMapper objectMapper) { final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); - final ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); converter.setObjectMapper(objectMapper); - converters.add(converter); - final StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(Charset.forName( - Constants.UTF_8_ENCODING)); - converters.add(stringConverter); - super.configureMessageConverters(converters); + return converter; + } + + @Bean + public HttpMessageConverter resourceMessageConverter() { + return new ResourceHttpMessageConverter(); + } + + /** + * Registers a filter that allows using current user's username in log pattern. + */ + @Bean + public FilterRegistrationBean mdcFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new DiagnosticsContextFilter()); + registrationBean.addUrlPatterns("/*"); + return registrationBean; + } + + @Override + public void configurePathMatch(PathMatchConfigurer matcher) { + matcher.addPathPrefix(Constants.REST_API_REFIX, HandlerTypePredicate.forAnnotation(RestController.class)); } } diff --git a/src/main/java/cz/cvut/kbss/study/persistence/FormGenPersistenceFactory.java b/src/main/java/cz/cvut/kbss/study/persistence/FormGenPersistenceFactory.java index 358409c5..bad6ff41 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/FormGenPersistenceFactory.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/FormGenPersistenceFactory.java @@ -2,18 +2,19 @@ import cz.cvut.kbss.jopa.Persistence; import cz.cvut.kbss.jopa.model.EntityManagerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; import java.util.HashMap; import java.util.Map; -import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.*; +import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.CACHE_ENABLED; +import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.DATA_SOURCE_CLASS; +import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.ONTOLOGY_PHYSICAL_URI_KEY; import static cz.cvut.kbss.study.util.ConfigParam.DRIVER; import static cz.cvut.kbss.study.util.ConfigParam.FORM_GEN_REPOSITORY_URL; diff --git a/src/main/java/cz/cvut/kbss/study/persistence/PersistenceFactory.java b/src/main/java/cz/cvut/kbss/study/persistence/PersistenceFactory.java index 3f6ed437..9cc8f31d 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/PersistenceFactory.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/PersistenceFactory.java @@ -3,22 +3,24 @@ import cz.cvut.kbss.jopa.Persistence; import cz.cvut.kbss.jopa.model.EntityManagerFactory; import cz.cvut.kbss.jopa.model.JOPAPersistenceProvider; -import cz.cvut.kbss.ontodriver.config.OntoDriverProperties; import cz.cvut.kbss.study.util.Constants; -import org.springframework.beans.factory.annotation.Autowired; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.*; +import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.DATA_SOURCE_CLASS; +import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.JPA_PERSISTENCE_PROVIDER; +import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.LANG; +import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.ONTOLOGY_PHYSICAL_URI_KEY; +import static cz.cvut.kbss.jopa.model.JOPAPersistenceProperties.SCAN_PACKAGE; import static cz.cvut.kbss.ontodriver.config.OntoDriverProperties.DATA_SOURCE_PASSWORD; import static cz.cvut.kbss.ontodriver.config.OntoDriverProperties.DATA_SOURCE_USERNAME; import static cz.cvut.kbss.study.util.ConfigParam.DRIVER; @@ -69,7 +71,7 @@ private void close() { private static Map initParams() { final Map map = new HashMap<>(); - map.put(OntoDriverProperties.ONTOLOGY_LANGUAGE, Constants.PU_LANGUAGE); + map.put(LANG, Constants.PU_LANGUAGE); map.put(SCAN_PACKAGE, "cz.cvut.kbss.study"); map.put(JPA_PERSISTENCE_PROVIDER, JOPAPersistenceProvider.class.getName()); return map; diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/ActionHistoryDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/ActionHistoryDao.java index 5fea7433..ad377150 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/dao/ActionHistoryDao.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/ActionHistoryDao.java @@ -2,7 +2,7 @@ import cz.cvut.kbss.jopa.exceptions.NoResultException; import cz.cvut.kbss.jopa.model.EntityManager; -import cz.cvut.kbss.jopa.model.query.Query; +import cz.cvut.kbss.jopa.model.query.TypedQuery; import cz.cvut.kbss.study.model.ActionHistory; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.model.Vocabulary; @@ -14,27 +14,24 @@ import java.util.Objects; @Repository -public class ActionHistoryDao extends OwlKeySupportingDao{ +public class ActionHistoryDao extends OwlKeySupportingDao { - public ActionHistoryDao() { - super(ActionHistory.class); + public ActionHistoryDao(EntityManager em) { + super(ActionHistory.class, em); } public ActionHistory findByKey(String key) { Objects.requireNonNull(key); - final EntityManager em = entityManager(); try { ActionHistory action = em.createNativeQuery( - "SELECT ?x WHERE { ?x ?hasKey ?key . }", ActionHistory.class) - .setParameter("hasKey", URI.create(Vocabulary.s_p_key)) - .setParameter("key", key, Constants.PU_LANGUAGE) - .getSingleResult(); + "SELECT ?x WHERE { ?x ?hasKey ?key . }", ActionHistory.class) + .setParameter("hasKey", URI.create(Vocabulary.s_p_key)) + .setParameter("key", key, Constants.PU_LANGUAGE) + .getSingleResult(); action.getPayload(); return action; } catch (NoResultException e) { return null; - } finally { - em.close(); } } @@ -51,26 +48,22 @@ public List findAllWithParams(String typeFilter, User author, int } else { params = "; ?hasOwner ?author; ?isType ?actionType . filter contains(?actionType, ?typeFilter) } "; } - final EntityManager em = entityManager(); - try { - Query q = em.createNativeQuery("SELECT ?r WHERE { ?r a ?type ; ?isCreated ?timestamp " + - params + "ORDER BY DESC(?timestamp)", ActionHistory.class) - .setParameter("type", typeUri) - .setParameter("isCreated", URI.create(Vocabulary.s_p_created)) - .setFirstResult((pageNumber - 1) * Constants.ACTIONS_PER_PAGE) - .setMaxResults(Constants.ACTIONS_PER_PAGE + 1); + TypedQuery q = em.createNativeQuery("SELECT ?r WHERE { ?r a ?type ; ?isCreated ?timestamp " + + params + "ORDER BY DESC(?timestamp)", + ActionHistory.class) + .setParameter("type", typeUri) + .setParameter("isCreated", URI.create(Vocabulary.s_p_created)) + .setFirstResult((pageNumber - 1) * Constants.ACTIONS_PER_PAGE) + .setMaxResults(Constants.ACTIONS_PER_PAGE + 1); - if (author != null) { - q.setParameter("hasOwner", URI.create(Vocabulary.s_p_has_owner)) - .setParameter("author", author.getUri()); - } - if (typeFilter != null) { - q.setParameter("typeFilter", typeFilter, Constants.PU_LANGUAGE) - .setParameter("isType", URI.create(Vocabulary.s_p_action_type)); - } - return q.getResultList(); - } finally { - em.close(); + if (author != null) { + q.setParameter("hasOwner", URI.create(Vocabulary.s_p_has_owner)) + .setParameter("author", author.getUri()); + } + if (typeFilter != null) { + q.setParameter("typeFilter", typeFilter, Constants.PU_LANGUAGE) + .setParameter("isType", URI.create(Vocabulary.s_p_action_type)); } + return q.getResultList(); } } diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/BaseDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/BaseDao.java index 380479d2..7b3f550a 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/dao/BaseDao.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/BaseDao.java @@ -1,13 +1,11 @@ package cz.cvut.kbss.study.persistence.dao; import cz.cvut.kbss.jopa.model.EntityManager; -import cz.cvut.kbss.jopa.model.EntityManagerFactory; import cz.cvut.kbss.jopa.model.annotations.OWLClass; import cz.cvut.kbss.study.exception.PersistenceException; import cz.cvut.kbss.study.model.util.EntityToOwlClassMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import java.net.URI; import java.util.Collection; @@ -24,37 +22,24 @@ public abstract class BaseDao implements GenericDao { protected final Class type; final URI typeUri; - protected BaseDao(Class type) { + protected final EntityManager em; + + protected BaseDao(Class type, EntityManager em) { this.type = type; this.typeUri = URI.create(EntityToOwlClassMapper.getOwlClassForEntity(type)); + this.em = em; } - @Autowired - private EntityManagerFactory emf; - @Override public T find(URI uri) { Objects.requireNonNull(uri); - final EntityManager em = entityManager(); - try { - return findByUri(uri, em); - } finally { - em.close(); - } - } - - protected T findByUri(URI uri, EntityManager em) { - return em.find(type, uri); + return em.find(type, uri); } @Override public List findAll() { - final EntityManager em = entityManager(); - try { - return findAll(em); - } finally { - em.close(); - } + return em.createNativeQuery("SELECT ?x WHERE { ?x a ?type . }", type).setParameter("type", typeUri) + .getResultList(); } protected List findAll(EntityManager em) { @@ -65,120 +50,58 @@ protected List findAll(EntityManager em) { @Override public void persist(T entity) { Objects.requireNonNull(entity); - final EntityManager em = entityManager(); try { - em.getTransaction().begin(); - persist(entity, em); - em.getTransaction().commit(); + em.persist(entity); } catch (RuntimeException e) { LOG.error("Error when persisting entity.", e); throw new PersistenceException(e); - } finally { - em.close(); } } - protected void persist(T entity, EntityManager em) { - em.persist(entity); - } - @Override public void persist(Collection entities) { Objects.requireNonNull(entities); if (entities.isEmpty()) { return; } - final EntityManager em = entityManager(); - try { - em.getTransaction().begin(); - entities.forEach(e -> persist(e, em)); - em.getTransaction().commit(); - } catch (RuntimeException e) { - LOG.error("Error when persisting entities.", e); - throw new PersistenceException(e); - } finally { - em.close(); - } + entities.forEach(this::persist); } @Override public void update(T entity) { Objects.requireNonNull(entity); - final EntityManager em = entityManager(); try { - em.getTransaction().begin(); - update(entity, em); - em.getTransaction().commit(); + em.merge(entity); } catch (RuntimeException e) { LOG.error("Error when updating entity.", e); throw new PersistenceException(e); - } finally { - em.close(); } } - protected void update(T entity, EntityManager em) { - em.merge(entity); - } - @Override public void remove(T entity) { Objects.requireNonNull(entity); - final EntityManager em = entityManager(); try { - em.getTransaction().begin(); - remove(entity, em); - em.getTransaction().commit(); + final T toRemove = em.merge(entity); + assert toRemove != null; + em.remove(toRemove); } catch (RuntimeException e) { LOG.error("Error when removing entity.", e); throw new PersistenceException(e); - } finally { - em.close(); } } - protected void remove(T entity, EntityManager em) { - final T toRemove = em.merge(entity); - assert toRemove != null; - em.remove(toRemove); - } - @Override public void remove(Collection entities) { Objects.requireNonNull(entities); if (entities.isEmpty()) { return; } - final EntityManager em = entityManager(); - try { - em.getTransaction().begin(); - entities.forEach(entity -> { - final T toRemove = em.merge(entity); - em.remove(toRemove); - }); - em.getTransaction().commit(); - } catch (RuntimeException e) { - LOG.error("Error when removing entities.", e); - throw new PersistenceException(e); - } finally { - em.close(); - } + entities.forEach(this::remove); } @Override public boolean exists(URI uri) { - if (uri == null) { - return false; - } - final EntityManager em = entityManager(); - try { - return exists(uri, em); - } finally { - em.close(); - } - } - - protected boolean exists(URI uri, EntityManager em) { if (uri == null) { return false; } @@ -186,8 +109,4 @@ protected boolean exists(URI uri, EntityManager em) { return em.createNativeQuery("ASK { ?individual a ?type . }", Boolean.class).setParameter("individual", uri) .setParameter("type", URI.create(owlClass)).getSingleResult(); } - - EntityManager entityManager() { - return emf.createEntityManager(); - } } diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/DerivableUriDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/DerivableUriDao.java index fa23c3a0..acfc4c74 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/dao/DerivableUriDao.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/DerivableUriDao.java @@ -3,6 +3,8 @@ import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.study.model.util.HasDerivableUri; +import java.util.Objects; + /** * Data access object for classes with derivable URI. *

@@ -12,20 +14,19 @@ */ abstract class DerivableUriDao extends BaseDao { - protected DerivableUriDao(Class type) { - super(type); + protected DerivableUriDao(Class type, EntityManager em) { + super(type, em); } /** * Generates URI and then calls persist. * * @param entity Entity to persist - * @param em Current entity manager */ @Override - protected void persist(T entity, EntityManager em) { - assert entity != null; + public void persist(T entity) { + Objects.requireNonNull(entity); entity.generateUri(); - super.persist(entity, em); + super.persist(entity); } } diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/InstitutionDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/InstitutionDao.java index a6780454..448ecc57 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/dao/InstitutionDao.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/InstitutionDao.java @@ -12,8 +12,8 @@ @Repository public class InstitutionDao extends OwlKeySupportingDao { - public InstitutionDao() { - super(Institution.class); + public InstitutionDao(EntityManager em) { + super(Institution.class, em); } /** @@ -26,15 +26,12 @@ public Institution findByName(String name) { if (name == null) { return null; } - final EntityManager em = entityManager(); try { return em.createNativeQuery("SELECT ?x WHERE { ?x ?hasName ?name . }", Institution.class) .setParameter("hasName", URI.create(Vocabulary.s_p_label)) .setParameter("name", name, Constants.PU_LANGUAGE).getSingleResult(); } catch (NoResultException e) { return null; - } finally { - em.close(); } } } diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/OwlKeySupportingDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/OwlKeySupportingDao.java index 627a3d2f..a0d03383 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/dao/OwlKeySupportingDao.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/OwlKeySupportingDao.java @@ -17,21 +17,20 @@ */ public abstract class OwlKeySupportingDao extends BaseDao { - protected OwlKeySupportingDao(Class type) { - super(type); + protected OwlKeySupportingDao(Class type, EntityManager em) { + super(type, em); } /** * Generates key and then calls persist. * * @param entity The instance to persist - * @param em Current EntityManager */ @Override - protected void persist(T entity, EntityManager em) { - assert entity != null; + public void persist(T entity) { + Objects.requireNonNull(entity); entity.setKey(IdentificationUtils.generateKey()); - super.persist(entity, em); + super.persist(entity); } /** @@ -42,18 +41,9 @@ protected void persist(T entity, EntityManager em) { */ public T findByKey(String key) { Objects.requireNonNull(key); - final EntityManager em = entityManager(); - try { - return findByKey(key, em); - } finally { - em.close(); - } - } - - protected T findByKey(String key, EntityManager em) { try { return em.createNativeQuery("SELECT ?x WHERE { ?x ?hasKey ?key ;" + - "a ?type }", type) + "a ?type }", type) .setParameter("hasKey", URI.create(Vocabulary.s_p_key)) .setParameter("key", key, Constants.PU_LANGUAGE).setParameter("type", typeUri).getSingleResult(); } catch (NoResultException e) { diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java index 175d33e7..b36ba023 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java @@ -2,16 +2,15 @@ import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.study.dto.PatientRecordDto; -import cz.cvut.kbss.study.exception.PersistenceException; import cz.cvut.kbss.study.exception.ValidationException; import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.PatientRecord; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.model.Vocabulary; import cz.cvut.kbss.study.persistence.dao.util.QuestionSaver; -import java.math.BigInteger; import org.springframework.stereotype.Repository; +import java.math.BigInteger; import java.net.URI; import java.util.List; import java.util.Objects; @@ -19,20 +18,20 @@ @Repository public class PatientRecordDao extends OwlKeySupportingDao { - public PatientRecordDao() { - super(PatientRecord.class); + public PatientRecordDao(EntityManager em) { + super(PatientRecord.class, em); } @Override - protected void persist(PatientRecord entity, EntityManager em) { - assert entity != null; - super.persist(entity, em); + public void persist(PatientRecord entity) { + super.persist(entity); final QuestionSaver questionSaver = new QuestionSaver(); questionSaver.persistIfNecessary(entity.getQuestion(), em); } @Override - protected void update(PatientRecord entity, EntityManager em) { + public void update(PatientRecord entity) { + Objects.requireNonNull(entity); final PatientRecord orig = em.find(PatientRecord.class, entity.getUri()); assert orig != null; orig.setQuestion(null); @@ -40,12 +39,9 @@ protected void update(PatientRecord entity, EntityManager em) { } public List findAllRecords() { - final EntityManager em = entityManager(); - try { - return findAllRecords(em); - } finally { - em.close(); - } + return em.createNativeQuery("SELECT ?x WHERE { ?x a ?type . }", PatientRecordDto.class) + .setParameter("type", typeUri) + .getResultList(); } /** @@ -56,16 +52,12 @@ public List findAllRecords() { */ public List findByInstitution(Institution institution) { Objects.requireNonNull(institution); - final EntityManager em = entityManager(); - try { - return em.createNativeQuery("SELECT ?r WHERE { ?r a ?type ; ?treatedAt ?institution . }", PatientRecordDto.class) - .setParameter("type", typeUri) - .setParameter("treatedAt", URI.create(Vocabulary.s_p_was_treated_at)) - .setParameter("institution", institution.getUri()) - .getResultList(); - } finally { - em.close(); - } + return em.createNativeQuery("SELECT ?r WHERE { ?r a ?type ; ?treatedAt ?institution . }", + PatientRecordDto.class) + .setParameter("type", typeUri) + .setParameter("treatedAt", URI.create(Vocabulary.s_p_was_treated_at)) + .setParameter("institution", institution.getUri()) + .getResultList(); } /** @@ -76,56 +68,40 @@ public List findByInstitution(Institution institution) { */ public List findByAuthor(User author) { Objects.requireNonNull(author); - final EntityManager em = entityManager(); - try { - return em.createNativeQuery("SELECT ?r WHERE { ?r a ?type ; ?createdBy ?author . }", PatientRecord.class) - .setParameter("type", typeUri) - .setParameter("createdBy", URI.create(Vocabulary.s_p_has_author)) - .setParameter("author", author.getUri()).getResultList(); - } finally { - em.close(); - } + return em.createNativeQuery("SELECT ?r WHERE { ?r a ?type ; ?createdBy ?author . }", PatientRecord.class) + .setParameter("type", typeUri) + .setParameter("createdBy", URI.create(Vocabulary.s_p_has_author)) + .setParameter("author", author.getUri()).getResultList(); } public int getNumberOfProcessedRecords() { - final EntityManager em = entityManager(); - try { - return ((BigInteger) em.createNativeQuery( - "SELECT (count(?p) as ?patientRecordsCount) WHERE { ?p a ?record . }") - .setParameter("record", URI.create(Vocabulary.s_c_patient_record)) - .getSingleResult() - ).intValue(); - } finally { - em.close(); - } - } - - private List findAllRecords(EntityManager em) { - return em.createNativeQuery("SELECT ?x WHERE { ?x a ?type . }", PatientRecordDto.class) - .setParameter("type", typeUri) - .getResultList(); + return ((BigInteger) em.createNativeQuery( + "SELECT (count(?p) as ?patientRecordsCount) WHERE { ?p a ?record . }") + .setParameter("record", URI.create(Vocabulary.s_c_patient_record)) + .getSingleResult() + ).intValue(); } /** * Ensure that local name of provided record is unique within its organization. * * @param entity The local name to be checked for uniqueness - * @return Local names of matching records */ public void requireUniqueNonEmptyLocalName(PatientRecord entity) { Objects.requireNonNull(entity.getInstitution()); if (entity.getLocalName() == null || entity.getLocalName().isEmpty()) { throw new ValidationException("error.record.localNameOfRecordIsEmpty", - "Local name of record is empty for entity " + entity); + "Local name of record is empty for entity " + entity); } boolean unique = findByInstitution(entity.getInstitution()).stream() - .filter(pr -> (entity.getFormTemplate() != null) && entity.getFormTemplate().equals(pr.getFormTemplate())) - .filter(pr -> pr.getLocalName() - .equals(entity.getLocalName())) - .noneMatch(pr -> ! pr.getUri().equals(entity.getUri())); - if (! unique) { + .filter(pr -> (entity.getFormTemplate() != null) && entity.getFormTemplate() + .equals(pr.getFormTemplate())) + .filter(pr -> pr.getLocalName() + .equals(entity.getLocalName())) + .allMatch(pr -> pr.getUri().equals(entity.getUri())); + if (!unique) { throw new ValidationException("error.record.localNameOfRecordIsNotUnique", - "Local name of record is not unique for entity " + entity); + "Local name of record is not unique for entity " + entity); } } diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/UserDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/UserDao.java index 564bc2b1..9e461d9f 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/dao/UserDao.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/UserDao.java @@ -6,11 +6,11 @@ import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.model.Vocabulary; import cz.cvut.kbss.study.util.Constants; -import java.math.BigInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Repository; +import java.math.BigInteger; import java.net.URI; import java.util.List; import java.util.Objects; @@ -20,58 +20,47 @@ public class UserDao extends DerivableUriDao { protected static final Logger LOG = LoggerFactory.getLogger(UserDao.class); - public UserDao() { - super(User.class); + public UserDao(EntityManager em) { + super(User.class, em); } public User findByUsername(String username) { Objects.requireNonNull(username); - final EntityManager em = entityManager(); try { - return em.createNativeQuery( - "SELECT ?x WHERE { ?x ?hasUsername ?username . }", User.class) + return em.createNativeQuery("SELECT ?x WHERE { ?x ?hasUsername ?username . }", User.class) .setParameter("hasUsername", URI.create(Vocabulary.s_p_accountName)) .setParameter("username", username, Constants.PU_LANGUAGE) .getSingleResult(); } catch (NoResultException e) { return null; - } finally { - em.close(); } } public User findByEmail(String email) { Objects.requireNonNull(email); - final EntityManager em = entityManager(); final String normalizedEmail = email.trim().toLowerCase(); try { return em.createNativeQuery( - "SELECT ?x WHERE { " + - "?x ?hasEmail ?emailAddress . " + - "FILTER(lcase(?emailAddress) = ?normalizedEmailAddress) }", User.class) - .setParameter("hasEmail", URI.create(Vocabulary.s_p_mbox)) - .setParameter("normalizedEmailAddress", normalizedEmail, Constants.PU_LANGUAGE) - .getSingleResult(); + "SELECT ?x WHERE { " + + "?x ?hasEmail ?emailAddress . " + + "FILTER(lcase(?emailAddress) = ?normalizedEmailAddress) }", User.class) + .setParameter("hasEmail", URI.create(Vocabulary.s_p_mbox)) + .setParameter("normalizedEmailAddress", normalizedEmail, Constants.PU_LANGUAGE) + .getSingleResult(); } catch (NoResultException e) { return null; - } finally { - em.close(); } } public User findByToken(String token) { Objects.requireNonNull(token); - final EntityManager em = entityManager(); try { - return em.createNativeQuery( - "SELECT ?x WHERE { ?x ?valid ?token . }", User.class) - .setParameter("valid", URI.create(Vocabulary.s_p_token)) - .setParameter("token", token, Constants.PU_LANGUAGE) - .getSingleResult(); + return em.createNativeQuery("SELECT ?x WHERE { ?x ?valid ?token . }", User.class) + .setParameter("valid", URI.create(Vocabulary.s_p_token)) + .setParameter("token", token, Constants.PU_LANGUAGE) + .getSingleResult(); } catch (NoResultException e) { return null; - } finally { - em.close(); } } @@ -83,30 +72,20 @@ public User findByToken(String token) { */ public List findByInstitution(Institution institution) { Objects.requireNonNull(institution); - final EntityManager em = entityManager(); - try { - return em.createNativeQuery( - "SELECT ?x WHERE { ?x a ?type ; ?hasUsername ?username ; ?isMemberOf ?institution . } ORDER BY ?username", - User.class) - .setParameter("type", typeUri) - .setParameter("hasUsername", URI.create(Vocabulary.s_p_accountName)) - .setParameter("isMemberOf", URI.create(Vocabulary.s_p_is_member_of)) - .setParameter("institution", institution.getUri()).getResultList(); - } finally { - em.close(); - } + return em.createNativeQuery( + "SELECT ?x WHERE { ?x a ?type ; ?hasUsername ?username ; ?isMemberOf ?institution . } ORDER BY ?username", + User.class) + .setParameter("type", typeUri) + .setParameter("hasUsername", URI.create(Vocabulary.s_p_accountName)) + .setParameter("isMemberOf", URI.create(Vocabulary.s_p_is_member_of)) + .setParameter("institution", institution.getUri()).getResultList(); } public int getNumberOfInvestigators() { - final EntityManager em = entityManager(); - try { - return ((BigInteger) em.createNativeQuery( - "SELECT (count(?p) as ?investigatorCount) WHERE { ?p a ?typeDoctor . MINUS {?p a ?typeAdmin}}") - .setParameter("typeDoctor", URI.create(Vocabulary.s_c_doctor)) - .setParameter("typeAdmin", URI.create(Vocabulary.s_c_administrator)).getSingleResult() - ).intValue(); - } finally { - em.close(); - } + return ((BigInteger) em.createNativeQuery( + "SELECT (count(?p) as ?investigatorCount) WHERE { ?p a ?typeDoctor . MINUS {?p a ?typeAdmin}}") + .setParameter("typeDoctor", URI.create(Vocabulary.s_c_doctor)) + .setParameter("typeAdmin", URI.create(Vocabulary.s_c_administrator)).getSingleResult() + ).intValue(); } } diff --git a/src/main/java/cz/cvut/kbss/study/persistence/data/RemoteDataLoader.java b/src/main/java/cz/cvut/kbss/study/persistence/data/RemoteDataLoader.java index 45995998..75ea8d2e 100644 --- a/src/main/java/cz/cvut/kbss/study/persistence/data/RemoteDataLoader.java +++ b/src/main/java/cz/cvut/kbss/study/persistence/data/RemoteDataLoader.java @@ -5,7 +5,6 @@ import cz.cvut.kbss.study.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -53,14 +52,14 @@ public String loadData(String remoteUrl, Map params) { final URI urlWithQuery = Utils.prepareUri(remoteUrl, params); final HttpEntity entity = new HttpEntity<>(null, headers); if (LOG.isTraceEnabled()) { - LOG.trace("Getting remote data using {}", urlWithQuery.toString()); + LOG.trace("Getting remote data using {}", urlWithQuery); } try { - final ResponseEntity result = restTemplate.exchange(urlWithQuery, HttpMethod.GET, entity, - String.class); + final ResponseEntity result = + restTemplate.exchange(urlWithQuery, HttpMethod.GET, entity, String.class); return result.getBody(); } catch (Exception e) { - LOG.error("Error when requesting remote data, url: {}.", urlWithQuery.toString(), e); + LOG.error("Error when requesting remote data, url: {}.", urlWithQuery, e); throw new WebServiceIntegrationException("Unable to fetch remote data.", e); } } diff --git a/src/main/java/cz/cvut/kbss/study/rest/handler/RestExceptionHandler.java b/src/main/java/cz/cvut/kbss/study/rest/handler/RestExceptionHandler.java index 87119bb1..0a97bfa7 100644 --- a/src/main/java/cz/cvut/kbss/study/rest/handler/RestExceptionHandler.java +++ b/src/main/java/cz/cvut/kbss/study/rest/handler/RestExceptionHandler.java @@ -1,6 +1,7 @@ package cz.cvut.kbss.study.rest.handler; import cz.cvut.kbss.study.exception.*; +import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; @@ -9,8 +10,6 @@ import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; -import javax.servlet.http.HttpServletRequest; - /** * Exception handlers for REST controllers. *

diff --git a/src/main/java/cz/cvut/kbss/study/rest/servlet/DiagnosticsContextFilter.java b/src/main/java/cz/cvut/kbss/study/rest/servlet/DiagnosticsContextFilter.java new file mode 100644 index 00000000..b21f9e41 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/rest/servlet/DiagnosticsContextFilter.java @@ -0,0 +1,58 @@ +/** + * TermIt + * Copyright (C) 2019 Czech Technical University in Prague + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package cz.cvut.kbss.study.rest.servlet; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import org.slf4j.MDC; +import org.springframework.web.filter.GenericFilterBean; + +import java.io.IOException; +import java.security.Principal; + +/** + * Stores user info into the Mapped Diagnostic Context for the logging framework. + */ +public class DiagnosticsContextFilter extends GenericFilterBean { + + static final String MDC_KEY = "username"; + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + final HttpServletRequest req = (HttpServletRequest) servletRequest; + final Principal principal = req.getUserPrincipal(); + boolean mdcSet = false; + if (principal != null) { + final String username = req.getUserPrincipal().getName(); + MDC.put(MDC_KEY, username); + mdcSet = true; + } + + try { + filterChain.doFilter(servletRequest, servletResponse); + } finally { + if (mdcSet) { + MDC.remove(MDC_KEY); + } + } + } +} diff --git a/src/main/java/cz/cvut/kbss/study/rest/util/RestUtils.java b/src/main/java/cz/cvut/kbss/study/rest/util/RestUtils.java index cf27e256..078021ea 100644 --- a/src/main/java/cz/cvut/kbss/study/rest/util/RestUtils.java +++ b/src/main/java/cz/cvut/kbss/study/rest/util/RestUtils.java @@ -2,14 +2,15 @@ import cz.cvut.kbss.study.exception.WebServiceIntegrationException; import cz.cvut.kbss.study.util.Constants; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.HttpHeaders; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; public class RestUtils { @@ -65,11 +66,7 @@ public static HttpHeaders createLocationHeaderFromContextPath(String path, Objec * @return Encoded string */ public static String encodeUrl(String value) { - try { - return URLEncoder.encode(value, Constants.UTF_8_ENCODING); - } catch (UnsupportedEncodingException e) { - throw new WebServiceIntegrationException("Encoding not found.", e); - } + return URLEncoder.encode(value, StandardCharsets.UTF_8); } public static String getCookie(HttpServletRequest request, String cookieName) { diff --git a/src/main/java/cz/cvut/kbss/study/security/AuthenticationFailure.java b/src/main/java/cz/cvut/kbss/study/security/AuthenticationFailure.java index 11c2501c..36c08401 100644 --- a/src/main/java/cz/cvut/kbss/study/security/AuthenticationFailure.java +++ b/src/main/java/cz/cvut/kbss/study/security/AuthenticationFailure.java @@ -2,16 +2,15 @@ import com.fasterxml.jackson.databind.ObjectMapper; import cz.cvut.kbss.study.security.model.LoginStatus; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Service; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** @@ -30,7 +29,7 @@ public AuthenticationFailure(ObjectMapper mapper) { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, - AuthenticationException e) throws IOException, ServletException { + AuthenticationException e) throws IOException { if (LOG.isTraceEnabled()) { LOG.trace("Login failed for user {}.", httpServletRequest.getParameter(SecurityConstants.USERNAME_PARAM)); } diff --git a/src/main/java/cz/cvut/kbss/study/security/AuthenticationSuccess.java b/src/main/java/cz/cvut/kbss/study/security/AuthenticationSuccess.java index a6dcbb6d..7dfb3777 100644 --- a/src/main/java/cz/cvut/kbss/study/security/AuthenticationSuccess.java +++ b/src/main/java/cz/cvut/kbss/study/security/AuthenticationSuccess.java @@ -6,6 +6,8 @@ import cz.cvut.kbss.study.security.model.UserDetails; import cz.cvut.kbss.study.service.ConfigReader; import cz.cvut.kbss.study.util.ConfigParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; @@ -14,9 +16,6 @@ import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.stereotype.Service; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.Collection; @@ -34,8 +33,7 @@ public class AuthenticationSuccess implements AuthenticationSuccessHandler, Logo private final ConfigReader config; - public AuthenticationSuccess(ObjectMapper mapper, - ConfigReader config) { + public AuthenticationSuccess(ObjectMapper mapper, ConfigReader config) { this.mapper = mapper; this.config = config; } @@ -120,13 +118,11 @@ private void addSameSiteCookieAttribute(HttpServletResponse response) { // there can be multiple Set-Cookie attributes for (String header : headers) { if (firstHeader) { - response.setHeader(HttpHeaders.SET_COOKIE, - String.format("%s; %s", header, headerValues.toString())); + response.setHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, headerValues)); firstHeader = false; continue; } - response.addHeader(HttpHeaders.SET_COOKIE, - String.format("%s; %s", header, headerValues.toString())); + response.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, headerValues)); } } diff --git a/src/main/java/cz/cvut/kbss/study/security/CsrfHeaderFilter.java b/src/main/java/cz/cvut/kbss/study/security/CsrfHeaderFilter.java index bfee7611..99c4dd83 100644 --- a/src/main/java/cz/cvut/kbss/study/security/CsrfHeaderFilter.java +++ b/src/main/java/cz/cvut/kbss/study/security/CsrfHeaderFilter.java @@ -1,14 +1,14 @@ package cz.cvut.kbss.study.security; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.web.csrf.CsrfToken; import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.util.WebUtils; -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; /** diff --git a/src/main/java/cz/cvut/kbss/study/security/HttpAuthenticationEntryPoint.java b/src/main/java/cz/cvut/kbss/study/security/HttpAuthenticationEntryPoint.java deleted file mode 100644 index e0934bb4..00000000 --- a/src/main/java/cz/cvut/kbss/study/security/HttpAuthenticationEntryPoint.java +++ /dev/null @@ -1,23 +0,0 @@ -package cz.cvut.kbss.study.security; - -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * Returns 401 Unauthorized response when the user tries to access a resource and is not logged in. - */ -@Component -public class HttpAuthenticationEntryPoint implements AuthenticationEntryPoint { - - @Override - public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, - AuthenticationException e) throws IOException, ServletException { - httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication required."); - } -} diff --git a/src/main/java/cz/cvut/kbss/study/security/OntologyAuthenticationProvider.java b/src/main/java/cz/cvut/kbss/study/security/OntologyAuthenticationProvider.java index 6f996982..b16f7d16 100644 --- a/src/main/java/cz/cvut/kbss/study/security/OntologyAuthenticationProvider.java +++ b/src/main/java/cz/cvut/kbss/study/security/OntologyAuthenticationProvider.java @@ -4,7 +4,6 @@ import cz.cvut.kbss.study.security.model.UserDetails; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; diff --git a/src/main/java/cz/cvut/kbss/study/security/SessionTimeoutManager.java b/src/main/java/cz/cvut/kbss/study/security/SessionTimeoutManager.java index 156ce64f..8817ed3a 100644 --- a/src/main/java/cz/cvut/kbss/study/security/SessionTimeoutManager.java +++ b/src/main/java/cz/cvut/kbss/study/security/SessionTimeoutManager.java @@ -1,8 +1,8 @@ package cz.cvut.kbss.study.security; -import javax.servlet.annotation.WebListener; -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; +import jakarta.servlet.annotation.WebListener; +import jakarta.servlet.http.HttpSessionEvent; +import jakarta.servlet.http.HttpSessionListener; @WebListener public class SessionTimeoutManager implements HttpSessionListener { diff --git a/src/main/java/cz/cvut/kbss/study/service/EmailService.java b/src/main/java/cz/cvut/kbss/study/service/EmailService.java index b987ecd3..b3789f67 100644 --- a/src/main/java/cz/cvut/kbss/study/service/EmailService.java +++ b/src/main/java/cz/cvut/kbss/study/service/EmailService.java @@ -3,18 +3,17 @@ import cz.cvut.kbss.study.exception.ValidationException; import cz.cvut.kbss.study.util.ConfigParam; import cz.cvut.kbss.study.util.etemplates.BaseEmailTemplate; +import jakarta.mail.Message; +import jakarta.mail.MessagingException; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.AddressException; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.AddressException; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; import java.io.UnsupportedEncodingException; import java.util.Properties; diff --git a/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java b/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java index 2f4d2933..3d02624d 100644 --- a/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java +++ b/src/main/java/cz/cvut/kbss/study/service/SystemInitializer.java @@ -3,12 +3,11 @@ import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.model.Vocabulary; +import jakarta.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import javax.annotation.PostConstruct; - @Service public class SystemInitializer { diff --git a/src/main/java/cz/cvut/kbss/study/service/formgen/FormGenService.java b/src/main/java/cz/cvut/kbss/study/service/formgen/FormGenService.java index 0ea92458..0184ca4d 100644 --- a/src/main/java/cz/cvut/kbss/study/service/formgen/FormGenService.java +++ b/src/main/java/cz/cvut/kbss/study/service/formgen/FormGenService.java @@ -9,12 +9,12 @@ import cz.cvut.kbss.study.service.security.SecurityUtils; import cz.cvut.kbss.study.util.ConfigParam; import cz.cvut.kbss.study.util.Utils; +import jakarta.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; -import javax.annotation.PostConstruct; import java.net.URI; import java.util.*; diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/BaseRepositoryService.java b/src/main/java/cz/cvut/kbss/study/service/repository/BaseRepositoryService.java index e0d946fd..d920d82f 100644 --- a/src/main/java/cz/cvut/kbss/study/service/repository/BaseRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/study/service/repository/BaseRepositoryService.java @@ -4,6 +4,7 @@ import cz.cvut.kbss.study.service.BaseService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.transaction.annotation.Transactional; import java.net.URI; import java.util.Collection; @@ -16,6 +17,7 @@ public abstract class BaseRepositoryService implements BaseService { protected abstract GenericDao getPrimaryDao(); + @Transactional(readOnly = true) @Override public List findAll() { final List result = getPrimaryDao().findAll(); @@ -23,6 +25,7 @@ public List findAll() { return result; } + @Transactional(readOnly = true) @Override public T find(URI uri) { final T result = getPrimaryDao().find(uri); @@ -30,6 +33,7 @@ public T find(URI uri) { return result; } + @Transactional @Override public void persist(T instance) { Objects.requireNonNull(instance); @@ -37,6 +41,7 @@ public void persist(T instance) { getPrimaryDao().persist(instance); } + @Transactional @Override public void persist(Collection instances) { Objects.requireNonNull(instances); @@ -47,6 +52,7 @@ public void persist(Collection instances) { getPrimaryDao().persist(instances); } + @Transactional @Override public void update(T instance) { Objects.requireNonNull(instance); @@ -54,6 +60,7 @@ public void update(T instance) { getPrimaryDao().update(instance); } + @Transactional @Override public void remove(T instance) { Objects.requireNonNull(instance); @@ -61,11 +68,13 @@ public void remove(T instance) { getPrimaryDao().remove(instance); } + @Transactional @Override public void remove(Collection instances) { getPrimaryDao().remove(instances); } + @Transactional(readOnly = true) @Override public boolean exists(URI uri) { return getPrimaryDao().exists(uri); diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/KeySupportingRepositoryService.java b/src/main/java/cz/cvut/kbss/study/service/repository/KeySupportingRepositoryService.java index 0a7f41d4..0d77a805 100644 --- a/src/main/java/cz/cvut/kbss/study/service/repository/KeySupportingRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/study/service/repository/KeySupportingRepositoryService.java @@ -3,6 +3,7 @@ import cz.cvut.kbss.study.model.util.HasOwlKey; import cz.cvut.kbss.study.persistence.dao.OwlKeySupportingDao; +import org.springframework.transaction.annotation.Transactional; /** * Implements the {@link #findByKey(String)} method for all services which support key-based identification. @@ -14,6 +15,7 @@ abstract class KeySupportingRepositoryService extends BaseR @Override protected abstract OwlKeySupportingDao getPrimaryDao(); + @Transactional(readOnly = true) public T findByKey(String key) { return getPrimaryDao().findByKey(key); } diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryActionHistoryService.java b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryActionHistoryService.java index 2ccc53b8..82522b0b 100644 --- a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryActionHistoryService.java +++ b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryActionHistoryService.java @@ -5,8 +5,8 @@ import cz.cvut.kbss.study.persistence.dao.ActionHistoryDao; import cz.cvut.kbss.study.persistence.dao.GenericDao; import cz.cvut.kbss.study.service.ActionHistoryService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -24,11 +24,13 @@ protected GenericDao getPrimaryDao() { return actionHistoryDao; } + @Transactional(readOnly = true) @Override public ActionHistory findByKey(String key) { return actionHistoryDao.findByKey(key); } + @Transactional(readOnly = true) @Override public List findAllWithParams(String type, User author, int pageNumber) { return actionHistoryDao.findAllWithParams(type, author, pageNumber); diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryInstitutionService.java b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryInstitutionService.java index 6fe51690..e6047284 100644 --- a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryInstitutionService.java +++ b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryInstitutionService.java @@ -8,8 +8,8 @@ import cz.cvut.kbss.study.persistence.dao.UserDao; import cz.cvut.kbss.study.service.InstitutionService; import cz.cvut.kbss.study.util.Validator; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service public class RepositoryInstitutionService extends KeySupportingRepositoryService implements InstitutionService { @@ -33,6 +33,7 @@ protected OwlKeySupportingDao getPrimaryDao() { return institutionDao; } + @Transactional(readOnly = true) @Override public Institution findByName(String name) { return institutionDao.findByName(name); diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java index 83eb4975..dd45e36c 100644 --- a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java +++ b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java @@ -10,6 +10,7 @@ import cz.cvut.kbss.study.service.security.SecurityUtils; import cz.cvut.kbss.study.util.IdentificationUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.List; @@ -33,16 +34,19 @@ protected OwlKeySupportingDao getPrimaryDao() { return recordDao; } + @Transactional(readOnly = true) @Override public List findByInstitution(Institution institution) { return recordDao.findByInstitution(institution); } + @Transactional(readOnly = true) @Override public List findByAuthor(User user) { return recordDao.findByAuthor(user); } + @Transactional(readOnly = true) @Override public List findAllRecords() { return recordDao.findAllRecords(); diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryStatisticsService.java b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryStatisticsService.java index fd102d0c..e888728d 100644 --- a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryStatisticsService.java +++ b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryStatisticsService.java @@ -3,8 +3,8 @@ import cz.cvut.kbss.study.persistence.dao.PatientRecordDao; import cz.cvut.kbss.study.persistence.dao.UserDao; import cz.cvut.kbss.study.service.StatisticsService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service public class RepositoryStatisticsService implements StatisticsService { @@ -19,11 +19,13 @@ public RepositoryStatisticsService(UserDao userDao, this.recordDao = recordDao; } + @Transactional(readOnly = true) @Override public int getNumberOfInvestigators() { return userDao.getNumberOfInvestigators(); } + @Transactional(readOnly = true) @Override public int getNumberOfProcessedRecords() { return recordDao.getNumberOfProcessedRecords(); diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryUserService.java b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryUserService.java index 7ffaa610..3de075b0 100644 --- a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryUserService.java +++ b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryUserService.java @@ -15,12 +15,16 @@ import cz.cvut.kbss.study.service.security.SecurityUtils; import cz.cvut.kbss.study.util.IdentificationUtils; import cz.cvut.kbss.study.util.Validator; -import cz.cvut.kbss.study.util.etemplates.*; +import cz.cvut.kbss.study.util.etemplates.BaseEmailTemplate; +import cz.cvut.kbss.study.util.etemplates.PasswordChange; +import cz.cvut.kbss.study.util.etemplates.PasswordReset; +import cz.cvut.kbss.study.util.etemplates.ProfileUpdate; +import cz.cvut.kbss.study.util.etemplates.UserInvite; import org.apache.commons.lang.StringUtils; import org.eclipse.rdf4j.http.protocol.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.Comparator; import java.util.List; @@ -61,18 +65,20 @@ protected GenericDao getPrimaryDao() { return userDao; } + @Transactional(readOnly = true) @Override public User findByUsername(String username) { - User user = userDao.findByUsername(username); - return user; + return userDao.findByUsername(username); } + @Transactional(readOnly = true) @Override public List findByInstitution(Institution institution) { Objects.requireNonNull(institution); return userDao.findByInstitution(institution); } + @Transactional(readOnly = true) @Override public User findByEmail(String email) { return Optional.ofNullable(userDao.findByEmail(email)) @@ -90,6 +96,7 @@ public User findByEmail(String email) { ); } + @Transactional(readOnly = true) @Override public User findByToken(String token) { return userDao.findByToken(token); @@ -101,11 +108,12 @@ public String generateUsername(String usernamePrefix) { .filter(u -> u.getUsername().startsWith(usernamePrefix)) .map(u -> u.getUsername().replaceFirst(usernamePrefix, "")) .filter(s -> StringUtils.isNotBlank(s) && StringUtils.isNumeric(s)) - .map(s -> Integer.parseInt(s)) + .map(Integer::parseInt) .max(Comparator.naturalOrder()) .orElse(0) + 1); } + @Transactional @Override public void update(User user, boolean sendEmail, String emailType) { final User currentUser = securityUtils.getCurrentUser(); @@ -120,6 +128,7 @@ public void update(User user, boolean sendEmail, String emailType) { } } + @Transactional @Override public void changePassword(User user, String newPassword, String currentPassword, boolean sendEmail) { final User currentUser = securityUtils.getCurrentUser(); @@ -132,6 +141,7 @@ public void changePassword(User user, String newPassword, String currentPassword this.update(user, sendEmail, "passwordChange"); } + @Transactional @Override public void changePasswordByToken(User user, String password) { Objects.requireNonNull(user); @@ -141,6 +151,7 @@ public void changePasswordByToken(User user, String password) { userDao.update(user); } + @Transactional @Override public void resetPassword(User user, String recipientEmail) { Objects.requireNonNull(user); @@ -150,6 +161,7 @@ public void resetPassword(User user, String recipientEmail) { userDao.update(user); } + @Transactional @Override public void sendInvitation(User user) { final User currentUser = securityUtils.getCurrentUser(); diff --git a/src/main/java/cz/cvut/kbss/study/service/security/UserDetailsService.java b/src/main/java/cz/cvut/kbss/study/service/security/UserDetailsService.java index 8dffdb62..2498dfa3 100644 --- a/src/main/java/cz/cvut/kbss/study/service/security/UserDetailsService.java +++ b/src/main/java/cz/cvut/kbss/study/service/security/UserDetailsService.java @@ -2,7 +2,6 @@ import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.persistence.dao.UserDao; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; diff --git a/src/main/java/cz/cvut/kbss/study/util/Constants.java b/src/main/java/cz/cvut/kbss/study/util/Constants.java index 640bc26a..0a22c590 100644 --- a/src/main/java/cz/cvut/kbss/study/util/Constants.java +++ b/src/main/java/cz/cvut/kbss/study/util/Constants.java @@ -6,6 +6,8 @@ private Constants() { throw new AssertionError(); } + public static final String REST_API_REFIX = "/rest"; + public static final String BASE_URI = "http://onto.fel.cvut.cz/ontologies/record-manager/"; /** @@ -18,21 +20,11 @@ private Constants() { */ public static final String FORM_GEN_CONTEXT_BASE = "http://onto.fel.cvut.cz/ontologies/record-manager/formGen"; - /** - * UTF-8 encoding identifier. - */ - public static final String UTF_8_ENCODING = "UTF-8"; - /** * JSON-LD MIME type. */ public static final String APPLICATION_JSON_LD_TYPE = "application/ld+json"; - /** - * Prefix for basic authentication for the Authorization HTTP header. - */ - public static final String BASIC_AUTHORIZATION_PREFIX = "Basic "; - /** * Number of history actions fetched from database. Needs to be changes also in front-end. */ diff --git a/src/main/java/cz/cvut/kbss/study/util/PasswordGenerator.java b/src/main/java/cz/cvut/kbss/study/util/PasswordGenerator.java deleted file mode 100644 index 0793816a..00000000 --- a/src/main/java/cz/cvut/kbss/study/util/PasswordGenerator.java +++ /dev/null @@ -1,13 +0,0 @@ -package cz.cvut.kbss.study.util; - -import org.apache.commons.lang.RandomStringUtils; - -public class PasswordGenerator { - private static final int PASSWORD_LENGHT = 4; - - private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - - public static String generatePassword() { - return RandomStringUtils.random( PASSWORD_LENGHT, CHARACTERS ); - } -} diff --git a/src/main/java/cz/cvut/kbss/study/util/json/ManageableIgnoreMixin.java b/src/main/java/cz/cvut/kbss/study/util/json/ManageableIgnoreMixin.java new file mode 100644 index 00000000..6837db8b --- /dev/null +++ b/src/main/java/cz/cvut/kbss/study/util/json/ManageableIgnoreMixin.java @@ -0,0 +1,10 @@ +package cz.cvut.kbss.study.util.json; + +import com.fasterxml.jackson.annotation.JsonIgnoreType; + +/** + * Mixin declared to allow ignoring JOPA's Manageable reference to the current UnitOfWork + */ +@JsonIgnoreType +public class ManageableIgnoreMixin { +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 00000000..efe77d59 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +server.servlet.context-path=/record-manager \ No newline at end of file diff --git a/src/main/resources/config.properties b/src/main/resources/config.properties index 851acd6a..c5c10c45 100644 --- a/src/main/resources/config.properties +++ b/src/main/resources/config.properties @@ -25,7 +25,7 @@ smtp.password=AdminOrganization123 email.displayName=Record Manager # if email.from is not entered, smtp.user is used instead email.from= -# Email cc addresses where all invitations will be send. For more use delimiter "," (can remain empty) +# Email cc addresses where all invitations will be sent. For more use delimiter "," (can remain empty) email.replyTo= email.cc= email.bcc= diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 74aea883..997332de 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -31,7 +31,7 @@ - %date{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{30} - %msg%n + %date{dd-MM-yyyy HH:mm:ss.SSS} [%X{username}] [%thread] %-5level %logger{30} - %msg%n @@ -54,7 +54,7 @@ - + diff --git a/src/test/java/cz/cvut/kbss/study/environment/Transaction.java b/src/test/java/cz/cvut/kbss/study/environment/Transaction.java new file mode 100644 index 00000000..2842ac17 --- /dev/null +++ b/src/test/java/cz/cvut/kbss/study/environment/Transaction.java @@ -0,0 +1,55 @@ +/** + * TermIt + * Copyright (C) 2019 Czech Technical University in Prague + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package cz.cvut.kbss.study.environment; + +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +/** + * Utility class for executing operations in transaction. + *

+ * It is required for proper JOPA functionality in tests. The tests cannot function in one transaction like regular + * JPA-based Spring tests, since JOPA is not able to add pending changes to query results. + */ +public class Transaction { + + /** + * Helper method for executing the specified portion of code in a transaction. + *

+ * Since JOPA does not understand SPARQL queries, any method using a query will not be able to see uncommitted + * transactional changes. So the whole test cannot run in a single transaction, as is common in regular Spring + * testing. + *

+ * Instead, we need to perform methods which change the state of the storage in transactions, so that the changes + * are really committed into the storage. + * + * @param txManager Transaction manager to use to run the transactional code + * @param procedure Code to execute + */ + public static void execute(PlatformTransactionManager txManager, Runnable procedure) { + new TransactionTemplate(txManager).execute(new TransactionCallbackWithoutResult() { + + @Override + protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { + procedure.run(); + } + }); + } +} diff --git a/src/test/java/cz/cvut/kbss/study/environment/TransactionalTestRunner.java b/src/test/java/cz/cvut/kbss/study/environment/TransactionalTestRunner.java new file mode 100644 index 00000000..84d3781a --- /dev/null +++ b/src/test/java/cz/cvut/kbss/study/environment/TransactionalTestRunner.java @@ -0,0 +1,31 @@ +/** + * TermIt + * Copyright (C) 2019 Czech Technical University in Prague + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package cz.cvut.kbss.study.environment; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; + +public abstract class TransactionalTestRunner { + + @Autowired + protected PlatformTransactionManager txManager; + + protected void transactional(Runnable procedure) { + Transaction.execute(txManager, procedure); + } +} diff --git a/src/test/java/cz/cvut/kbss/study/environment/config/MockServiceConfig.java b/src/test/java/cz/cvut/kbss/study/environment/config/MockServiceConfig.java index dba0b188..0aaabc93 100644 --- a/src/test/java/cz/cvut/kbss/study/environment/config/MockServiceConfig.java +++ b/src/test/java/cz/cvut/kbss/study/environment/config/MockServiceConfig.java @@ -1,17 +1,22 @@ package cz.cvut.kbss.study.environment.config; import cz.cvut.kbss.study.persistence.dao.ActionHistoryDao; -import cz.cvut.kbss.study.service.*; +import cz.cvut.kbss.study.service.ActionHistoryService; +import cz.cvut.kbss.study.service.ConfigReader; +import cz.cvut.kbss.study.service.InstitutionService; +import cz.cvut.kbss.study.service.PatientRecordService; +import cz.cvut.kbss.study.service.StatisticsService; +import cz.cvut.kbss.study.service.UserService; import cz.cvut.kbss.study.service.security.UserDetailsService; +import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import static org.mockito.Mockito.mock; -@Configuration +@TestConfiguration @ComponentScan(basePackages = "cz.cvut.kbss.study.service") public class MockServiceConfig { diff --git a/src/test/java/cz/cvut/kbss/study/environment/config/PropertyMockingApplicationContextInitializer.java b/src/test/java/cz/cvut/kbss/study/environment/config/PropertyMockingApplicationContextInitializer.java deleted file mode 100644 index 862619b8..00000000 --- a/src/test/java/cz/cvut/kbss/study/environment/config/PropertyMockingApplicationContextInitializer.java +++ /dev/null @@ -1,18 +0,0 @@ -package cz.cvut.kbss.study.environment.config; - -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.mock.env.MockEnvironment; - -/** - * Uses {@link MockEnvironment}, which supports setting environment property values at runtime. - */ -public class PropertyMockingApplicationContextInitializer - implements ApplicationContextInitializer { - - @Override - public void initialize(ConfigurableApplicationContext configurableApplicationContext) { - MockEnvironment mockEnvironment = new MockEnvironment(); - configurableApplicationContext.setEnvironment(mockEnvironment); - } -} diff --git a/src/test/java/cz/cvut/kbss/study/environment/config/TestPersistenceConfig.java b/src/test/java/cz/cvut/kbss/study/environment/config/TestPersistenceConfig.java index cdf2cb79..e90c285a 100644 --- a/src/test/java/cz/cvut/kbss/study/environment/config/TestPersistenceConfig.java +++ b/src/test/java/cz/cvut/kbss/study/environment/config/TestPersistenceConfig.java @@ -1,20 +1,24 @@ package cz.cvut.kbss.study.environment.config; +import cz.cvut.kbss.study.config.PersistenceConfig; import cz.cvut.kbss.study.persistence.TestFormGenPersistenceFactory; import cz.cvut.kbss.study.persistence.TestPersistenceFactory; import cz.cvut.kbss.study.persistence.data.RemoteDataLoader; +import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.Import; +import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.client.RestTemplate; import static org.mockito.Mockito.mock; -@Configuration +@TestConfiguration +@EnableAspectJAutoProxy(proxyTargetClass = true) @ComponentScan(basePackages = {"cz.cvut.kbss.study.persistence.dao"}) -@Import({TestPersistenceFactory.class, - TestFormGenPersistenceFactory.class}) +@Import({PersistenceConfig.class, TestPersistenceFactory.class, TestFormGenPersistenceFactory.class}) +@EnableTransactionManagement public class TestPersistenceConfig { @Bean(name = "remoteDataLoader") diff --git a/src/test/java/cz/cvut/kbss/study/environment/config/TestSecurityConfig.java b/src/test/java/cz/cvut/kbss/study/environment/config/TestSecurityConfig.java index 3aa3e841..27faa650 100644 --- a/src/test/java/cz/cvut/kbss/study/environment/config/TestSecurityConfig.java +++ b/src/test/java/cz/cvut/kbss/study/environment/config/TestSecurityConfig.java @@ -1,9 +1,17 @@ package cz.cvut.kbss.study.environment.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cvut.kbss.study.environment.util.Environment; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -@Configuration +@TestConfiguration @ComponentScan(basePackages = "cz.cvut.kbss.study.security") public class TestSecurityConfig { + + @Bean + public ObjectMapper objectMapper() { + return Environment.getObjectMapper(); + } } diff --git a/src/test/java/cz/cvut/kbss/study/environment/config/TestServiceConfig.java b/src/test/java/cz/cvut/kbss/study/environment/config/TestServiceConfig.java new file mode 100644 index 00000000..5c347a1e --- /dev/null +++ b/src/test/java/cz/cvut/kbss/study/environment/config/TestServiceConfig.java @@ -0,0 +1,17 @@ +package cz.cvut.kbss.study.environment.config; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@TestConfiguration +@ComponentScan(basePackages = "cz.cvut.kbss.study.service") +public class TestServiceConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/src/test/java/cz/cvut/kbss/study/environment/util/Environment.java b/src/test/java/cz/cvut/kbss/study/environment/util/Environment.java index 11c8516b..5e167e93 100644 --- a/src/test/java/cz/cvut/kbss/study/environment/util/Environment.java +++ b/src/test/java/cz/cvut/kbss/study/environment/util/Environment.java @@ -1,12 +1,10 @@ package cz.cvut.kbss.study.environment.util; -import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cvut.kbss.study.config.WebAppConfig; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.security.model.AuthenticationToken; import cz.cvut.kbss.study.security.model.UserDetails; -import cz.cvut.kbss.study.util.Constants; -import java.nio.charset.Charset; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.ResourceHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; @@ -15,6 +13,8 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextImpl; +import java.nio.charset.StandardCharsets; + public class Environment { private static User currentUser; @@ -54,8 +54,7 @@ public static User getCurrentUser() { */ public static ObjectMapper getObjectMapper() { if (objectMapper == null) { - objectMapper = new ObjectMapper(); - objectMapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true); + objectMapper = WebAppConfig.createJsonObjectMapper(); } return objectMapper; } @@ -65,7 +64,7 @@ public static HttpMessageConverter createDefaultMessageConverter() { } public static HttpMessageConverter createStringEncodingMessageConverter() { - return new StringHttpMessageConverter(Charset.forName(Constants.UTF_8_ENCODING)); + return new StringHttpMessageConverter(StandardCharsets.UTF_8); } public static HttpMessageConverter createResourceMessageConverter() { diff --git a/src/test/java/cz/cvut/kbss/study/model/UserTest.java b/src/test/java/cz/cvut/kbss/study/model/UserTest.java index fa0102f5..759cfce6 100644 --- a/src/test/java/cz/cvut/kbss/study/model/UserTest.java +++ b/src/test/java/cz/cvut/kbss/study/model/UserTest.java @@ -1,23 +1,22 @@ package cz.cvut.kbss.study.model; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.springframework.security.crypto.password.StandardPasswordEncoder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import java.net.URI; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class UserTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - private User user; - @Before + @BeforeEach public void setUp() { this.user = new User(); } @@ -29,15 +28,14 @@ public void newInstanceHasAgentInTypes() { @Test public void encodePasswordThrowsIllegalStateForNullPassword() { - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Cannot encode an empty password."); - user.encodePassword(new StandardPasswordEncoder()); + final IllegalStateException ex = assertThrows(IllegalStateException.class, () -> user.encodePassword(new BCryptPasswordEncoder())); + assertEquals("Cannot encode an empty password.", ex.getMessage()); } @Test public void encodePasswordChangesPassword() { user.setPassword("password"); - user.encodePassword(new StandardPasswordEncoder()); + user.encodePassword(new BCryptPasswordEncoder()); assertFalse(user.getPassword().contains("password")); } @@ -54,36 +52,32 @@ public void generateUriCreatesUriFromFirstNameAndLastName() { @Test public void generateUriThrowsIllegalStateForMissingFirstName() { - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Cannot generate Person URI without first name."); user.setLastName("b"); - user.generateUri(); + final IllegalStateException ex = assertThrows(IllegalStateException.class, () -> user.generateUri()); + assertEquals("Cannot generate Person URI without first name.", ex.getMessage()); } @Test public void generateUriThrowsIllegalStateForEmptyFirstName() { - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Cannot generate Person URI without first name."); user.setFirstName(""); user.setLastName("b"); - user.generateUri(); + final IllegalStateException ex = assertThrows(IllegalStateException.class, () -> user.generateUri()); + assertEquals("Cannot generate Person URI without first name.", ex.getMessage()); } @Test public void generateUriThrowsIllegalStateForMissingLastName() { - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Cannot generate Person URI without last name."); user.setFirstName("John"); - user.generateUri(); + final IllegalStateException ex = assertThrows(IllegalStateException.class, () -> user.generateUri()); + assertEquals("Cannot generate Person URI without last name.", ex.getMessage()); } @Test public void generateUriThrowsIllegalStateForEmptyLastName() { - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Cannot generate Person URI without last name."); user.setFirstName("John"); user.setLastName(""); - user.generateUri(); + final IllegalStateException ex = assertThrows(IllegalStateException.class, () -> user.generateUri()); + assertEquals("Cannot generate Person URI without last name.", ex.getMessage()); } @Test @@ -95,7 +89,7 @@ public void generateUriDoesNothingIfTheUriIsAlreadySet() { } @Test - public void generateUriEncodesUsersWithComplexName() throws Exception { + public void generateUriEncodesUsersWithComplexName() { User user = new User(); user.setFirstName("Mike John"); @@ -109,7 +103,7 @@ public void generateUriEncodesUsersWithComplexName() throws Exception { } @Test - public void newUserHasRoleDoctor() throws Exception { + public void newUserHasRoleDoctor() { User user = new User(); assertTrue(user.getTypes().toString().contains(Vocabulary.s_c_doctor)); } diff --git a/src/test/java/cz/cvut/kbss/study/model/qam/AnswerTest.java b/src/test/java/cz/cvut/kbss/study/model/qam/AnswerTest.java index 709514cd..fff4d364 100644 --- a/src/test/java/cz/cvut/kbss/study/model/qam/AnswerTest.java +++ b/src/test/java/cz/cvut/kbss/study/model/qam/AnswerTest.java @@ -2,10 +2,10 @@ import cz.cvut.kbss.study.environment.generator.Generator; import cz.cvut.kbss.study.model.Vocabulary; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class AnswerTest { diff --git a/src/test/java/cz/cvut/kbss/study/model/qam/QuestionTest.java b/src/test/java/cz/cvut/kbss/study/model/qam/QuestionTest.java index f1901ed8..7980c937 100644 --- a/src/test/java/cz/cvut/kbss/study/model/qam/QuestionTest.java +++ b/src/test/java/cz/cvut/kbss/study/model/qam/QuestionTest.java @@ -2,10 +2,10 @@ import cz.cvut.kbss.study.environment.generator.Generator; import cz.cvut.kbss.study.model.Vocabulary; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class QuestionTest { diff --git a/src/test/java/cz/cvut/kbss/study/model/util/EntityToOwlClassMapperTest.java b/src/test/java/cz/cvut/kbss/study/model/util/EntityToOwlClassMapperTest.java index 7a5080c7..ae8874bb 100644 --- a/src/test/java/cz/cvut/kbss/study/model/util/EntityToOwlClassMapperTest.java +++ b/src/test/java/cz/cvut/kbss/study/model/util/EntityToOwlClassMapperTest.java @@ -2,9 +2,10 @@ import cz.cvut.kbss.study.model.PatientRecord; import cz.cvut.kbss.study.model.Vocabulary; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class EntityToOwlClassMapperTest { @@ -13,8 +14,8 @@ public void getOWlClassForEntityExtractsOwlClassIriFromEntityClass() { assertEquals(Vocabulary.s_c_patient_record, EntityToOwlClassMapper.getOwlClassForEntity(PatientRecord.class)); } - @Test(expected = IllegalArgumentException.class) + @Test public void getOwlClassForEntityThrowsIllegalArgumentForNonEntity() { - EntityToOwlClassMapper.getOwlClassForEntity(Object.class); + assertThrows(IllegalArgumentException.class, () -> EntityToOwlClassMapper.getOwlClassForEntity(Object.class)); } } \ No newline at end of file diff --git a/src/test/java/cz/cvut/kbss/study/persistence/BaseDaoTestRunner.java b/src/test/java/cz/cvut/kbss/study/persistence/BaseDaoTestRunner.java index 8c2e9ccd..2edd1a47 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/BaseDaoTestRunner.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/BaseDaoTestRunner.java @@ -1,13 +1,16 @@ package cz.cvut.kbss.study.persistence; +import cz.cvut.kbss.study.environment.TransactionalTestRunner; import cz.cvut.kbss.study.environment.config.TestPersistenceConfig; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringJUnit4ClassRunner.class) +@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = {TestPersistenceConfig.class}) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) -abstract public class BaseDaoTestRunner { +@ActiveProfiles("test") +abstract public class BaseDaoTestRunner extends TransactionalTestRunner { } diff --git a/src/test/java/cz/cvut/kbss/study/persistence/TestFormGenPersistenceFactory.java b/src/test/java/cz/cvut/kbss/study/persistence/TestFormGenPersistenceFactory.java index 0c4b485a..c400b9c4 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/TestFormGenPersistenceFactory.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/TestFormGenPersistenceFactory.java @@ -5,20 +5,23 @@ import cz.cvut.kbss.jopa.model.JOPAPersistenceProperties; import cz.cvut.kbss.study.util.ConfigParam; import java.util.Map; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; @Configuration @PropertySource("classpath:config.properties") +@Profile("test") public class TestFormGenPersistenceFactory { - private static final String URL_PROPERTY = "test." + ConfigParam.FORM_GEN_REPOSITORY_URL.toString(); - private static final String DRIVER_PROPERTY = "test." + ConfigParam.DRIVER.toString(); + private static final String URL_PROPERTY = "test." + ConfigParam.FORM_GEN_REPOSITORY_URL; + private static final String DRIVER_PROPERTY = "test." + ConfigParam.DRIVER; @Autowired private Environment environment; diff --git a/src/test/java/cz/cvut/kbss/study/persistence/TestPersistenceFactory.java b/src/test/java/cz/cvut/kbss/study/persistence/TestPersistenceFactory.java index f5e1a62d..a8edbae9 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/TestPersistenceFactory.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/TestPersistenceFactory.java @@ -4,29 +4,32 @@ import cz.cvut.kbss.jopa.model.EntityManagerFactory; import cz.cvut.kbss.jopa.model.JOPAPersistenceProperties; import cz.cvut.kbss.jopa.model.JOPAPersistenceProvider; -import cz.cvut.kbss.ontodriver.config.OntoDriverProperties; -import static cz.cvut.kbss.ontodriver.config.OntoDriverProperties.DATA_SOURCE_PASSWORD; -import static cz.cvut.kbss.ontodriver.config.OntoDriverProperties.DATA_SOURCE_USERNAME; import cz.cvut.kbss.ontodriver.rdf4j.config.Rdf4jOntoDriverProperties; import cz.cvut.kbss.study.util.ConfigParam; import cz.cvut.kbss.study.util.Constants; -import java.util.HashMap; -import java.util.Map; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; +import java.util.HashMap; +import java.util.Map; + +import static cz.cvut.kbss.ontodriver.config.OntoDriverProperties.DATA_SOURCE_PASSWORD; +import static cz.cvut.kbss.ontodriver.config.OntoDriverProperties.DATA_SOURCE_USERNAME; + @Configuration @PropertySource("classpath:config.properties") +@Profile("test") public class TestPersistenceFactory { private static final String URL_PROPERTY = "test." + ConfigParam.REPOSITORY_URL; - private static final String DRIVER_PROPERTY = "test." + ConfigParam.DRIVER.toString(); + private static final String DRIVER_PROPERTY = "test." + ConfigParam.DRIVER; private static final String USERNAME_PROPERTY = "test.username"; private static final String PASSWORD_PROPERTY = "test.password"; @@ -62,7 +65,7 @@ private void close() { static Map getDefaultProperties() { final Map properties = new HashMap<>(); - properties.put(OntoDriverProperties.ONTOLOGY_LANGUAGE, Constants.PU_LANGUAGE); + properties.put(JOPAPersistenceProperties.LANG, Constants.PU_LANGUAGE); properties.put(JOPAPersistenceProperties.SCAN_PACKAGE, "cz.cvut.kbss.study"); properties.put(Rdf4jOntoDriverProperties.USE_VOLATILE_STORAGE, Boolean.TRUE.toString()); properties.put(Rdf4jOntoDriverProperties.USE_INFERENCE, Boolean.FALSE.toString()); diff --git a/src/test/java/cz/cvut/kbss/study/persistence/dao/ActionHistoryDaoTest.java b/src/test/java/cz/cvut/kbss/study/persistence/dao/ActionHistoryDaoTest.java index 3aa49d8c..db39b0e7 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/dao/ActionHistoryDaoTest.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/dao/ActionHistoryDaoTest.java @@ -5,13 +5,13 @@ import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.persistence.BaseDaoTestRunner; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; -import static junit.framework.TestCase.assertEquals; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class ActionHistoryDaoTest extends BaseDaoTestRunner { @@ -29,38 +29,37 @@ public class ActionHistoryDaoTest extends BaseDaoTestRunner { private final String LOAD_PENDING = "LOAD_PENDING"; @Test - public void findByKeyReturnsActionWithPayload() throws Exception { + public void findByKeyReturnsActionWithPayload() { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - User user = Generator.generateUser(institution); - userDao.persist(user); - ActionHistory action = Generator.generateActionHistory(user); - actionHistoryDao.persist(action); - action = actionHistoryDao.findByKey(action.getKey()); + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(user); + actionHistoryDao.persist(action); + }); - assertNotNull(action); - assertNotNull(action.getPayload()); + final ActionHistory result = actionHistoryDao.findByKey(action.getKey()); + + assertNotNull(result); + assertNotNull(result.getPayload()); } @Test - public void findAllWithParamsWithoutParamsReturnsAllActions() throws Exception { + public void findAllWithParamsWithoutParamsReturnsAllActions() { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - User user1 = Generator.generateUser(institution); - userDao.persist(user1); User user2 = Generator.generateUser(institution); - userDao.persist(user2); - ActionHistory action1 = Generator.generateActionHistory(user1); ActionHistory action2 = Generator.generateActionHistory(user1); ActionHistory action3 = Generator.generateActionHistory(user2); - actionHistoryDao.persist(action1); - actionHistoryDao.persist(action2); - actionHistoryDao.persist(action3); + + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(List.of(user1, user2)); + actionHistoryDao.persist(List.of(action1, action2, action3)); + }); List actionsList = actionHistoryDao.findAllWithParams(null, null, 1); @@ -68,23 +67,20 @@ public void findAllWithParamsWithoutParamsReturnsAllActions() throws Exception { } @Test - public void findAllWithParamsWithAuthorReturnsAuthorsActions() throws Exception { + public void findAllWithParamsWithAuthorReturnsAuthorsActions() { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - User user1 = Generator.generateUser(institution); - userDao.persist(user1); User user2 = Generator.generateUser(institution); - userDao.persist(user2); User user3 = Generator.generateUser(institution); - userDao.persist(user3); - ActionHistory action1 = Generator.generateActionHistory(user1); ActionHistory action2 = Generator.generateActionHistory(user1); ActionHistory action3 = Generator.generateActionHistory(user2); - actionHistoryDao.persist(action1); - actionHistoryDao.persist(action2); - actionHistoryDao.persist(action3); + + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(List.of(user1, user2, user3)); + actionHistoryDao.persist(List.of(action1, action2, action3)); + }); List actionsList1 = actionHistoryDao.findAllWithParams(null, user1, 1); List actionsList2 = actionHistoryDao.findAllWithParams(null, user2, 1); @@ -96,22 +92,21 @@ public void findAllWithParamsWithAuthorReturnsAuthorsActions() throws Exception } @Test - public void findAllWithParamsWithTypeReturnsActionsWithExactType() throws Exception { + public void findAllWithParamsWithTypeReturnsActionsWithExactType() { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - User user = Generator.generateUser(institution); - userDao.persist(user); - ActionHistory action1 = Generator.generateActionHistory(user); action1.setType(LOAD_SUCCESS); ActionHistory action2 = Generator.generateActionHistory(user); action2.setType(LOAD_SUCCESS); ActionHistory action3 = Generator.generateActionHistory(user); action3.setType(LOAD_ERROR); - actionHistoryDao.persist(action1); - actionHistoryDao.persist(action2); - actionHistoryDao.persist(action3); + + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(user); + actionHistoryDao.persist(List.of(action1, action2, action3)); + }); List actionsList1 = actionHistoryDao.findAllWithParams(LOAD_SUCCESS, null, 1); List actionsList2 = actionHistoryDao.findAllWithParams(LOAD_ERROR, null, 1); @@ -123,22 +118,20 @@ public void findAllWithParamsWithTypeReturnsActionsWithExactType() throws Except } @Test - public void findAllWithParamsWithTypeReturnsActionsWithTypeContained() throws Exception { + public void findAllWithParamsWithTypeReturnsActionsWithTypeContained() { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - User user = Generator.generateUser(institution); - userDao.persist(user); - ActionHistory action1 = Generator.generateActionHistory(user); action1.setType(LOAD_SUCCESS); ActionHistory action2 = Generator.generateActionHistory(user); action2.setType(LOAD_SUCCESS); ActionHistory action3 = Generator.generateActionHistory(user); - actionHistoryDao.persist(action1); - actionHistoryDao.persist(action2); - actionHistoryDao.persist(action3); + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(user); + actionHistoryDao.persist(List.of(action1, action2, action3)); + }); List actionsList = actionHistoryDao.findAllWithParams("LOAD", null, 1); @@ -146,15 +139,10 @@ public void findAllWithParamsWithTypeReturnsActionsWithTypeContained() throws Ex } @Test - public void findAllWithParamsReturnsMatchingActions() throws Exception { + public void findAllWithParamsReturnsMatchingActions() { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - User user1 = Generator.generateUser(institution); - userDao.persist(user1); User user2 = Generator.generateUser(institution); - userDao.persist(user2); - ActionHistory action1 = Generator.generateActionHistory(user1); action1.setType(LOAD_SUCCESS); ActionHistory action2 = Generator.generateActionHistory(user1); @@ -162,9 +150,11 @@ public void findAllWithParamsReturnsMatchingActions() throws Exception { ActionHistory action3 = Generator.generateActionHistory(user2); action3.setType(LOAD_ERROR); - actionHistoryDao.persist(action1); - actionHistoryDao.persist(action2); - actionHistoryDao.persist(action3); + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(List.of(user1, user2)); + actionHistoryDao.persist(List.of(action1, action2, action3)); + }); List actionsList1 = actionHistoryDao.findAllWithParams(LOAD_SUCCESS, user1, 1); List actionsList2 = actionHistoryDao.findAllWithParams(LOAD_SUCCESS, user2, 1); diff --git a/src/test/java/cz/cvut/kbss/study/persistence/dao/BaseDaoTest.java b/src/test/java/cz/cvut/kbss/study/persistence/dao/BaseDaoTest.java index 4aec48c6..c5dee144 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/dao/BaseDaoTest.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/dao/BaseDaoTest.java @@ -3,13 +3,15 @@ import cz.cvut.kbss.study.environment.generator.Generator; import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.persistence.BaseDaoTestRunner; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; public class BaseDaoTest extends BaseDaoTestRunner{ @@ -23,7 +25,7 @@ public void findAllReturnsAllExistingInstances() { institutions.add(i1); final Institution i2 = Generator.generateInstitution(); institutions.add(i2); - institutionDao.persist(institutions); + transactional(() -> institutionDao.persist(institutions)); final List result = institutionDao.findAll(); assertEquals(institutions.size(), result.size()); @@ -34,14 +36,14 @@ public void findAllReturnsAllExistingInstances() { } @Test - public void removeInstitution() throws Exception { + public void removeInstitution() { final Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); + transactional(() -> institutionDao.persist(institution)); Institution i1 = institutionDao.findByName(institution.getName()); assertNotNull(i1); - institutionDao.remove(i1); + transactional(() -> institutionDao.remove(i1)); Institution i2 = institutionDao.findByName(institution.getName()); assertNull(i2); } @@ -54,25 +56,25 @@ public void removeListOfInstitutions() { institutions.add(i1); final Institution i2 = Generator.generateInstitution(); institutions.add(i2); - institutionDao.persist(institutions); + transactional(() -> institutionDao.persist(institutions)); final List foundInstitutions = institutionDao.findAll(); assertEquals(institutions.size(), foundInstitutions.size()); - institutionDao.remove(institutions); + transactional(() -> institutionDao.remove(institutions)); final List result = institutionDao.findAll(); assertEquals(0, result.size()); } @Test - public void updateInstitution() throws Exception { + public void updateInstitution() { final Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); + transactional(() -> institutionDao.persist(institution)); Institution i1 = institutionDao.findByName(institution.getName()); assertNotNull(i1); i1.setName("Random Gynecology"); - institutionDao.update(i1); + transactional(() -> institutionDao.update(i1)); Institution i2 = institutionDao.findByName(i1.getName()); assertEquals(institution.getUri(),i2.getUri()); diff --git a/src/test/java/cz/cvut/kbss/study/persistence/dao/DerivableUriDaoTest.java b/src/test/java/cz/cvut/kbss/study/persistence/dao/DerivableUriDaoTest.java index f4fa5e8f..e191e2de 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/dao/DerivableUriDaoTest.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/dao/DerivableUriDaoTest.java @@ -4,10 +4,10 @@ import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.persistence.BaseDaoTestRunner; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class DerivableUriDaoTest extends BaseDaoTestRunner { @@ -20,12 +20,14 @@ public class DerivableUriDaoTest extends BaseDaoTestRunner { @Test public void persistedInstanceHasGeneratedUri(){ final Institution institution = Generator.generateInstitution(); - User user = Generator.generateUser(institution); + final User user = Generator.generateUser(institution); - institutionDao.persist(institution); - userDao.persist(user); + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(user); + }); - user = userDao.findByUsername(user.getUsername()); - assertNotNull(user.getUri()); + final User result = userDao.findByUsername(user.getUsername()); + assertNotNull(result.getUri()); } } diff --git a/src/test/java/cz/cvut/kbss/study/persistence/dao/InstitutionDaoTest.java b/src/test/java/cz/cvut/kbss/study/persistence/dao/InstitutionDaoTest.java index 1bafc1f9..ab0faa92 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/dao/InstitutionDaoTest.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/dao/InstitutionDaoTest.java @@ -3,25 +3,25 @@ import cz.cvut.kbss.study.environment.generator.Generator; import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.persistence.BaseDaoTestRunner; - -import java.util.UUID; -import static junit.framework.TestCase.assertEquals; - -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class InstitutionDaoTest extends BaseDaoTestRunner { @Autowired private InstitutionDao institutionDao; @Test - public void getInstitutionByName() throws Exception { + public void getInstitutionByName() { Institution institution1 = Generator.generateInstitution(); Institution institution2 = Generator.generateInstitution(); - institutionDao.persist(institution1); - institutionDao.persist(institution2); + transactional(() -> { + institutionDao.persist(institution1); + institutionDao.persist(institution2); + }); assertEquals(institution1.getUri(), institutionDao.findByName(institution1.getName()).getUri()); } diff --git a/src/test/java/cz/cvut/kbss/study/persistence/dao/OwlKeySupportingDaoTest.java b/src/test/java/cz/cvut/kbss/study/persistence/dao/OwlKeySupportingDaoTest.java index f206f090..fb2aab5f 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/dao/OwlKeySupportingDaoTest.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/dao/OwlKeySupportingDaoTest.java @@ -3,10 +3,10 @@ import cz.cvut.kbss.study.environment.generator.Generator; import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.persistence.BaseDaoTestRunner; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class OwlKeySupportingDaoTest extends BaseDaoTestRunner { @Autowired @@ -15,14 +15,14 @@ public class OwlKeySupportingDaoTest extends BaseDaoTestRunner { @Test public void persistedInstanceHasGeneratedKey() { final Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); + transactional(() -> institutionDao.persist(institution)); assertNotNull(institution.getKey()); } @Test public void getInstitutionByKey() { final Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); + transactional(() -> institutionDao.persist(institution)); assertNotNull(institutionDao.findByKey(institution.getKey())); } diff --git a/src/test/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDaoTest.java b/src/test/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDaoTest.java index 81445850..625d851e 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDaoTest.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDaoTest.java @@ -7,16 +7,16 @@ import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.persistence.BaseDaoTestRunner; import java.util.List; -import java.util.UUID; -import static junit.framework.TestCase.assertEquals; -import org.junit.Ignore; -import org.junit.Test; + +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class PatientRecordDaoTest extends BaseDaoTestRunner { @Autowired - private PatientRecordDao patienRecordDao; + private PatientRecordDao patientRecordDao; @Autowired private UserDao userDao; @@ -25,28 +25,26 @@ public class PatientRecordDaoTest extends BaseDaoTestRunner { private InstitutionDao institutionDao; @Test - public void findByInstitutionReturnsMatchingRecords() throws Exception { + public void findByInstitutionReturnsMatchingRecords() { Institution institution = Generator.generateInstitution(); Institution institutionOther = Generator.generateInstitution(); - institutionDao.persist(institution); - institutionDao.persist(institutionOther); - User user1 = Generator.generateUser(institution); - userDao.persist(user1); - user1 = userDao.findByUsername(user1.getUsername()); User user2 = Generator.generateUser(institutionOther); - userDao.persist(user2); - user2 = userDao.findByUsername(user2.getUsername()); - PatientRecord record1 = Generator.generatePatientRecord(user1); PatientRecord record2 = Generator.generatePatientRecord(user1); PatientRecord recordOther = Generator.generatePatientRecord(user2); - patienRecordDao.persist(record1); - patienRecordDao.persist(record2); - patienRecordDao.persist(recordOther); + transactional(() -> { + institutionDao.persist(institution); + institutionDao.persist(institutionOther); + userDao.persist(user1); + userDao.persist(user2); + patientRecordDao.persist(record1); + patientRecordDao.persist(record2); + patientRecordDao.persist(recordOther); + }); - List records = patienRecordDao.findByInstitution(institution); + List records = patientRecordDao.findByInstitution(institution); assertEquals(2, records.size()); assertEquals(1, records.stream().filter(rs -> record1.getUri().equals(rs.getUri())).count()); @@ -54,74 +52,68 @@ public void findByInstitutionReturnsMatchingRecords() throws Exception { } @Test - public void findAllRecordsReturnAllRecords() throws Exception { + public void findAllRecordsReturnAllRecords() { Institution institution1 = Generator.generateInstitution(); Institution institution2 = Generator.generateInstitution(); - institutionDao.persist(institution1); - institutionDao.persist(institution2); - User user1 = Generator.generateUser(institution1); User user2 = Generator.generateUser(institution2); - userDao.persist(user1); - userDao.persist(user2); - user1 = userDao.findByUsername(user1.getUsername()); - user2 = userDao.findByUsername(user2.getUsername()); - PatientRecord record1 = Generator.generatePatientRecord(user1); PatientRecord record2 = Generator.generatePatientRecord(user1); PatientRecord record3 = Generator.generatePatientRecord(user2); - patienRecordDao.persist(record1); - patienRecordDao.persist(record2); - patienRecordDao.persist(record3); + transactional(() -> { + institutionDao.persist(institution1); + institutionDao.persist(institution2); + userDao.persist(user1); + userDao.persist(user2); + patientRecordDao.persist(record1); + patientRecordDao.persist(record2); + patientRecordDao.persist(record3); + }); - List records = patienRecordDao.findAllRecords(); + List records = patientRecordDao.findAllRecords(); assertEquals(3, records.size()); } @Test - public void getNumberOfProcessedRecords() throws Exception { + public void getNumberOfProcessedRecords() { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - User user = Generator.generateUser(institution); - userDao.persist(user); - user = userDao.findByUsername(user.getUsername()); - PatientRecord record1 = Generator.generatePatientRecord(user); PatientRecord record2 = Generator.generatePatientRecord(user); + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(user); + patientRecordDao.persist(record1); + patientRecordDao.persist(record2); + }); - patienRecordDao.persist(record1); - patienRecordDao.persist(record2); - - int numberOfProcessedRecords = patienRecordDao.getNumberOfProcessedRecords(); + int numberOfProcessedRecords = patientRecordDao.getNumberOfProcessedRecords(); assertEquals(2, numberOfProcessedRecords); } @Test - public void findByAuthorReturnsMatchingRecords() throws Exception { + public void findByAuthorReturnsMatchingRecords() { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - User user1 = Generator.generateUser(institution); User user2 = Generator.generateUser(institution); - userDao.persist(user1); - userDao.persist(user2); - user1 = userDao.findByUsername(user1.getUsername()); - user2 = userDao.findByUsername(user2.getUsername()); - PatientRecord record1 = Generator.generatePatientRecord(user1); PatientRecord record2 = Generator.generatePatientRecord(user1); PatientRecord record3 = Generator.generatePatientRecord(user2); - patienRecordDao.persist(record1); - patienRecordDao.persist(record2); - patienRecordDao.persist(record3); - - List records1 = patienRecordDao.findByAuthor(user1); - List records2 = patienRecordDao.findByAuthor(user2); + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(user1); + userDao.persist(user2); + patientRecordDao.persist(record1); + patientRecordDao.persist(record2); + patientRecordDao.persist(record3); + }); + + List records1 = patientRecordDao.findByAuthor(user1); + List records2 = patientRecordDao.findByAuthor(user2); assertEquals(2, records1.size()); assertEquals(1, records2.size()); diff --git a/src/test/java/cz/cvut/kbss/study/persistence/dao/UserDaoTest.java b/src/test/java/cz/cvut/kbss/study/persistence/dao/UserDaoTest.java index 79aa222e..5395b647 100644 --- a/src/test/java/cz/cvut/kbss/study/persistence/dao/UserDaoTest.java +++ b/src/test/java/cz/cvut/kbss/study/persistence/dao/UserDaoTest.java @@ -5,14 +5,17 @@ import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.model.Vocabulary; import cz.cvut.kbss.study.persistence.BaseDaoTestRunner; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import static org.junit.Assert.*; import java.util.HashSet; import java.util.List; import java.util.Set; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + public class UserDaoTest extends BaseDaoTestRunner { @Autowired @@ -70,18 +73,18 @@ public void getUserByEmailWithNonExistingEmailReturnsNull() { @Test public void getUsersByToken() { Institution institution = Generator.generateInstitution(); - - institutionDao.persist(institution); - User user = Generator.generateUser(institution); user.setToken("Token"); - userDao.persist(user); + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(user); + }); - user = userDao.findByToken("Token"); + final User result = userDao.findByToken("Token"); User userNull = userDao.findByUsername("NotExistingToken"); - assertNotNull(user); + assertNotNull(result); assertNull(userNull); } @@ -89,15 +92,15 @@ public void getUsersByToken() { public void getUsersByInstitution() { Institution institution1 = Generator.generateInstitution(); Institution institution2 = Generator.generateInstitution(); - - institutionDao.persist(institution1); - institutionDao.persist(institution2); - User user1 = Generator.generateUser(institution1); User user2 = Generator.generateUser(institution1); - userDao.persist(user1); - userDao.persist(user2); + transactional(() -> { + institutionDao.persist(institution1); + institutionDao.persist(institution2); + userDao.persist(user1); + userDao.persist(user2); + }); List usersList = userDao.findByInstitution(institution1); List emptyList = userDao.findByInstitution(institution2); @@ -105,7 +108,7 @@ public void getUsersByInstitution() { assertEquals(2, usersList.size()); assertEquals(0, emptyList.size()); - userDao.remove(user1); + transactional(() -> userDao.remove(user1)); usersList = userDao.findByInstitution(institution1); assertEquals(1, usersList.size()); @@ -114,9 +117,6 @@ public void getUsersByInstitution() { @Test public void getNumberOfInvestigators() { Institution institution = Generator.generateInstitution(); - - institutionDao.persist(institution); - User user1 = Generator.generateUser(institution); User user2 = Generator.generateUser(institution); User user3 = Generator.generateUser(institution); @@ -127,9 +127,10 @@ public void getNumberOfInvestigators() { user3.setTypes(types); - userDao.persist(user1); - userDao.persist(user2); - userDao.persist(user3); + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(List.of(user1, user2, user3)); + }); int numberOfInvestigators = userDao.getNumberOfInvestigators(); @@ -139,10 +140,11 @@ public void getNumberOfInvestigators() { private User getPersistedUser() { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - User user = Generator.generateUser(institution); - userDao.persist(user); + transactional(() -> { + institutionDao.persist(institution); + userDao.persist(user); + }); return user; } diff --git a/src/test/java/cz/cvut/kbss/study/rest/ActionHistoryControllerTest.java b/src/test/java/cz/cvut/kbss/study/rest/ActionHistoryControllerTest.java index f1d979f2..393a0ded 100644 --- a/src/test/java/cz/cvut/kbss/study/rest/ActionHistoryControllerTest.java +++ b/src/test/java/cz/cvut/kbss/study/rest/ActionHistoryControllerTest.java @@ -7,17 +7,14 @@ import cz.cvut.kbss.study.model.ActionHistory; import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.User; -import static org.junit.Assert.*; - import cz.cvut.kbss.study.service.ActionHistoryService; import cz.cvut.kbss.study.service.UserService; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MvcResult; @@ -26,9 +23,14 @@ import java.util.Collections; import java.util.List; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; - +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +@ExtendWith(MockitoExtension.class) public class ActionHistoryControllerTest extends BaseControllerTestRunner { @Mock @@ -40,9 +42,8 @@ public class ActionHistoryControllerTest extends BaseControllerTestRunner { @InjectMocks private ActionHistoryController controller; - @Before + @BeforeEach public void setUp() { - MockitoAnnotations.initMocks(this); super.setUp(controller); Institution institution = Generator.generateInstitution(); User user = Generator.generateUser(institution); @@ -117,9 +118,8 @@ public void getActionsReturnsAllActions() throws Exception { } @Test - public void getActionsByAuthorReturnsEmptyList() throws Exception { + public void getActionsByUnknownAuthorReturnsEmptyList() throws Exception { String username = "Tom"; - when(actionHistoryServiceMock.findAllWithParams(null, null, 1)).thenReturn(Collections.emptyList()); when(userServiceMock.findByUsername(username)).thenThrow(NotFoundException.create("User", username)); final MvcResult result = mockMvc.perform(get("/history/") diff --git a/src/test/java/cz/cvut/kbss/study/rest/BaseControllerTestRunner.java b/src/test/java/cz/cvut/kbss/study/rest/BaseControllerTestRunner.java index 976dde6f..640d26d0 100644 --- a/src/test/java/cz/cvut/kbss/study/rest/BaseControllerTestRunner.java +++ b/src/test/java/cz/cvut/kbss/study/rest/BaseControllerTestRunner.java @@ -3,16 +3,16 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import cz.cvut.kbss.study.environment.util.Environment; -import static cz.cvut.kbss.study.environment.util.Environment.createDefaultMessageConverter; -import static cz.cvut.kbss.study.environment.util.Environment.createResourceMessageConverter; -import static cz.cvut.kbss.study.environment.util.Environment.createStringEncodingMessageConverter; import cz.cvut.kbss.study.rest.handler.RestExceptionHandler; import org.springframework.http.HttpHeaders; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import static org.junit.Assert.assertEquals; +import static cz.cvut.kbss.study.environment.util.Environment.createDefaultMessageConverter; +import static cz.cvut.kbss.study.environment.util.Environment.createResourceMessageConverter; +import static cz.cvut.kbss.study.environment.util.Environment.createStringEncodingMessageConverter; +import static org.junit.jupiter.api.Assertions.assertEquals; public abstract class BaseControllerTestRunner { @@ -26,7 +26,6 @@ public void setUp(BaseController controller) { .setMessageConverters( createDefaultMessageConverter(), createStringEncodingMessageConverter(), createResourceMessageConverter()) - .setUseSuffixPatternMatch(false) .build(); } diff --git a/src/test/java/cz/cvut/kbss/study/rest/InstitutionControllerTest.java b/src/test/java/cz/cvut/kbss/study/rest/InstitutionControllerTest.java index 0a3d03c6..57db1670 100644 --- a/src/test/java/cz/cvut/kbss/study/rest/InstitutionControllerTest.java +++ b/src/test/java/cz/cvut/kbss/study/rest/InstitutionControllerTest.java @@ -6,18 +6,14 @@ import cz.cvut.kbss.study.environment.util.Environment; import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.User; -import static org.junit.Assert.*; - import cz.cvut.kbss.study.service.InstitutionService; import cz.cvut.kbss.study.service.PatientRecordService; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MvcResult; @@ -26,9 +22,16 @@ import java.util.Collections; import java.util.List; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; - +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +@ExtendWith(MockitoExtension.class) public class InstitutionControllerTest extends BaseControllerTestRunner { @Mock private InstitutionService institutionServiceMock; @@ -39,9 +42,8 @@ public class InstitutionControllerTest extends BaseControllerTestRunner { @InjectMocks private InstitutionController controller; - @Before + @BeforeEach public void setUp() { - MockitoAnnotations.initMocks(this); super.setUp(controller); Institution institution = Generator.generateInstitution(); User user = Generator.generateUser(institution); @@ -167,14 +169,12 @@ public void updateInstitutionReturnsResponseStatusNoContent() throws Exception { } @Test - public void updateInstitutionReturnsResponseStatusBadRequest() throws Exception { + public void updateInstitutionWithNonMatchingKeyReturnsResponseStatusBadRequest() throws Exception { final String key = "12345"; Institution institution = Generator.generateInstitution(); institution.setKey(key); - when(institutionServiceMock.findByKey(key)).thenReturn(institution); - final MvcResult result = mockMvc.perform(put("/institutions/123456" ).content(toJson(institution)) .contentType(MediaType.APPLICATION_JSON_VALUE)).andReturn(); diff --git a/src/test/java/cz/cvut/kbss/study/rest/PatientRecordControllerTest.java b/src/test/java/cz/cvut/kbss/study/rest/PatientRecordControllerTest.java index 4b2a1a91..88806edc 100644 --- a/src/test/java/cz/cvut/kbss/study/rest/PatientRecordControllerTest.java +++ b/src/test/java/cz/cvut/kbss/study/rest/PatientRecordControllerTest.java @@ -9,14 +9,18 @@ import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.service.InstitutionService; import cz.cvut.kbss.study.service.PatientRecordService; -import static org.junit.Assert.*; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.mockito.MockitoAnnotations; + +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MvcResult; @@ -27,7 +31,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; - +@ExtendWith(MockitoExtension.class) public class PatientRecordControllerTest extends BaseControllerTestRunner { @Mock @@ -39,9 +43,8 @@ public class PatientRecordControllerTest extends BaseControllerTestRunner { @InjectMocks private PatientRecordController controller; - @Before + @BeforeEach public void setUp() { - MockitoAnnotations.initMocks(this); super.setUp(controller); Institution institution = Generator.generateInstitution(); User user = Generator.generateUser(institution); @@ -112,7 +115,7 @@ public void getRecordsReturnsAllRecords() throws Exception { } @Test - public void finyByInstitutionReturnsRecords() throws Exception { + public void finByInstitutionReturnsRecords() throws Exception { final String key = "12345"; Institution institution = Generator.generateInstitution(); @@ -181,7 +184,7 @@ public void updateRecordReturnsResponseStatusNoContent() throws Exception { } @Test - public void updateRecordReturnsResponseStatusBadRequest() throws Exception { + public void updateRecordWithNonMatchingKeyReturnsResponseStatusBadRequest() throws Exception { final String key = "12345"; Institution institution = Generator.generateInstitution(); @@ -189,8 +192,6 @@ public void updateRecordReturnsResponseStatusBadRequest() throws Exception { PatientRecord record = Generator.generatePatientRecord(user); record.setKey(key); - when(patientRecordServiceMock.findByKey(key)).thenReturn(record); - final MvcResult result = mockMvc.perform(put("/records/123456" ).content(toJson(record)) .contentType(MediaType.APPLICATION_JSON_VALUE)).andReturn(); diff --git a/src/test/java/cz/cvut/kbss/study/rest/StatisticsControllerTest.java b/src/test/java/cz/cvut/kbss/study/rest/StatisticsControllerTest.java index 82c33fa6..554d5e26 100644 --- a/src/test/java/cz/cvut/kbss/study/rest/StatisticsControllerTest.java +++ b/src/test/java/cz/cvut/kbss/study/rest/StatisticsControllerTest.java @@ -4,21 +4,21 @@ import cz.cvut.kbss.study.environment.util.Environment; import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.User; -import static org.junit.Assert.*; - import cz.cvut.kbss.study.service.StatisticsService; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.mockito.Mockito.when; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.test.web.servlet.MvcResult; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; - +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +@ExtendWith(MockitoExtension.class) public class StatisticsControllerTest extends BaseControllerTestRunner { @Mock @@ -27,9 +27,8 @@ public class StatisticsControllerTest extends BaseControllerTestRunner { @InjectMocks private StatisticsController controller; - @Before + @BeforeEach public void setUp() { - MockitoAnnotations.initMocks(this); super.setUp(controller); Institution institution = Generator.generateInstitution(); User user = Generator.generateUser(institution); diff --git a/src/test/java/cz/cvut/kbss/study/rest/UserControllerTest.java b/src/test/java/cz/cvut/kbss/study/rest/UserControllerTest.java index 16101a5b..5cad18ac 100644 --- a/src/test/java/cz/cvut/kbss/study/rest/UserControllerTest.java +++ b/src/test/java/cz/cvut/kbss/study/rest/UserControllerTest.java @@ -8,24 +8,35 @@ import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.model.Vocabulary; import cz.cvut.kbss.study.service.InstitutionService; -import static org.junit.Assert.*; - import cz.cvut.kbss.study.service.UserService; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MvcResult; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +@ExtendWith(MockitoExtension.class) public class UserControllerTest extends BaseControllerTestRunner { @Mock @@ -37,9 +48,8 @@ public class UserControllerTest extends BaseControllerTestRunner { @InjectMocks private UserController controller; - @Before + @BeforeEach public void setUp() { - MockitoAnnotations.initMocks(this); super.setUp(controller); Institution institution = Generator.generateInstitution(); User user = Generator.generateUser(institution); @@ -76,7 +86,6 @@ public void createUserReturnsResponseStatusCreated() throws Exception { assertEquals(HttpStatus.CREATED, HttpStatus.valueOf(result.getResponse().getStatus())); } - @Test public void getUsersReturnsEmptyListWhenNoUsersAreFound() throws Exception { when(userServiceMock.findAll()).thenReturn(Collections.emptyList()); @@ -170,12 +179,8 @@ public void updateUserReturnsResponseStatusNoContent() throws Exception { } @Test - public void updateUserReturnsResponseStatusBadRequest() throws Exception { - final String username = "tom"; - - when(userServiceMock.findByUsername(username)).thenReturn(Environment.getCurrentUser()); - - final MvcResult result = mockMvc.perform(put("/users/tomas" ).content(toJson(Environment.getCurrentUser())) + public void updateUserWithNonMatchingUsernameReturnsResponseStatusBadRequest() throws Exception { + final MvcResult result = mockMvc.perform(put("/users/tomas").content(toJson(Environment.getCurrentUser())) .contentType(MediaType.APPLICATION_JSON_VALUE)).andReturn(); assertEquals(HttpStatus.BAD_REQUEST, HttpStatus.valueOf(result.getResponse().getStatus())); diff --git a/src/test/java/cz/cvut/kbss/study/security/OntologyAuthenticationProviderTest.java b/src/test/java/cz/cvut/kbss/study/security/OntologyAuthenticationProviderTest.java index 0d836c71..8e2d6612 100644 --- a/src/test/java/cz/cvut/kbss/study/security/OntologyAuthenticationProviderTest.java +++ b/src/test/java/cz/cvut/kbss/study/security/OntologyAuthenticationProviderTest.java @@ -1,12 +1,11 @@ package cz.cvut.kbss.study.security; -import cz.cvut.kbss.study.config.RestConfig; import cz.cvut.kbss.study.environment.config.TestSecurityConfig; import cz.cvut.kbss.study.security.model.UserDetails; import cz.cvut.kbss.study.service.BaseServiceTestRunner; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.authentication.AuthenticationProvider; @@ -19,29 +18,34 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.test.context.ContextConfiguration; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; -@ContextConfiguration(classes = {TestSecurityConfig.class, RestConfig.class}) +@ContextConfiguration(classes = {TestSecurityConfig.class}) public class OntologyAuthenticationProviderTest extends BaseServiceTestRunner { @Autowired @Qualifier("ontologyAuthenticationProvider") private AuthenticationProvider provider; - @Before + @BeforeEach public void setUp() throws Exception { super.setUp(); SecurityContextHolder.setContext(new SecurityContextImpl()); } - @After - public void tearDown() throws Exception { + @AfterEach + public void tearDown() { SecurityContextHolder.setContext(new SecurityContextImpl()); } @Test public void successfulAuthenticationSetsSecurityContext() { - final Authentication auth = new UsernamePasswordAuthenticationToken(BaseServiceTestRunner.USERNAME, BaseServiceTestRunner.PASSWORD); + final Authentication auth = + new UsernamePasswordAuthenticationToken(BaseServiceTestRunner.USERNAME, BaseServiceTestRunner.PASSWORD); final SecurityContext context = SecurityContextHolder.getContext(); assertNull(context.getAuthentication()); final Authentication result = provider.authenticate(auth); @@ -51,31 +55,21 @@ public void successfulAuthenticationSetsSecurityContext() { assertTrue(result.isAuthenticated()); } - @Test(expected = UsernameNotFoundException.class) + @Test public void authenticateThrowsUserNotFoundExceptionForUnknownUsername() { - final Authentication auth = new UsernamePasswordAuthenticationToken("unknownUsername", BaseServiceTestRunner.PASSWORD); - try { - provider.authenticate(auth); - } finally { - final SecurityContext context = SecurityContextHolder.getContext(); - assertNull(context.getAuthentication()); - final Authentication result = provider.authenticate(auth); - assertNotNull(SecurityContextHolder.getContext()); - final UserDetails details = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getDetails(); - assertEquals(USERNAME, details.getUsername()); - assertTrue(result.isAuthenticated()); - } + final Authentication auth = + new UsernamePasswordAuthenticationToken("unknownUsername", BaseServiceTestRunner.PASSWORD); + assertThrows(UsernameNotFoundException.class, () -> provider.authenticate(auth)); + final SecurityContext context = SecurityContextHolder.getContext(); + assertNull(context.getAuthentication()); } - @Test(expected = BadCredentialsException.class) + @Test public void authenticateThrowsBadCredentialsForInvalidPassword() { final Authentication auth = new UsernamePasswordAuthenticationToken(USERNAME, "unknownPassword"); - try { - provider.authenticate(auth); - } finally { - final SecurityContext context = SecurityContextHolder.getContext(); - assertNull(context.getAuthentication()); - } + assertThrows(BadCredentialsException.class, () -> provider.authenticate(auth)); + final SecurityContext context = SecurityContextHolder.getContext(); + assertNull(context.getAuthentication()); } } diff --git a/src/test/java/cz/cvut/kbss/study/service/BaseServiceTestRunner.java b/src/test/java/cz/cvut/kbss/study/service/BaseServiceTestRunner.java index 2b1d40cb..9b2fc7f1 100644 --- a/src/test/java/cz/cvut/kbss/study/service/BaseServiceTestRunner.java +++ b/src/test/java/cz/cvut/kbss/study/service/BaseServiceTestRunner.java @@ -1,26 +1,29 @@ package cz.cvut.kbss.study.service; -import cz.cvut.kbss.study.config.ServiceConfig; +import cz.cvut.kbss.study.environment.TransactionalTestRunner; import cz.cvut.kbss.study.environment.config.TestPersistenceConfig; - +import cz.cvut.kbss.study.environment.config.TestServiceConfig; import cz.cvut.kbss.study.environment.generator.Generator; import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.persistence.dao.InstitutionDao; import cz.cvut.kbss.study.persistence.dao.UserDao; -import org.junit.Before; -import org.junit.runner.RunWith; - +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = {ServiceConfig.class, TestPersistenceConfig.class}) +@EnableAspectJAutoProxy(proxyTargetClass = true) +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {TestServiceConfig.class, TestPersistenceConfig.class}) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) -public abstract class BaseServiceTestRunner { +@ActiveProfiles("test") +public abstract class BaseServiceTestRunner extends TransactionalTestRunner { @Autowired private UserDao userDao; @@ -37,15 +40,16 @@ public abstract class BaseServiceTestRunner { public static final String PASSWORD = "john117"; public static final String EMAIL = "john117@gmail.com"; - @Before + @BeforeEach public void setUp() throws Exception { Institution institution = Generator.generateInstitution(); - institutionDao.persist(institution); - user = Generator.getUser(USERNAME, PASSWORD, "John", "Grant", EMAIL, institution); - if (userDao.findByUsername(user.getUsername()) == null) { - user.encodePassword(passwordEncoder); - userDao.persist(user); - } + transactional(() -> { + institutionDao.persist(institution); + if (userDao.findByUsername(user.getUsername()) == null) { + user.encodePassword(passwordEncoder); + userDao.persist(user); + } + }); } } diff --git a/src/test/java/cz/cvut/kbss/study/service/UserDetailsServiceTest.java b/src/test/java/cz/cvut/kbss/study/service/UserDetailsServiceTest.java index 559b0be9..0e58a1d6 100644 --- a/src/test/java/cz/cvut/kbss/study/service/UserDetailsServiceTest.java +++ b/src/test/java/cz/cvut/kbss/study/service/UserDetailsServiceTest.java @@ -4,12 +4,14 @@ import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.User; import cz.cvut.kbss.study.service.security.UserDetailsService; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import static junit.framework.TestCase.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + public class UserDetailsServiceTest extends BaseServiceTestRunner { @Autowired @@ -22,7 +24,7 @@ public class UserDetailsServiceTest extends BaseServiceTestRunner { private InstitutionService institutionService; @Test - public void loadUserByUsername() throws Exception { + public void loadUserByUsername() { Institution institution = Generator.generateInstitution(); institutionService.persist(institution); @@ -33,8 +35,8 @@ public void loadUserByUsername() throws Exception { assertEquals(userDetails.getUsername(), user.getUsername()); } - @Test(expected = UsernameNotFoundException.class) - public void loadUserByUsernameExpectException() throws Exception { - userDetailsService.loadUserByUsername("CarolansRoyal12"); + @Test + public void loadUserByUsernameExpectException() { + assertThrows(UsernameNotFoundException.class, () -> userDetailsService.loadUserByUsername("CarolansRoyal12")); } } diff --git a/src/test/java/cz/cvut/kbss/study/service/security/SecurityUtilsTest.java b/src/test/java/cz/cvut/kbss/study/service/security/SecurityUtilsTest.java index 491cc2c1..8d7ea4eb 100644 --- a/src/test/java/cz/cvut/kbss/study/service/security/SecurityUtilsTest.java +++ b/src/test/java/cz/cvut/kbss/study/service/security/SecurityUtilsTest.java @@ -5,22 +5,23 @@ import cz.cvut.kbss.study.model.Institution; import cz.cvut.kbss.study.model.PatientRecord; import cz.cvut.kbss.study.model.User; -import cz.cvut.kbss.study.model.Vocabulary; import cz.cvut.kbss.study.security.model.UserDetails; import cz.cvut.kbss.study.service.BaseServiceTestRunner; import cz.cvut.kbss.study.service.InstitutionService; import cz.cvut.kbss.study.service.PatientRecordService; import cz.cvut.kbss.study.service.UserService; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.context.SecurityContextHolder; -import java.util.HashSet; -import java.util.Set; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.Assert.*; public class SecurityUtilsTest extends BaseServiceTestRunner { @@ -40,7 +41,7 @@ public class SecurityUtilsTest extends BaseServiceTestRunner { public static final String USERNAME = "halsey"; public static final String PASSWORD = "john117"; - @Before + @BeforeEach public void setUp() { Institution institution = Generator.generateInstitution(); institutionService.persist(institution); @@ -49,7 +50,7 @@ public void setUp() { userService.persist(user); } - @After + @AfterEach public void tearDown() { SecurityContextHolder.clearContext(); }