diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..814842b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.github +.idea +LICENSE +CHANGELOG.md +CONTRIBUTING.md +README.md +SECURITY.md +target/** +!target/fdp-spring-boot.jar +!target/classes/application-production.yml +nb-configuration.xml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..016b37f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,165 @@ +name: "Build" + +on: + push: + pull_request: + +jobs: + + test: + name: Maven Test & Package + runs-on: ubuntu-latest + + env: + JAVA_DISTRIBUTION: temurin + JAVA_VERSION: 17 + + services: + postgres: + image: postgres:15.1 + ports: + - 5432:5432 + env: + POSTGRES_DB: train_handler_test + POSTGRES_USER: postgres + POSTGRES_PASSWORD: password + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + + - name: Verify Maven and Java + run: | + mvn --version + + - name: Run tests + run: | + mvn --quiet -U -B org.jacoco:jacoco-maven-plugin:prepare-agent test -Dspring.profiles.active=ci + + - name: Build package + run: | + mvn --quiet -B -U --fail-fast -DskipTests package + + docker: + name: Docker build + runs-on: ubuntu-latest + needs: test + + env: + PUBLIC_IMAGE: fairdata/trainhandler-server + PRIVATE_IMAGE: ${{ secrets.PRIVATE_REGISTRY_URL }}/trainhandler-server + PRIVATE_REGISTRY_URL: ${{ secrets.PRIVATE_REGISTRY_URL }} + DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2 + + - name: Check available platforms + run: echo ${{ steps.buildx.outputs.platforms }} + + - name: Docker meta [test] + id: meta-test + uses: docker/metadata-action@v4 + with: + images: | + ${{ env.PUBLIC_IMAGE }} + tags: | + type=sha + - name: Docker build+push [test] + uses: docker/build-push-action@v4 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: false + tags: ${{ steps.meta-test.outputs.tags }} + labels: ${{ steps.meta-test.outputs.labels }} + + # PRIVATE: DOCKER REGISTRY + - name: Docker login [private] + if: github.event_name == 'push' && env.PRIVATE_REGISTRY_URL != '' + uses: docker/login-action@v2 + with: + registry: ${{ secrets.PRIVATE_REGISTRY_URL }} + username: ${{ secrets.PRIVATE_REGISTRY_USERNAME }} + password: ${{ secrets.PRIVATE_REGISTRY_PASSWORD }} + + - name: Docker meta [private] + id: meta-private + if: github.event_name == 'push' && env.PRIVATE_REGISTRY_URL != '' + uses: docker/metadata-action@v4 + with: + images: | + ${{ env.PRIVATE_IMAGE }} + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + + - name: Docker build+push [private] + uses: docker/build-push-action@v4 + if: github.event_name == 'push' && env.PRIVATE_REGISTRY_URL != '' && steps.meta-private.outputs.tags != '' + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta-private.outputs.tags }} + labels: ${{ steps.meta-private.outputs.labels }} + + # PUBLIC: DOCKER HUB + - name: Docker login [public] + if: github.event_name == 'push' && env.DOCKER_HUB_USERNAME != '' + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + + - name: Docker meta [public] + id: meta-public + if: github.event_name == 'push' && env.DOCKER_HUB_USERNAME != '' + uses: docker/metadata-action@v4 + with: + images: | + ${{ env.PUBLIC_IMAGE }} + tags: | + type=raw,value=develop,enable=${{ github.ref == format('refs/heads/{0}', 'develop') }} + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }} + + - name: Docker build+push [public] + uses: docker/build-push-action@v4 + if: github.event_name == 'push' && env.DOCKER_HUB_USERNAME != '' && steps.meta-public.outputs.tags != '' + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta-public.outputs.tags }} + labels: ${{ steps.meta-public.outputs.labels }} diff --git a/.github/workflows/code-style.yml b/.github/workflows/code-style.yml new file mode 100644 index 0000000..56063c5 --- /dev/null +++ b/.github/workflows/code-style.yml @@ -0,0 +1,88 @@ +name: "Code Style" + +on: + push: + pull_request: + +jobs: + + checkstyle: + name: Checkstyle + runs-on: ubuntu-latest + + env: + JAVA_DISTRIBUTION: temurin + JAVA_VERSION: 17 + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + + - name: Verify Maven and Java + run: | + mvn --version + + - name: Run Checkstyle + run: | + mvn -B checkstyle:checkstyle + + spotbugs: + name: SpotBugs + runs-on: ubuntu-latest + + env: + JAVA_DISTRIBUTION: temurin + JAVA_VERSION: 17 + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + + - name: Verify Maven and Java + run: | + mvn --version + + - name: Run SpotBugs + run: | + mvn -B spotbugs:check + + license-head: + name: License Headers + runs-on: ubuntu-latest + + env: + JAVA_DISTRIBUTION: temurin + JAVA_VERSION: 17 + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + + - name: Verify Maven and Java + run: | + mvn --version + + - name: Check license + run: | + mvn -B license:check diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..6d6e355 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,102 @@ +name: "Security Audit" + +on: + push: + branches: [ develop, master ] + pull_request: + branches: [ develop ] + schedule: + - cron: '23 4 * * 1' + +jobs: + codeql: + name: CodeQL + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + env: + JAVA_DISTRIBUTION: temurin + JAVA_VERSION: 17 + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup Java + uses: actions/setup-java@v2 + with: + distribution: ${{ env.JAVA_DISTRIBUTION }} + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + + - name: Verify Maven and Java + run: | + mvn --version + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: 'java' + + - name: Build package + run: | + mvn --quiet -B -U --fail-fast -DskipTests package + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + + snyk: + name: Snyk (Maven) + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + steps: + + - name: Checkout repository + uses: actions/checkout@master + + - name: Perform Snyk Check (Maven) + uses: snyk/actions/maven@master + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + with: + args: --severity-threshold=critical + + snyk-docker: + name: Snyk (Docker) + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + env: + PUBLIC_IMAGE: fairdata/trainhandler-server + TAG_DEVELOP: develop + + steps: + + - name: Checkout repository + uses: actions/checkout@master + + - name: Docker build + run: | + docker pull $PUBLIC_IMAGE:$TAG_DEVELOP + docker build --cache-from $PUBLIC_IMAGE:$TAG_DEVELOP -t fdp:snyk-test -f Dockerfile . + + - name: Perform Snyk Check (Docker) + uses: snyk/actions/docker@master + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + with: + image: fdp:snyk-test + args: --severity-threshold=critical diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..273ae66 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Custom ### +logs/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 19d61e9..f94f153 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,13 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [0.1.0] + ### Added - Initiated Train Handler server project - +- Setup CI, code style checks, and security audits [Unreleased]: /../../compare/master...develop +[0.1.0]: /../../tree/v0.1.0 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b3614a9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +# +# The MIT License +# Copyright © 2022 FAIR Data Team +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +FROM maven:3-eclipse-temurin-17 as builder + +WORKDIR /builder + +ADD . /builder + +RUN mvn --quiet -B -U --fail-fast -DskipTests package + +################################################################################ +# RUN STAGE +FROM eclipse-temurin:17 + +WORKDIR /app +EXPOSE 8080 + +ENV SPRING_PROFILE=production + +# Mount point for rolling log files +RUN mkdir /app/logs + +COPY --from=builder /builder/target/app.jar /app/app.jar +COPY --from=builder /builder/target/classes/application.yml /app/application.yml + +ENTRYPOINT java -jar app.jar --spring.profiles.active=$SPRING_PROFILE --spring.config.location=classpath:/application.yml,file:/app/application.yml diff --git a/README.md b/README.md index 2319cea..d545786 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,65 @@ ## Usage -*To be done* +Train Handler is intended to be used together with [client](https://github.com/FAIRDataTeam/TrainHandler-client) via Docker (unless for development purposes). + +The intended use is via Docker and Docker Compose, configured via envvars: + +```yaml + trainhandler-server: + image: fairdata/trainhandler-server:latest + restart: unless-stopped + # volumes: + # - ${PROJECT_ROOT}/application.yml:/app/application.yml:ro + environment: + FDT_DISPATCH_ROOT: ${API_URL} + FDT_DISPATCH_INTERVAL: PT60S + FDT_POSTGRES_DB: ${POSTGRES_DB} + FDT_POSTGRES_USERNAME: ${POSTGRES_USER} + FDT_POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + FDT_KEYCLOAK_ENABLED: true + FDT_KEYCLOAK_URL: ${KEYCLOAK_URL} + FDT_KEYCLOAK_REALM: ${KEYCLOAK_REALM} + FDT_KEYCLOAK_RESOURCE: ${KEYCLOAK_CLIENT_API} +``` ## Development -*To be done* +### Build & Run + +To run the application, a PostgreSQL database is required to be running. To configure the MongoDB with standard +connection (`postgresql://localhost:5432/train-handler`), simply instruct Spring Boot to use the `dev` profile. Then run: + +```bash +$ mvn spring-boot:run -Dspring-boot.run.profiles=dev +``` + +Alternatively, set the `dev` profile in your IDE that is used to launch the application. + +### Run tests + +Run from the root of the project: + +```bash +$ mvn test +``` + +### Package the application + +Run from the root of the project: + +```bash +$ mvn package +``` + +### Create a Docker image + +You do not have to install Java and IDE locally, we supply multistage Dockerfile that first +build `jar` file and then creates the image for deploying Train Handler: + +```bash +$ docker build -t trainhandler-server:local . +``` ## Contributing diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 0000000..3bdffe8 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,784 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..261b696 --- /dev/null +++ b/pom.xml @@ -0,0 +1,329 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + + org.fairdatatrain + trainhandler + 0.1.0 + + Train Handler + FAIR Data Train Handler + 2022 + + + The MIT License + https://opensource.org/licenses/MIT + + + + + + Marek Suchánek + https://github.com/MarekSuchanek + + + + + 17 + + + 1.6.14 + 42.5.4 + 1.18.26 + 2.14.1 + 4.2.3 + 21.0.1 + + + 4.1 + 3.2.1 + 4.7.3.2 + 5.0.0 + 0.2.0 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-configuration-processor + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-starter-security + + + + org.flywaydb + flyway-core + + + org.projectlombok + lombok + ${lombok.version} + + + org.springdoc + springdoc-openapi-ui + ${springdoc.version} + + + + org.postgresql + postgresql + ${postgresql.version} + runtime + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + org.eclipse.rdf4j + rdf4j-runtime + ${rdf4j.version} + pom + + + ch.qos.logback + logback-classic + + + + + org.eclipse.rdf4j + rdf4j-rio-api + ${rdf4j.version} + + + org.eclipse.rdf4j + rdf4j-sail-nativerdf + ${rdf4j.version} + + + + org.keycloak + keycloak-spring-boot-starter + ${keycloak.version} + + + org.keycloak + keycloak-spring-security-adapter + ${keycloak.version} + + + + + + + org.keycloak.bom + keycloak-adapter-bom + ${keycloak.version} + pom + import + + + + + + app + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + spring-boot + nl.dtls.fairdatapoint.Application + + + + build-info + + build-info + + + + + + com.mycila + license-maven-plugin + ${plugin.license.version} + +
com/mycila/maven/plugin/license/templates/MIT.txt
+ + FAIR Data Team + + + JAVADOC_STYLE + + + pom.xml + **/maven.config + **/*.ttl + **/*.yml + **/*.sparql + **/*.properties + **/*.xml + **/*.json + LICENSE + .gitignore + .dockerignore + +
+ + + process-sources + + format + + + +
+ + org.apache.maven.plugins + maven-checkstyle-plugin + ${plugin.checkstyle.version} + + true + true + checkstyle.xml + + + + com.puppycrawl.tools + checkstyle + 10.7.0 + + + io.spring.javaformat + spring-javaformat-checkstyle + 0.0.38 + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${plugin.spotbugs.version} + + + io.github.git-commit-id + git-commit-id-maven-plugin + ${plugin.git_commit_id.version} + + + get-the-git-infos + + revision + + initialize + + + + false + true + ${project.build.outputDirectory}/META-INF/git.properties + full + + + + com.github.kburger + rdf4j-generator-maven-plugin + ${plugin.rdf4j_generator.version} + + + + generate + + + + + nl.dtls.fairdatapoint.vocabulary + false + + + https://raw.githubusercontent.com/FAIRDataTeam/FDP-O/v1.1/fdp-ontology.owl + https://w3id.org/fdp/fdp-o# + fdp + + + https://raw.githubusercontent.com/FAIRDataTeam/FDT-O/778dcc29d54608fc942eb6b3260e9667a6227edc/fdt-ontology.owl + https://w3id.org/fdt/fdt-o# + fdt + + + + +
+
+ + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + +
diff --git a/src/main/java/org/fairdatatrain/trainhandler/Application.java b/src/main/java/org/fairdatatrain/trainhandler/Application.java new file mode 100644 index 0000000..93b2411 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/Application.java @@ -0,0 +1,43 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@SpringBootApplication +@EnableAsync +@EnableScheduling +@EnableWebMvc +@ComponentScan(basePackages = "org.fairdatatrain.trainhandler.*") +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java new file mode 100644 index 0000000..680ffea --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java @@ -0,0 +1,88 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import org.fairdatatrain.trainhandler.api.dto.error.ErrorDTO; +import org.fairdatatrain.trainhandler.exception.CannotPerformException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.exception.NotImplementedException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +import javax.validation.ValidationException; + +import static java.lang.String.format; + +@ControllerAdvice +public class ApiExceptionHandler { + + @ExceptionHandler(NotImplementedException.class) + public ResponseEntity handleNotImplementedException( + NotImplementedException exception) { + return new ResponseEntity<>( + new ErrorDTO("HTTP-501", "Not yet implemented."), HttpStatus.NOT_IMPLEMENTED); + } + + @ExceptionHandler(NotFoundException.class) + public ResponseEntity handleNotFoundException(NotFoundException exception) { + return new ResponseEntity<>( + new ErrorDTO( + "HTTP-404", + format( + "Cannot find entity %s with %s", + exception.getEntityName(), exception.getFields() + ) + ), + HttpStatus.NOT_FOUND + ); + } + + @ExceptionHandler(CannotPerformException.class) + public ResponseEntity handleCannotDeleteException(CannotPerformException exception) { + return new ResponseEntity<>( + new ErrorDTO( + "HTTP-400-DeletionError", + format( + "Cannot perform %s on entity %s (with %s)", + exception.getOperation(), + exception.getEntityName(), + exception.getFields() + ) + ), + HttpStatus.BAD_REQUEST + ); + } + + @ExceptionHandler(ValidationException.class) + public ResponseEntity handleValidationException(ValidationException exception) { + return new ResponseEntity<>( + new ErrorDTO( + "HTTP-400-ValidationError", + exception.getMessage() + ), + HttpStatus.BAD_REQUEST + ); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java new file mode 100644 index 0000000..c7e69f1 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java @@ -0,0 +1,106 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.job.*; +import org.fairdatatrain.trainhandler.data.model.JobArtifact; +import org.fairdatatrain.trainhandler.exception.JobSecurityException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.job.artifact.JobArtifactService; +import org.fairdatatrain.trainhandler.service.job.event.JobEventService; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +import static java.lang.String.format; + +@Tag(name = "Runs") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/runs") +@RequiredArgsConstructor +public class JobArtifactController { + + public static final String ARTIFACT_CALLBACK_LOCATION = "/{runUuid}/jobs/{jobUuid}/artifacts"; + + private final JobArtifactService jobArtifactService; + + private final JobEventService jobEventService; + + @GetMapping( + path = "/{runUuid}/jobs/{jobUuid}/artifacts", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public List getJobArtifacts( + @PathVariable UUID runUuid, @PathVariable UUID jobUuid + ) throws NotFoundException { + return jobArtifactService.getArtifacts(runUuid, jobUuid); + } + + @GetMapping( + path = "/{runUuid}/jobs/{jobUuid}/artifacts/{artifactUuid}/download" + ) + public ResponseEntity getJobArtifactData( + @PathVariable UUID runUuid, + @PathVariable UUID jobUuid, + @PathVariable UUID artifactUuid + ) throws NotFoundException { + final JobArtifact artifact = jobArtifactService.getArtifact(runUuid, jobUuid, artifactUuid); + final byte[] data = jobArtifactService.getArtifactData(artifact); + final ByteArrayResource resource = new ByteArrayResource(data); + return ResponseEntity + .ok() + .contentLength(artifact.getBytesize()) + .contentType(MediaType.parseMediaType(artifact.getContentType())) + .header( + HttpHeaders.CONTENT_DISPOSITION, + format("attachment;filename=%s", artifact.getFilename()) + ) + .body(resource); + } + + @PostMapping( + path = ARTIFACT_CALLBACK_LOCATION, + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public JobArtifactDTO addJobArtifact( + @PathVariable UUID runUuid, + @PathVariable UUID jobUuid, + @RequestBody @Valid JobArtifactCreateDTO reqDto + ) throws NotFoundException, JobSecurityException { + final JobArtifactDTO dto = jobArtifactService.createArtifact(runUuid, jobUuid, reqDto); + jobEventService.notify(jobUuid); + return dto; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java new file mode 100644 index 0000000..6682ebb --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java @@ -0,0 +1,72 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.job.*; +import org.fairdatatrain.trainhandler.config.DispatcherConfig; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.job.JobService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.async.DeferredResult; + +import java.util.UUID; + +@Tag(name = "Runs") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/runs") +@RequiredArgsConstructor +public class JobController { + + private final JobService jobService; + + private final DispatcherConfig config; + + @GetMapping(path = "/{runUuid}/jobs", produces = MediaType.APPLICATION_JSON_VALUE) + public Page getJobs(@PathVariable UUID runUuid, Pageable pageable) { + return jobService.getJobsForRun(runUuid, pageable); + } + + @GetMapping( + path = "/{runUuid}/jobs/{jobUuid}", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public DeferredResult pollJob( + @PathVariable UUID runUuid, + @PathVariable UUID jobUuid, + @RequestParam(required = false, defaultValue = "0") Long after + ) throws NotFoundException { + final JobDTO currentJob = jobService.getSingle(runUuid, jobUuid); + final DeferredResult result = new DeferredResult<>( + config.getPolling().getTimeoutMs(), currentJob + ); + jobService.poll(jobUuid, result, after, currentJob); + return result; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java new file mode 100644 index 0000000..20a0654 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java @@ -0,0 +1,75 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.job.*; +import org.fairdatatrain.trainhandler.exception.JobSecurityException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.job.event.JobEventService; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +@Tag(name = "Runs") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/runs") +@RequiredArgsConstructor +public class JobEventController { + + public static final String EVENT_CALLBACK_LOCATION = "/{runUuid}/jobs/{jobUuid}/events"; + + private final JobEventService jobEventService; + + @GetMapping( + path = "/{runUuid}/jobs/{jobUuid}/events", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public List getJobEvents( + @PathVariable UUID runUuid, + @PathVariable UUID jobUuid + ) throws NotFoundException { + return jobEventService.getEvents(runUuid, jobUuid); + } + + @PostMapping( + path = EVENT_CALLBACK_LOCATION, + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public JobEventDTO addJobEvent( + @PathVariable UUID runUuid, + @PathVariable UUID jobUuid, + @RequestBody @Valid JobEventCreateDTO reqDto + ) throws NotFoundException, JobSecurityException { + final JobEventDTO dto = jobEventService.createEvent(runUuid, jobUuid, reqDto); + jobEventService.notify(jobUuid); + return dto; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java new file mode 100644 index 0000000..a1870b3 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java @@ -0,0 +1,98 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.plan.PlanCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.plan.PlanDTO; +import org.fairdatatrain.trainhandler.api.dto.plan.PlanSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.plan.PlanUpdateDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunSimpleDTO; +import org.fairdatatrain.trainhandler.exception.CannotPerformException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.plan.PlanService; +import org.fairdatatrain.trainhandler.service.run.RunService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.UUID; + +@Tag(name = "Plans") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/plans") +@RequiredArgsConstructor +public class PlanController { + + private final PlanService planService; + + private final RunService runService; + + @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) + public Page getPaged( + @RequestParam(value = "query", required = false, defaultValue = "") String query, + @PageableDefault(sort = "displayName") Pageable pageable) { + return planService.getPaged(query, pageable); + } + + @PostMapping( + path = "", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(code = HttpStatus.CREATED) + public PlanDTO create(@Valid @RequestBody PlanCreateDTO reqDto) throws NotFoundException { + return planService.create(reqDto); + } + + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public PlanDTO getSingle(@PathVariable UUID uuid) throws NotFoundException { + return planService.getSingle(uuid); + } + + @PutMapping( + path = "/{uuid}", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + public PlanDTO update(@PathVariable UUID uuid, @Valid @RequestBody PlanUpdateDTO reqDto) + throws NotFoundException, CannotPerformException { + return planService.update(uuid, reqDto); + } + + @DeleteMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(code = HttpStatus.NO_CONTENT) + public void delete(@PathVariable UUID uuid) throws NotFoundException, CannotPerformException { + planService.delete(uuid); + } + + @GetMapping(path = "/{uuid}/runs", produces = MediaType.APPLICATION_JSON_VALUE) + public Page getPlanRuns(@PathVariable UUID uuid, Pageable pageable) { + return runService.getRunsForPlanUuid(uuid, pageable); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanLatestController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanLatestController.java new file mode 100644 index 0000000..f6aa533 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanLatestController.java @@ -0,0 +1,83 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.job.JobArtifactDTO; +import org.fairdatatrain.trainhandler.data.model.JobArtifact; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.plan.latest.PlanLatestService; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +import static java.lang.String.format; + +@Tag(name = "Plans") +@RestController +@RequestMapping("/plans") +@RequiredArgsConstructor +public class PlanLatestController { + + private final PlanLatestService planLatestService; + + @GetMapping(path = "/{planUuid}/latest/artifacts", produces = MediaType.APPLICATION_JSON_VALUE) + public List getLatestArtifacts(@PathVariable UUID planUuid) throws NotFoundException { + return planLatestService.getLatestArtifacts(planUuid); + } + + @GetMapping(path = "/{planUuid}/latest/artifacts/{artifactUuid}") + public ResponseEntity downloadLatestArtifact( + @PathVariable UUID planUuid, @PathVariable UUID artifactUuid + ) throws NotFoundException { + final JobArtifact artifact = planLatestService.getLatestJobArtifact(planUuid, artifactUuid); + final byte[] data = planLatestService.getArtifactData(artifact); + final ByteArrayResource resource = new ByteArrayResource(data); + return ResponseEntity + .ok() + .contentLength(artifact.getBytesize()) + .contentType(MediaType.parseMediaType(artifact.getContentType())) + .header( + HttpHeaders.CONTENT_DISPOSITION, + format("attachment;filename=%s", artifact.getFilename()) + ) + .body(resource); + } + + @GetMapping( + path = "/{planUuid}/target/{targetUuid}/latest/artifacts", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public List getLatestArtifactsOfTarget( + @PathVariable UUID planUuid, @PathVariable UUID targetUuid + ) throws NotFoundException { + return planLatestService.getLatestArtifactsOfTarget(planUuid, targetUuid); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java new file mode 100644 index 0000000..a7c80d5 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java @@ -0,0 +1,95 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.run.RunCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunUpdateDTO; +import org.fairdatatrain.trainhandler.config.DispatcherConfig; +import org.fairdatatrain.trainhandler.exception.CannotPerformException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.async.AsyncEventPublisher; +import org.fairdatatrain.trainhandler.service.run.RunService; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.async.DeferredResult; + +import javax.validation.Valid; +import java.util.UUID; + +@Tag(name = "Runs") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/runs") +@RequiredArgsConstructor +public class RunController { + + private final RunService runService; + + private final AsyncEventPublisher asyncEventPublisher; + + private final DispatcherConfig dispatcherConfig; + + @PostMapping( + path = "", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + @ResponseStatus(code = HttpStatus.CREATED) + public RunDTO create(@Valid @RequestBody RunCreateDTO reqDto) throws NotFoundException { + return runService.create(reqDto); + } + + @GetMapping( + path = "/{uuid}", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public DeferredResult pollRun( + @PathVariable UUID uuid, + @RequestParam(required = false, defaultValue = "0") Long after + ) throws NotFoundException { + final RunDTO currentRun = runService.getSingle(uuid); + final DeferredResult result = new DeferredResult<>( + dispatcherConfig.getPolling().getTimeoutMs(), currentRun + ); + runService.poll(uuid, result, after, currentRun); + return result; + } + + @PutMapping( + path = "/{uuid}", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public RunDTO update( + @PathVariable UUID uuid, @Valid @RequestBody RunUpdateDTO reqDto + ) throws NotFoundException, CannotPerformException { + final RunDTO run = runService.update(uuid, reqDto); + asyncEventPublisher.publishNewJobEventNotification(run); + return run; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java new file mode 100644 index 0000000..ce13268 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java @@ -0,0 +1,105 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.station.StationCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationUpdateDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.station.StationService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +@Tag(name = "Stations") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/stations") +@RequiredArgsConstructor +public class StationController { + + private final StationService stationService; + + @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) + public Page getPaged( + @RequestParam(value = "query", required = false, defaultValue = "") String query, + @PageableDefault(sort = "title") Pageable pageable) { + return stationService.getPaged(query, pageable); + } + + @GetMapping(path = "/all", produces = MediaType.APPLICATION_JSON_VALUE) + public List getPaged( + @RequestParam(value = "query", required = false, defaultValue = "") String query) { + return stationService.getAll(query); + } + + @PostMapping( + path = "", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public StationDTO create( + @RequestBody @Valid StationCreateDTO reqDto + ) throws NotFoundException { + return stationService.create(reqDto); + } + + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public StationDTO getSingle(@PathVariable UUID uuid) throws NotFoundException { + return stationService.getSingle(uuid); + } + + @GetMapping(path = "/{uuid}/trains", produces = MediaType.APPLICATION_JSON_VALUE) + public List getSuitableTrains(@PathVariable UUID uuid) + throws NotFoundException { + return stationService.getSuitableStations(uuid); + } + + @PutMapping( + path = "/{uuid}", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public StationDTO update( + @PathVariable UUID uuid, + @RequestBody @Valid StationUpdateDTO reqDto + ) throws NotFoundException { + return stationService.update(uuid, reqDto); + } + + @DeleteMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public StationDTO delete(@PathVariable UUID uuid) throws NotFoundException { + return stationService.softDelete(uuid); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java new file mode 100644 index 0000000..2b2c41e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java @@ -0,0 +1,96 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.stationdirectory.StationDirectoryService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.UUID; + +@Tag(name = "Station Directories") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/station-directories") +@RequiredArgsConstructor +public class StationDirectoryController { + + private final StationDirectoryService stationDirectoryService; + + @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) + public Page getPaged( + @RequestParam(value = "query", required = false, defaultValue = "") String query, + @PageableDefault(sort = "displayName") Pageable pageable) { + return stationDirectoryService.getPaged(query, pageable); + } + + @PostMapping( + path = "", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(code = HttpStatus.CREATED) + public StationDirectoryDTO create( + @Valid @RequestBody StationDirectoryChangeDTO reqDto + ) throws NotFoundException { + final StationDirectoryDTO dto = stationDirectoryService.create(reqDto); + stationDirectoryService.reindex(dto.getUuid()); + return dto; + } + + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public StationDirectoryDTO getSingle(@PathVariable UUID uuid) throws NotFoundException { + return stationDirectoryService.getSingle(uuid); + } + + @PutMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public StationDirectoryDTO update( + @PathVariable UUID uuid, @Valid @RequestBody StationDirectoryChangeDTO reqDto) + throws NotFoundException { + final StationDirectoryDTO dto = stationDirectoryService.update(uuid, reqDto); + stationDirectoryService.reindex(dto.getUuid()); + return dto; + } + + @DeleteMapping(path = "/{uuid}") + @ResponseStatus(code = HttpStatus.NO_CONTENT) + public void delete(@PathVariable UUID uuid) throws NotFoundException { + stationDirectoryService.delete(uuid); + } + + @PutMapping(path = "/{uuid}/stations", params = "refresh") + @ResponseStatus(code = HttpStatus.ACCEPTED) + public void refreshStations(@PathVariable UUID uuid) throws NotFoundException { + stationDirectoryService.reindex(uuid); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java new file mode 100644 index 0000000..9ebd2ea --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java @@ -0,0 +1,105 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainUpdateDTO; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.train.TrainService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +@Tag(name = "Trains") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/trains") +@RequiredArgsConstructor +public class TrainController { + + private final TrainService trainService; + + @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) + public Page getPaged( + @RequestParam(value = "query", required = false, defaultValue = "") String query, + @PageableDefault(sort = "title") Pageable pageable) { + return trainService.getPaged(query, pageable); + } + + @GetMapping(path = "/all", produces = MediaType.APPLICATION_JSON_VALUE) + public List getPaged( + @RequestParam(value = "query", required = false, defaultValue = "") String query) { + return trainService.getAll(query); + } + + @PostMapping( + path = "", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public TrainDTO create( + @RequestBody @Valid TrainCreateDTO reqDto + ) throws NotFoundException { + return trainService.create(reqDto); + } + + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public TrainDTO getSingle(@PathVariable UUID uuid) throws NotFoundException { + return trainService.getSingle(uuid); + } + + @GetMapping(path = "/{uuid}/stations", produces = MediaType.APPLICATION_JSON_VALUE) + public List getSuitableStations(@PathVariable UUID uuid) + throws NotFoundException { + return trainService.getSuitableStations(uuid); + } + + @PutMapping( + path = "/{uuid}", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public TrainDTO update( + @PathVariable UUID uuid, + @RequestBody @Valid TrainUpdateDTO reqDto + ) throws NotFoundException { + return trainService.update(uuid, reqDto); + } + + @DeleteMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public TrainDTO delete(@PathVariable UUID uuid) throws NotFoundException { + return trainService.softDelete(uuid); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java new file mode 100644 index 0000000..9643a0d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java @@ -0,0 +1,96 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.traingarage.TrainGarageService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.UUID; + +@Tag(name = "Train Garages") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/train-garages") +@RequiredArgsConstructor +public class TrainGarageController { + + private final TrainGarageService trainGarageService; + + @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) + public Page getPaged( + @RequestParam(value = "query", required = false, defaultValue = "") String query, + @PageableDefault(sort = "displayName") Pageable pageable) { + return trainGarageService.getPaged(query, pageable); + } + + @PostMapping( + path = "", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(code = HttpStatus.CREATED) + public TrainGarageDTO create( + @Valid @RequestBody TrainGarageChangeDTO reqDto + ) throws NotFoundException { + final TrainGarageDTO dto = trainGarageService.create(reqDto); + trainGarageService.reindex(dto.getUuid()); + return dto; + } + + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public TrainGarageDTO getSingle(@PathVariable UUID uuid) throws NotFoundException { + return trainGarageService.getSingle(uuid); + } + + @PutMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public TrainGarageDTO update( + @PathVariable UUID uuid, @Valid @RequestBody TrainGarageChangeDTO reqDto + ) throws NotFoundException { + final TrainGarageDTO dto = trainGarageService.update(uuid, reqDto); + trainGarageService.reindex(dto.getUuid()); + return dto; + } + + @DeleteMapping(path = "/{uuid}") + @ResponseStatus(code = HttpStatus.NO_CONTENT) + public void delete(@PathVariable UUID uuid) throws NotFoundException { + trainGarageService.delete(uuid); + } + + @PutMapping(path = "/{uuid}/trains", params = "refresh") + @ResponseStatus(code = HttpStatus.ACCEPTED) + public void refreshTrains(@PathVariable UUID uuid) throws NotFoundException { + trainGarageService.reindex(uuid); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java new file mode 100644 index 0000000..11049cf --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java @@ -0,0 +1,91 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeSimpleDTO; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.traintype.TrainTypeService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +@Tag(name = "Train Types") +@PreAuthorize("hasRole('user')") +@RestController +@RequestMapping("/train-types") +@RequiredArgsConstructor +public class TrainTypeController { + + private final TrainTypeService trainTypeService; + + @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) + public Page getPaged( + @RequestParam(value = "query", required = false, defaultValue = "") String query, + @PageableDefault(sort = "title") Pageable pageable) { + return trainTypeService.getPaged(query, pageable); + } + + @GetMapping(path = "/all", produces = MediaType.APPLICATION_JSON_VALUE) + public List getAll() { + return trainTypeService.getAll(); + } + + @PostMapping( + path = "", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(code = HttpStatus.CREATED) + public TrainTypeDTO create(@Valid @RequestBody TrainTypeChangeDTO reqDto) { + return trainTypeService.create(reqDto); + } + + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public TrainTypeDTO getSingle(@PathVariable UUID uuid) throws NotFoundException { + return trainTypeService.getSingle(uuid); + } + + @PutMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public TrainTypeDTO update( + @PathVariable UUID uuid, @Valid @RequestBody TrainTypeChangeDTO reqDto) + throws NotFoundException { + return trainTypeService.update(uuid, reqDto); + } + + @DeleteMapping(path = "/{uuid}") + @ResponseStatus(code = HttpStatus.NO_CONTENT) + public void delete(@PathVariable UUID uuid) throws NotFoundException { + trainTypeService.delete(uuid); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/error/ErrorDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/error/ErrorDTO.java new file mode 100644 index 0000000..2135093 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/error/ErrorDTO.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.error; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.Collections; +import java.util.Map; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class ErrorDTO { + + private String code; + + private String message; + + private Map fields = Collections.emptyMap(); + + public ErrorDTO(String code, String message) { + this.code = code; + this.message = message; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactCreateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactCreateDTO.java new file mode 100644 index 0000000..e2041cb --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactCreateDTO.java @@ -0,0 +1,65 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.job; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotNull; +import java.time.Instant; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class JobArtifactCreateDTO { + + @NotNull + private String displayName; + + @NotNull + private String filename; + + @NotNull + private String hash; + + @NotNull + private Long bytesize; + + @NotNull + private String contentType; + + @NotNull + private Instant occurredAt; + + @NotNull + private String remoteId; + + @NotNull + private String secret; + + @NotNull + private String base64data; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.java new file mode 100644 index 0000000..4b9e7cd --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.java @@ -0,0 +1,53 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.job; + +import lombok.*; + +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class JobArtifactDTO { + + private UUID uuid; + + private String displayName; + + private String filename; + + private Long bytesize; + + private String contentType; + + private String hash; + + private String occurredAt; + + private String createdAt; + + private String updatedAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java new file mode 100644 index 0000000..fb2577d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java @@ -0,0 +1,63 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.job; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.run.RunSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class JobDTO { + + private UUID uuid; + + private String remoteId; + + private JobStatus status; + + private String startedAt; + + private String finishedAt; + + private StationSimpleDTO target; + + private RunSimpleDTO run; + + private List events; + + private List artifacts; + + private String createdAt; + + private String updatedAt; + + private Long version; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventCreateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventCreateDTO.java new file mode 100644 index 0000000..0b80f7e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventCreateDTO.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.job; + +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; + +import javax.validation.constraints.NotNull; +import java.time.Instant; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder +public class JobEventCreateDTO { + + private JobStatus resultStatus; + + @NotNull + private String message; + + @NotNull + private Instant occurredAt; + + @NotNull + private String remoteId; + + @NotNull + private String secret; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventDTO.java new file mode 100644 index 0000000..451c13a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventDTO.java @@ -0,0 +1,48 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.job; + +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; + +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class JobEventDTO { + + private UUID uuid; + + private JobStatus resultStatus; + + private String message; + + private String occurredAt; + + private String createdAt; + + private String updatedAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobSimpleDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobSimpleDTO.java new file mode 100644 index 0000000..3893b79 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobSimpleDTO.java @@ -0,0 +1,56 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.job; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class JobSimpleDTO { + + private UUID uuid; + + private String remoteId; + + private JobStatus status; + + private String startedAt; + + private String finishedAt; + + private StationSimpleDTO target; + + private List artifacts; + + private UUID runUuid; + + private Long version; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanCreateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanCreateDTO.java new file mode 100644 index 0000000..c659f4d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanCreateDTO.java @@ -0,0 +1,55 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.plan; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class PlanCreateDTO { + + @NotNull + private UUID trainUuid; + + @NotNull + private List targets; + + @NotBlank + private String displayName; + + @NotNull + private String note; + + @NotNull + private Boolean publishArtifacts = false; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanDTO.java new file mode 100644 index 0000000..3cc9c48 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanDTO.java @@ -0,0 +1,53 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.plan; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.train.TrainDTO; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class PlanDTO { + + private UUID uuid; + + private String displayName; + + private String note; + + private TrainDTO train; + + private List targets; + + private Boolean publishArtifacts; + + private String createdAt; + + private String updatedAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanSimpleDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanSimpleDTO.java new file mode 100644 index 0000000..9c05b5e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanSimpleDTO.java @@ -0,0 +1,52 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.plan; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; + +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class PlanSimpleDTO { + + private UUID uuid; + + private String displayName; + + private String note; + + @NotNull + private TrainSimpleDTO train; + + @NotNull + private List targets; + + private Boolean publishArtifacts; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanTargetChangeDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanTargetChangeDTO.java new file mode 100644 index 0000000..eb03d57 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanTargetChangeDTO.java @@ -0,0 +1,42 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.plan; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder +public class PlanTargetChangeDTO { + + @NotNull + private UUID stationUuid; + + @NotNull + private Boolean publishArtifacts = false; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanTargetDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanTargetDTO.java new file mode 100644 index 0000000..80b8c9b --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanTargetDTO.java @@ -0,0 +1,42 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.plan; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; + +import javax.validation.constraints.NotNull; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder +public class PlanTargetDTO { + + @NotNull + private StationSimpleDTO station; + + @NotNull + private Boolean publishArtifacts = false; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanUpdateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanUpdateDTO.java new file mode 100644 index 0000000..f097aae --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanUpdateDTO.java @@ -0,0 +1,54 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.plan; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class PlanUpdateDTO { + + @NotNull + private UUID trainUuid; + + @NotNull + private List targets; + + @NotBlank + private String displayName; + + @NotNull + private String note; + + private Boolean publishArtifacts = false; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunCreateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunCreateDTO.java new file mode 100644 index 0000000..7ec88b6 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunCreateDTO.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.run; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.Instant; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class RunCreateDTO { + + @NotBlank + private String displayName; + + @NotNull + private String note; + + @NotNull + private UUID planUuid; + + private Instant shouldStartAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunDTO.java new file mode 100644 index 0000000..3c2b24c --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunDTO.java @@ -0,0 +1,63 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.run; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.job.JobSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.plan.PlanSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class RunDTO { + + private UUID uuid; + + private String displayName; + + private String note; + + private RunStatus status; + + private PlanSimpleDTO plan; + + private List jobs; + + private String shouldStartAt; + + private String startedAt; + + private String finishedAt; + + private String createdAt; + + private String updatedAt; + + private Long version; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunSimpleDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunSimpleDTO.java new file mode 100644 index 0000000..ab47fd4 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunSimpleDTO.java @@ -0,0 +1,58 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.run; + +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; + +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class RunSimpleDTO { + + private UUID uuid; + + private String displayName; + + private String note; + + private RunStatus status; + + private UUID trainUuid; + + private UUID planUuid; + + private String shouldStartAt; + + private String startedAt; + + private String finishedAt; + + private String createdAt; + + private String updatedAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunUpdateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunUpdateDTO.java new file mode 100644 index 0000000..2018ebe --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunUpdateDTO.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.run; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class RunUpdateDTO { + + @NotBlank + private String displayName; + + @NotNull + private String note; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationCreateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationCreateDTO.java new file mode 100644 index 0000000..ec206ce --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationCreateDTO.java @@ -0,0 +1,64 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.station; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class StationCreateDTO { + + @NotNull + private String uri; + + @NotNull + private String title; + + @NotNull + private String description; + + @NotNull + private String endpointUrl; + + @NotNull + private String endpointDescription; + + @NotNull + private List keywords; + + @NotNull + private String metadata; + + @NotNull + private List trainTypeUuids; + + @NotNull + private Boolean fetch = false; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java new file mode 100644 index 0000000..d15ad9a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java @@ -0,0 +1,69 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.station; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectorySimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class StationDTO { + + private UUID uuid; + + private String uri; + + private String title; + + private String description; + + private List keywords; + + private String endpointUrl; + + private String endpointDescription; + + private SyncItemStatus status; + + private String metadata; + + private Boolean softDeleted; + + private StationDirectorySimpleDTO directory; + + private List types; + + private String lastContactAt; + + private String createdAt; + + private String updatedAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationSimpleDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationSimpleDTO.java new file mode 100644 index 0000000..168f7e5 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationSimpleDTO.java @@ -0,0 +1,57 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.station; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectorySimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class StationSimpleDTO { + + private UUID uuid; + + private String uri; + + private String title; + + private List keywords; + + private String endpointUrl; + + private String endpointDescription; + + private SyncItemStatus status; + + private StationDirectorySimpleDTO directory; + + private List types; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java new file mode 100644 index 0000000..8adec9a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java @@ -0,0 +1,67 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.station; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class StationUpdateDTO { + + @NotNull + private String uri; + + @NotNull + private String title; + + @NotNull + private String description; + + @NotNull + private List keywords; + + @NotNull + private String endpointUrl; + + @NotNull + private String endpointDescription; + + @NotNull + private String metadata; + + @NotNull + private List trainTypeUuids; + + private Boolean softDeleted; + + @NotNull + private Boolean fetch = false; + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryChangeDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryChangeDTO.java new file mode 100644 index 0000000..6dff10d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryChangeDTO.java @@ -0,0 +1,46 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.stationdirectory; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class StationDirectoryChangeDTO { + + @NotBlank + private String uri; + + @NotBlank + private String displayName; + + @NotNull + private String note; + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java new file mode 100644 index 0000000..3d3d635 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java @@ -0,0 +1,56 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.stationdirectory; + +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; + +import java.util.UUID; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class StationDirectoryDTO { + + private UUID uuid; + + private String uri; + + private String displayName; + + private String note; + + private String metadata; + + private SyncServiceStatus status; + + private Boolean deletable; + + private String lastContactAt; + + private String createdAt; + + private String updatedAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectorySimpleDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectorySimpleDTO.java new file mode 100644 index 0000000..8ee852d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectorySimpleDTO.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.stationdirectory; + +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; + +import java.util.UUID; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class StationDirectorySimpleDTO { + + private UUID uuid; + + private String uri; + + private String displayName; + + private SyncServiceStatus status; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainCreateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainCreateDTO.java new file mode 100644 index 0000000..c27bd3f --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainCreateDTO.java @@ -0,0 +1,58 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.train; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainCreateDTO { + + @NotNull + private String uri; + + @NotNull + private String title; + + @NotNull + private String description; + + @NotNull + private List keywords; + + @NotNull + private String metadata; + + @NotNull + private List trainTypeUuids; + + @NotNull + private Boolean fetch = false; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.java new file mode 100644 index 0000000..828de4d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.java @@ -0,0 +1,65 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.train; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainDTO { + + private UUID uuid; + + private String uri; + + private String title; + + private String description; + + private List keywords; + + private SyncItemStatus status; + + private String metadata; + + private Boolean softDeleted; + + private TrainGarageSimpleDTO garage; + + private List types; + + private String lastContactAt; + + private String createdAt; + + private String updatedAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainSimpleDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainSimpleDTO.java new file mode 100644 index 0000000..32688d7 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainSimpleDTO.java @@ -0,0 +1,53 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.train; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainSimpleDTO { + + private UUID uuid; + + private String uri; + + private String title; + + private List keywords; + + private SyncItemStatus status; + + private TrainGarageSimpleDTO garage; + + private List types; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java new file mode 100644 index 0000000..ebc4f83 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java @@ -0,0 +1,61 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.train; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainUpdateDTO { + + @NotNull + private String uri; + + @NotNull + private String title; + + @NotNull + private String description; + + @NotNull + private List keywords; + + @NotNull + private String metadata; + + @NotNull + private List trainTypeUuids; + + private Boolean softDeleted; + + @NotNull + private Boolean fetch = false; + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageChangeDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageChangeDTO.java new file mode 100644 index 0000000..1283055 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageChangeDTO.java @@ -0,0 +1,46 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.traingarage; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainGarageChangeDTO { + + @NotBlank + private String uri; + + @NotBlank + private String displayName; + + @NotNull + private String note; + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java new file mode 100644 index 0000000..8f40aac --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java @@ -0,0 +1,57 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.traingarage; + +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; + +import java.util.UUID; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainGarageDTO { + + private UUID uuid; + + private String uri; + + private String displayName; + + private String note; + + private String metadata; + + private SyncServiceStatus status; + + private Boolean deletable; + + private String lastContactAt; + + private String createdAt; + + private String updatedAt; +} + diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageSimpleDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageSimpleDTO.java new file mode 100644 index 0000000..7843b57 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageSimpleDTO.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.traingarage; + +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; + +import java.util.UUID; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainGarageSimpleDTO { + + private UUID uuid; + + private String uri; + + private String displayName; + + private SyncServiceStatus status; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeChangeDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeChangeDTO.java new file mode 100644 index 0000000..48a160f --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeChangeDTO.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.traintype; + +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainTypeChangeDTO { + @NotBlank + private String uri; + + @NotBlank + private String title; + + @NotNull + private String note; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeDTO.java new file mode 100644 index 0000000..2040b62 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeDTO.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.traintype; + +import lombok.*; + +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainTypeDTO { + + private UUID uuid; + + private String uri; + + private String title; + + private String note; + + private String createdAt; + + private String updatedAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeSimpleDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeSimpleDTO.java new file mode 100644 index 0000000..226586a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeSimpleDTO.java @@ -0,0 +1,41 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.dto.traintype; + +import lombok.*; + +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainTypeSimpleDTO { + + private UUID uuid; + + private String uri; + + private String title; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/filter/CorsFilter.java b/src/main/java/org/fairdatatrain/trainhandler/api/filter/CorsFilter.java new file mode 100644 index 0000000..b55ed77 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/filter/CorsFilter.java @@ -0,0 +1,80 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.filter; + +import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Component +public class CorsFilter extends OncePerRequestFilter { + + static final String DELIMITER = ","; + + static final String ALLOWED_METHODS = String.join( + DELIMITER, + RequestMethod.GET.name(), + RequestMethod.DELETE.name(), + RequestMethod.PATCH.name(), + RequestMethod.POST.name(), + RequestMethod.PUT.name() + ); + + static final String ALLOWED_HEADERS = String.join( + DELIMITER, + HttpHeaders.ACCEPT, + HttpHeaders.AUTHORIZATION, + HttpHeaders.CONTENT_TYPE, + HttpHeaders.ORIGIN + ); + + static final String EXPOSED_HEADERS = String.join( + DELIMITER, + HttpHeaders.LINK, + HttpHeaders.LOCATION + ); + + @Override + public void doFilterInternal( + @Nullable final HttpServletRequest request, + final HttpServletResponse response, + final FilterChain filterChain + ) throws IOException, ServletException { + logger.debug("Setting CORS headers (via request filter)"); + response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); + response.setHeader(HttpHeaders.ALLOW, ALLOWED_METHODS); + response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, ALLOWED_METHODS); + response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, ALLOWED_HEADERS); + response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, EXPOSED_HEADERS); + + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/filter/LoggingFilter.java b/src/main/java/org/fairdatatrain/trainhandler/api/filter/LoggingFilter.java new file mode 100644 index 0000000..987caf7 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/filter/LoggingFilter.java @@ -0,0 +1,66 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.api.filter; + +import org.apache.logging.log4j.ThreadContext; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.UUID; + +import static java.lang.String.format; + +@Component +public class LoggingFilter extends OncePerRequestFilter { + + @Override + public void doFilterInternal( + final HttpServletRequest request, + final HttpServletResponse response, + final FilterChain fc + ) throws IOException, ServletException { + ThreadContext.put("ipAddress", request.getRemoteAddr()); + ThreadContext.put("requestMethod", request.getMethod()); + ThreadContext.put("requestURI", request.getRequestURI()); + ThreadContext.put("requestProtocol", request.getProtocol()); + ThreadContext.put("responseStatus", String.valueOf(response.getStatus())); + ThreadContext.put("contentSize", response.getHeader(HttpHeaders.CONTENT_LENGTH)); + ThreadContext.put("traceId", UUID.randomUUID().toString()); + + logger.info(format("%s %s", request.getMethod(), request.getRequestURL())); + fc.doFilter(request, response); + logger.info(format( + "%s %s [Response: %s]", + request.getMethod(), request.getRequestURL(), response.getStatus()) + ); + + ThreadContext.clearAll(); + } + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/DispatcherConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/DispatcherConfig.java new file mode 100644 index 0000000..ad04a4e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/DispatcherConfig.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.config; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.fairdatatrain.trainhandler.config.properties.DispatchProperties; +import org.fairdatatrain.trainhandler.config.properties.PollingProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Configuration +@EnableConfigurationProperties +@ConfigurationProperties(prefix = "dispatcher") +public class DispatcherConfig { + + private DispatchProperties dispatch; + + private PollingProperties polling; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/HttpClientConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/HttpClientConfig.java new file mode 100644 index 0000000..05c1e70 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/HttpClientConfig.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.netty.http.client.HttpClient; + +import java.time.Duration; + +@Configuration +public class HttpClientConfig { + private static final long TIMEOUT = 5; + + @Bean + public WebClient webClient() { + final HttpClient client = HttpClient.create() + .followRedirect(true) + .responseTimeout(Duration.ofSeconds(TIMEOUT)); + + return WebClient.builder() + .clientConnector(new ReactorClientHttpConnector(client)) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/PropertiesConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/PropertiesConfig.java new file mode 100644 index 0000000..f177734 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/PropertiesConfig.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.core.io.ClassPathResource; + +@Configuration +public class PropertiesConfig { + + private static final String GIT_FILE = "META-INF/git.properties"; + + private static final String BUILD_INFO_FILE = "META-INF/build-info.properties"; + + @Bean + public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() { + final PropertySourcesPlaceholderConfigurer propsConfig = + new PropertySourcesPlaceholderConfigurer(); + propsConfig.setLocations( + new ClassPathResource(GIT_FILE), + new ClassPathResource(BUILD_INFO_FILE) + ); + propsConfig.setIgnoreResourceNotFound(true); + propsConfig.setIgnoreUnresolvablePlaceholders(true); + return propsConfig; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/SecurityDisabledConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/SecurityDisabledConfig.java new file mode 100644 index 0000000..39a66fe --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/SecurityDisabledConfig.java @@ -0,0 +1,46 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@ConditionalOnProperty(name = "keycloak.enabled", havingValue = "false") +public class SecurityDisabledConfig { + + @Bean + public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception { + return http + .csrf().disable() + .authorizeHttpRequests(auth -> { + auth + .anyRequest() + .permitAll(); + }) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/SecurityKeycloakConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/SecurityKeycloakConfig.java new file mode 100644 index 0000000..36bbb8a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/SecurityKeycloakConfig.java @@ -0,0 +1,66 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.config; + +import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; +import org.keycloak.adapters.springsecurity.KeycloakConfiguration; +import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; +import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; +import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy; + +@KeycloakConfiguration +@ConditionalOnProperty(name = "keycloak.enabled", havingValue = "true", matchIfMissing = true) +@EnableMethodSecurity +@Import(KeycloakSpringBootConfigResolver.class) +public class SecurityKeycloakConfig extends KeycloakWebSecurityConfigurerAdapter { + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) { + final KeycloakAuthenticationProvider keycloakAuthenticationProvider = + keycloakAuthenticationProvider(); + keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); + auth.authenticationProvider(keycloakAuthenticationProvider); + } + + @Bean + @Override + protected NullAuthenticatedSessionStrategy sessionAuthenticationStrategy() { + return new NullAuthenticatedSessionStrategy(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + super.configure(http); + http + .csrf().disable() + .authorizeHttpRequests(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/WebConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/WebConfig.java new file mode 100644 index 0000000..458a816 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/WebConfig.java @@ -0,0 +1,30 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/properties/DispatchProperties.java b/src/main/java/org/fairdatatrain/trainhandler/config/properties/DispatchProperties.java new file mode 100644 index 0000000..784f8d7 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/properties/DispatchProperties.java @@ -0,0 +1,38 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.config.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class DispatchProperties { + + private String callbackRoot; + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/properties/PollingProperties.java b/src/main/java/org/fairdatatrain/trainhandler/config/properties/PollingProperties.java new file mode 100644 index 0000000..25ece7f --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/properties/PollingProperties.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.config.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class PollingProperties { + + private Duration timeout = Duration.parse("PT50S"); + + public long getTimeoutMs() { + return timeout.toMillis(); + } + + public Instant getTimeoutForCurrentPoll() { + return Instant.now().plus(getTimeoutMs(), ChronoUnit.MILLIS); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java new file mode 100644 index 0000000..112397e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java @@ -0,0 +1,88 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; +import java.util.List; + +@Entity(name = "Job") +@Table(name = "job") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class Job extends BaseEntity { + + @NotNull + @Column(name = "secret", nullable = false) + private String secret; + + @Column(name = "remote_id") + private String remoteId; + + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "job_status", nullable = false) + private JobStatus status; + + @Column(name = "started_at") + private Timestamp startedAt; + + @Column(name = "finished_at") + private Timestamp finishedAt; + + @Column(name = "version", nullable = false) + private Long version; + + @NotNull + @ManyToOne + @JoinColumn(name = "plan_target_id") + private PlanTarget target; + + @NotNull + @ManyToOne + @JoinColumn(name = "run_id", nullable = false) + private Run run; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "job") + private List events; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "job") + private List artifacts; + + public boolean isFinished() { + return getStatus().equals(JobStatus.FAILED) + || getStatus().equals(JobStatus.FINISHED) + || getStatus().equals(JobStatus.ERRORED); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/JobArtifact.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/JobArtifact.java new file mode 100644 index 0000000..f25f1ac --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/JobArtifact.java @@ -0,0 +1,86 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.ArtifactStorage; +import org.hibernate.annotations.Type; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; + +@Entity(name = "JobArtifact") +@Table(name = "job_artifact") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class JobArtifact extends BaseEntity { + + @NotNull + @Column(name = "display_name") + private String displayName; + + @NotNull + @Column(name = "filename", nullable = false) + private String filename; + + @NotNull + @Column(name = "bytesize", nullable = false) + private Long bytesize; + + @NotNull + @Column(name = "hash", nullable = false) + private String hash; + + @NotNull + @Column(name = "content_type", nullable = false) + private String contentType; + + @NotNull + @Enumerated(EnumType.STRING) + @Column(name = "storage", columnDefinition = "artifact_storage", nullable = false) + private ArtifactStorage storage; + + @NotNull + @Column(name = "occurred_at", nullable = false) + private Timestamp occurredAt; + + @Lob + @Column(name = "data") + @Type(type = "org.hibernate.type.BinaryType") + private byte[] data; + + @NotNull + @ManyToOne + @JoinColumn(name = "job_id", nullable = false) + private Job job; + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/JobEvent.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/JobEvent.java new file mode 100644 index 0000000..9fda6a6 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/JobEvent.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; + +@Entity(name = "JobEvent") +@Table(name = "job_event") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class JobEvent extends BaseEntity { + + @Enumerated(EnumType.STRING) + @Column(name = "result_status", columnDefinition = "job_status") + private JobStatus resultStatus; + + @NotNull + @Column(name = "occurred_at", nullable = false) + private Timestamp occurredAt; + + @NotNull + @Column(name = "message", nullable = false) + private String message; + + @NotNull + @ManyToOne + @JoinColumn(name = "job_id", nullable = false) + private Job job; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Plan.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Plan.java new file mode 100644 index 0000000..4aea02c --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Plan.java @@ -0,0 +1,69 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Entity(name = "Plan") +@Table(name = "plan") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class Plan extends BaseEntity { + + @NotBlank + @NotNull + @Column(name = "display_name", nullable = false) + private String displayName; + + @NotNull + @Column(name = "note", nullable = false) + private String note; + + @NotNull + @Column(name = "publish_artifacts", nullable = false) + private Boolean publishArtifacts; + + @NotNull + @ManyToOne + @JoinColumn(name = "train_id") + private Train train; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "plan") + private List targets; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "plan") + private List runs; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/PlanTarget.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/PlanTarget.java new file mode 100644 index 0000000..152648a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/PlanTarget.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.UUID; + +@Entity(name = "PlanTarget") +@Table(name = "plan_target") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class PlanTarget extends BaseEntity { + + @NotNull + @ManyToOne + @JoinColumn(name = "station_id") + private Station station; + + @NotNull + @ManyToOne + @JoinColumn(name = "plan_id") + private Plan plan; + + @NotNull + @Column(name = "publish_artifacts", nullable = false) + private Boolean publishArtifacts; + + public UUID getStationUuid() { + return station.getUuid(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java new file mode 100644 index 0000000..75e856e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java @@ -0,0 +1,86 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; +import java.util.List; + +@Entity(name = "Run") +@Table(name = "run") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class Run extends BaseEntity { + + @NotBlank + @NotNull + @Column(name = "display_name", nullable = false) + private String displayName; + + @NotNull + @Column(name = "note", nullable = false) + private String note; + + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "run_status", nullable = false) + private RunStatus status; + + @Column(name = "should_start_at") + private Timestamp shouldStartAt; + + @Column(name = "started_at") + private Timestamp startedAt; + + @Column(name = "finished_at") + private Timestamp finishedAt; + + @Column(name = "version", nullable = false) + private Long version; + + @NotNull + @ManyToOne + @JoinColumn(name = "plan_id") + private Plan plan; + + @OneToMany(fetch = FetchType.EAGER, mappedBy = "run") + private List jobs; + + public boolean isFinished() { + return getStatus().equals(RunStatus.FAILED) + || getStatus().equals(RunStatus.FINISHED) + || getStatus().equals(RunStatus.ERRORED); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java new file mode 100644 index 0000000..6e089df --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java @@ -0,0 +1,97 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; +import java.util.List; + +@Entity(name = "Station") +@Table(name = "station") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder(toBuilder = true) +public class Station extends BaseEntity { + + @NotBlank + @NotNull + @Column(name = "uri", nullable = false) + private String uri; + + @NotBlank + @NotNull + @Column(name = "title", nullable = false) + private String title; + + @NotNull + @Column(name = "description", nullable = false) + private String description; + + @NotNull + @Column(name = "keywords", nullable = false) + private String keywords; + + @NotNull + @Column(name = "endpoint_url", nullable = false) + private String endpointUrl; + + @NotNull + @Column(name = "endpoint_description", nullable = false) + private String endpointDescription; + + @Column(name = "metadata") + private String metadata; + + @Column(name = "soft_deleted") + private Boolean softDeleted; + + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "sync_item_status", nullable = false) + private SyncItemStatus status; + + @Column(name = "last_contact_at") + private Timestamp lastContactAt; + + @ManyToOne + @JoinColumn(name = "station_directory_id") + private StationDirectory directory; + + @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @JoinTable( + name = "station_train_type", + joinColumns = @JoinColumn(name = "station_id"), + inverseJoinColumns = @JoinColumn(name = "train_type_id")) + private List types; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java new file mode 100644 index 0000000..ef1b673 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java @@ -0,0 +1,89 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +@Entity(name = "StationDirectory") +@Table(name = "station_directory") +@SuperBuilder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class StationDirectory extends BaseEntity { + + @NotBlank + @NotNull + @Column(name = "uri", nullable = false) + private String uri; + + @NotBlank + @NotNull + @Column(name = "display_name", nullable = false) + private String displayName; + + @NotNull + @Column(name = "note", nullable = false) + private String note; + + @Column(name = "metadata") + private String metadata; + + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "sync_service_status", nullable = false) + private SyncServiceStatus status; + + @Column(name = "last_contact_at") + private Timestamp lastContactAt; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "directory") + private List stations; + + public List getStations() { + if (stations == null) { + stations = new ArrayList<>(); + } + return stations; + } + + public Boolean isDeletable() { + if (getStatus().equals(SyncServiceStatus.SYNCING)) { + return false; + } + return getStations().isEmpty(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java new file mode 100644 index 0000000..f1c7074 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java @@ -0,0 +1,89 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; +import java.util.List; + +@Entity(name = "Train") +@Table(name = "train") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder(toBuilder = true) +public class Train extends BaseEntity { + + @NotBlank + @NotNull + @Column(name = "uri", nullable = false) + private String uri; + + @NotBlank + @NotNull + @Column(name = "title", nullable = false) + private String title; + + @NotNull + @Column(name = "description", nullable = false) + private String description; + + @NotNull + @Column(name = "keywords", nullable = false) + private String keywords; + + @Column(name = "metadata") + private String metadata; + + @Column(name = "soft_deleted") + private Boolean softDeleted; + + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "sync_item_status", nullable = false) + private SyncItemStatus status; + + @ManyToOne + @JoinColumn(name = "train_garage_id") + private TrainGarage garage; + + @Column(name = "last_contact_at") + private Timestamp lastContactAt; + + @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @JoinTable( + name = "train_train_type", + joinColumns = @JoinColumn(name = "train_id"), + inverseJoinColumns = @JoinColumn(name = "train_type_id")) + private List types; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java new file mode 100644 index 0000000..7073bc1 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java @@ -0,0 +1,89 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +@Entity(name = "TrainGarage") +@Table(name = "train_garage") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class TrainGarage extends BaseEntity { + + @NotBlank + @NotNull + @Column(name = "uri", nullable = false) + private String uri; + + @NotBlank + @NotNull + @Column(name = "display_name", nullable = false) + private String displayName; + + @NotNull + @Column(name = "note", nullable = false) + private String note; + + @Column(name = "metadata") + private String metadata; + + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "sync_service_status", nullable = false) + private SyncServiceStatus status; + + @Column(name = "last_contact_at") + private Timestamp lastContactAt; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "garage") + private List trains; + + public List getTrains() { + if (trains == null) { + trains = new ArrayList<>(); + } + return trains; + } + + public Boolean isDeletable() { + if (getStatus().equals(SyncServiceStatus.SYNCING)) { + return false; + } + return getTrains().isEmpty(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainType.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainType.java new file mode 100644 index 0000000..8b20494 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainType.java @@ -0,0 +1,63 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Entity(name = "TrainType") +@Table(name = "train_type") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class TrainType extends BaseEntity { + + @NotBlank + @Column(name = "uri", nullable = false) + private String uri; + + @NotBlank + @Column(name = "title", nullable = false) + private String title; + + @NotNull + @Column(name = "note", nullable = false) + private String note; + + @ManyToMany(mappedBy = "types", fetch = FetchType.LAZY) + private List trains; + + @ManyToMany(mappedBy = "types", fetch = FetchType.LAZY) + private List stations; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/base/BaseEntity.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/base/BaseEntity.java new file mode 100644 index 0000000..649c14a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/base/BaseEntity.java @@ -0,0 +1,79 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model.base; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; +import java.util.Objects; +import java.util.UUID; + +@MappedSuperclass +@SuperBuilder(toBuilder = true) +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @NotNull + @Column(name = "uuid", nullable = false, updatable = false) + private UUID uuid; + + @CreationTimestamp + @NotNull + @Column(name = "created_at", nullable = false, updatable = false) + private Timestamp createdAt; + + @UpdateTimestamp + @NotNull + @Column(name = "updated_at", nullable = false) + private Timestamp updatedAt; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final BaseEntity that = (BaseEntity) o; + return uuid.equals(that.uuid); + } + + @Override + public int hashCode() { + return Objects.hash(uuid); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/ArtifactStorage.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/ArtifactStorage.java new file mode 100644 index 0000000..b9cf6e9 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/ArtifactStorage.java @@ -0,0 +1,29 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model.enums; + +public enum ArtifactStorage { + POSTGRES, + S3, + LOCALFS +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobStatus.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobStatus.java new file mode 100644 index 0000000..dc151ea --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobStatus.java @@ -0,0 +1,34 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model.enums; + +public enum JobStatus { + PREPARED, + QUEUED, + RUNNING, + FINISHED, + ABORTING, + ABORTED, + ERRORED, + FAILED +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/RunStatus.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/RunStatus.java new file mode 100644 index 0000000..8002b3e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/RunStatus.java @@ -0,0 +1,34 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model.enums; + +public enum RunStatus { + SCHEDULED, + PREPARED, + RUNNING, + FINISHED, + ABORTING, + ABORTED, + ERRORED, + FAILED +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/SyncItemStatus.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/SyncItemStatus.java new file mode 100644 index 0000000..ab2629a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/SyncItemStatus.java @@ -0,0 +1,28 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model.enums; + +public enum SyncItemStatus { + SYNCED, + DELETED +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/SyncServiceStatus.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/SyncServiceStatus.java new file mode 100644 index 0000000..c4c7170 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/SyncServiceStatus.java @@ -0,0 +1,31 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.model.enums; + +public enum SyncServiceStatus { + SYNCED, + SYNCING, + UNREACHABLE, + INVALID, + DELETED +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobArtifactRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobArtifactRepository.java new file mode 100644 index 0000000..7ab600b --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobArtifactRepository.java @@ -0,0 +1,63 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.JobArtifact; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.UUID; + +@Repository +public interface JobArtifactRepository extends BaseRepository { + + @Query( + """ + SELECT ja + FROM JobArtifact ja + JOIN Job j ON ja.job = j + JOIN PlanTarget pt ON j.target = pt + JOIN Plan p ON pt.plan = p + WHERE p.uuid = :planUuid + AND p.publishArtifacts = TRUE + AND pt.publishArtifacts = TRUE + """ + ) + List getPublicJobArtifactsOfPlan(UUID planUuid); + + @Query( + """ + SELECT ja + FROM JobArtifact ja + JOIN Job j ON ja.job = j + JOIN PlanTarget pt ON j.target = pt + JOIN Plan p ON pt.plan = p + WHERE pt.uuid = :targetUuid + AND p.publishArtifacts = TRUE + AND pt.publishArtifacts = TRUE + """ + ) + List getPublicJobArtifactsOfTarget(UUID targetUuid); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobEventRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobEventRepository.java new file mode 100644 index 0000000..6b40333 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobEventRepository.java @@ -0,0 +1,39 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.model.JobEvent; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.stereotype.Repository; + +import java.sql.Timestamp; +import java.util.List; + +@Repository +public interface JobEventRepository extends BaseRepository { + + List findAllByJobOrderByOccurredAtAsc(Job job); + + List findAllByJobAndOccurredAtAfterOrderByOccurredAtAsc(Job job, Timestamp threshold); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobRepository.java new file mode 100644 index 0000000..e870830 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobRepository.java @@ -0,0 +1,38 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface JobRepository extends BaseRepository { + + Page findAllByRunUuid(UUID runUuid, Pageable pageable); + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/PlanRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/PlanRepository.java new file mode 100644 index 0000000..ec4ecf7 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/PlanRepository.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.Plan; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + +@Repository +public interface PlanRepository extends BaseRepository { + + Page findByDisplayNameContainingIgnoreCase(String query, Pageable pageable); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/PlanTargetRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/PlanTargetRepository.java new file mode 100644 index 0000000..7cefd36 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/PlanTargetRepository.java @@ -0,0 +1,31 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.PlanTarget; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PlanTargetRepository extends BaseRepository { +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java new file mode 100644 index 0000000..3047e4d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java @@ -0,0 +1,57 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.Run; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.sql.Timestamp; +import java.util.UUID; + +@Repository +public interface RunRepository extends BaseRepository { + + Page findAllByPlanUuid(UUID planUuid, Pageable pageable); + + @Query(""" + SELECT r + FROM Run r + WHERE + ( + r.status = 'SCHEDULED' + AND r.shouldStartAt IS NOT NULL + AND r.shouldStartAt < :timestamp + ) OR ( + r.status = 'PREPARED' + AND r.startedAt IS NULL + AND r.shouldStartAt IS NULL + ) + ORDER BY r.shouldStartAt ASC + """) + Page findRunToDispatch(@Param("timestamp") Timestamp timestamp, Pageable pageable); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationDirectoryRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationDirectoryRepository.java new file mode 100644 index 0000000..cc7e656 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationDirectoryRepository.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + +@Repository +public interface StationDirectoryRepository extends BaseRepository { + + Page findByDisplayNameContainingIgnoreCase(String query, Pageable pageable); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationRepository.java new file mode 100644 index 0000000..2d26f3b --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationRepository.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.Station; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface StationRepository extends BaseRepository { + + Page findAllBySoftDeletedIsFalse(Pageable pageable); + + Page findByTitleContainingIgnoreCaseAndSoftDeletedIsFalse( + String query, Pageable pageable + ); + + @Query(""" + SELECT s + FROM Station s + WHERE LOWER(s.title) LIKE %:query% + AND s.softDeleted IS FALSE + ORDER BY s.title""") + List findByTitleContainingIgnoreCase(@Param("query") String query); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainGarageRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainGarageRepository.java new file mode 100644 index 0000000..7aa0638 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainGarageRepository.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + +@Repository +public interface TrainGarageRepository extends BaseRepository { + + Page findByDisplayNameContainingIgnoreCase(String query, Pageable pageable); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainRepository.java new file mode 100644 index 0000000..b9fac9a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainRepository.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.Train; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface TrainRepository extends BaseRepository { + + Page findAllBySoftDeletedIsFalse(Pageable pageable); + + Page findByTitleContainingIgnoreCaseAndSoftDeletedIsFalse( + String query, Pageable pageable + ); + + @Query(""" + SELECT t + FROM Train t + WHERE LOWER(t.title) LIKE %:query% + AND t.softDeleted IS FALSE + ORDER BY t.title""") + List findByTitleContainingIgnoreCase(@Param("query") String query); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java new file mode 100644 index 0000000..9641abc --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository; + +import org.fairdatatrain.trainhandler.data.model.TrainType; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + +@Repository +public interface TrainTypeRepository extends BaseRepository { + + Page findByTitleContainingIgnoreCase(String query, Pageable pageable); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/base/BaseRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/base/BaseRepository.java new file mode 100644 index 0000000..ca78e8f --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/base/BaseRepository.java @@ -0,0 +1,32 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.data.repository.base; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.NoRepositoryBean; + +import java.util.UUID; + +@NoRepositoryBean +public interface BaseRepository extends JpaRepository { +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/exception/CannotPerformException.java b/src/main/java/org/fairdatatrain/trainhandler/exception/CannotPerformException.java new file mode 100644 index 0000000..af30e1d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/exception/CannotPerformException.java @@ -0,0 +1,46 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Map; +import java.util.UUID; + +@AllArgsConstructor +@Getter +public class CannotPerformException extends Exception { + + private final String entityName; + + private final String operation; + + private final Map fields; + + public CannotPerformException(String entityName, UUID uuid, String operation, String message) { + this.entityName = entityName; + this.operation = operation; + this.fields = Map.of("uuid", uuid.toString(), "info", message); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/exception/JobSecurityException.java b/src/main/java/org/fairdatatrain/trainhandler/exception/JobSecurityException.java new file mode 100644 index 0000000..9e2e2fa --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/exception/JobSecurityException.java @@ -0,0 +1,33 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class JobSecurityException extends Exception { + + private final String message; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/exception/NotFoundException.java b/src/main/java/org/fairdatatrain/trainhandler/exception/NotFoundException.java new file mode 100644 index 0000000..a0c4420 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/exception/NotFoundException.java @@ -0,0 +1,43 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Map; +import java.util.UUID; + +@AllArgsConstructor +@Getter +public class NotFoundException extends Exception { + + private final String entityName; + + private final Map fields; + + public NotFoundException(String entityName, UUID uuid) { + this.entityName = entityName; + this.fields = Map.of("uuid", uuid.toString()); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/exception/NotImplementedException.java b/src/main/java/org/fairdatatrain/trainhandler/exception/NotImplementedException.java new file mode 100644 index 0000000..a3ac0c4 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/exception/NotImplementedException.java @@ -0,0 +1,26 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.exception; + +public class NotImplementedException extends Exception { +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/actuator/AppInfoContributor.java b/src/main/java/org/fairdatatrain/trainhandler/service/actuator/AppInfoContributor.java new file mode 100644 index 0000000..b1a59fd --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/actuator/AppInfoContributor.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.actuator; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.stereotype.Component; + +import static java.lang.String.format; + +@Component +public class AppInfoContributor implements InfoContributor { + + @Value("${git.branch}") + private String branch; + + @Value("${git.commit.id.abbrev}") + private String commitShort; + + @Value("${git.tags}") + private String tag; + + @Value("${build.time}") + private String buildTime; + + @Override + public void contribute(Info.Builder builder) { + builder.withDetail("name", "FAIR Data Point"); + builder.withDetail("version", getAppVersion()); + builder.withDetail("builtAt", buildTime); + } + + public String getAppVersion() { + String version = branch; + if (tag != null && !tag.isBlank()) { + version = tag; + } + return format("%s~%s", version, commitShort); + } + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java new file mode 100644 index 0000000..1c958e0 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java @@ -0,0 +1,57 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.async; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.api.dto.job.JobDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunDTO; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import static java.lang.String.format; + +@Component +@AllArgsConstructor +@Slf4j +public class AsyncEventPublisher { + + private final ApplicationEventPublisher publisher; + + public void publishNewJobEventNotification(final RunDTO run, final JobDTO job) { + log.info(format( + "Publishing new job notification for job %s (run %s)", + job.getUuid(), run.getUuid() + )); + publisher.publishEvent(new JobNotification(this, run, job)); + } + + public void publishNewJobEventNotification(final RunDTO run) { + log.info(format( + "Publishing new run notification for run %s", + run.getUuid() + )); + publisher.publishEvent(new JobNotification(this, run, null)); + } + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotification.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotification.java new file mode 100644 index 0000000..89379dd --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotification.java @@ -0,0 +1,48 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.async; + +import org.fairdatatrain.trainhandler.api.dto.job.JobDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunDTO; +import org.springframework.context.ApplicationEvent; + +public class JobNotification extends ApplicationEvent { + + private final RunDTO run; + + private final JobDTO job; + + JobNotification(Object source, RunDTO run, JobDTO job) { + super(source); + this.run = run; + this.job = job; + } + + public RunDTO getRun() { + return run; + } + + public JobDTO getJob() { + return job; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java new file mode 100644 index 0000000..6a28e4a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java @@ -0,0 +1,127 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.async; + +import lombok.RequiredArgsConstructor; +import lombok.Synchronized; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.api.dto.job.JobDTO; +import org.fairdatatrain.trainhandler.config.DispatcherConfig; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.async.DeferredResult; + +import java.time.Instant; +import java.util.*; + +import static java.lang.String.format; + +@Component +@Slf4j +@RequiredArgsConstructor +public class JobNotificationListener { + + private final DispatcherConfig config; + + private final Map>> queues = new HashMap<>(); + + @EventListener + public void handleJobEventNotification(JobNotification notification) { + if (notification.getJob() != null) { + log.debug("Handling new job notification"); + updateResults(notification.getJob()); + } + } + + @Synchronized + public void updateResults(JobDTO job) { + log.info(format( + "Updating results for job '%s' (version '%s'): start", + job.getUuid(), job.getVersion() + )); + final Instant now = Instant.now(); + if (queues.containsKey(job.getUuid())) { + final List> remaining = new ArrayList<>(); + queues.get(job.getUuid()) + .stream() + .filter(container -> container.getTimeoutsAt().isAfter(now)) + .forEach(container -> { + if (container.getVersion() <= job.getVersion()) { + log.info(format("Sending job for requested version: %s", + container.getVersion())); + container.getResult().setResult(job); + } + else { + remaining.add(container); + } + }); + log.debug(format( + "Job %s queue size before %s and after %s", + job.getUuid(), queues.get(job.getUuid()).size(), remaining.size() + )); + queues.put(job.getUuid(), remaining); + } + log.info(format( + "Updating results for job '%s' (version '%s'): done", + job.getUuid(), job.getVersion() + )); + } + + @Synchronized + public void enqueue(UUID jobUuid, Long version, DeferredResult result) { + log.info(format( + "Enqueueing deferred result for job '%s' (version '%s')", + jobUuid, version + )); + final Instant now = Instant.now(); + if (!queues.containsKey(jobUuid)) { + log.debug("Initializing new job queue"); + queues.put(jobUuid, new ArrayList<>()); + } + else { + log.debug("Cleaning up existing job queue"); + final List> remaining = new ArrayList<>(); + queues.get(jobUuid).forEach(container -> { + if (container.getTimeoutsAt().isAfter(now)) { + remaining.add(container); + } + }); + log.debug(format( + "Existing job queue size before %s and after %s", + queues.get(jobUuid).size(), remaining.size() + )); + queues.put(jobUuid, remaining); + } + queues.get(jobUuid).add( + new PollContainer<>( + version, + config.getPolling().getTimeoutForCurrentPoll(), + result + ) + ); + log.debug(format( + "Enqueueing deferred result for job '%s' (version '%s'): done", + jobUuid, version + )); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/PollContainer.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/PollContainer.java new file mode 100644 index 0000000..903c5ca --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/PollContainer.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.async; + +import lombok.*; +import org.springframework.web.context.request.async.DeferredResult; + +import java.time.Instant; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder +public class PollContainer implements Comparable> { + + private Long version; + + private Instant timeoutsAt; + + private DeferredResult result; + + @Override + public int compareTo(PollContainer o) { + return version.compareTo(o.version); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java new file mode 100644 index 0000000..427fbb5 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java @@ -0,0 +1,126 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.async; + +import lombok.RequiredArgsConstructor; +import lombok.Synchronized; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.api.dto.run.RunDTO; +import org.fairdatatrain.trainhandler.config.DispatcherConfig; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.async.DeferredResult; + +import java.time.Instant; +import java.util.*; + +import static java.lang.String.format; + +@Component +@Slf4j +@RequiredArgsConstructor +public class RunNotificationListener { + + private final DispatcherConfig config; + + private final Map>> queues = new HashMap<>(); + + @EventListener + public void handleJobEventNotification(JobNotification notification) { + log.debug("Handling new run notification"); + updateResults(notification.getRun()); + } + + @Synchronized + public void updateResults(RunDTO run) { + log.info(format( + "Updating results for run '%s' (version '%s')", + run.getUuid(), run.getVersion()) + ); + final Instant now = Instant.now(); + if (queues.containsKey(run.getUuid())) { + final List> remaining = new ArrayList<>(); + queues.get(run.getUuid()) + .stream() + .filter(container -> container.getTimeoutsAt().isAfter(now)) + .forEach(container -> { + if (container.getVersion() <= run.getVersion()) { + log.info(format("Sending run for requested version: %s", + container.getVersion())); + container.getResult().setResult(run); + } + else { + remaining.add(container); + } + }); + log.debug(format( + "Run %s queue size before %s and after %s", + run.getUuid(), queues.get(run.getUuid()).size(), remaining.size() + )); + queues.put(run.getUuid(), remaining); + } + log.info(format( + "Updating results for run '%s' (version '%s'): done", + run.getUuid(), run.getVersion() + )); + } + + @Synchronized + public void enqueue(UUID runUuid, Long version, DeferredResult result) { + log.info(format( + "Enqueueing deferred result for run '%s' (version '%s')", + runUuid, version + )); + final Instant now = Instant.now(); + if (!queues.containsKey(runUuid)) { + log.debug("Initializing new run queue"); + queues.put(runUuid, new ArrayList<>()); + } + else { + log.debug("Cleaning up existing job queue"); + final List> remaining = new ArrayList<>(); + queues.get(runUuid).forEach(container -> { + if (container.getTimeoutsAt().isAfter(now)) { + remaining.add(container); + } + }); + log.debug(format( + "Existing run queue size before %s and after %s", + queues.get(runUuid).size(), remaining.size() + )); + queues.put(runUuid, remaining); + } + queues.get(runUuid).add( + new PollContainer<>( + version, + config.getPolling().getTimeoutForCurrentPoll(), + result + ) + ); + log.debug(format( + "Enqueueing deferred result for run '%s' (version '%s'): done", + runUuid, version + )); + } + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchMapper.java new file mode 100644 index 0000000..4dde076 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchMapper.java @@ -0,0 +1,57 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.dispatch; + +import org.fairdatatrain.trainhandler.api.controller.JobArtifactController; +import org.fairdatatrain.trainhandler.api.controller.JobEventController; +import org.fairdatatrain.trainhandler.data.model.Job; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class DispatchMapper { + + @Value("${dispatcher.dispatch.root}") + private String dispatchRoot; + + public DispatchPayload toPayload(Job job) { + return DispatchPayload + .builder() + .jobUuid(job.getUuid()) + .secret(job.getSecret()) + .trainUri(job.getRun().getPlan().getTrain().getUri()) + .callbackEventLocation(makeCallback( + JobEventController.EVENT_CALLBACK_LOCATION, job + )) + .callbackArtifactLocation(makeCallback( + JobArtifactController.ARTIFACT_CALLBACK_LOCATION, job + )) + .build(); + } + + private String makeCallback(String fragment, Job job) { + return dispatchRoot + "/runs" + fragment + .replace("{runUuid}", job.getRun().getUuid().toString()) + .replace("{jobUuid}", job.getUuid().toString()); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchPayload.java b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchPayload.java new file mode 100644 index 0000000..43a2263 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchPayload.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.dispatch; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class DispatchPayload { + + @NotNull + private UUID jobUuid; + + @NotNull + private String secret; + + @NotNull + private String callbackEventLocation; + + @NotNull + private String callbackArtifactLocation; + + @NotNull + private String trainUri; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java new file mode 100644 index 0000000..4cb146c --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java @@ -0,0 +1,77 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.dispatch; + +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientException; + +import static java.lang.String.format; + +@Slf4j +@Service +@RequiredArgsConstructor +public class DispatchService { + + private final DispatchMapper dispatchMapper; + + private final WebClient webClient; + + public void dispatch(Job job) throws JsonProcessingException { + if (!job.getStatus().equals(JobStatus.PREPARED)) { + throw new RuntimeException("Job not in state PREPARED, cannot dispatch"); + } + final DispatchPayload payload = dispatchMapper.toPayload(job); + // TODO: should it POST directly to the station URI or some other endpoint? + // TODO: what should be the response? + final String uri = job.getTarget().getStation().getUri(); + log.info(format("Dispatching job %s by POST to %s", job.getUuid(), uri)); + try { + final String response = webClient + .post() + .uri(uri) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(payload) + .retrieve() + .bodyToMono(String.class) + .block(); + } + catch (WebClientException exception) { + exception.printStackTrace(); + log.warn(format( + "Dispatching job %s failed: %s", job.getUuid(), exception.getMessage() + )); + throw new RuntimeException( + "Station responded with status: " + exception.getMessage() + ); + } + log.info(format("Dispatching job %s accepted", job.getUuid())); + } + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/indexing/BaseIndexer.java b/src/main/java/org/fairdatatrain/trainhandler/service/indexing/BaseIndexer.java new file mode 100644 index 0000000..3076703 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/indexing/BaseIndexer.java @@ -0,0 +1,84 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.indexing; + +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.vocabulary.LDP; +import org.eclipse.rdf4j.rio.RDFFormat; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientException; + +import java.net.URI; +import java.util.List; + +import static java.lang.String.format; +import static java.util.Optional.ofNullable; +import static org.fairdatatrain.trainhandler.utils.RdfIOUtils.read; + +@Slf4j +@Service +@RequiredArgsConstructor +public class BaseIndexer { + + private final WebClient webClient; + + public List extractChildren(Model model) { + return model + .filter(null, LDP.CONTAINS, null) + .parallelStream() + .map(statement -> statement.getObject().stringValue()) + .toList(); + } + + @SneakyThrows + public Model makeRequest(String uri) { + log.info(format("Making request to '%s'", uri)); + try { + final String response = webClient + .get() + .uri(URI.create(uri)) + .accept(MediaType.parseMediaType(RDFFormat.TURTLE.getDefaultMIMEType())) + .retrieve() + .bodyToMono(String.class) + .block(); + log.info(format("Request to '%s' successfully received", uri)); + final Model result = read(response, uri, RDFFormat.TURTLE); + log.info(format("Request to '%s' successfully parsed", uri)); + return result; + } + catch (WebClientException exception) { + log.info(format("Request to '%s' failed", uri)); + throw new HttpClientErrorException( + HttpStatus.INTERNAL_SERVER_ERROR, + ofNullable(exception.getMessage()).orElse("HTTP request failed") + ); + } + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java new file mode 100644 index 0000000..a61b637 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java @@ -0,0 +1,144 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.job; + +import org.fairdatatrain.trainhandler.api.dto.job.JobDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.*; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; +import org.fairdatatrain.trainhandler.service.job.artifact.JobArtifactMapper; +import org.fairdatatrain.trainhandler.service.job.event.JobEventMapper; +import org.fairdatatrain.trainhandler.service.run.RunMapper; +import org.fairdatatrain.trainhandler.service.station.StationMapper; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Comparator; +import java.util.Optional; +import java.util.UUID; + +import static org.fairdatatrain.trainhandler.utils.RandomUtils.randomSecret; + +@Component +public class JobMapper { + + private final StationMapper stationMapper; + + private final RunMapper runMapper; + + private final JobEventMapper jobEventMapper; + + private final JobArtifactMapper jobArtifactMapper; + + public JobMapper( + StationMapper stationMapper, + JobEventMapper jobEventMapper, + JobArtifactMapper jobArtifactMapper, + @Lazy RunMapper runMapper + ) { + this.stationMapper = stationMapper; + this.runMapper = runMapper; + this.jobEventMapper = jobEventMapper; + this.jobArtifactMapper = jobArtifactMapper; + } + + public JobSimpleDTO toSimpleDTO(Job job) { + return JobSimpleDTO.builder() + .uuid(job.getUuid()) + .remoteId(job.getRemoteId()) + .status(job.getStatus()) + .startedAt( + Optional.ofNullable(job.getStartedAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .finishedAt( + Optional.ofNullable(job.getFinishedAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) + .artifacts(job + .getArtifacts() + .stream() + .sorted(Comparator.comparing(JobArtifact::getOccurredAt)) + .map(jobArtifactMapper::toDTO) + .toList() + ) + .runUuid(job.getRun().getUuid()) + .version(job.getVersion()) + .build(); + } + + public JobDTO toDTO(Job job) { + return JobDTO.builder() + .uuid(job.getUuid()) + .remoteId(job.getRemoteId()) + .status(job.getStatus()) + .startedAt( + Optional.ofNullable(job.getStartedAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .finishedAt( + Optional.ofNullable(job.getFinishedAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) + .run(runMapper.toSimpleDTO(job.getRun())) + .events(job + .getEvents() + .stream() + .sorted(Comparator.comparing(JobEvent::getOccurredAt)) + .map(jobEventMapper::toDTO) + .toList() + ) + .artifacts(job + .getArtifacts() + .stream() + .sorted(Comparator.comparing(JobArtifact::getOccurredAt)) + .map(jobArtifactMapper::toDTO) + .toList() + ) + .createdAt(job.getCreatedAt().toInstant().toString()) + .updatedAt(job.getUpdatedAt().toInstant().toString()) + .version(job.getVersion()) + .build(); + } + + public Job fromTarget(Run run, PlanTarget target) { + return Job.builder() + .uuid(UUID.randomUUID()) + .status(JobStatus.PREPARED) + .target(target) + .run(run) + .secret(randomSecret()) + .createdAt(run.getCreatedAt()) + .updatedAt(run.getUpdatedAt()) + .version(run.getVersion()) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java new file mode 100644 index 0000000..080b47e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java @@ -0,0 +1,93 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.job; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.api.dto.job.JobDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.repository.JobRepository; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.async.JobNotificationListener; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.request.async.DeferredResult; + +import java.util.UUID; + +import static java.lang.String.format; + +@Service +@RequiredArgsConstructor +@Slf4j +public class JobService { + + public static final String ENTITY_NAME = "Job"; + + private final JobRepository jobRepository; + + private final JobMapper jobMapper; + + private final JobNotificationListener jobNotificationListener; + + public Job getByIdOrThrow(UUID uuid) throws NotFoundException { + return jobRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public Page getJobsForRun(UUID runUuid, Pageable pageable) { + return jobRepository + .findAllByRunUuid(runUuid, pageable) + .map(jobMapper::toSimpleDTO); + } + + public JobDTO getSingle(UUID runUuid, UUID jobUuid) throws NotFoundException { + final Job job = getByIdOrThrow(jobUuid); + if (!job.getRun().getUuid().equals(runUuid)) { + throw new NotFoundException(ENTITY_NAME, jobUuid); + } + return jobMapper.toDTO(job); + } + + @Transactional + public void poll( + UUID jobUuid, + DeferredResult result, + Long version, + JobDTO currentJob + ) { + log.info(format("REQUESTED VERSION: %s", version)); + log.info(format("CURRENT VERSION: %s", currentJob.getVersion())); + if (version < currentJob.getVersion()) { + result.setResult(currentJob); + } + else { + log.info("No job update at this point, enqueueing..."); + jobNotificationListener.enqueue(jobUuid, version, result); + } + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactMapper.java new file mode 100644 index 0000000..d291a6b --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactMapper.java @@ -0,0 +1,72 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.job.artifact; + +import org.fairdatatrain.trainhandler.api.dto.job.JobArtifactCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobArtifactDTO; +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.model.JobArtifact; +import org.fairdatatrain.trainhandler.data.model.enums.ArtifactStorage; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.util.UUID; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Component +public class JobArtifactMapper { + public JobArtifactDTO toDTO(JobArtifact artifact) { + return JobArtifactDTO + .builder() + .uuid(artifact.getUuid()) + .displayName(artifact.getDisplayName()) + .filename(artifact.getFilename()) + .bytesize(artifact.getBytesize()) + .contentType(artifact.getContentType()) + .hash(artifact.getHash()) + .occurredAt(artifact.getOccurredAt().toInstant().toString()) + .createdAt(artifact.getCreatedAt().toInstant().toString()) + .updatedAt(artifact.getUpdatedAt().toInstant().toString()) + .build(); + } + + public JobArtifact fromCreateDTO(JobArtifactCreateDTO reqDto, Job job, byte[] data) { + final Timestamp now = now(); + return JobArtifact + .builder() + .uuid(UUID.randomUUID()) + .displayName(reqDto.getDisplayName()) + .filename(reqDto.getFilename()) + .hash(reqDto.getHash()) + .bytesize(reqDto.getBytesize()) + .contentType(reqDto.getContentType()) + .data(data) + .storage(ArtifactStorage.POSTGRES) + .occurredAt(Timestamp.from(reqDto.getOccurredAt())) + .job(job) + .createdAt(now) + .updatedAt(now) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactService.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactService.java new file mode 100644 index 0000000..94fc96b --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactService.java @@ -0,0 +1,158 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.job.artifact; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.api.dto.job.JobArtifactCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobArtifactDTO; +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.model.JobArtifact; +import org.fairdatatrain.trainhandler.data.model.enums.ArtifactStorage; +import org.fairdatatrain.trainhandler.data.repository.JobArtifactRepository; +import org.fairdatatrain.trainhandler.data.repository.JobRepository; +import org.fairdatatrain.trainhandler.data.repository.RunRepository; +import org.fairdatatrain.trainhandler.exception.JobSecurityException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.job.JobService; +import org.fairdatatrain.trainhandler.service.run.RunService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.validation.ValidationException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import static java.lang.String.format; +import static org.fairdatatrain.trainhandler.utils.HashUtils.bytesToHex; + +@Service +@RequiredArgsConstructor +@Slf4j +public class JobArtifactService { + + public static final String ENTITY_NAME = "JobArtifact"; + + private final RunRepository runRepository; + + private final JobRepository jobRepository; + + private final JobArtifactRepository jobArtifactRepository; + + private final JobArtifactMapper jobArtifactMapper; + + private final JobService jobService; + + @PersistenceContext + private final EntityManager entityManager; + + public JobArtifact getByIdOrThrow(UUID uuid) throws NotFoundException { + return jobArtifactRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public List getArtifacts(UUID runUuid, UUID jobUuid) throws NotFoundException { + final Job job = jobService.getByIdOrThrow(jobUuid); + if (!job.getRun().getUuid().equals(runUuid)) { + throw new NotFoundException(JobService.ENTITY_NAME, jobUuid); + } + return job.getArtifacts().stream().map(jobArtifactMapper::toDTO).toList(); + } + + public JobArtifact getArtifact( + UUID runUuid, UUID jobUuid, UUID artifactUuid + ) throws NotFoundException { + final JobArtifact artifact = getByIdOrThrow(artifactUuid); + if (!artifact.getJob().getUuid().equals(jobUuid)) { + throw new NotFoundException(JobService.ENTITY_NAME, jobUuid); + } + if (!artifact.getJob().getRun().getUuid().equals(runUuid)) { + throw new NotFoundException(RunService.ENTITY_NAME, runUuid); + } + return artifact; + } + + public byte[] getArtifactData(JobArtifact artifact) { + if (artifact.getStorage().equals(ArtifactStorage.POSTGRES)) { + return artifact.getData(); + } + throw new RuntimeException( + format("Unsupported artifact storage: %s", artifact.getStorage()) + ); + } + + @Transactional + public JobArtifactDTO createArtifact( + UUID runUuid, UUID jobUuid, JobArtifactCreateDTO reqDto + ) throws NotFoundException, JobSecurityException { + final Job job = jobService.getByIdOrThrow(jobUuid); + if (!job.getRun().getUuid().equals(runUuid)) { + throw new NotFoundException(JobService.ENTITY_NAME, jobUuid); + } + if (!Objects.equals(job.getSecret(), reqDto.getSecret())) { + throw new JobSecurityException("Incorrect secret for creating job event"); + } + if (job.getRemoteId() == null) { + job.setRemoteId(reqDto.getRemoteId()); + } + else if (!Objects.equals(job.getRemoteId(), reqDto.getRemoteId())) { + throw new JobSecurityException("Incorrect remote ID for creating job event"); + } + final byte[] data = Base64.getDecoder().decode(reqDto.getBase64data()); + validate(reqDto, data); + final JobArtifact jobArtifact = jobArtifactRepository.saveAndFlush( + jobArtifactMapper.fromCreateDTO(reqDto, job, data) + ); + job.setVersion(jobArtifact.getUpdatedAt().toInstant().toEpochMilli()); + jobRepository.saveAndFlush(job); + job.getRun().setVersion(job.getVersion()); + runRepository.saveAndFlush(job.getRun()); + entityManager.flush(); + entityManager.refresh(jobArtifact); + return jobArtifactMapper.toDTO(jobArtifact); + } + + private void validate(JobArtifactCreateDTO reqDto, byte[] data) { + final MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-256"); + } + catch (NoSuchAlgorithmException exc) { + throw new RuntimeException("SHA-256 hashing is not supported"); + } + final String hash = bytesToHex(digest.digest(data)); + if (data.length != reqDto.getBytesize()) { + throw new ValidationException("Bytesize does not match"); + } + if (!hash.equals(reqDto.getHash())) { + throw new ValidationException("SHA-256 hash does not match"); + } + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventMapper.java new file mode 100644 index 0000000..9c4ff06 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventMapper.java @@ -0,0 +1,63 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.job.event; + +import org.fairdatatrain.trainhandler.api.dto.job.JobEventCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobEventDTO; +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.model.JobEvent; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.util.UUID; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Component +public class JobEventMapper { + public JobEventDTO toDTO(JobEvent jobEvent) { + return JobEventDTO + .builder() + .uuid(jobEvent.getUuid()) + .message(jobEvent.getMessage()) + .resultStatus(jobEvent.getResultStatus()) + .createdAt(jobEvent.getCreatedAt().toInstant().toString()) + .updatedAt(jobEvent.getUpdatedAt().toInstant().toString()) + .occurredAt(jobEvent.getOccurredAt().toInstant().toString()) + .build(); + } + + public JobEvent fromCreateDTO(JobEventCreateDTO reqDto, Job job) { + final Timestamp now = now(); + return JobEvent + .builder() + .uuid(UUID.randomUUID()) + .message(reqDto.getMessage()) + .resultStatus(reqDto.getResultStatus()) + .occurredAt(Timestamp.from(reqDto.getOccurredAt())) + .job(job) + .createdAt(now) + .updatedAt(now) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java new file mode 100644 index 0000000..4555ce5 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java @@ -0,0 +1,171 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.job.event; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.api.dto.job.JobDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobEventCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobEventDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunDTO; +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.model.JobEvent; +import org.fairdatatrain.trainhandler.data.model.Run; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; +import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; +import org.fairdatatrain.trainhandler.data.repository.JobEventRepository; +import org.fairdatatrain.trainhandler.data.repository.JobRepository; +import org.fairdatatrain.trainhandler.data.repository.RunRepository; +import org.fairdatatrain.trainhandler.exception.JobSecurityException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.async.AsyncEventPublisher; +import org.fairdatatrain.trainhandler.service.job.JobMapper; +import org.fairdatatrain.trainhandler.service.job.JobService; +import org.fairdatatrain.trainhandler.service.run.RunMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.sql.Timestamp; +import java.util.*; + +@Service +@RequiredArgsConstructor +@Slf4j +public class JobEventService { + + public static final String ENTITY_NAME = "JobEvent"; + + private final RunRepository runRepository; + + private final JobRepository jobRepository; + + private final JobMapper jobMapper; + + private final RunMapper runMapper; + + private final JobService jobService; + + private final JobEventRepository jobEventRepository; + + private final JobEventMapper jobEventMapper; + + private final AsyncEventPublisher asyncEventPublisher; + + @PersistenceContext + private final EntityManager entityManager; + + public JobEvent getByIdOrThrow(UUID uuid) throws NotFoundException { + return jobEventRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public List getEvents(UUID runUuid, UUID jobUuid) throws NotFoundException { + final Job job = jobService.getByIdOrThrow(jobUuid); + if (!job.getRun().getUuid().equals(runUuid)) { + throw new NotFoundException(JobService.ENTITY_NAME, jobUuid); + } + return jobEventRepository + .findAllByJobOrderByOccurredAtAsc(job) + .parallelStream() + .map(jobEventMapper::toDTO) + .toList(); + } + + @Transactional + public JobEventDTO createEvent( + UUID runUuid, UUID jobUuid, JobEventCreateDTO reqDto + ) throws NotFoundException, JobSecurityException { + final Job job = jobService.getByIdOrThrow(jobUuid); + final Run run = job.getRun(); + if (!run.getUuid().equals(runUuid)) { + throw new NotFoundException(JobService.ENTITY_NAME, jobUuid); + } + if (!Objects.equals(job.getSecret(), reqDto.getSecret())) { + throw new JobSecurityException("Incorrect secret for creating job event"); + } + if (job.getRemoteId() == null) { + job.setRemoteId(reqDto.getRemoteId()); + } + else if (!Objects.equals(job.getRemoteId(), reqDto.getRemoteId())) { + throw new JobSecurityException("Incorrect remote ID for creating job event"); + } + if (reqDto.getResultStatus() != null) { + job.setStatus(reqDto.getResultStatus()); + if (job.getFinishedAt() == null && job.isFinished()) { + job.setFinishedAt(Timestamp.from(reqDto.getOccurredAt())); + } + run.setStatus(getNextRunStatus(job, reqDto)); + if (run.getFinishedAt() == null && run.isFinished()) { + run.setFinishedAt(Timestamp.from(reqDto.getOccurredAt())); + } + } + final JobEvent jobEvent = jobEventRepository.saveAndFlush( + jobEventMapper.fromCreateDTO(reqDto, job) + ); + job.setVersion(jobEvent.getUpdatedAt().toInstant().toEpochMilli()); + jobRepository.saveAndFlush(job); + job.getRun().setVersion(job.getVersion()); + runRepository.saveAndFlush(run); + entityManager.flush(); + entityManager.refresh(jobEvent); + return jobEventMapper.toDTO(jobEvent); + } + + @Transactional + public void notify(UUID jobUuid) throws NotFoundException { + final Job job = jobService.getByIdOrThrow(jobUuid); + final JobDTO jobDto = jobMapper.toDTO(job); + final RunDTO runDto = runMapper.toDTO(job.getRun()); + asyncEventPublisher.publishNewJobEventNotification(runDto, jobDto); + } + + private RunStatus getNextRunStatus(Job job, JobEventCreateDTO reqDto) { + final List jobStatuses = job.getRun().getJobs().stream().map(job1 -> { + if (job1.getUuid() == job.getUuid()) { + return reqDto.getResultStatus(); + } + else { + return job.getStatus(); + } + }).toList(); + if (jobStatuses.stream().anyMatch(JobStatus.RUNNING::equals)) { + return RunStatus.RUNNING; + } + if (jobStatuses.stream().anyMatch(JobStatus.ABORTING::equals)) { + return RunStatus.ABORTING; + } + if (jobStatuses.stream().allMatch(JobStatus.ERRORED::equals)) { + return RunStatus.ERRORED; + } + if (jobStatuses.stream().allMatch(JobStatus.FINISHED::equals)) { + return RunStatus.FINISHED; + } + if (jobStatuses.stream().anyMatch(JobStatus.FAILED::equals)) { + return RunStatus.FAILED; + } + return job.getRun().getStatus(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java new file mode 100644 index 0000000..d569c0d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java @@ -0,0 +1,118 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.plan; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.plan.*; +import org.fairdatatrain.trainhandler.data.model.Plan; +import org.fairdatatrain.trainhandler.data.model.PlanTarget; +import org.fairdatatrain.trainhandler.data.model.Train; +import org.fairdatatrain.trainhandler.service.station.StationMapper; +import org.fairdatatrain.trainhandler.service.train.TrainMapper; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.util.Collections; +import java.util.Comparator; +import java.util.UUID; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Component +@RequiredArgsConstructor +public class PlanMapper { + + private static final Comparator TARGET_CMP = + Comparator.comparing((PlanTargetDTO item) -> item.getStation().getTitle()); + + private final TrainMapper trainMapper; + + private final StationMapper stationMapper; + + public PlanDTO toDTO(Plan plan) { + return PlanDTO.builder() + .uuid(plan.getUuid()) + .displayName(plan.getDisplayName()) + .note(plan.getNote()) + .train(trainMapper.toDTO(plan.getTrain())) + .targets( + plan.getTargets() + .stream() + .map(this::toPlanTargetDTO) + .sorted(TARGET_CMP) + .toList() + ) + .publishArtifacts(plan.getPublishArtifacts()) + .createdAt(plan.getCreatedAt().toInstant().toString()) + .updatedAt(plan.getUpdatedAt().toInstant().toString()) + .build(); + } + + public PlanSimpleDTO toSimpleDTO(Plan plan) { + return PlanSimpleDTO.builder() + .uuid(plan.getUuid()) + .displayName(plan.getDisplayName()) + .note(plan.getNote()) + .train(trainMapper.toSimpleDTO(plan.getTrain())) + .targets( + plan.getTargets() + .stream() + .map(this::toPlanTargetDTO) + .sorted(TARGET_CMP) + .toList() + ) + .publishArtifacts(plan.getPublishArtifacts()) + .build(); + } + + public Plan fromCreateDTO(PlanCreateDTO reqDto, Train train) { + final Timestamp now = now(); + return Plan.builder() + .uuid(UUID.randomUUID()) + .displayName(reqDto.getDisplayName()) + .note(reqDto.getNote()) + .train(train) + .targets(Collections.emptyList()) + .publishArtifacts(reqDto.getPublishArtifacts()) + .createdAt(now) + .updatedAt(now) + .build(); + } + + public Plan fromUpdateDTO(PlanUpdateDTO reqDto, Plan plan, Train train) { + final Timestamp now = now(); + plan.setTrain(train); + plan.setDisplayName(reqDto.getDisplayName()); + plan.setNote(reqDto.getNote()); + plan.setUpdatedAt(now); + plan.setPublishArtifacts(reqDto.getPublishArtifacts()); + return plan; + } + + public PlanTargetDTO toPlanTargetDTO(PlanTarget target) { + return PlanTargetDTO.builder() + .station(stationMapper.toSimpleDTO(target.getStation())) + .publishArtifacts(target.getPublishArtifacts()) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java new file mode 100644 index 0000000..c8f9edd --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java @@ -0,0 +1,198 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.plan; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.plan.*; +import org.fairdatatrain.trainhandler.data.model.Plan; +import org.fairdatatrain.trainhandler.data.model.PlanTarget; +import org.fairdatatrain.trainhandler.data.model.Station; +import org.fairdatatrain.trainhandler.data.model.Train; +import org.fairdatatrain.trainhandler.data.repository.PlanRepository; +import org.fairdatatrain.trainhandler.data.repository.PlanTargetRepository; +import org.fairdatatrain.trainhandler.exception.CannotPerformException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.station.StationService; +import org.fairdatatrain.trainhandler.service.train.TrainService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static org.fairdatatrain.trainhandler.utils.CompareUtils.compareListContents; + +@Service +@RequiredArgsConstructor +public class PlanService { + + private static final String ENTITY_NAME = "Plan"; + + private final PlanRepository planRepository; + + private final PlanTargetRepository planTargetRepository; + + private final PlanMapper planMapper; + + private final PlanTargetMapper planTargetMapper; + + private final TrainService trainService; + + private final StationService stationService; + + @PersistenceContext + private final EntityManager entityManager; + + public Plan getByIdOrThrow(UUID uuid) throws NotFoundException { + return planRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public Page getPaged(String query, Pageable pageable) { + return planRepository + .findByDisplayNameContainingIgnoreCase(query, pageable) + .map(planMapper::toSimpleDTO); + } + + public PlanDTO getSingle(UUID uuid) throws NotFoundException { + final Plan plan = getByIdOrThrow(uuid); + return planMapper.toDTO(plan); + } + + @Transactional + public PlanDTO create(PlanCreateDTO reqDto) throws NotFoundException { + final Train train = trainService.getByIdOrThrow(reqDto.getTrainUuid()); + final Map stations = new HashMap<>(); + for (PlanTargetChangeDTO targetDto : reqDto.getTargets()) { + stations.put(targetDto.getStationUuid(), + stationService.getByIdOrThrow(targetDto.getStationUuid())); + } + final Plan newPlan = + planRepository.saveAndFlush(planMapper.fromCreateDTO(reqDto, train)); + entityManager.flush(); + entityManager.refresh(newPlan); + final List targets = + reqDto.getTargets() + .stream() + .map(targetDto -> { + return planTargetMapper.forPlan( + newPlan, + targetDto, + stations.get(targetDto.getStationUuid()) + ); + }) + .toList(); + newPlan.setTargets(targets); + planTargetRepository.saveAllAndFlush(targets); + entityManager.flush(); + entityManager.refresh(newPlan); + return planMapper.toDTO(newPlan); + } + + @Transactional + public PlanDTO update(UUID uuid, PlanUpdateDTO reqDto) + throws NotFoundException, CannotPerformException { + final String action = "update"; + final Plan plan = getByIdOrThrow(uuid); + final Set oldStationUuids = plan + .getTargets() + .stream() + .map(PlanTarget::getStation) + .map(Station::getUuid) + .collect(Collectors.toSet()); + final Map oldTargets = plan + .getTargets() + .stream() + .collect(Collectors.toMap(PlanTarget::getStationUuid, Function.identity())); + final Set newStationUuids = reqDto + .getTargets() + .stream() + .map(PlanTargetChangeDTO::getStationUuid) + .collect(Collectors.toSet()); + final boolean planExecuted = !plan.getRuns().isEmpty(); + final boolean changeTrain = reqDto.getTrainUuid() != plan.getTrain().getUuid(); + final boolean changeTargets = + compareListContents(newStationUuids, oldStationUuids); + if (planExecuted && changeTrain) { + throw new CannotPerformException( + ENTITY_NAME, + uuid, + action, + "It is not possible to change train of already used plan."); + } + if (planExecuted && changeTargets) { + throw new CannotPerformException( + ENTITY_NAME, + uuid, + action, + "It is not possible to change targets of already used plan."); + } + final Train train = trainService.getByIdOrThrow(reqDto.getTrainUuid()); + final List targets = new ArrayList<>(); + for (PlanTargetChangeDTO targetDto : reqDto.getTargets()) { + if (oldTargets.containsKey(targetDto.getStationUuid())) { + final PlanTarget target = oldTargets.get(targetDto.getStationUuid()); + target.setPublishArtifacts(targetDto.getPublishArtifacts()); + targets.add(planTargetRepository.saveAndFlush(target)); + } + else { + final Station station = + stationService.getByIdOrThrow(targetDto.getStationUuid()); + targets.add(planTargetRepository.saveAndFlush( + planTargetMapper.forPlan(plan, targetDto, station) + )); + } + } + for (PlanTarget target : plan.getTargets()) { + if (!newStationUuids.contains(target.getStation().getUuid())) { + planTargetRepository.delete(target); + } + } + plan.setTargets(targets); + final Plan updatedPlan = + planRepository.saveAndFlush(planMapper.fromUpdateDTO(reqDto, plan, train)); + entityManager.flush(); + entityManager.refresh(updatedPlan); + return planMapper.toDTO(updatedPlan); + } + + @Transactional + public void delete(UUID uuid) throws NotFoundException, CannotPerformException { + final Plan plan = getByIdOrThrow(uuid); + if (!plan.getRuns().isEmpty()) { + throw new CannotPerformException( + ENTITY_NAME, + uuid, + "delete", + format("There are already %d runs for this plan.", plan.getRuns().size())); + } + planRepository.delete(plan); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanTargetMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanTargetMapper.java new file mode 100644 index 0000000..f15e32a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanTargetMapper.java @@ -0,0 +1,48 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.plan; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.plan.PlanTargetChangeDTO; +import org.fairdatatrain.trainhandler.data.model.Plan; +import org.fairdatatrain.trainhandler.data.model.PlanTarget; +import org.fairdatatrain.trainhandler.data.model.Station; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +@Component +@RequiredArgsConstructor +public class PlanTargetMapper { + + public PlanTarget forPlan(Plan newPlan, PlanTargetChangeDTO targetDto, Station station) { + return PlanTarget.builder() + .uuid(UUID.randomUUID()) + .plan(newPlan) + .station(station) + .publishArtifacts(targetDto.getPublishArtifacts()) + .createdAt(newPlan.getCreatedAt()) + .updatedAt(newPlan.getUpdatedAt()) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/plan/latest/PlanLatestService.java b/src/main/java/org/fairdatatrain/trainhandler/service/plan/latest/PlanLatestService.java new file mode 100644 index 0000000..fd428b7 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/latest/PlanLatestService.java @@ -0,0 +1,91 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.plan.latest; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.api.dto.job.JobArtifactDTO; +import org.fairdatatrain.trainhandler.data.model.JobArtifact; +import org.fairdatatrain.trainhandler.data.model.Plan; +import org.fairdatatrain.trainhandler.data.repository.JobArtifactRepository; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.job.artifact.JobArtifactMapper; +import org.fairdatatrain.trainhandler.service.job.artifact.JobArtifactService; +import org.fairdatatrain.trainhandler.service.plan.PlanService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PlanLatestService { + + private final PlanService planService; + + private final JobArtifactService jobArtifactService; + + private final JobArtifactRepository jobArtifactRepository; + + private final JobArtifactMapper jobArtifactMapper; + + public JobArtifact getLatestJobArtifact(UUID planUuid, UUID artifactUuid) throws NotFoundException { + final JobArtifact jobArtifact = jobArtifactService.getByIdOrThrow(artifactUuid); + if (!jobArtifact.getJob().getTarget().getPublishArtifacts() + || !jobArtifact.getJob().getTarget().getPlan().getUuid().equals(planUuid)) { + throw new NotFoundException("Cannot find public artifact", artifactUuid); + } + return jobArtifact; + } + + public List getLatestArtifacts(UUID planUuid) throws NotFoundException { + final Plan plan = planService.getByIdOrThrow(planUuid); + if (!plan.getPublishArtifacts()) { + return List.of(); + } + return jobArtifactRepository + .getPublicJobArtifactsOfPlan(planUuid) + .stream() + .map(jobArtifactMapper::toDTO) + .toList(); + } + + public List getLatestArtifactsOfTarget( + UUID planUuid, UUID targetUuid + ) throws NotFoundException { + final Plan plan = planService.getByIdOrThrow(planUuid); + if (!plan.getPublishArtifacts()) { + return List.of(); + } + return jobArtifactRepository + .getPublicJobArtifactsOfTarget(targetUuid) + .stream() + .map(jobArtifactMapper::toDTO) + .toList(); + } + + public byte[] getArtifactData(JobArtifact jobArtifact) { + return jobArtifactService.getArtifactData(jobArtifact); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java new file mode 100644 index 0000000..03d84e3 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java @@ -0,0 +1,142 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.run; + +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.api.dto.job.JobEventCreateDTO; +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.model.Run; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; +import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; +import org.fairdatatrain.trainhandler.data.repository.JobRepository; +import org.fairdatatrain.trainhandler.data.repository.RunRepository; +import org.fairdatatrain.trainhandler.service.dispatch.DispatchService; +import org.fairdatatrain.trainhandler.service.job.event.JobEventService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import static java.lang.String.format; +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Slf4j +@Service +@RequiredArgsConstructor +public class RunDispatcher { + + private final DispatchService dispatchService; + + private final JobRepository jobRepository; + + private final RunRepository runRepository; + + private final JobEventService jobEventService; + + @Scheduled( + initialDelayString = "${dispatcher.dispatch.initDelay:PT1M}", + fixedRateString = "${dispatcher.dispatch.interval:PT1M}" + ) + public void dispatchScheduledRuns() { + log.debug("Dispatching scheduled runs"); + final Set dispatchedRuns = new HashSet<>(); + boolean dispatching = true; + while (dispatching) { + final UUID dispatchedRun = tryDispatchRun(); + dispatching = dispatchedRun != null && !dispatchedRuns.contains(dispatchedRun); + if (dispatching) { + dispatchedRuns.add(dispatchedRun); + log.debug("Dispatched run: " + dispatchedRun); + } + else { + log.debug("No more runs to be dispatched now"); + } + } + } + + public UUID tryDispatchRun() { + final Page runs = runRepository.findRunToDispatch( + now(), + Pageable.ofSize(1).withPage(0) + ); + if (runs.isEmpty()) { + return null; + } + final Run run = runs.getContent().get(0); + log.info("Run selected for dispatching: " + run.getUuid()); + dispatchRun(run); + return run.getUuid(); + } + + @Transactional + protected void dispatchRun(Run run) { + run.setStartedAt(now()); + run.getJobs().forEach(job -> { + job.setStartedAt(now()); + jobRepository.save(job); + }); + run.setStatus(RunStatus.RUNNING); + runRepository.save(run); + run.getJobs().forEach(job -> dispatchJob(run.getUuid(), job)); + } + + @SneakyThrows + protected void dispatchJob(UUID runUuid, Job job) { + try { + jobEventService.createEvent( + runUuid, + job.getUuid(), + JobEventCreateDTO.builder() + .message("Dispatching job from train handler") + .occurredAt(Instant.now()) + .resultStatus(JobStatus.RUNNING) + .secret(job.getSecret()) + .build() + ); + jobEventService.notify(job.getUuid()); + dispatchService.dispatch(job); + } + catch (Exception ex) { + log.warn(format("Failed to dispatch job %s: %s", job.getUuid(), ex.getMessage())); + jobEventService.createEvent( + runUuid, + job.getUuid(), + JobEventCreateDTO.builder() + .message(format("Dispatch failed: %s", ex.getMessage())) + .occurredAt(Instant.now()) + .resultStatus(JobStatus.ERRORED) + .secret(job.getSecret()) + .build() + ); + jobEventService.notify(job.getUuid()); + } + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java new file mode 100644 index 0000000..e958578 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java @@ -0,0 +1,153 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.run; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.job.JobSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunUpdateDTO; +import org.fairdatatrain.trainhandler.data.model.Plan; +import org.fairdatatrain.trainhandler.data.model.Run; +import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; +import org.fairdatatrain.trainhandler.service.job.JobMapper; +import org.fairdatatrain.trainhandler.service.plan.PlanMapper; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Component +@RequiredArgsConstructor +public class RunMapper { + + private static final Comparator JOB_SIMPLE_CMP = + Comparator.comparing((JobSimpleDTO item) -> item.getTarget().getTitle()); + + private final PlanMapper planMapper; + + private final JobMapper jobMapper; + + public RunSimpleDTO toSimpleDTO(Run run) { + return RunSimpleDTO.builder() + .uuid(run.getUuid()) + .displayName(run.getDisplayName()) + .note(run.getNote()) + .status(run.getStatus()) + .trainUuid(run.getPlan().getTrain().getUuid()) + .planUuid(run.getPlan().getUuid()) + .shouldStartAt( + Optional.ofNullable(run.getShouldStartAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .startedAt( + Optional.ofNullable(run.getStartedAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .finishedAt( + Optional.ofNullable(run.getFinishedAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .createdAt(run.getCreatedAt().toInstant().toString()) + .updatedAt(run.getUpdatedAt().toInstant().toString()) + .build(); + } + + public RunDTO toDTO(Run run) { + final List jobs = run + .getJobs() + .stream() + .map(jobMapper::toSimpleDTO) + .sorted(JOB_SIMPLE_CMP) + .toList(); + return RunDTO.builder() + .uuid(run.getUuid()) + .displayName(run.getDisplayName()) + .note(run.getNote()) + .status(run.getStatus()) + .plan(planMapper.toSimpleDTO(run.getPlan())) + .jobs(jobs) + .version(run.getVersion()) + .shouldStartAt( + Optional.ofNullable(run.getShouldStartAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .startedAt( + Optional.ofNullable(run.getStartedAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .finishedAt( + Optional.ofNullable(run.getFinishedAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .createdAt(run.getCreatedAt().toInstant().toString()) + .updatedAt(run.getUpdatedAt().toInstant().toString()) + .build(); + } + + public Run fromCreateDTO(RunCreateDTO reqDto, Plan plan) { + final Timestamp now = now(); + final Long version = now.toInstant().toEpochMilli(); + return Run.builder() + .uuid(UUID.randomUUID()) + .displayName(reqDto.getDisplayName()) + .note(reqDto.getNote()) + .status(reqDto.getShouldStartAt() == null + ? RunStatus.PREPARED + : RunStatus.SCHEDULED) + .plan(plan) + .shouldStartAt( + Optional.ofNullable(reqDto.getShouldStartAt()) + .map(Timestamp::from) + .orElse(null)) + .startedAt(null) + .finishedAt(null) + .createdAt(now) + .updatedAt(now) + .version(version) + .build(); + } + + public Run fromUpdateDTO(RunUpdateDTO reqDto, Run run) { + final Timestamp now = now(); + final Long version = now.toInstant().toEpochMilli(); + run.setDisplayName(reqDto.getDisplayName()); + run.setNote(reqDto.getNote()); + run.setUpdatedAt(now); + run.setVersion(version); + return run; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java new file mode 100644 index 0000000..4298e00 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java @@ -0,0 +1,130 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.run; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fairdatatrain.trainhandler.api.dto.run.RunCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunUpdateDTO; +import org.fairdatatrain.trainhandler.data.model.Job; +import org.fairdatatrain.trainhandler.data.model.Plan; +import org.fairdatatrain.trainhandler.data.model.Run; +import org.fairdatatrain.trainhandler.data.repository.JobRepository; +import org.fairdatatrain.trainhandler.data.repository.RunRepository; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.async.RunNotificationListener; +import org.fairdatatrain.trainhandler.service.job.JobMapper; +import org.fairdatatrain.trainhandler.service.plan.PlanService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.request.async.DeferredResult; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; +import java.util.UUID; + +import static java.lang.String.format; + +@Service +@RequiredArgsConstructor +@Slf4j +public class RunService { + + public static final String ENTITY_NAME = "Run"; + + private final RunRepository runRepository; + + private final RunMapper runMapper; + + private final PlanService planService; + + private final JobMapper jobMapper; + + private final JobRepository jobRepository; + + private final RunNotificationListener runNotificationListener; + + @PersistenceContext + private final EntityManager entityManager; + + public Run getByIdOrThrow(UUID uuid) throws NotFoundException { + return runRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public Page getRunsForPlanUuid(UUID planUuid, Pageable pageable) { + return runRepository.findAllByPlanUuid(planUuid, pageable).map(runMapper::toSimpleDTO); + } + + public RunDTO getSingle(UUID uuid) throws NotFoundException { + final Run run = getByIdOrThrow(uuid); + return runMapper.toDTO(run); + } + + @Transactional + public RunDTO create(RunCreateDTO reqDto) throws NotFoundException { + final Plan plan = planService.getByIdOrThrow(reqDto.getPlanUuid()); + final Run newRun = runRepository.save(runMapper.fromCreateDTO(reqDto, plan)); + entityManager.flush(); + entityManager.refresh(newRun); + final List jobs = plan.getTargets().stream() + .map(target -> jobMapper.fromTarget(newRun, target)) + .toList(); + jobRepository.saveAllAndFlush(jobs); + entityManager.flush(); + entityManager.refresh(newRun); + newRun.getJobs().forEach(entityManager::refresh); + return runMapper.toDTO(newRun); + } + + @Transactional + public RunDTO update(UUID uuid, RunUpdateDTO reqDto) throws NotFoundException { + // TODO: abort (?) + final Run run = getByIdOrThrow(uuid); + final Run updatedRun = + runRepository.saveAndFlush(runMapper.fromUpdateDTO(reqDto, run)); + return runMapper.toDTO(updatedRun); + } + + @Transactional + public void poll( + UUID runUuid, + DeferredResult result, + Long version, + RunDTO currentRun + ) { + log.info(format("REQUESTED VERSION: %s", version)); + log.info(format("CURRENT VERSION: %s", currentRun.getVersion())); + if (version < currentRun.getVersion()) { + result.setResult(currentRun); + } + log.info("No run update at this point, enqueueing..."); + runNotificationListener.enqueue(runUuid, version, result); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java new file mode 100644 index 0000000..c750aee --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java @@ -0,0 +1,158 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.station; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.station.StationCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationUpdateDTO; +import org.fairdatatrain.trainhandler.data.model.Station; +import org.fairdatatrain.trainhandler.data.model.TrainType; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; +import org.fairdatatrain.trainhandler.service.stationdirectory.StationDirectoryMapper; +import org.fairdatatrain.trainhandler.service.traintype.TrainTypeMapper; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Component +@RequiredArgsConstructor +public class StationMapper { + + private static final String KEYWORD_SEP = ","; + + private final StationDirectoryMapper stationDirectoryMapper; + + private final TrainTypeMapper trainTypeMapper; + + public StationDTO toDTO(Station station) { + return StationDTO.builder() + .uuid(station.getUuid()) + .title(station.getTitle()) + .uri(station.getUri()) + .description(station.getDescription()) + .keywords( + Arrays.stream(station.getKeywords().split(KEYWORD_SEP)) + .map(String::trim) + .filter(item -> !item.isBlank()) + .toList()) + .endpointUrl(station.getEndpointUrl()) + .endpointDescription(station.getEndpointDescription()) + .status(station.getStatus()) + .softDeleted(station.getSoftDeleted()) + .metadata(station.getMetadata()) + .directory( + Optional.ofNullable(station.getDirectory()) + .map(stationDirectoryMapper::toSimpleDTO) + .orElse(null) + ) + .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) + .lastContactAt( + Optional.ofNullable(station.getLastContactAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null) + ) + .createdAt(station.getCreatedAt().toInstant().toString()) + .updatedAt(station.getUpdatedAt().toInstant().toString()) + .build(); + } + + public StationSimpleDTO toSimpleDTO(Station station) { + return StationSimpleDTO.builder() + .uuid(station.getUuid()) + .title(station.getTitle()) + .uri(station.getUri()) + .keywords( + Arrays.stream(station.getKeywords().split(KEYWORD_SEP)) + .map(String::trim) + .filter(item -> !item.isBlank()) + .toList()) + .endpointUrl(station.getEndpointUrl()) + .endpointDescription(station.getEndpointDescription()) + .status(station.getStatus()) + .directory( + Optional.ofNullable(station.getDirectory()) + .map(stationDirectoryMapper::toSimpleDTO) + .orElse(null) + ) + .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) + .build(); + } + + public Station fromUpdateDTO(StationUpdateDTO dto, Station station, List trainTypes) { + return station.toBuilder() + .uri(dto.getUri()) + .title(dto.getTitle()) + .description(dto.getDescription()) + .keywords(String.join(KEYWORD_SEP, dto.getKeywords())) + .endpointUrl(dto.getEndpointUrl()) + .endpointDescription(dto.getEndpointDescription()) + .metadata(dto.getMetadata()) + .types(trainTypes) + .softDeleted( + Optional.ofNullable(dto.getSoftDeleted()) + .orElse(station.getSoftDeleted()) + ) + .updatedAt(now()) + .build(); + } + + public Station fromCreateDTO(StationCreateDTO dto, List trainTypes) { + final Timestamp now = now(); + return Station.builder() + .uri(dto.getUri()) + .title(dto.getTitle()) + .description(dto.getDescription()) + .keywords(String.join(KEYWORD_SEP, dto.getKeywords())) + .endpointUrl(dto.getEndpointUrl()) + .endpointDescription(dto.getEndpointDescription()) + .metadata(dto.getMetadata()) + .types(trainTypes) + .status(SyncItemStatus.SYNCED) + .softDeleted(false) + .createdAt(now) + .updatedAt(now) + .build(); + } + + public Station updateFetch(Station station, Station fetchedStation) { + return station.toBuilder() + .title(fetchedStation.getTitle()) + .description(fetchedStation.getDescription()) + .keywords(fetchedStation.getKeywords()) + .metadata(fetchedStation.getMetadata()) + .lastContactAt(fetchedStation.getLastContactAt()) + .types(fetchedStation.getTypes()) + .status(fetchedStation.getStatus()) + .updatedAt(now()) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java new file mode 100644 index 0000000..7e3cf8a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java @@ -0,0 +1,138 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.station; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.station.StationCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationUpdateDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.Station; +import org.fairdatatrain.trainhandler.data.model.Train; +import org.fairdatatrain.trainhandler.data.model.TrainType; +import org.fairdatatrain.trainhandler.data.repository.StationRepository; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.stationdirectory.StationDirectoryIndexer; +import org.fairdatatrain.trainhandler.service.train.TrainMapper; +import org.fairdatatrain.trainhandler.service.traintype.TrainTypeService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +@Service +@RequiredArgsConstructor +public class StationService { + + private static final String ENTITY_NAME = "Station"; + + private final StationRepository stationRepository; + + private final StationMapper stationMapper; + + private final TrainMapper trainMapper; + + private final TrainTypeService trainTypeService; + + private final StationDirectoryIndexer stationDirectoryIndexer; + + public Station getByIdOrThrow(UUID uuid) throws NotFoundException { + return stationRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public Page getPaged(String query, Pageable pageable) { + if (query.isBlank()) { + return stationRepository + .findAllBySoftDeletedIsFalse(pageable) + .map(stationMapper::toSimpleDTO); + } + return stationRepository + .findByTitleContainingIgnoreCaseAndSoftDeletedIsFalse(query, pageable) + .map(stationMapper::toSimpleDTO); + } + + public StationDTO getSingle(UUID uuid) throws NotFoundException { + final Station station = getByIdOrThrow(uuid); + return stationMapper.toDTO(station); + } + + public List getAll(String query) { + return stationRepository + .findByTitleContainingIgnoreCase(query) + .stream() + .map(stationMapper::toSimpleDTO) + .toList(); + } + + public List getSuitableStations(UUID uuid) throws NotFoundException { + final Station station = getByIdOrThrow(uuid); + final Set suitableTrains = new HashSet<>(); + station.getTypes().stream().map(TrainType::getTrains).forEach(suitableTrains::addAll); + return suitableTrains.stream().map(trainMapper::toSimpleDTO).toList(); + } + + @Transactional + public StationDTO update(UUID uuid, StationUpdateDTO dto) throws NotFoundException { + final Station station = getByIdOrThrow(uuid); + final List trainTypes = + trainTypeService.getTrainTypes(dto.getTrainTypeUuids()); + Station newStation = stationRepository + .saveAndFlush(stationMapper.fromUpdateDTO(dto, station, trainTypes)); + if (dto.getFetch()) { + newStation = updateFetch(newStation); + } + return stationMapper.toDTO(newStation); + } + + @Transactional + public StationDTO softDelete(UUID uuid) throws NotFoundException { + final Station station = getByIdOrThrow(uuid); + station.setSoftDeleted(true); + return stationMapper.toDTO(stationRepository.save(station)); + } + + public StationDTO create(StationCreateDTO dto) { + final List trainTypes = + trainTypeService.getTrainTypes(dto.getTrainTypeUuids()); + Station newStation = stationRepository + .saveAndFlush(stationMapper.fromCreateDTO(dto, trainTypes)); + if (dto.getFetch()) { + newStation = updateFetch(newStation); + } + return stationMapper.toDTO(newStation); + } + + private Station updateFetch(Station station) { + final Station fetchedStation = stationDirectoryIndexer.tryToFetchStation(station.getUri()); + if (fetchedStation != null) { + return stationRepository + .saveAndFlush(stationMapper.updateFetch(station, fetchedStation)); + } + return station; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java new file mode 100644 index 0000000..7c363f2 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java @@ -0,0 +1,284 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.stationdirectory; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import nl.dtls.fairdatapoint.vocabulary.FDT; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.Resource; +import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.model.vocabulary.DCAT; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.model.vocabulary.RDFS; +import org.fairdatatrain.trainhandler.data.model.*; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; +import org.fairdatatrain.trainhandler.data.repository.*; +import org.fairdatatrain.trainhandler.service.indexing.BaseIndexer; +import org.fairdatatrain.trainhandler.utils.ValueFactoryUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static org.fairdatatrain.trainhandler.utils.RdfIOUtils.write; +import static org.fairdatatrain.trainhandler.utils.RdfUtils.getObjectsBy; +import static org.fairdatatrain.trainhandler.utils.RdfUtils.getStringObjectBy; +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; +import static org.fairdatatrain.trainhandler.utils.ValueFactoryUtils.i; + +@Slf4j +@Service +@RequiredArgsConstructor +public class StationDirectoryIndexer { + + // TODO: from config/ontology + private static final Map> MECHANISM_TRAIN_TYPES = new HashMap<>(); + + private final StationDirectoryRepository stationDirectoryRepository; + + private final TrainTypeRepository trainTypeRepository; + + private final StationRepository stationRepository; + + private final BaseIndexer baseIndexer; + + static { + MECHANISM_TRAIN_TYPES.put(FDT.SPARQL, List.of(FDT.SPARQLTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.PYTHON, List.of(FDT.PYTHONTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.DOCKER, List.of(FDT.DOCKERTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.GRAPHQL, List.of(FDT.GRAPHQLTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.API, List.of(FDT.APITRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.SCRIPT, List.of(FDT.SCRIPTTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.SINGULARITY, List.of(FDT.SINGULARITYTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.FHIRAPI, List.of(FDT.FHIRTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.EXECUTABLECONTAINER, List.of(FDT.CONTAINERTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.R, List.of(FDT.RTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.QUERY, List.of(FDT.QUERYTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.SQL, List.of(FDT.SQLTRAIN)); + MECHANISM_TRAIN_TYPES.put(FDT.RESTAPI, List.of(FDT.RESTTRAIN)); + } + + @Transactional + public void indexDirectory(StationDirectory stationDirectory) { + final Set visitedUris = new HashSet<>(); + final Queue toVisitUris = new LinkedList<>(); + final List stations = new ArrayList<>(); + final List trainTypes = trainTypeRepository.findAll(); + + Model model; + try { + model = baseIndexer.makeRequest(stationDirectory.getUri()); + updateDirectory(stationDirectory, model); + stations.addAll(extractStations(stationDirectory, model, trainTypes)); + toVisitUris.addAll(baseIndexer.extractChildren(model)); + } + catch (Exception exception) { + updateFaultyDirectory(stationDirectory); + } + + while (!toVisitUris.isEmpty()) { + final String uri = toVisitUris.poll(); + log.debug(format("Indexing garage (%s): traversing %s", + stationDirectory.getUri(), uri)); + if (visitedUris.contains(uri)) { + continue; + } + else { + visitedUris.add(uri); + } + try { + model = baseIndexer.makeRequest(uri); + stations.addAll(extractStations(stationDirectory, model, trainTypes)); + toVisitUris.addAll(baseIndexer.extractChildren(model)); + } + catch (Exception exception) { + log.debug(format("Skipping %s (exception: %s)", uri, exception)); + } + } + + updateStations(stationDirectory, stations); + } + + public Station tryToFetchStation(String uri) { + final List trainTypes = trainTypeRepository.findAll(); + try { + final Model model = baseIndexer.makeRequest(uri); + final List stations = extractStations(null, model, trainTypes); + if (stations.size() > 0) { + return stations.get(0); + } + } + catch (Exception exception) { + log.debug(format("Failed to fetch %s (exception: %s)", uri, exception)); + } + return null; + } + + private void updateDirectory(StationDirectory stationDirectory, Model model) { + stationDirectory.setMetadata(""); + stationDirectory.setLastContactAt(now()); + stationDirectory.setStatus(SyncServiceStatus.SYNCED); + stationDirectoryRepository.saveAndFlush(stationDirectory); + } + + private void updateFaultyDirectory(StationDirectory stationDirectory) { + stationDirectory.setStatus(SyncServiceStatus.UNREACHABLE); + stationDirectoryRepository.saveAndFlush(stationDirectory); + } + + private void updateStations(StationDirectory stationDirectory, List stations) { + final List stationsToSave = new ArrayList<>(); + final Map existingStations = stationDirectory + .getStations() + .stream() + .collect(Collectors.toMap(Station::getUri, Function.identity())); + final Map currentStations = stations + .stream() + .collect(Collectors.toMap(Station::getUri, Function.identity())); + + currentStations.forEach((uri, station) -> { + if (existingStations.containsKey(uri)) { + updateStation(existingStations.get(uri), station); + } + else { + station.setDirectory(stationDirectory); + stationDirectory.getStations().add(station); + stationsToSave.add(station); + } + }); + existingStations.forEach((uri, station) -> { + if (!currentStations.containsKey(uri)) { + deprecateStation(station); + } + }); + + stationRepository.saveAllAndFlush(stationsToSave); + } + + private void deprecateStation(Station existingStation) { + existingStation.setStatus(SyncItemStatus.DELETED); + existingStation.setUpdatedAt(now()); + } + + private void updateStation(Station existingStation, Station newStation) { + existingStation.setTitle(newStation.getTitle()); + existingStation.setDescription(newStation.getDescription()); + existingStation.setKeywords(newStation.getKeywords()); + existingStation.setTypes(newStation.getTypes()); + existingStation.setMetadata(newStation.getMetadata()); + existingStation.setLastContactAt(newStation.getLastContactAt()); + existingStation.setUpdatedAt(now()); + } + + private List extractStations( + StationDirectory stationDirectory, + Model model, + List trainTypes + ) { + return model + .filter(null, RDF.TYPE, i(FDT.DATASTATION)) + .parallelStream() + .map(stmt -> extractStation(stationDirectory, stmt.getSubject(), model, trainTypes)) + .filter(Objects::nonNull) + .toList(); + } + + private Station extractStation( + StationDirectory stationDirectory, + Resource resource, + Model model, + List trainTypes + ) { + log.info(format("Station found: %s", resource)); + final String title = getStringObjectBy(model, resource, RDFS.LABEL); + final String description = getStringObjectBy(model, resource, RDFS.COMMENT); + final String endpointUrl = getStringObjectBy(model, resource, DCAT.ENDPOINT_URL); + final String endpointDescription = getStringObjectBy(model, resource, DCAT.ENDPOINT_DESCRIPTION); + final List keywords = getObjectsBy(model, resource, DCAT.KEYWORD) + .stream() + .map(Value::stringValue) + .toList(); + + final Set interactionMechanisms = + getObjectsBy(model, resource, FDT.IMPLEMENTSINTERACTIONMECHANISM) + .stream() + .map(Value::stringValue) + .map(ValueFactoryUtils::i) + .collect(Collectors.toSet()); + final Set trainTypeUris = interactionMechanisms + .stream() + .map(this::getTrainsByInteractionMechanism) + .flatMap(List::stream) + .map(IRI::stringValue) + .collect(Collectors.toSet()); + + if (title == null) { + log.warn(format("Skipping station %s (missing required information: title)", resource)); + return null; + } + if (endpointUrl == null) { + log.warn(format("Skipping station %s (missing required information: endpoint URL)", resource)); + return null; + } + + final List matchingTrainTypes = trainTypes + .stream() + .filter(trainType -> trainTypeUris.contains(trainType.getUri())) + .toList(); + + if (matchingTrainTypes.isEmpty()) { + log.warn(format("No matching train type found: %s", trainTypeUris)); + return null; + } + + return Station + .builder() + .uuid(UUID.randomUUID()) + .uri(resource.stringValue()) + .title(title) + .description(description == null ? "" : description) + .keywords(String.join(",", keywords)) + .endpointUrl(endpointUrl) + .endpointDescription(endpointDescription == null ? "" : endpointDescription) + .metadata(write(model)) + .types(matchingTrainTypes) + .directory(stationDirectory) + .status(SyncItemStatus.SYNCED) + .lastContactAt(now()) + .createdAt(now()) + .updatedAt(now()) + .softDeleted(false) + .build(); + } + + private List getTrainsByInteractionMechanism(IRI interactionMechanism) { + return Optional.ofNullable(MECHANISM_TRAIN_TYPES.get(interactionMechanism)) + .orElse(Collections.emptyList()); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java new file mode 100644 index 0000000..ffd532b --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java @@ -0,0 +1,91 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.stationdirectory; + +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectorySimpleDTO; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Optional; + +@Component +public class StationDirectoryMapper { + public StationDirectoryDTO toDTO(StationDirectory stationDirectory) { + return StationDirectoryDTO.builder() + .uuid(stationDirectory.getUuid()) + .uri(stationDirectory.getUri()) + .displayName(stationDirectory.getDisplayName()) + .metadata(stationDirectory.getMetadata()) + .note(stationDirectory.getNote()) + .status(stationDirectory.getStatus()) + .deletable(stationDirectory.isDeletable()) + .lastContactAt( + Optional.ofNullable(stationDirectory.getLastContactAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .createdAt(stationDirectory.getCreatedAt().toInstant().toString()) + .updatedAt(stationDirectory.getUpdatedAt().toInstant().toString()) + .build(); + } + + public StationDirectory fromCreateDTO(StationDirectoryChangeDTO reqDto) { + final Timestamp now = Timestamp.from(Instant.now()); + return StationDirectory.builder() + .uri(reqDto.getUri()) + .displayName(reqDto.getDisplayName()) + .note(reqDto.getNote()) + .status(SyncServiceStatus.SYNCING) + .metadata(null) + .lastContactAt(null) + .createdAt(now) + .updatedAt(now) + .build(); + } + + public StationDirectory fromUpdateDTO( + StationDirectoryChangeDTO reqDto, + StationDirectory stationDirectory + ) { + final Timestamp now = Timestamp.from(Instant.now()); + stationDirectory.setUri(reqDto.getUri()); + stationDirectory.setDisplayName(reqDto.getDisplayName()); + stationDirectory.setNote(reqDto.getNote()); + stationDirectory.setStatus(SyncServiceStatus.SYNCING); + stationDirectory.setUpdatedAt(now); + return stationDirectory; + } + + public StationDirectorySimpleDTO toSimpleDTO(StationDirectory stationDirectory) { + return StationDirectorySimpleDTO.builder() + .uuid(stationDirectory.getUuid()) + .uri(stationDirectory.getUri()) + .displayName(stationDirectory.getDisplayName()) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java new file mode 100644 index 0000000..100ba57 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java @@ -0,0 +1,110 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.stationdirectory; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; +import org.fairdatatrain.trainhandler.data.repository.StationDirectoryRepository; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class StationDirectoryService { + + private static final String ENTITY_NAME = "StationDirectory"; + + private final StationDirectoryRepository stationDirectoryRepository; + + private final StationDirectoryMapper stationDirectoryMapper; + + private final StationDirectoryIndexer stationDirectoryIndexer; + + private StationDirectory getByIdOrThrow(UUID uuid) throws NotFoundException { + return stationDirectoryRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public void delete(UUID uuid) throws NotFoundException { + final StationDirectory stationDirectory = getByIdOrThrow(uuid); + stationDirectoryRepository.delete(stationDirectory); + } + + public Page getPaged(String query, Pageable pageable) { + if (query.isBlank()) { + return stationDirectoryRepository.findAll(pageable).map(stationDirectoryMapper::toDTO); + } + return stationDirectoryRepository + .findByDisplayNameContainingIgnoreCase(query, pageable) + .map(stationDirectoryMapper::toDTO); + } + + public StationDirectoryDTO getSingle(UUID uuid) throws NotFoundException { + final StationDirectory stationDirectory = getByIdOrThrow(uuid); + return stationDirectoryMapper.toDTO(stationDirectory); + } + + @Transactional + public StationDirectoryDTO create(StationDirectoryChangeDTO reqDto) { + // TODO: validate? + final StationDirectory newStationDirectory = + stationDirectoryRepository.saveAndFlush( + stationDirectoryMapper.fromCreateDTO(reqDto)); + return this.stationDirectoryMapper.toDTO(newStationDirectory); + } + + @Transactional + public StationDirectoryDTO update(UUID uuid, StationDirectoryChangeDTO reqDto) + throws NotFoundException { + // TODO: validate? + final StationDirectory stationDirectory = getByIdOrThrow(uuid); + final StationDirectory updatedStationDirectory = + stationDirectoryRepository.saveAndFlush( + stationDirectoryMapper.fromUpdateDTO(reqDto, stationDirectory)); + return this.stationDirectoryMapper.toDTO(updatedStationDirectory); + } + + @Transactional + public void reindex(UUID uuid) throws NotFoundException { + final StationDirectory stationDirectory = getByIdOrThrow(uuid); + stationDirectory.setStatus(SyncServiceStatus.SYNCING); + final StationDirectory updatedStationDirectory = + stationDirectoryRepository.saveAndFlush(stationDirectory); + triggerAsyncIndexing(updatedStationDirectory); + } + + @Async + protected void triggerAsyncIndexing(StationDirectory stationDirectory) { + stationDirectoryIndexer.indexDirectory(stationDirectory); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java new file mode 100644 index 0000000..b7f5365 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java @@ -0,0 +1,150 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.train; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.train.TrainCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainUpdateDTO; +import org.fairdatatrain.trainhandler.data.model.Train; +import org.fairdatatrain.trainhandler.data.model.TrainType; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; +import org.fairdatatrain.trainhandler.service.traingarage.TrainGarageMapper; +import org.fairdatatrain.trainhandler.service.traintype.TrainTypeMapper; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Component +@RequiredArgsConstructor +public class TrainMapper { + + private static final String KEYWORD_SEP = ","; + + private final TrainGarageMapper trainGarageMapper; + + private final TrainTypeMapper trainTypeMapper; + + public TrainDTO toDTO(Train train) { + return TrainDTO.builder() + .uuid(train.getUuid()) + .title(train.getTitle()) + .uri(train.getUri()) + .description(train.getDescription()) + .keywords( + Arrays.stream(train.getKeywords().split(KEYWORD_SEP)) + .map(String::trim) + .filter(item -> !item.isBlank()) + .toList()) + .status(train.getStatus()) + .softDeleted(train.getSoftDeleted()) + .metadata(train.getMetadata()) + .garage( + Optional.ofNullable(train.getGarage()) + .map(trainGarageMapper::toSimpleDTO) + .orElse(null) + ) + .types(train.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) + .lastContactAt( + Optional.ofNullable(train.getLastContactAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null) + ) + .createdAt(train.getCreatedAt().toInstant().toString()) + .updatedAt(train.getUpdatedAt().toInstant().toString()) + .build(); + } + + public TrainSimpleDTO toSimpleDTO(Train train) { + return TrainSimpleDTO.builder() + .uuid(train.getUuid()) + .title(train.getTitle()) + .uri(train.getUri()) + .keywords( + Arrays.stream(train.getKeywords().split(KEYWORD_SEP)) + .map(String::trim) + .filter(item -> !item.isBlank()) + .toList()) + .status(train.getStatus()) + .garage( + Optional.ofNullable(train.getGarage()) + .map(trainGarageMapper::toSimpleDTO) + .orElse(null) + ) + .types(train.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) + .build(); + } + + public Train fromUpdateDTO(TrainUpdateDTO dto, Train train, List trainTypes) { + return train.toBuilder() + .uri(dto.getUri()) + .title(dto.getTitle()) + .description(dto.getDescription()) + .keywords(String.join(KEYWORD_SEP, dto.getKeywords())) + .metadata(dto.getMetadata()) + .types(trainTypes) + .softDeleted( + Optional.ofNullable(dto.getSoftDeleted()) + .orElse(train.getSoftDeleted()) + ) + .updatedAt(now()) + .build(); + } + + public Train fromCreateDTO(TrainCreateDTO dto, List trainTypes) { + final Timestamp now = now(); + return Train.builder() + .uri(dto.getUri()) + .title(dto.getTitle()) + .description(dto.getDescription()) + .keywords(String.join(KEYWORD_SEP, dto.getKeywords())) + .metadata(dto.getMetadata()) + .types(trainTypes) + .status(SyncItemStatus.SYNCED) + .softDeleted(false) + .createdAt(now) + .updatedAt(now) + .build(); + } + + public Train updateFetch(Train train, Train fetchedTrain) { + return train.toBuilder() + .title(fetchedTrain.getTitle()) + .description(fetchedTrain.getDescription()) + .keywords(fetchedTrain.getKeywords()) + .metadata(fetchedTrain.getMetadata()) + .lastContactAt(fetchedTrain.getLastContactAt()) + .types(fetchedTrain.getTypes()) + .status(fetchedTrain.getStatus()) + .updatedAt(now()) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java new file mode 100644 index 0000000..1f607d6 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java @@ -0,0 +1,142 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.train; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainUpdateDTO; +import org.fairdatatrain.trainhandler.data.model.Station; +import org.fairdatatrain.trainhandler.data.model.Train; +import org.fairdatatrain.trainhandler.data.model.TrainType; +import org.fairdatatrain.trainhandler.data.repository.TrainRepository; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.station.StationMapper; +import org.fairdatatrain.trainhandler.service.traingarage.TrainGarageIndexer; +import org.fairdatatrain.trainhandler.service.traintype.TrainTypeService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class TrainService { + + private static final String ENTITY_NAME = "Train"; + + private final TrainRepository trainRepository; + + private final TrainMapper trainMapper; + + private final StationMapper stationMapper; + + private final TrainTypeService trainTypeService; + + private final TrainGarageIndexer trainGarageIndexer; + + public Train getByIdOrThrow(UUID uuid) throws NotFoundException { + return trainRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public Page getPaged(String query, Pageable pageable) { + if (query.isBlank()) { + return trainRepository + .findAllBySoftDeletedIsFalse(pageable) + .map(trainMapper::toSimpleDTO); + } + return trainRepository + .findByTitleContainingIgnoreCaseAndSoftDeletedIsFalse(query, pageable) + .map(trainMapper::toSimpleDTO); + } + + public TrainDTO getSingle(UUID uuid) throws NotFoundException { + final Train train = getByIdOrThrow(uuid); + return trainMapper.toDTO(train); + } + + public List getAll(String query) { + return trainRepository + .findByTitleContainingIgnoreCase(query) + .stream() + .map(trainMapper::toSimpleDTO) + .toList(); + } + + public List getSuitableStations(UUID uuid) throws NotFoundException { + final Train train = getByIdOrThrow(uuid); + final Set suitableStations = new HashSet<>(); + train.getTypes().stream().map(TrainType::getStations).forEach(suitableStations::addAll); + return suitableStations.stream().map(stationMapper::toSimpleDTO).toList(); + } + + @Transactional + public TrainDTO update(UUID uuid, TrainUpdateDTO dto) throws NotFoundException { + final Train train = getByIdOrThrow(uuid); + final List trainTypes = + trainTypeService.getTrainTypes(dto.getTrainTypeUuids()); + Train newTrain = + trainRepository.saveAndFlush(trainMapper.fromUpdateDTO(dto, train, trainTypes)); + if (dto.getFetch()) { + newTrain = updateFetch(newTrain); + } + return trainMapper.toDTO(newTrain); + } + + @Transactional + public TrainDTO softDelete(UUID uuid) throws NotFoundException { + final Train train = getByIdOrThrow(uuid); + train.setSoftDeleted(true); + return trainMapper.toDTO(trainRepository.saveAndFlush(train)); + } + + @Transactional + public TrainDTO create(TrainCreateDTO dto) { + final List trainTypes = + trainTypeService.getTrainTypes(dto.getTrainTypeUuids()); + Train newTrain = trainRepository + .saveAndFlush(trainMapper.fromCreateDTO(dto, trainTypes)); + if (dto.getFetch()) { + newTrain = updateFetch(newTrain); + } + return trainMapper.toDTO(newTrain); + } + + private Train updateFetch(Train train) { + final Train fetchedTrain = trainGarageIndexer.tryToFetchTrain(train.getUri()); + if (fetchedTrain != null) { + return trainRepository + .saveAndFlush(trainMapper.updateFetch(train, fetchedTrain)); + } + return train; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java new file mode 100644 index 0000000..376548f --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java @@ -0,0 +1,241 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.traingarage; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import nl.dtls.fairdatapoint.vocabulary.FDT; +import org.eclipse.rdf4j.model.*; +import org.eclipse.rdf4j.model.vocabulary.DCAT; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.model.vocabulary.RDFS; +import org.fairdatatrain.trainhandler.data.model.Train; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.model.TrainType; +import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; +import org.fairdatatrain.trainhandler.data.repository.TrainGarageRepository; +import org.fairdatatrain.trainhandler.data.repository.TrainRepository; +import org.fairdatatrain.trainhandler.data.repository.TrainTypeRepository; +import org.fairdatatrain.trainhandler.service.indexing.BaseIndexer; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static org.fairdatatrain.trainhandler.utils.RdfIOUtils.*; +import static org.fairdatatrain.trainhandler.utils.RdfUtils.getObjectsBy; +import static org.fairdatatrain.trainhandler.utils.RdfUtils.getStringObjectBy; +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Slf4j +@Service +@RequiredArgsConstructor +public class TrainGarageIndexer { + + private final TrainGarageRepository trainGarageRepository; + + private final TrainTypeRepository trainTypeRepository; + + private final TrainRepository trainRepository; + + private final BaseIndexer baseIndexer; + + @Transactional + public void indexGarage(TrainGarage trainGarage) { + final Set visitedUris = new HashSet<>(); + final Queue toVisitUris = new LinkedList<>(); + final List trains = new ArrayList<>(); + final List trainTypes = trainTypeRepository.findAll(); + + Model model; + try { + model = baseIndexer.makeRequest(trainGarage.getUri()); + updateGarage(trainGarage, model); + trains.addAll(extractTrains(trainGarage, model, trainTypes)); + toVisitUris.addAll(baseIndexer.extractChildren(model)); + } + catch (Exception exception) { + updateFaultyGarage(trainGarage); + } + + while (!toVisitUris.isEmpty()) { + final String uri = toVisitUris.poll(); + log.debug(format("Indexing garage (%s): traversing %s", trainGarage.getUri(), uri)); + if (visitedUris.contains(uri)) { + continue; + } + else { + visitedUris.add(uri); + } + try { + model = baseIndexer.makeRequest(uri); + trains.addAll(extractTrains(trainGarage, model, trainTypes)); + toVisitUris.addAll(baseIndexer.extractChildren(model)); + } + catch (Exception exception) { + log.debug(format("Failed to fetch %s (exception: %s)", uri, exception)); + } + } + + updateTrains(trainGarage, trains); + } + + public Train tryToFetchTrain(String uri) { + final List trainTypes = trainTypeRepository.findAll(); + try { + final Model model = baseIndexer.makeRequest(uri); + final List trains = extractTrains(null, model, trainTypes); + if (!trains.isEmpty()) { + return trains.get(0); + } + } + catch (Exception exception) { + log.debug(format("Skipping %s (exception: %s)", uri, exception)); + } + return null; + } + + private void updateGarage(TrainGarage trainGarage, Model model) { + trainGarage.setMetadata(""); + trainGarage.setLastContactAt(now()); + trainGarage.setStatus(SyncServiceStatus.SYNCED); + trainGarageRepository.saveAndFlush(trainGarage); + } + + private void updateFaultyGarage(TrainGarage trainGarage) { + trainGarage.setStatus(SyncServiceStatus.UNREACHABLE); + trainGarageRepository.saveAndFlush(trainGarage); + } + + private void updateTrains(TrainGarage trainGarage, List trains) { + final List trainsToSave = new ArrayList<>(); + final Map existingTrains = trainGarage + .getTrains() + .stream() + .collect(Collectors.toMap(Train::getUri, Function.identity())); + final Map currentTrains = trains + .stream() + .collect(Collectors.toMap(Train::getUri, Function.identity())); + + currentTrains.forEach((uri, train) -> { + if (existingTrains.containsKey(uri)) { + updateTrain(existingTrains.get(uri), train); + } + else { + train.setGarage(trainGarage); + trainGarage.getTrains().add(train); + trainsToSave.add(train); + } + }); + existingTrains.forEach((uri, train) -> { + if (!currentTrains.containsKey(uri)) { + deprecateTrain(train); + } + }); + + trainRepository.saveAllAndFlush(trainsToSave); + } + + private void deprecateTrain(Train existingTrain) { + existingTrain.setStatus(SyncItemStatus.DELETED); + existingTrain.setUpdatedAt(now()); + } + + private void updateTrain(Train existingTrain, Train newTrain) { + existingTrain.setTitle(newTrain.getTitle()); + existingTrain.setDescription(newTrain.getDescription()); + existingTrain.setKeywords(newTrain.getKeywords()); + existingTrain.setTypes(newTrain.getTypes()); + existingTrain.setMetadata(newTrain.getMetadata()); + existingTrain.setLastContactAt(newTrain.getLastContactAt()); + existingTrain.setUpdatedAt(now()); + } + + private List extractTrains( + TrainGarage trainGarage, + Model model, + List trainTypes + ) { + return model + .filter(null, RDF.TYPE, FDT.TRAIN) + .parallelStream() + .map(stmt -> extractTrain(trainGarage, stmt.getSubject(), model, trainTypes)) + .filter(Objects::nonNull) + .toList(); + } + + private Train extractTrain( + TrainGarage trainGarage, + Resource resource, + Model model, + List trainTypes + ) { + log.info(format("Train found: %s", resource)); + final String title = getStringObjectBy(model, resource, RDFS.LABEL); + final String description = getStringObjectBy(model, resource, RDFS.COMMENT); + final List keywords = getObjectsBy(model, resource, DCAT.KEYWORD) + .stream() + .map(Value::stringValue) + .toList(); + final Set trainTypeUris = getObjectsBy(model, resource, FDT.HASTRAINTYPE) + .stream() + .map(Value::stringValue) + .collect(Collectors.toSet()); + + if (title == null || trainTypeUris.isEmpty()) { + log.warn(format("Skipping train %s (missing required information)", resource)); + return null; + } + + final List matchingTrainTypes = trainTypes + .stream() + .filter(trainType -> trainTypeUris.contains(trainType.getUri())) + .toList(); + + if (matchingTrainTypes.isEmpty()) { + log.warn(format("No matching train type found: %s", trainTypeUris)); + return null; + } + + return Train + .builder() + .uuid(UUID.randomUUID()) + .uri(resource.stringValue()) + .title(title) + .description(description == null ? "" : description) + .keywords(String.join(",", keywords)) + .metadata(write(model)) + .types(matchingTrainTypes) + .garage(trainGarage) + .status(SyncItemStatus.SYNCED) + .lastContactAt(now()) + .createdAt(now()) + .updatedAt(now()) + .softDeleted(false) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java new file mode 100644 index 0000000..80e1fd3 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java @@ -0,0 +1,90 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.traingarage; + +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Optional; + +@Component +public class TrainGarageMapper { + public TrainGarageDTO toDTO(TrainGarage trainGarage) { + return TrainGarageDTO.builder() + .uuid(trainGarage.getUuid()) + .uri(trainGarage.getUri()) + .displayName(trainGarage.getDisplayName()) + .note(trainGarage.getNote()) + .metadata(trainGarage.getMetadata()) + .status(trainGarage.getStatus()) + .deletable(trainGarage.isDeletable()) + .lastContactAt( + Optional.ofNullable(trainGarage.getLastContactAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null)) + .createdAt(trainGarage.getCreatedAt().toInstant().toString()) + .updatedAt(trainGarage.getCreatedAt().toInstant().toString()) + .build(); + } + + public TrainGarage fromCreateDTO(TrainGarageChangeDTO reqDto) { + final Timestamp now = Timestamp.from(Instant.now()); + return TrainGarage.builder() + .uri(reqDto.getUri()) + .displayName(reqDto.getDisplayName()) + .note(reqDto.getNote()) + .status(SyncServiceStatus.SYNCING) + .metadata(null) + .lastContactAt(null) + .createdAt(now) + .updatedAt(now) + .build(); + } + + public TrainGarage fromUpdateDTO( + TrainGarageChangeDTO reqDto, + TrainGarage trainGarage + ) { + final Timestamp now = Timestamp.from(Instant.now()); + trainGarage.setUri(reqDto.getUri()); + trainGarage.setDisplayName(reqDto.getDisplayName()); + trainGarage.setNote(reqDto.getNote()); + trainGarage.setUpdatedAt(now); + return trainGarage; + } + + public TrainGarageSimpleDTO toSimpleDTO(TrainGarage trainGarage) { + return TrainGarageSimpleDTO.builder() + .uuid(trainGarage.getUuid()) + .uri(trainGarage.getUri()) + .displayName(trainGarage.getDisplayName()) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java new file mode 100644 index 0000000..9349e96 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java @@ -0,0 +1,109 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.traingarage; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; +import org.fairdatatrain.trainhandler.data.repository.TrainGarageRepository; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class TrainGarageService { + + private static final String ENTITY_NAME = "TrainGarage"; + + private final TrainGarageRepository trainGarageRepository; + + private final TrainGarageMapper trainGarageMapper; + + private final TrainGarageIndexer trainGarageIndexer; + + private TrainGarage getByIdOrThrow(UUID uuid) throws NotFoundException { + return trainGarageRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public void delete(UUID uuid) throws NotFoundException { + final TrainGarage trainGarage = getByIdOrThrow(uuid); + trainGarageRepository.delete(trainGarage); + } + + public Page getPaged(String query, Pageable pageable) { + if (query.isBlank()) { + return trainGarageRepository.findAll(pageable).map(trainGarageMapper::toDTO); + } + return trainGarageRepository + .findByDisplayNameContainingIgnoreCase(query, pageable) + .map(trainGarageMapper::toDTO); + } + + public TrainGarageDTO getSingle(UUID uuid) throws NotFoundException { + final TrainGarage trainGarage = getByIdOrThrow(uuid); + return trainGarageMapper.toDTO(trainGarage); + } + + @Transactional + public TrainGarageDTO create(TrainGarageChangeDTO reqDto) { + // TODO: validate? + final TrainGarage newTrainGarage = + trainGarageRepository.saveAndFlush(trainGarageMapper.fromCreateDTO(reqDto)); + return trainGarageMapper.toDTO(newTrainGarage); + } + + @Transactional + public TrainGarageDTO update(UUID uuid, TrainGarageChangeDTO reqDto) + throws NotFoundException { + // TODO: validate? + final TrainGarage trainGarage = getByIdOrThrow(uuid); + final TrainGarage updatedTrainGarage = + trainGarageRepository.saveAndFlush( + trainGarageMapper.fromUpdateDTO(reqDto, trainGarage)); + return trainGarageMapper.toDTO(updatedTrainGarage); + } + + @Transactional + public void reindex(UUID uuid) throws NotFoundException { + final TrainGarage trainGarage = getByIdOrThrow(uuid); + trainGarage.setStatus(SyncServiceStatus.SYNCING); + final TrainGarage updatedTrainGarage = + trainGarageRepository.saveAndFlush(trainGarage); + triggerAsyncIndexing(updatedTrainGarage); + } + + @Async + protected void triggerAsyncIndexing(TrainGarage trainGarage) { + trainGarageIndexer.indexGarage(trainGarage); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeMapper.java new file mode 100644 index 0000000..fc04153 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeMapper.java @@ -0,0 +1,76 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.traintype; + +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.TrainType; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.UUID; + +@Component +public class TrainTypeMapper { + public TrainTypeDTO toDTO(TrainType trainType) { + return TrainTypeDTO.builder() + .uuid(trainType.getUuid()) + .title(trainType.getTitle()) + .uri(trainType.getUri()) + .note(trainType.getNote()) + .createdAt(trainType.getCreatedAt().toInstant().toString()) + .updatedAt(trainType.getUpdatedAt().toInstant().toString()) + .build(); + } + + public TrainType fromCreateDTO(TrainTypeChangeDTO reqDto) { + final Timestamp now = Timestamp.from(Instant.now()); + return TrainType.builder() + .uuid(UUID.randomUUID()) + .title(reqDto.getTitle()) + .uri(reqDto.getUri()) + .note(reqDto.getNote()) + .createdAt(now) + .updatedAt(now) + .build(); + } + + public TrainType fromUpdateDTO(TrainTypeChangeDTO reqDto, TrainType trainType) { + final Timestamp now = Timestamp.from(Instant.now()); + trainType.setTitle(reqDto.getTitle()); + trainType.setUri(reqDto.getUri()); + trainType.setNote(reqDto.getNote()); + trainType.setUpdatedAt(now); + return trainType; + } + + public TrainTypeSimpleDTO toSimpleDTO(TrainType trainType) { + return TrainTypeSimpleDTO.builder() + .uuid(trainType.getUuid()) + .title(trainType.getTitle()) + .uri(trainType.getUri()) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java new file mode 100644 index 0000000..4fcc2e6 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java @@ -0,0 +1,114 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.service.traintype; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeDTO; +import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.TrainType; +import org.fairdatatrain.trainhandler.data.repository.TrainTypeRepository; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class TrainTypeService { + + private static final String ENTITY_NAME = "TrainType"; + + private final TrainTypeRepository trainTypeRepository; + + private final TrainTypeMapper trainTypeMapper; + + public TrainType getByIdOrThrow(UUID uuid) throws NotFoundException { + return trainTypeRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + public TrainType getByIdOrNull(UUID uuid) { + return trainTypeRepository + .findById(uuid) + .orElse(null); + } + + public List getTrainTypes(List uuids) { + return uuids + .stream() + .map(this::getByIdOrNull) + .filter(Objects::nonNull) + .toList(); + } + + public void delete(UUID uuid) throws NotFoundException { + final TrainType trainType = getByIdOrThrow(uuid); + trainTypeRepository.delete(trainType); + } + + public Page getPaged(String query, Pageable pageable) { + if (query.isBlank()) { + return trainTypeRepository.findAll(pageable).map(trainTypeMapper::toDTO); + } + return trainTypeRepository + .findByTitleContainingIgnoreCase(query, pageable) + .map(trainTypeMapper::toDTO); + } + + public TrainTypeDTO getSingle(UUID uuid) throws NotFoundException { + final TrainType trainType = getByIdOrThrow(uuid); + return trainTypeMapper.toDTO(trainType); + } + + @Transactional + public TrainTypeDTO create(TrainTypeChangeDTO reqDto) { + // TODO: validate? + final TrainType newTrainType = + trainTypeRepository.saveAndFlush(trainTypeMapper.fromCreateDTO(reqDto)); + return trainTypeMapper.toDTO(newTrainType); + } + + @Transactional + public TrainTypeDTO update(UUID uuid, TrainTypeChangeDTO reqDto) throws NotFoundException { + // TODO: validate? + final TrainType trainType = getByIdOrThrow(uuid); + final TrainType updatedTrainType = + trainTypeRepository.saveAndFlush(trainTypeMapper.fromUpdateDTO(reqDto, trainType)); + return trainTypeMapper.toDTO(updatedTrainType); + } + + public List getAll() { + return trainTypeRepository + .findAll() + .stream() + .map(trainTypeMapper::toSimpleDTO) + .toList(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/utils/CompareUtils.java b/src/main/java/org/fairdatatrain/trainhandler/utils/CompareUtils.java new file mode 100644 index 0000000..fd97189 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/utils/CompareUtils.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.utils; + +import java.util.Collection; + +public class CompareUtils { + + public static boolean compareListContents(Collection listA, Collection listB) { + if (listA.size() != listB.size()) { + return false; + } + return listA.retainAll(listB); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/utils/HashUtils.java b/src/main/java/org/fairdatatrain/trainhandler/utils/HashUtils.java new file mode 100644 index 0000000..6e89aee --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/utils/HashUtils.java @@ -0,0 +1,39 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.utils; + +public class HashUtils { + private static final int MASK = 0xff; + + public static String bytesToHex(byte[] hash) { + final StringBuilder hexString = new StringBuilder(2 * hash.length); + for (byte b : hash) { + final String hex = Integer.toHexString(MASK & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/utils/RandomUtils.java b/src/main/java/org/fairdatatrain/trainhandler/utils/RandomUtils.java new file mode 100644 index 0000000..68b85a2 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/utils/RandomUtils.java @@ -0,0 +1,31 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.utils; + +import java.util.UUID; + +public class RandomUtils { + public static String randomSecret() { + return UUID.randomUUID().toString(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/utils/RdfIOUtils.java b/src/main/java/org/fairdatatrain/trainhandler/utils/RdfIOUtils.java new file mode 100644 index 0000000..5dacaae --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/utils/RdfIOUtils.java @@ -0,0 +1,81 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.utils; + +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.vocabulary.*; +import org.eclipse.rdf4j.rio.*; +import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; + +public class RdfIOUtils { + + private static final WriterConfig WRITER_CONFIG = new WriterConfig(); + + static { + WRITER_CONFIG.set(BasicWriterSettings.INLINE_BLANK_NODES, true); + } + + public static Model read(String content, String baseUri) { + return read(content, baseUri, RDFFormat.TURTLE); + } + + public static Model read(String content, String baseUri, RDFFormat format) { + try (InputStream inputStream = new ByteArrayInputStream(content.getBytes())) { + return Rio.parse(inputStream, baseUri, format); + } + catch (IOException exception) { + throw new RuntimeException("Unable to read RDF (IO exception)"); + } + catch (RDFParseException exception) { + throw new RuntimeException("Unable to read RDF (parse exception)"); + } + catch (RDFHandlerException exception) { + throw new RuntimeException("Unable to read RDF (handler exception)"); + } + } + + public static String write(Model model) { + return write(model, RDFFormat.TURTLE); + } + + public static String write(Model model, RDFFormat format) { + model.setNamespace(DCTERMS.NS); + model.setNamespace(DCAT.NS); + model.setNamespace(FOAF.NS); + model.setNamespace(XMLSchema.NS); + model.setNamespace(LDP.NS); + + try (StringWriter out = new StringWriter()) { + Rio.write(model, out, format, WRITER_CONFIG); + return out.toString(); + } + catch (IOException exception) { + throw new RuntimeException("Unable to write RDF (IO exception)"); + } + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/utils/RdfUtils.java b/src/main/java/org/fairdatatrain/trainhandler/utils/RdfUtils.java new file mode 100644 index 0000000..1e3a91f --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/utils/RdfUtils.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.utils; + +import org.eclipse.rdf4j.model.*; +import org.eclipse.rdf4j.model.util.Models; + +import java.util.List; + +import static org.fairdatatrain.trainhandler.utils.ValueFactoryUtils.i; + +public class RdfUtils { + + public static List getObjectsBy(Model model, Resource subject, IRI predicate) { + return Models.getProperties(model, subject, predicate).stream().toList(); + } + + public static List getObjectsBy(Model model, String subject, String predicate) { + return getObjectsBy(model, i(subject, model), i(predicate, model)); + } + + public static Value getObjectBy(Model model, Resource subject, IRI predicate) { + return Models.getProperty(model, subject, predicate).orElse(null); + } + + public static String getStringObjectBy(Model model, Resource subject, IRI predicate) { + return Models.getProperty(model, subject, predicate).map(Value::stringValue).orElse(null); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/utils/TimeUtils.java b/src/main/java/org/fairdatatrain/trainhandler/utils/TimeUtils.java new file mode 100644 index 0000000..2dc49d3 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/utils/TimeUtils.java @@ -0,0 +1,33 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.utils; + +import java.sql.Timestamp; +import java.time.Instant; + +public class TimeUtils { + + public static Timestamp now() { + return Timestamp.from(Instant.now()); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/utils/ValueFactoryUtils.java b/src/main/java/org/fairdatatrain/trainhandler/utils/ValueFactoryUtils.java new file mode 100644 index 0000000..aa5d059 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/utils/ValueFactoryUtils.java @@ -0,0 +1,91 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.utils; + +import org.eclipse.rdf4j.model.*; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.model.util.Values; + +import java.util.Optional; + +public class ValueFactoryUtils { + + private static final String PREFIX_SEP = ":"; + + private static final ValueFactory VF = SimpleValueFactory.getInstance(); + + public static IRI i(String iri) { + if (iri == null) { + return null; + } + return Values.iri(iri); + } + + public static IRI i(Optional optionalIri) { + if (optionalIri.isEmpty()) { + return null; + } + return i(optionalIri.get()); + } + + public static IRI i(String iri, Model model) { + if (iri != null) { + // URI: ':title' + if (iri.startsWith(PREFIX_SEP)) { + final Optional optionalNamespace = model.getNamespace(""); + final String prefix = optionalNamespace.get().getName(); + return i(prefix + iri.substring(1)); + } + + // URI: 'rda:title' + final String[] splitted = iri.split(PREFIX_SEP); + if (splitted.length == 2 && splitted[1].charAt(0) != '/') { + final Optional optionalNamespace = model.getNamespace(splitted[0]); + final String prefix = optionalNamespace.get().getName(); + return i(prefix + splitted[1]); + } + + // URI: 'http://schema.org/person#title' + if (iri.contains("://")) { + return i(iri); + } + + } + return null; + } + + public static IRI i(Value value) { + if (value == null) { + return null; + } + return i(value.stringValue()); + } + + public static Statement s(Resource subject, IRI predicate, Value object) { + return VF.createStatement(subject, predicate, object); + } + + public static Statement s(Resource subject, IRI predicate, Value object, Resource context) { + return VF.createStatement(subject, predicate, object, context); + } +} diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..b08f455 --- /dev/null +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,24 @@ +{ + "properties": [ + { + "name": "dispatcher.polling.timeout", + "type": "java.lang.String", + "description": "HTTP Long polling timeout (ISO-8601 duration)" + }, + { + "name": "dispatcher.dispatch.root", + "type": "java.lang.String", + "description": "Root URL for composing callback URLs" + }, + { + "name": "dispatcher.dispatch.initDelay", + "type": "java.lang.String", + "description": "Initial delay for periodic dispatching task (ISO-8601 duration)" + }, + { + "name": "dispatcher.dispatch.interval", + "type": "java.lang.String", + "description": "Interval for periodic dispatching task (ISO-8601 duration)" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/application-ci.yml b/src/main/resources/application-ci.yml new file mode 100644 index 0000000..604bf29 --- /dev/null +++ b/src/main/resources/application-ci.yml @@ -0,0 +1,5 @@ +spring: + datasource: + url: jdbc:postgresql://localhost/train-handler-test + username: train-handler + password: password diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..0556729 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,23 @@ +spring: + datasource: + url: jdbc:postgresql://localhost/train_handler + username: postgres + password: password + flyway: + locations: classpath:db/migration,classpath:dev/db/migration + +keycloak: + enabled: false + realm: myrealm + auth-server-url: http://localhost:8000 + resource: myapi + public-client: true + bearer-only: true + +dispatcher: + dispatch: + root: http://localhost:8080 + +logging: + level: + com.zaxxer.hikari: TRACE diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml new file mode 100644 index 0000000..df22c71 --- /dev/null +++ b/src/main/resources/application-test.yml @@ -0,0 +1,8 @@ +spring: + datasource: + url: jdbc:postgresql://localhost/train_handler_test + username: postgres + password: password + +keycloak: + enabled: false diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..d3e5126 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,51 @@ +dispatcher: + polling: + timeout: ${FDT_POLLING_TIMEOUT:PT2M} + dispatch: + root: ${FDT_DISPATCH_ROOT:http://localhost:8080} + initDelay: ${FDT_DISPATCH_INIT_DELAY:PT30S} + interval: ${FDT_DISPATCH_INTERVAL:PT30S} + +spring: + main: + banner-mode: off + datasource: + url: jdbc:postgresql://${FDT_POSTGRES_HOST:postgres}:${FDT_POSTGRES_PORT:5432}/${FDT_POSTGRES_DB:train_handler} + username: ${FDT_POSTGRES_USERNAME:postgres} + password: ${FDT_POSTGRES_PASSWORD:password} + hikari: + pool-name: PGHikariPool + max-pool-size: 10 + min-idle: 5 + flyway: + locations: classpath:db/migration + jpa: + properties: + hibernate: + ddl-auto: validate + dialect: org.hibernate.dialect.PostgreSQLDialect + +keycloak: + enabled: ${FDT_KEYCLOAK_ENABLED:false} + realm: ${FDT_KEYCLOAK_REALM:myrealm} + auth-server-url: ${FDT_KEYCLOAK_URL:http://localhost:8000} + resource: ${FDT_KEYCLOAK_RESOURCE:myapi} + public-client: true + bearer-only: true + +springdoc: + swagger-ui: + disable-swagger-default-url: true + operationsSorter: alpha + +management: + health: + solr: + enabled: false + info: + defaults: + enabled: false + endpoints: + web: + exposure: + include: health, info diff --git a/src/main/resources/db/migration/.gitkeep b/src/main/resources/db/migration/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/db/migration/V0001__directory-and-garage.sql b/src/main/resources/db/migration/V0001__directory-and-garage.sql new file mode 100644 index 0000000..311a55e --- /dev/null +++ b/src/main/resources/db/migration/V0001__directory-and-garage.sql @@ -0,0 +1,50 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +CREATE TABLE IF NOT EXISTS station_directory +( + uuid UUID NOT NULL + CONSTRAINT station_directory_pk PRIMARY KEY, + uri TEXT NOT NULL, + display_name VARCHAR(255) NOT NULL, + note TEXT NOT NULL, + metadata TEXT, + status VARCHAR(50), + last_contact TIMESTAMP, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +CREATE TABLE IF NOT EXISTS train_garage +( + uuid UUID NOT NULL + CONSTRAINT train_garage_pk PRIMARY KEY, + uri TEXT NOT NULL, + display_name VARCHAR(255) NOT NULL, + note TEXT NOT NULL, + metadata TEXT, + status VARCHAR(50), + last_contact TIMESTAMP, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); diff --git a/src/main/resources/db/migration/V0002.0__trains-stations.sql b/src/main/resources/db/migration/V0002.0__trains-stations.sql new file mode 100644 index 0000000..c83f2b1 --- /dev/null +++ b/src/main/resources/db/migration/V0002.0__trains-stations.sql @@ -0,0 +1,108 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +ALTER TABLE station_directory + RENAME COLUMN last_contact TO last_contact_at; +ALTER TABLE train_garage + RENAME COLUMN last_contact TO last_contact_at; + +CREATE TABLE IF NOT EXISTS train_type +( + uuid UUID NOT NULL + CONSTRAINT train_type_pk PRIMARY KEY, + uri TEXT NOT NULL, + title TEXT NOT NULL, + note TEXT NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +CREATE TABLE IF NOT EXISTS train +( + uuid UUID NOT NULL + CONSTRAINT train_pk PRIMARY KEY, + uri TEXT NOT NULL, + title TEXT NOT NULL, + description TEXT NOT NULL, + keywords TEXT, + metadata TEXT, + status VARCHAR(50), + last_contact_at TIMESTAMP, + train_garage_id UUID NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +ALTER TABLE train + ADD CONSTRAINT train_train_garage_fk FOREIGN KEY (train_garage_id) REFERENCES train_garage (uuid); + +CREATE TABLE IF NOT EXISTS station +( + uuid UUID NOT NULL + CONSTRAINT station_pk PRIMARY KEY, + uri TEXT NOT NULL, + title TEXT NOT NULL, + description TEXT NOT NULL, + keywords TEXT, + metadata TEXT, + status VARCHAR(50), + last_contact_at TIMESTAMP, + station_directory_id UUID NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +ALTER TABLE station + ADD CONSTRAINT station_station_directory_fk FOREIGN KEY (station_directory_id) REFERENCES station_directory (uuid); + + +CREATE TABLE IF NOT EXISTS train_train_type +( + train_type_id uuid NOT NULL, + train_id uuid NOT NULL +); + +ALTER TABLE ONLY train_train_type + ADD CONSTRAINT train_train_type_pk PRIMARY KEY (train_type_id, train_id); + +ALTER TABLE ONLY train_train_type + ADD CONSTRAINT train_train_type_train_type_fk FOREIGN KEY (train_type_id) REFERENCES train_type (uuid); + +ALTER TABLE ONLY train_train_type + ADD CONSTRAINT train_train_type_train_fk FOREIGN KEY (train_id) REFERENCES train (uuid); + + +CREATE TABLE IF NOT EXISTS station_train_type +( + train_type_id uuid NOT NULL, + station_id uuid NOT NULL +); + +ALTER TABLE ONLY station_train_type + ADD CONSTRAINT station_train_type_pk PRIMARY KEY (train_type_id, station_id); + +ALTER TABLE ONLY station_train_type + ADD CONSTRAINT station_train_type_train_type_fk FOREIGN KEY (train_type_id) REFERENCES train_type (uuid); + +ALTER TABLE ONLY station_train_type + ADD CONSTRAINT station_train_type_station_fk FOREIGN KEY (station_id) REFERENCES station (uuid); diff --git a/src/main/resources/db/migration/V0003.0__plans-runs.sql b/src/main/resources/db/migration/V0003.0__plans-runs.sql new file mode 100644 index 0000000..fb193a0 --- /dev/null +++ b/src/main/resources/db/migration/V0003.0__plans-runs.sql @@ -0,0 +1,52 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +CREATE TABLE IF NOT EXISTS plan +( + uuid UUID NOT NULL + CONSTRAINT train_instance_pk PRIMARY KEY, + display_name TEXT NOT NULL, + note TEXT NOT NULL, + train_id UUID NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +ALTER TABLE plan + ADD CONSTRAINT plan_train_fk FOREIGN KEY (train_id) REFERENCES train (uuid); + +CREATE TABLE IF NOT EXISTS plan_target +( + uuid UUID NOT NULL + CONSTRAINT plan_target_pk PRIMARY KEY, + station_id UUID NOT NULL, + plan_id UUID NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +ALTER TABLE plan_target + ADD CONSTRAINT plan_target_station_fk FOREIGN KEY (station_id) REFERENCES station (uuid); + +ALTER TABLE plan_target + ADD CONSTRAINT plan_target_plan_fk FOREIGN KEY (plan_id) REFERENCES plan (uuid); diff --git a/src/main/resources/db/migration/V0003.1__sync-status-enums.sql b/src/main/resources/db/migration/V0003.1__sync-status-enums.sql new file mode 100644 index 0000000..09e2a94 --- /dev/null +++ b/src/main/resources/db/migration/V0003.1__sync-status-enums.sql @@ -0,0 +1,59 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +CREATE TYPE sync_service_status AS ENUM ( + 'SYNCED', + 'SYNCING', + 'UNREACHABLE', + 'INVALID', + 'DELETED' + ); + +CREATE CAST (character varying AS sync_service_status) WITH INOUT AS ASSIGNMENT; + +ALTER TABLE station_directory + DROP COLUMN status; +ALTER TABLE station_directory + ADD COLUMN status sync_service_status NOT NULL DEFAULT 'SYNCED'; + +ALTER TABLE train_garage + DROP COLUMN status; +ALTER TABLE train_garage + ADD COLUMN status sync_service_status NOT NULL DEFAULT 'SYNCED'; + +CREATE TYPE sync_item_status AS ENUM ( + 'SYNCED', + 'DELETED' + ); + +CREATE CAST (character varying AS sync_item_status) WITH INOUT AS ASSIGNMENT; + +ALTER TABLE train + DROP COLUMN status; +ALTER TABLE train + ADD COLUMN status sync_item_status NOT NULL DEFAULT 'SYNCED'; + +ALTER TABLE station + DROP COLUMN status; +ALTER TABLE station + ADD COLUMN status sync_item_status NOT NULL DEFAULT 'SYNCED'; diff --git a/src/main/resources/db/migration/V0003.2__runs_jobs_events.sql b/src/main/resources/db/migration/V0003.2__runs_jobs_events.sql new file mode 100644 index 0000000..b53ad77 --- /dev/null +++ b/src/main/resources/db/migration/V0003.2__runs_jobs_events.sql @@ -0,0 +1,115 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +CREATE TYPE run_status AS ENUM ( + 'SCHEDULED', + 'PREPARED', + 'RUNNING', + 'FINISHED', + 'ABORTING', + 'ABORTED', + 'ERRORED', + 'FAILED' + ); + +CREATE CAST (character varying AS run_status) WITH INOUT AS ASSIGNMENT; + +CREATE TYPE job_status AS ENUM ( + 'PREPARED', + 'QUEUED', + 'RUNNING', + 'FINISHED', + 'ABORTING', + 'ABORTED', + 'ERRORED', + 'FAILED' + ); + +CREATE CAST (character varying AS job_status) WITH INOUT AS ASSIGNMENT; + +CREATE TYPE job_event_type AS ENUM ( + 'ARTEFACT', + 'INIT', + 'INFO' + ); + +CREATE CAST (character varying AS job_event_type) WITH INOUT AS ASSIGNMENT; + +CREATE TABLE IF NOT EXISTS run +( + uuid UUID NOT NULL + CONSTRAINT run_pk PRIMARY KEY, + display_name VARCHAR(255) NOT NULL, + note TEXT NOT NULL, + status run_status NOT NULL, + should_start_at TIMESTAMP, + started_at TIMESTAMP, + finished_at TIMESTAMP, + plan_id UUID NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +ALTER TABLE ONLY run + ADD CONSTRAINT run_plan_fk FOREIGN KEY (plan_id) REFERENCES plan (uuid); + +CREATE TABLE IF NOT EXISTS job +( + uuid UUID NOT NULL + CONSTRAINT job_pk PRIMARY KEY, + secret VARCHAR(255) NOT NULL, + remote_id TEXT, + status job_status NOT NULL, + started_at TIMESTAMP, + finished_at TIMESTAMP, + plan_target_id UUID NOT NULL, + run_id UUID NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +ALTER TABLE ONLY job + ADD CONSTRAINT job_plan_target_fk FOREIGN KEY (plan_target_id) REFERENCES plan_target (uuid); + +ALTER TABLE ONLY job + ADD CONSTRAINT job_run_fk FOREIGN KEY (run_id) REFERENCES run (uuid); + +CREATE TABLE IF NOT EXISTS job_event +( + uuid UUID NOT NULL + CONSTRAINT job_event_pk PRIMARY KEY, + type job_event_type NOT NULL, + result_status job_status, + occurred_at TIMESTAMP, + message TEXT NOT NULL, + payload JSON, + job_id UUID NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +ALTER TABLE ONLY job_event + ADD CONSTRAINT job_event_job_fk FOREIGN KEY (job_id) REFERENCES job (uuid); + + + diff --git a/src/main/resources/db/migration/V0003.4__job-artifacts.sql b/src/main/resources/db/migration/V0003.4__job-artifacts.sql new file mode 100644 index 0000000..876132e --- /dev/null +++ b/src/main/resources/db/migration/V0003.4__job-artifacts.sql @@ -0,0 +1,56 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +ALTER TABLE job_event + DROP COLUMN type; + +ALTER TABLE job_event + DROP COLUMN payload; + +CREATE TYPE artifact_storage AS ENUM ( + 'POSTGRES', + 'S3', + 'LOCALFS' + ); + +CREATE CAST (character varying AS artifact_storage) WITH INOUT AS ASSIGNMENT; + +CREATE TABLE IF NOT EXISTS job_artifact +( + uuid UUID NOT NULL + CONSTRAINT job_artifact_pk PRIMARY KEY, + display_name VARCHAR NOT NULL, + filename VARCHAR NOT NULL, + bytesize BIGINT NOT NULL, + hash VARCHAR(64) NOT NULL, + content_type VARCHAR NOT NULL, + storage artifact_storage NOT NULL, + occurred_at TIMESTAMP NOT NULL, + data BYTEA, + job_id UUID NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +ALTER TABLE ONLY job_artifact + ADD CONSTRAINT job_artifact_job_fk FOREIGN KEY (job_id) REFERENCES job (uuid); diff --git a/src/main/resources/db/migration/V0003.6__run-job-version.sql b/src/main/resources/db/migration/V0003.6__run-job-version.sql new file mode 100644 index 0000000..f0d367e --- /dev/null +++ b/src/main/resources/db/migration/V0003.6__run-job-version.sql @@ -0,0 +1,28 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +ALTER TABLE run + ADD COLUMN version BIGINT NOT NULL DEFAULT 0; + +ALTER TABLE job + ADD COLUMN version BIGINT NOT NULL DEFAULT 0; diff --git a/src/main/resources/db/migration/V0004.0__add-soft-delete.sql b/src/main/resources/db/migration/V0004.0__add-soft-delete.sql new file mode 100644 index 0000000..8e0ea36 --- /dev/null +++ b/src/main/resources/db/migration/V0004.0__add-soft-delete.sql @@ -0,0 +1,28 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +ALTER TABLE train + ADD COLUMN soft_deleted BOOLEAN NOT NULL DEFAULT FALSE; + +ALTER TABLE station + ADD COLUMN soft_deleted BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/src/main/resources/db/migration/V0005.0__default-train-types.sql b/src/main/resources/db/migration/V0005.0__default-train-types.sql new file mode 100644 index 0000000..e734071 --- /dev/null +++ b/src/main/resources/db/migration/V0005.0__default-train-types.sql @@ -0,0 +1,55 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +-- Default train types based on FDT ontology +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('8b4acd34-5738-49d4-918f-7d4955ded0bc', 'https://w3id.org/fdt/fdt-o#DockerTrain', 'Docker Train', '', + '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('f5eef54f-b85c-4109-b26b-18e15c8e0751', 'https://w3id.org/fdt/fdt-o#SPARQLTrain', 'SPARQL Train', '', + '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('32d36066-dbf6-4ed3-b4da-aad0edd1639a', 'https://w3id.org/fdt/fdt-o#SQLTrain', 'SQL Train', '', + '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('767a46c1-0bab-4b87-a8df-de5600946a66', 'https://w3id.org/fdt/fdt-o#FHIRTrain', 'FHIR Train', '', + '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('77aedb36-592d-4577-8732-7d837acc35ba', 'https://w3id.org/fdt/fdt-o#GraphQLTrain', 'GraphQL Train', '', + '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('4ec48955-484c-4eee-a8bb-fef0633062d6', 'https://w3id.org/fdt/fdt-o#PythonTrain', 'Python Train', '', + '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('0da459b5-ec93-4cd5-930d-d9fe86be0d2a', 'https://w3id.org/fdt/fdt-o#RESTTrain', 'REST Train', '', + '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('9f32d058-1791-4356-8c1e-f735026d91b0', 'https://w3id.org/fdt/fdt-o#RTrain', 'R Train', '', + '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('f1112bb9-d888-470c-91f3-39a8e888a6d1', 'https://w3id.org/fdt/fdt-o#SingularityTrain', 'Singularity Train', '', + '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); +INSERT INTO public.train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('5513164c-e440-455e-8c71-339324780576', 'https://w3id.org/fdt/fdt-o#TriplePatternFragmentTrain', + 'Triple Pattern Fragment Train', '', '2023-01-09 10:00:00.000000', '2023-01-09 10:00:00.000000'); + diff --git a/src/main/resources/db/migration/V0006.0__station-endpoint.sql b/src/main/resources/db/migration/V0006.0__station-endpoint.sql new file mode 100644 index 0000000..493fc9b --- /dev/null +++ b/src/main/resources/db/migration/V0006.0__station-endpoint.sql @@ -0,0 +1,31 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +ALTER TABLE station + ADD COLUMN endpoint_url TEXT NOT NULL DEFAULT ''; +ALTER TABLE station + ADD COLUMN endpoint_description TEXT NOT NULL DEFAULT ''; + +UPDATE station +SET endpoint_url = uri +WHERE station.endpoint_url = ''; \ No newline at end of file diff --git a/src/main/resources/db/migration/V0007.0__add-public-artifacts.sql b/src/main/resources/db/migration/V0007.0__add-public-artifacts.sql new file mode 100644 index 0000000..94f3b94 --- /dev/null +++ b/src/main/resources/db/migration/V0007.0__add-public-artifacts.sql @@ -0,0 +1,28 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +ALTER TABLE plan + ADD COLUMN publish_artifacts BOOLEAN NOT NULL DEFAULT FALSE; + +ALTER TABLE plan_target + ADD COLUMN publish_artifacts BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/src/main/resources/db/migration/V0007.1__fix-garage-requirement.sql b/src/main/resources/db/migration/V0007.1__fix-garage-requirement.sql new file mode 100644 index 0000000..b96d178 --- /dev/null +++ b/src/main/resources/db/migration/V0007.1__fix-garage-requirement.sql @@ -0,0 +1,28 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +ALTER TABLE train + ALTER COLUMN train_garage_id DROP NOT NULL; + +ALTER TABLE station + ALTER COLUMN station_directory_id DROP NOT NULL; diff --git a/src/main/resources/dev/db/migration/V0002.1__dev_data.sql b/src/main/resources/dev/db/migration/V0002.1__dev_data.sql new file mode 100644 index 0000000..8bdb338 --- /dev/null +++ b/src/main/resources/dev/db/migration/V0002.1__dev_data.sql @@ -0,0 +1,115 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +-- Station Directories +INSERT INTO station_directory (uuid, uri, display_name, note, metadata, status, last_contact_at, created_at, updated_at) +VALUES ('6dfc348a-3ceb-49b2-ac5a-eff83bdf7eae', 'http://example.com/fds/station-directory1', + 'Station Directory 1: Health', 'Note for Station Directory 1 which is an example...', '', 'SYNCED', NOW(), + NOW(), NOW()); + +INSERT INTO station_directory (uuid, uri, display_name, note, metadata, status, last_contact_at, created_at, updated_at) +VALUES ('4475579a-0497-4b4d-babe-56f6b7a38ee7', 'http://example.com/fds/station-directory2', + 'Station Directory 2: COVID', 'Note for Station Directory 2 which is an example...', '', 'SYNCED', NOW(), NOW(), + NOW()); + +INSERT INTO station_directory (uuid, uri, display_name, note, metadata, status, last_contact_at, created_at, updated_at) +VALUES ('1f50ad0e-aa8a-41b8-8934-d498ad0e2635', 'http://example.com/fds/station-directory3', + 'Station Directory 3: Random', 'Note for Station Directory 3 which is an example...', '', 'INVALID', NOW(), + NOW(), NOW()); + +-- Train Garages +INSERT INTO train_garage (uuid, uri, display_name, note, metadata, status, last_contact_at, created_at, updated_at) +VALUES ('a3bad37e-9333-4963-88ca-7c0b05a61ee8', 'http://example.com/fds/train-garage1', 'Train Garage 1', + 'Note for Train Garage 1 which is an example...', '', 'SYNCED', NOW(), NOW(), NOW()); + +INSERT INTO train_garage (uuid, uri, display_name, note, metadata, status, last_contact_at, created_at, updated_at) +VALUES ('7c9594d1-d20e-449a-bd7f-393e1f6b87ac', 'http://example.com/fds/train-garage2', 'Train Garage 2', + 'Note for Train Garage 2 which is an example...', '', 'INVALID', NOW(), NOW(), NOW()); + +-- Train Type +INSERT INTO train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('f5eef54f-b85c-4109-b26b-18e15c8e075f', 'https://w3id.org/fdp/fdt-o#SPARQLTrain', 'SPARQL Train', + 'My note about the SPARQL Train type...', NOW(), NOW()); + +INSERT INTO train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('8b4acd34-5738-49d4-918f-7d4955ded0bf', 'https://w3id.org/fdp/fdt-o#DockerTrain', 'Docker Train', + 'My note about the Docker Train type...', NOW(), NOW()); + +INSERT INTO train_type (uuid, uri, title, note, created_at, updated_at) +VALUES ('32d36066-dbf6-4ed3-b4da-aad0edd1639f', 'https://w3id.org/fdp/fdt-o#SQLTrain', 'SQL Train', + 'My note about the SQL Train type...', NOW(), NOW()); + +-- Stations +INSERT INTO station (uuid, uri, title, description, keywords, metadata, status, last_contact_at, station_directory_id, + created_at, updated_at) +VALUES ('9b2f99bb-6ca4-4326-82c1-bba34fb39abc', 'http://example.com/fds/station1', + 'Station 1: Public Health Data Station', 'Description for station 1 ...', 'Health,SPARQL,SQL,Query', '', + 'SYNCED', NOW(), '6dfc348a-3ceb-49b2-ac5a-eff83bdf7eae', NOW(), NOW()); +INSERT INTO station_train_type (train_type_id, station_id) +VALUES ('f5eef54f-b85c-4109-b26b-18e15c8e075f', '9b2f99bb-6ca4-4326-82c1-bba34fb39abc'); +INSERT INTO station_train_type (train_type_id, station_id) +VALUES ('32d36066-dbf6-4ed3-b4da-aad0edd1639f', '9b2f99bb-6ca4-4326-82c1-bba34fb39abc'); + +INSERT INTO station (uuid, uri, title, description, keywords, metadata, status, last_contact_at, station_directory_id, + created_at, updated_at) +VALUES ('a4d6cf81-1e7a-4666-88e7-26fbdd992674', 'http://example.com/fds/station2', + 'Station 2: Public COVID Data Station', 'Description for station 2 ...', 'Health,COVID,SPARQL', '', 'SYNCED', + NOW(), '6dfc348a-3ceb-49b2-ac5a-eff83bdf7eae', NOW(), NOW()); +INSERT INTO station_train_type (train_type_id, station_id) +VALUES ('f5eef54f-b85c-4109-b26b-18e15c8e075f', 'a4d6cf81-1e7a-4666-88e7-26fbdd992674'); + +INSERT INTO station (uuid, uri, title, description, keywords, metadata, status, last_contact_at, station_directory_id, + created_at, updated_at) +VALUES ('f41417ab-ef19-408f-ba69-5d3a1bc42e23', 'http://example.com/fds/station3', + 'Station 3: Another COVID Data Station', 'Description for station 3 ...', 'Health,COVID,SPARQL,Docker', '', + 'SYNCED', NOW(), '4475579a-0497-4b4d-babe-56f6b7a38ee7', NOW(), NOW()); +INSERT INTO station_train_type (train_type_id, station_id) +VALUES ('f5eef54f-b85c-4109-b26b-18e15c8e075f', 'f41417ab-ef19-408f-ba69-5d3a1bc42e23'); +INSERT INTO station_train_type (train_type_id, station_id) +VALUES ('8b4acd34-5738-49d4-918f-7d4955ded0bf', 'f41417ab-ef19-408f-ba69-5d3a1bc42e23'); + +-- Stations +INSERT INTO train (uuid, uri, title, description, keywords, metadata, status, last_contact_at, train_garage_id, + created_at, updated_at) +VALUES ('e816b968-2663-4110-889d-7023b797c407', 'http://example.com/fds/train1', + 'SPARQL query to retrieve COVID 19 data', + 'SPARQL query to retrieve COVID 19 cases per region in the Netherlands', 'Health,COVID,SPARQL', '', 'SYNCED', + NOW(), 'a3bad37e-9333-4963-88ca-7c0b05a61ee8', NOW(), NOW()); +INSERT INTO train_train_type (train_type_id, train_id) +VALUES ('f5eef54f-b85c-4109-b26b-18e15c8e075f', 'e816b968-2663-4110-889d-7023b797c407'); + +INSERT INTO train (uuid, uri, title, description, keywords, metadata, status, last_contact_at, train_garage_id, + created_at, updated_at) +VALUES ('5dd5c8d4-d084-4ade-8647-cdf0df0702c2', 'http://example.com/fds/train2', 'SQL Train for nice table', + 'SQL train creating very nice table for health data', 'Health,SQL,Table', '', 'SYNCED', NOW(), + 'a3bad37e-9333-4963-88ca-7c0b05a61ee8', NOW(), NOW()); +INSERT INTO train_train_type (train_type_id, train_id) +VALUES ('32d36066-dbf6-4ed3-b4da-aad0edd1639f', '5dd5c8d4-d084-4ade-8647-cdf0df0702c2'); + +INSERT INTO train (uuid, uri, title, description, keywords, metadata, status, last_contact_at, train_garage_id, + created_at, updated_at) +VALUES ('a1eea8ce-e332-4e7b-b41d-880b53d709f4', 'http://example.com/fds/train3', 'SPARQL query summarizing COVID data', + 'SPARQL summary of COVID 19 cases for entire dataset', 'Health,COVID,SPARQL,Summary', '', 'SYNCED', NOW(), + 'a3bad37e-9333-4963-88ca-7c0b05a61ee8', NOW(), NOW()); +INSERT INTO train_train_type (train_type_id, train_id) +VALUES ('f5eef54f-b85c-4109-b26b-18e15c8e075f', 'a1eea8ce-e332-4e7b-b41d-880b53d709f4'); diff --git a/src/main/resources/dev/db/migration/V0003.3__dev_data.sql b/src/main/resources/dev/db/migration/V0003.3__dev_data.sql new file mode 100644 index 0000000..61a00e4 --- /dev/null +++ b/src/main/resources/dev/db/migration/V0003.3__dev_data.sql @@ -0,0 +1,79 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +INSERT INTO public.plan (uuid, display_name, note, train_id, created_at, updated_at) +VALUES ('4556f410-d400-4bce-b8a3-baf255add4e0', 'SPARQL for COVID Portal', + 'This plan dispatches the COVID-SPARQL train to compatible stations...', 'a1eea8ce-e332-4e7b-b41d-880b53d709f4', + '2022-04-09 21:04:13.000000', '2022-04-09 21:04:13.000000'); + +INSERT INTO public.plan_target (uuid, station_id, plan_id, created_at, updated_at) +VALUES ('c3602f76-8018-494d-834f-ccfc5959ca7c', 'a4d6cf81-1e7a-4666-88e7-26fbdd992674', + '4556f410-d400-4bce-b8a3-baf255add4e0', '2022-04-09 21:04:50.000000', '2022-04-09 21:04:50.000000'); +INSERT INTO public.plan_target (uuid, station_id, plan_id, created_at, updated_at) +VALUES ('edf65259-d79f-403c-83a9-452ea3905655', 'f41417ab-ef19-408f-ba69-5d3a1bc42e23', + '4556f410-d400-4bce-b8a3-baf255add4e0', '2022-04-09 21:05:21.000000', '2022-04-09 21:05:21.000000'); + +INSERT INTO public.run (uuid, display_name, note, status, should_start_at, started_at, finished_at, plan_id, created_at, + updated_at) +VALUES ('53135c4a-fa97-49e8-8c55-5e9a3f10d8c4', 'SPARQL for COVID Portal #1', 'Trying this for the first time...', + 'FINISHED', null, '2022-04-09 21:07:07.000000', '2022-04-09 21:09:16.000000', + '4556f410-d400-4bce-b8a3-baf255add4e0', '2022-04-09 21:07:26.000000', '2022-04-09 21:07:26.000000'); + +INSERT INTO public.job (uuid, secret, remote_id, status, started_at, finished_at, plan_target_id, run_id, created_at, + updated_at) +VALUES ('633879bd-df36-4c93-b455-6b9a56321771', 'verySecret', 'someRemoteId', 'FINISHED', '2022-04-09 21:10:43.000000', + '2022-04-09 22:03:47.000000', 'c3602f76-8018-494d-834f-ccfc5959ca7c', '53135c4a-fa97-49e8-8c55-5e9a3f10d8c4', + '2022-04-09 21:09:07.000000', '2022-04-09 21:09:07.000000'); +INSERT INTO public.job (uuid, secret, remote_id, status, started_at, finished_at, plan_target_id, run_id, created_at, + updated_at) +VALUES ('0f8fa3ca-02b6-4cd3-b346-93b156166554', 'anotherSecret', 'anotherRemoteId', 'FINISHED', + '2022-04-09 21:15:40.000000', '2022-04-09 21:56:44.000000', 'edf65259-d79f-403c-83a9-452ea3905655', + '53135c4a-fa97-49e8-8c55-5e9a3f10d8c4', '2022-04-09 21:09:56.000000', '2022-04-09 21:09:56.000000'); + +INSERT INTO public.job_event (uuid, type, result_status, occurred_at, message, payload, job_id, created_at, updated_at) +VALUES ('0fc29c4a-f099-46a7-8d66-90cf76eef59b', 'INFO', 'QUEUED', '2022-04-09 21:18:36.000000', + 'Train queued in the data station', '{}', '633879bd-df36-4c93-b455-6b9a56321771', '2022-04-09 21:19:01.000000', + '2022-04-09 21:19:01.000000'); +INSERT INTO public.job_event (uuid, type, result_status, occurred_at, message, payload, job_id, created_at, updated_at) +VALUES ('e035028e-57ab-4baa-adff-2aa5e1fb04c2', 'INFO', 'RUNNING', '2022-04-09 21:20:00.000000', + 'Started processing the train', '{}', '633879bd-df36-4c93-b455-6b9a56321771', '2022-04-09 21:20:27.000000', + '2022-04-09 21:20:27.000000'); +INSERT INTO public.job_event (uuid, type, result_status, occurred_at, message, payload, job_id, created_at, updated_at) +VALUES ('4fe592ca-b36a-46e5-8f3b-c7b169eb0269', 'INFO', null, '2022-04-09 21:20:52.000000', + 'Checking data access permissions', '{}', '633879bd-df36-4c93-b455-6b9a56321771', '2022-04-09 21:21:17.000000', + '2022-04-09 21:21:17.000000'); +INSERT INTO public.job_event (uuid, type, result_status, occurred_at, message, payload, job_id, created_at, updated_at) +VALUES ('0c6f3cca-f1a7-46db-874b-955cdd3abccc', 'INFO', null, '2022-04-09 21:21:53.000000', + 'Access granted, querying data', '{}', '633879bd-df36-4c93-b455-6b9a56321771', '2022-04-09 21:22:17.000000', + '2022-04-09 21:22:17.000000'); +INSERT INTO public.job_event (uuid, type, result_status, occurred_at, message, payload, job_id, created_at, updated_at) +VALUES ('80b6bfbb-d128-4af2-ac90-849b3574735b', 'INFO', 'FINISHED', '2022-04-09 21:22:49.000000', + 'Query executed successfully', '{}', '633879bd-df36-4c93-b455-6b9a56321771', '2022-04-09 21:23:08.000000', + '2022-04-09 21:23:08.000000'); +INSERT INTO public.job_event (uuid, type, result_status, occurred_at, message, payload, job_id, created_at, updated_at) +VALUES ('7a35a0a8-ed96-48a8-84e0-9718778a8f21', 'ARTEFACT', null, '2022-04-09 21:22:50.000000', + 'Sending the result to handler', '{ + "contentType": "text/plain", + "base64": false, + "content": "Hello, world!" + }', '633879bd-df36-4c93-b455-6b9a56321771', '2022-04-09 21:25:13.000000', '2022-04-09 21:25:13.000000'); diff --git a/src/main/resources/dev/db/migration/V0003.5__dev_data.sql b/src/main/resources/dev/db/migration/V0003.5__dev_data.sql new file mode 100644 index 0000000..662afc6 --- /dev/null +++ b/src/main/resources/dev/db/migration/V0003.5__dev_data.sql @@ -0,0 +1,26 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +INSERT INTO public.job_artifact (uuid, display_name, filename, bytesize, hash, content_type, storage, occurred_at, data, job_id, created_at, updated_at) +VALUES ('c667d5f3-6f34-490f-98c6-5890ddf5e456', 'Hello World Document', 'hello-world.txt', 14, 'd9014c4624844aa5bac314773d6b689ad467fa4e1d1a50a1b8a99d5a95f72ff5', 'text/plain', 'POSTGRES', '2022-04-09 21:22:00.000000', 'Hello, world! +', '633879bd-df36-4c93-b455-6b9a56321771', '2022-04-09 21:23:00.000000', '2022-04-04 21:23:00.000000'); diff --git a/src/main/resources/dev/db/migration/V0003.7__dev_data.sql b/src/main/resources/dev/db/migration/V0003.7__dev_data.sql new file mode 100644 index 0000000..8e43df7 --- /dev/null +++ b/src/main/resources/dev/db/migration/V0003.7__dev_data.sql @@ -0,0 +1,28 @@ +-- +-- The MIT License +-- Copyright © 2022 FAIR Data Team +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +-- + +UPDATE public.run SET version = 1649539513000 WHERE uuid = '53135c4a-fa97-49e8-8c55-5e9a3f10d8c4'; + +UPDATE public.job SET version = 1649539513000 WHERE uuid = '633879bd-df36-4c93-b455-6b9a56321771'; + +UPDATE public.job SET version = 1649538596000 WHERE uuid = '0f8fa3ca-02b6-4cd3-b346-93b156166554'; diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..54d9a89 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + %d{ISO8601}{GMT+0} %-6level [%t][traceId:%mdc{traceId}] %logger{1.}: %msg%n%throwable + + + + + + + + + + + + + + + + + diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/WebIntegrationTest.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/WebIntegrationTest.java new file mode 100644 index 0000000..f62f0af --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/WebIntegrationTest.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@ActiveProfiles("test") +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, + properties = {"spring.main.allow-bean-definition-overriding=true"} +) +@AutoConfigureMockMvc +public abstract class WebIntegrationTest { + + @Autowired + protected TestRestTemplate client; + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/ActuatorInfoDTO.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/ActuatorInfoDTO.java new file mode 100644 index 0000000..edccb02 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/ActuatorInfoDTO.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.actuator; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@JsonIgnoreProperties(ignoreUnknown = true) +public class ActuatorInfoDTO { + @NotNull + @NotBlank + private String name; + + @NotNull + @NotBlank + private String version; + + @NotNull + @NotBlank + private String builtAt; +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/CorsTest.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/CorsTest.java new file mode 100644 index 0000000..db43376 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/CorsTest.java @@ -0,0 +1,77 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.actuator; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.acceptance.actuator.ActuatorInfoDTO; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("OPTIONS /actuator/info") +public class CorsTest extends WebIntegrationTest { + + + private URI url() { + return URI.create("/actuator/info"); + } + + @Test + @DisplayName("Correct CORS headers") + public void corsHeaders() { + // GIVEN: + RequestEntity request = RequestEntity + .options(url()) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN), is(notNullValue())); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN).size(), is(equalTo(1))); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN).get(0), is(equalTo("*"))); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS), is(notNullValue())); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS).size(), is(equalTo(1))); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS).get(0), is(equalTo("GET,DELETE,PATCH,POST,PUT"))); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS), is(notNullValue())); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS).size(), is(equalTo(1))); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS).get(0), is(equalTo("Accept,Authorization,Content-Type,Origin"))); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS), is(notNullValue())); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS).size(), is(equalTo(1))); + assertThat(result.getHeaders().get(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS).get(0), is(equalTo("Link,Location"))); + } +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/List_Info_GET.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/List_Info_GET.java new file mode 100644 index 0000000..6f1123d --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/List_Info_GET.java @@ -0,0 +1,82 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.actuator; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("GET /actuator/info") +public class List_Info_GET extends WebIntegrationTest { + + @Value("${git.branch}") + private String branch; + + @Value("${git.commit.id.abbrev}") + private String commitShort; + + @Value("${git.tags}") + private String tag; + + @Value("${build.time}") + private String buildTime; + + private URI url() { + return URI.create("/actuator/info"); + } + + @Test + public void res200() { + // GIVEN: + RequestEntity request = RequestEntity + .get(url()) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody(), is(notNullValue())); + if (tag == null || tag.isEmpty()) { + assertThat(result.getBody().getVersion(), is(equalTo((format("%s~%s", branch, commitShort))))); + } else { + assertThat(result.getBody().getVersion(), is(equalTo((format("%s~%s", tag, commitShort))))); + } + assertThat(result.getBody().getBuiltAt(), is(equalTo(buildTime))); + } + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/helper/HelperPage.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/helper/HelperPage.java new file mode 100644 index 0000000..7366280 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/helper/HelperPage.java @@ -0,0 +1,56 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.helper; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class HelperPage { + + private List content; + + private int number; + + private int size; + + private int totalPages; + + private int totalElements; + + private int numberOfElements; + + private boolean first; + + private boolean last; + + private boolean empty; + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/openapi/OpenApiDocs_GET.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/openapi/OpenApiDocs_GET.java new file mode 100644 index 0000000..0e268d5 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/openapi/OpenApiDocs_GET.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.openapi; +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("GET /v3/api-docs") +public class OpenApiDocs_GET extends WebIntegrationTest { + + private URI url() { + return URI.create("/v3/api-docs"); + } + + @Test + @DisplayName("HTTP 200: API Docs") + public void res200_apiDocs() { + // GIVEN + RequestEntity request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity result = client.exchange(request, new ParameterizedTypeReference<>() {}); + + // THEN + assertThat("Response code is OK", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response is JSON", result.getHeaders().getContentType(), is(equalTo(MediaType.APPLICATION_JSON))); + } +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/openapi/SwaggerUI_GET.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/openapi/SwaggerUI_GET.java new file mode 100644 index 0000000..61124f1 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/openapi/SwaggerUI_GET.java @@ -0,0 +1,87 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.openapi; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("GET /swagger-ui.html") +public class SwaggerUI_GET extends WebIntegrationTest { + + private URI baseUrl() { + return URI.create("/swagger-ui.html"); + } + + private URI redirectedUrl() { + return URI.create("/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config"); + } +/* + @Test + @DisplayName("HTTP 302: Redirects to Swagger UI") + public void res302_redirectsToSwaggerUI() { + // GIVEN + RequestEntity request = RequestEntity + .get(baseUrl()) + .accept(MediaType.TEXT_HTML) + .build(); + + // WHEN + ResponseEntity result = client.exchange(request, new ParameterizedTypeReference<>() {}); + + // THEN + assertThat("Response code is FOUND", result.getStatusCode(), is(equalTo(HttpStatus.FOUND))); + assertThat("Contains Location header", result.getHeaders().getLocation(), is(notNullValue())); + assertThat("Contains correct Location header", result.getHeaders().getLocation().toString().endsWith(redirectedUrl().toString()), is(Boolean.TRUE)); + } +*/ + @Test + @DisplayName("HTTP 200: Swagger UI") + public void res200_swaggerUI() { + // GIVEN + RequestEntity request = RequestEntity + .get(redirectedUrl()) + .accept(MediaType.TEXT_HTML) + .build(); + + // WHEN + ResponseEntity result = client.exchange(request, new ParameterizedTypeReference<>() {}); + + // THEN + assertThat("Response code is OK", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response is Swagger UI in HTML", result.getHeaders().getContentType(), is(equalTo(MediaType.TEXT_HTML))); + } +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Common.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Common.java new file mode 100644 index 0000000..25d0df0 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Common.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.stationdirectory; + +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +public class Common { + + public static void assertEquals(StationDirectoryDTO dto, StationDirectory entity) { + assertThat(dto.getUuid(), is(equalTo(entity.getUuid()))); + assertThat(dto.getDisplayName(), is(equalTo(entity.getDisplayName()))); + assertThat(dto.getMetadata(), is(equalTo(entity.getMetadata()))); + assertThat(dto.getUri(), is(equalTo(entity.getUri()))); + assertThat(dto.getNote(), is(equalTo(entity.getNote()))); + assertThat(dto.getStatus(), is(equalTo(entity.getStatus()))); + } + + public static void assertEquals(StationDirectoryDTO dto, StationDirectoryChangeDTO changeDto) { + assertThat(dto.getDisplayName(), is(equalTo(changeDto.getDisplayName()))); + assertThat(dto.getUri(), is(equalTo(changeDto.getUri()))); + assertThat(dto.getNote(), is(equalTo(changeDto.getNote()))); + } +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_DELETE.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_DELETE.java new file mode 100644 index 0000000..f354854 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_DELETE.java @@ -0,0 +1,98 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.stationdirectory; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.repository.StationDirectoryRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.Optional; +import java.util.UUID; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +@DisplayName("DELETE /station-directories/:uuid") +public class Detail_DELETE extends WebIntegrationTest { + + private URI url(UUID uuid) { + return URI.create(format("/station-directories/%s", uuid)); + } + + @Autowired + private StationDirectoryRepository stationDirectoryRepository; + + @Test + @DisplayName("HTTP 204") + public void res204() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + StationDirectory directory = stationDirectoryRepository.save(StationDirectoryTestFixtures.STATION_DIRECTORY_A); + + // AND: prepare request + RequestEntity request = RequestEntity + .delete(url(directory.getUuid())) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NO_CONTENT))); + Optional directoryAfter = stationDirectoryRepository.findById(directory.getUuid()); + assertThat("Station directory is deleted", directoryAfter.isEmpty(), is(equalTo(true))); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + + // AND: prepare request + RequestEntity request = RequestEntity + .delete(url(UUID.randomUUID())) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NOT_FOUND))); + } + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_GET.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_GET.java new file mode 100644 index 0000000..fff0777 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_GET.java @@ -0,0 +1,97 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.stationdirectory; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.repository.StationDirectoryRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.UUID; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("GET /station-directories/:uuid") +public class Detail_GET extends WebIntegrationTest { + + private URI url(UUID uuid) { + return URI.create(format("/station-directories/%s", uuid)); + } + + @Autowired + private StationDirectoryRepository stationDirectoryRepository; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + StationDirectory directory = stationDirectoryRepository.save(StationDirectoryTestFixtures.STATION_DIRECTORY_A); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(url(directory.getUuid())) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + Common.assertEquals(result.getBody(), directory); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(url(UUID.randomUUID())) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NOT_FOUND))); + } + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_PUT.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_PUT.java new file mode 100644 index 0000000..867220b --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_PUT.java @@ -0,0 +1,134 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.stationdirectory; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.repository.StationDirectoryRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.Optional; +import java.util.UUID; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("PUT /station-directories/:uuid") +public class Detail_PUT extends WebIntegrationTest { + + private URI url(UUID uuid) { + return URI.create(format("/station-directories/%s", uuid)); + } + + @Autowired + private StationDirectoryRepository stationDirectoryRepository; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + StationDirectory directory = stationDirectoryRepository.save(StationDirectoryTestFixtures.STATION_DIRECTORY_A); + StationDirectoryChangeDTO reqDto = StationDirectoryTestFixtures.STATION_DIRECTORY_A_UPDATE; + + // AND: prepare request + RequestEntity request = RequestEntity + .put(url(directory.getUuid())) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + Common.assertEquals(result.getBody(), reqDto); + Optional directoryAfter = stationDirectoryRepository.findById(directory.getUuid()); + assertThat("Station directory is saved", directoryAfter.isPresent(), is(equalTo(true))); + Common.assertEquals(result.getBody(), directoryAfter.get()); + } + + @Test + @DisplayName("HTTP 400") + public void res400() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + StationDirectory directory = stationDirectoryRepository.save(StationDirectoryTestFixtures.STATION_DIRECTORY_A); + StationDirectoryChangeDTO reqDto = + StationDirectoryTestFixtures.STATION_DIRECTORY_A_UPDATE + .toBuilder() + .displayName("") + .build(); + + // AND: prepare request + RequestEntity request = RequestEntity + .put(url(directory.getUuid())) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + StationDirectoryChangeDTO reqDto = StationDirectoryTestFixtures.STATION_DIRECTORY_A_UPDATE; + + // AND: prepare request + RequestEntity request = RequestEntity + .put(url(UUID.randomUUID())) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NOT_FOUND))); + } + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_GET.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_GET.java new file mode 100644 index 0000000..601a180 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_GET.java @@ -0,0 +1,142 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.stationdirectory; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.acceptance.helper.HelperPage; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.repository.StationDirectoryRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.List; +import java.util.stream.StreamSupport; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("GET /station-directories") +public class List_GET extends WebIntegrationTest { + + private URI url() { + return URI.create("/station-directories"); + } + + private URI urlPaged(int page, int size) { + return URI.create(format("/station-directories?page=%d&size=%d", page, size)); + } + + @Autowired + private StationDirectoryRepository stationDirectoryRepository; + + @Test + @DisplayName("HTTP 200: empty") + public void res200_empty() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(url()) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + assertThat("Results page is declared as empty", result.getBody().isEmpty(), is(equalTo(true))); + assertThat("Results page is empty", result.getBody().getContent().isEmpty(), is(equalTo(true))); + } + + @Test + @DisplayName("HTTP 200: non-empty") + public void res200_nonEmpty() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + List stationDirectories = StreamSupport.stream( + stationDirectoryRepository.saveAll(StationDirectoryTestFixtures.STATION_DIRECTORIES).spliterator(), + false + ).toList(); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(url()) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + assertThat("Results page is declared as not-empty", result.getBody().isEmpty(), is(equalTo(false))); + assertThat("Results page has declared correct number of elements", result.getBody().getNumberOfElements(), comparesEqualTo(stationDirectories.size())); + assertThat("Results page has declared correct total elements", result.getBody().getTotalElements(), comparesEqualTo(stationDirectories.size())); + assertThat("Results page has correct size", result.getBody().getContent().size(), comparesEqualTo(stationDirectories.size())); + } + + @Test + @DisplayName("HTTP 200: multi-page") + public void res200_multiPage() { + // GIVEN: prepare data + stationDirectoryRepository.deleteAll(); + List stationDirectories = StreamSupport.stream( + stationDirectoryRepository.saveAll(StationDirectoryTestFixtures.STATION_DIRECTORIES).spliterator(), + false + ).toList(); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(urlPaged(2,1)) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + assertThat("Results page is declared as not-empty", result.getBody().isEmpty(), is(equalTo(false))); + assertThat("Results page has declared current page number", result.getBody().getNumber(), comparesEqualTo(2)); + assertThat("Results page has declared correct number of elements", result.getBody().getNumberOfElements(), comparesEqualTo(1)); + assertThat("Results page has declared correct total elements", result.getBody().getTotalElements(), comparesEqualTo(stationDirectories.size())); + assertThat("Results page has correct size", result.getBody().getContent().size(), comparesEqualTo(1)); + } + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_POST.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_POST.java new file mode 100644 index 0000000..eb9820e --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_POST.java @@ -0,0 +1,106 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.stationdirectory; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.repository.StationDirectoryRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("POST /station-directories") +public class List_POST extends WebIntegrationTest { + + private URI url() { + return URI.create("/station-directories"); + } + + @Autowired + private StationDirectoryRepository stationDirectoryRepository; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: Prepare data + stationDirectoryRepository.deleteAll(); + StationDirectoryChangeDTO reqDto = StationDirectoryTestFixtures.STATION_DIRECTORY_X_CREATE; + + // AND: Prepare request + RequestEntity request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.CREATED))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + Optional oStationDirectory = stationDirectoryRepository.findById(result.getBody().getUuid()); + assertThat("Entity is saved with UUID", oStationDirectory.isPresent(), is(equalTo(true))); + Common.assertEquals(result.getBody(), oStationDirectory.get()); + } + + @Test + @DisplayName("HTTP 400: invalid") + public void res400_invalid() { + // GIVEN: Prepare data + stationDirectoryRepository.deleteAll(); + StationDirectoryChangeDTO reqDto = + StationDirectoryTestFixtures.STATION_DIRECTORY_X_CREATE + .toBuilder() + .displayName("") + .build(); + + // AND: Prepare request + RequestEntity request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/StationDirectoryTestFixtures.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/StationDirectoryTestFixtures.java new file mode 100644 index 0000000..abe0b8c --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/StationDirectoryTestFixtures.java @@ -0,0 +1,91 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.stationdirectory; + +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +public class StationDirectoryTestFixtures { + + public static StationDirectory STATION_DIRECTORY_A = + StationDirectory.builder() + .uuid(UUID.randomUUID()) + .createdAt(Timestamp.from(Instant.now())) + .updatedAt(Timestamp.from(Instant.now())) + .uri("https://example.com/fdt/station-directory/A") + .displayName("Station Directory A") + .note("") + .metadata("") + .status(SyncServiceStatus.SYNCED) + .lastContactAt(Timestamp.from(Instant.now())) + .build(); + + public static StationDirectory STATION_DIRECTORY_B = + StationDirectory.builder() + .uuid(UUID.randomUUID()) + .createdAt(Timestamp.from(Instant.now())) + .updatedAt(Timestamp.from(Instant.now())) + .uri("https://example.com/fdt/station-directory/B") + .displayName("Station Directory B") + .note("") + .metadata("") + .status(SyncServiceStatus.SYNCED) + .lastContactAt(Timestamp.from(Instant.now())) + .build(); + + public static StationDirectory STATION_DIRECTORY_C = + StationDirectory.builder() + .uuid(UUID.randomUUID()) + .createdAt(Timestamp.from(Instant.now())) + .updatedAt(Timestamp.from(Instant.now())) + .uri("https://example.com/fdt/station-directory/C") + .displayName("Station Directory C") + .note("") + .metadata("") + .status(SyncServiceStatus.SYNCED) + .lastContactAt(Timestamp.from(Instant.now())) + .build(); + + public static StationDirectoryChangeDTO STATION_DIRECTORY_X_CREATE = StationDirectoryChangeDTO + .builder() + .uri("https://example.com/fdt/station-directory/X") + .displayName("Station Directory X") + .note("My custom station directory") + .build(); + + public static StationDirectoryChangeDTO STATION_DIRECTORY_A_UPDATE = StationDirectoryChangeDTO + .builder() + .uri("https://example.com/fdt/station-directory/A/edit") + .displayName("Station Directory A: EDIT") + .note("My custom station directory edited") + .build(); + + public static List STATION_DIRECTORIES = Arrays.asList(STATION_DIRECTORY_A, STATION_DIRECTORY_B, STATION_DIRECTORY_C); +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Common.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Common.java new file mode 100644 index 0000000..bf3c94f --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Common.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.traingarage; + +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +public class Common { + + public static void assertEquals(TrainGarageDTO dto, TrainGarage entity) { + assertThat(dto.getUuid(), is(equalTo(entity.getUuid()))); + assertThat(dto.getDisplayName(), is(equalTo(entity.getDisplayName()))); + assertThat(dto.getMetadata(), is(equalTo(entity.getMetadata()))); + assertThat(dto.getUri(), is(equalTo(entity.getUri()))); + assertThat(dto.getNote(), is(equalTo(entity.getNote()))); + assertThat(dto.getStatus(), is(equalTo(entity.getStatus()))); + } + + public static void assertEquals(TrainGarageDTO dto, TrainGarageChangeDTO changeDto) { + assertThat(dto.getDisplayName(), is(equalTo(changeDto.getDisplayName()))); + assertThat(dto.getUri(), is(equalTo(changeDto.getUri()))); + assertThat(dto.getNote(), is(equalTo(changeDto.getNote()))); + } +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_DELETE.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_DELETE.java new file mode 100644 index 0000000..2ce2f37 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_DELETE.java @@ -0,0 +1,98 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.traingarage; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.repository.TrainGarageRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.Optional; +import java.util.UUID; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +@DisplayName("DELETE /train-garages/:uuid") +public class Detail_DELETE extends WebIntegrationTest { + + private URI url(UUID uuid) { + return URI.create(format("/train-garages/%s", uuid)); + } + + @Autowired + private TrainGarageRepository trainGarageRepository; + + @Test + @DisplayName("HTTP 204") + public void res204() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + TrainGarage garage = trainGarageRepository.save(TrainGarageTestFixtures.TRAIN_GARAGE_A); + + // AND: prepare request + RequestEntity request = RequestEntity + .delete(url(garage.getUuid())) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NO_CONTENT))); + Optional directoryAfter = trainGarageRepository.findById(garage.getUuid()); + assertThat("Station directory is deleted", directoryAfter.isEmpty(), is(equalTo(true))); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + + // AND: prepare request + RequestEntity request = RequestEntity + .delete(url(UUID.randomUUID())) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NOT_FOUND))); + } + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_GET.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_GET.java new file mode 100644 index 0000000..282ca55 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_GET.java @@ -0,0 +1,97 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.traingarage; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.repository.TrainGarageRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.UUID; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("GET /train-garages/:uuid") +public class Detail_GET extends WebIntegrationTest { + + private URI url(UUID uuid) { + return URI.create(format("/train-garages/%s", uuid)); + } + + @Autowired + private TrainGarageRepository trainGarageRepository; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + TrainGarage garage = trainGarageRepository.save(TrainGarageTestFixtures.TRAIN_GARAGE_A); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(url(garage.getUuid())) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + Common.assertEquals(result.getBody(), garage); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(url(UUID.randomUUID())) + .build(); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NOT_FOUND))); + } + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_PUT.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_PUT.java new file mode 100644 index 0000000..71cd8b2 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_PUT.java @@ -0,0 +1,134 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.traingarage; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.repository.TrainGarageRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.Optional; +import java.util.UUID; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("PUT /train-garages/:uuid") +public class Detail_PUT extends WebIntegrationTest { + + private URI url(UUID uuid) { + return URI.create(format("/train-garages/%s", uuid)); + } + + @Autowired + private TrainGarageRepository trainGarageRepository; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + TrainGarage garage = trainGarageRepository.save(TrainGarageTestFixtures.TRAIN_GARAGE_A); + TrainGarageChangeDTO reqDto = TrainGarageTestFixtures.TRAIN_GARAGE_A_UPDATE; + + // AND: prepare request + RequestEntity request = RequestEntity + .put(url(garage.getUuid())) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + Common.assertEquals(result.getBody(), reqDto); + Optional directoryAfter = trainGarageRepository.findById(garage.getUuid()); + assertThat("Station directory is saved", directoryAfter.isPresent(), is(equalTo(true))); + Common.assertEquals(result.getBody(), directoryAfter.get()); + } + + @Test + @DisplayName("HTTP 400") + public void res400() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + TrainGarage garage = trainGarageRepository.save(TrainGarageTestFixtures.TRAIN_GARAGE_A); + TrainGarageChangeDTO reqDto = + TrainGarageTestFixtures.TRAIN_GARAGE_A_UPDATE + .toBuilder() + .displayName("") + .build(); + + // AND: prepare request + RequestEntity request = RequestEntity + .put(url(garage.getUuid())) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + TrainGarageChangeDTO reqDto = TrainGarageTestFixtures.TRAIN_GARAGE_A_UPDATE; + + // AND: prepare request + RequestEntity request = RequestEntity + .put(url(UUID.randomUUID())) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NOT_FOUND))); + } + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_GET.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_GET.java new file mode 100644 index 0000000..a7c0cb4 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_GET.java @@ -0,0 +1,142 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.traingarage; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.acceptance.helper.HelperPage; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.repository.TrainGarageRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.List; +import java.util.stream.StreamSupport; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("GET /train-garages") +public class List_GET extends WebIntegrationTest { + + private URI url() { + return URI.create("/train-garages"); + } + + private URI urlPaged(int page, int size) { + return URI.create(format("/train-garages?page=%d&size=%d", page, size)); + } + + @Autowired + private TrainGarageRepository trainGarageRepository; + + @Test + @DisplayName("HTTP 200: empty") + public void res200_empty() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(url()) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + assertThat("Results page is declared as empty", result.getBody().isEmpty(), is(equalTo(true))); + assertThat("Results page is empty", result.getBody().getContent().isEmpty(), is(equalTo(true))); + } + + @Test + @DisplayName("HTTP 200: non-empty") + public void res200_nonEmpty() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + List trainGarages = StreamSupport.stream( + trainGarageRepository.saveAll(TrainGarageTestFixtures.TRAIN_GARAGES).spliterator(), + false + ).toList(); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(url()) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + assertThat("Results page is declared as not-empty", result.getBody().isEmpty(), is(equalTo(false))); + assertThat("Results page has declared correct number of elements", result.getBody().getNumberOfElements(), comparesEqualTo(trainGarages.size())); + assertThat("Results page has declared correct total elements", result.getBody().getTotalElements(), comparesEqualTo(trainGarages.size())); + assertThat("Results page has correct size", result.getBody().getContent().size(), comparesEqualTo(trainGarages.size())); + } + + @Test + @DisplayName("HTTP 200: multi-page") + public void res200_multiPage() { + // GIVEN: prepare data + trainGarageRepository.deleteAll(); + List trainGarages = StreamSupport.stream( + trainGarageRepository.saveAll(TrainGarageTestFixtures.TRAIN_GARAGES).spliterator(), + false + ).toList(); + + // AND: prepare request + RequestEntity request = RequestEntity + .get(urlPaged(2,1)) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + assertThat("Results page is declared as not-empty", result.getBody().isEmpty(), is(equalTo(false))); + assertThat("Results page has declared current page number", result.getBody().getNumber(), comparesEqualTo(2)); + assertThat("Results page has declared correct number of elements", result.getBody().getNumberOfElements(), comparesEqualTo(1)); + assertThat("Results page has declared correct total elements", result.getBody().getTotalElements(), comparesEqualTo(trainGarages.size())); + assertThat("Results page has correct size", result.getBody().getContent().size(), comparesEqualTo(1)); + } + +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_POST.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_POST.java new file mode 100644 index 0000000..2ac669f --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_POST.java @@ -0,0 +1,106 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.traingarage; + +import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.repository.TrainGarageRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +@DisplayName("POST /train-garages") +public class List_POST extends WebIntegrationTest { + + private URI url() { + return URI.create("/train-garages"); + } + + @Autowired + private TrainGarageRepository trainGarageRepository; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: Prepare data + trainGarageRepository.deleteAll(); + TrainGarageChangeDTO reqDto = TrainGarageTestFixtures.TRAIN_GARAGE_X_CREATE; + + // AND: Prepare request + RequestEntity request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.CREATED))); + assertThat("Body is not null", result.getBody(), is(notNullValue())); + Optional oTrainGarage = trainGarageRepository.findById(result.getBody().getUuid()); + assertThat("Entity is saved with UUID", oTrainGarage.isPresent(), is(equalTo(true))); + Common.assertEquals(result.getBody(), oTrainGarage.get()); + } + + @Test + @DisplayName("HTTP 400: invalid") + public void res400_invalid() { + // GIVEN: Prepare data + trainGarageRepository.deleteAll(); + TrainGarageChangeDTO reqDto = + TrainGarageTestFixtures.TRAIN_GARAGE_X_CREATE + .toBuilder() + .displayName("") + .build(); + + // AND: Prepare request + RequestEntity request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } +} diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/TrainGarageTestFixtures.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/TrainGarageTestFixtures.java new file mode 100644 index 0000000..55eb786 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/TrainGarageTestFixtures.java @@ -0,0 +1,91 @@ +/** + * The MIT License + * Copyright © 2022 FAIR Data Team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.fairdatatrain.trainhandler.acceptance.traingarage; + +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +public class TrainGarageTestFixtures { + + public static TrainGarage TRAIN_GARAGE_A = + TrainGarage.builder() + .uuid(UUID.randomUUID()) + .createdAt(Timestamp.from(Instant.now())) + .updatedAt(Timestamp.from(Instant.now())) + .uri("https://example.com/fdt/train-garage/A") + .displayName("Train Garage A") + .note("") + .metadata("") + .status(SyncServiceStatus.SYNCED) + .lastContactAt(Timestamp.from(Instant.now())) + .build(); + + public static TrainGarage TRAIN_GARAGE_B = + TrainGarage.builder() + .uuid(UUID.randomUUID()) + .createdAt(Timestamp.from(Instant.now())) + .updatedAt(Timestamp.from(Instant.now())) + .uri("https://example.com/fdt/train-garage/B") + .displayName("Train Garage B") + .note("") + .metadata("") + .status(SyncServiceStatus.SYNCED) + .lastContactAt(Timestamp.from(Instant.now())) + .build(); + + public static TrainGarage TRAIN_GARAGE_C = + TrainGarage.builder() + .uuid(UUID.randomUUID()) + .createdAt(Timestamp.from(Instant.now())) + .updatedAt(Timestamp.from(Instant.now())) + .uri("https://example.com/fdt/train-garage/C") + .displayName("Train Garage C") + .note("") + .metadata("") + .status(SyncServiceStatus.SYNCED) + .lastContactAt(Timestamp.from(Instant.now())) + .build(); + + public static TrainGarageChangeDTO TRAIN_GARAGE_X_CREATE = TrainGarageChangeDTO + .builder() + .uri("https://example.com/fdt/train-garage/X") + .displayName("Train Garage X") + .note("My custom train garage") + .build(); + + public static TrainGarageChangeDTO TRAIN_GARAGE_A_UPDATE = TrainGarageChangeDTO + .builder() + .uri("https://example.com/fdt/train-garage/A/edit") + .displayName("Train Garage A: EDIT") + .note("My custom train garage edited") + .build(); + + public static List TRAIN_GARAGES = Arrays.asList(TRAIN_GARAGE_A, TRAIN_GARAGE_B, TRAIN_GARAGE_C); +}