From 23e82e6c0bf4d250983da504d9396c9729c93215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Fri, 11 Mar 2022 17:25:44 +0100 Subject: [PATCH 01/97] Init project and CI (#1) --- .dockerignore | 11 + .github/workflows/build.yml | 142 ++++ .github/workflows/code-style.yml | 88 ++ .github/workflows/security.yml | 102 +++ .gitignore | 33 + CHANGELOG.md | 1 + Dockerfile | 44 + checkstyle.xml | 786 ++++++++++++++++++ pom.xml | 219 +++++ .../trainhandler/Application.java | 39 + .../api/controller/ApiExceptionHandler.java | 55 ++ .../StationDirectoryController.java | 94 +++ .../api/controller/TrainGarageController.java | 94 +++ .../trainhandler/api/dto/error/ErrorDTO.java | 40 + .../StationDirectoryChangeDTO.java | 46 + .../stationdirectory/StationDirectoryDTO.java | 51 ++ .../dto/stationdirectory/StationInfoDTO.java | 39 + .../dto/traingarage/TrainGarageChangeDTO.java | 46 + .../api/dto/traingarage/TrainGarageDTO.java | 51 ++ .../api/dto/traingarage/TrainInfoDTO.java | 39 + .../trainhandler/config/PropertiesConfig.java | 49 ++ .../trainhandler/config/WebConfig.java | 37 + .../exception/NotFoundException.java | 43 + .../exception/NotImplementedException.java | 26 + .../trainhandler/model/StationDirectory.java | 65 ++ .../trainhandler/model/TrainGarage.java | 70 ++ .../trainhandler/model/base/BaseEntity.java | 76 ++ .../StationDirectoryRepository.java | 35 + .../repository/TrainGarageRepository.java | 35 + .../repository/base/BaseRepository.java | 32 + .../service/actuator/AppInfoContributor.java | 62 ++ .../fixtures/StationDirectoryFixtures.java | 45 + .../service/fixtures/TrainGarageFixtures.java | 43 + .../StationDirectoryMapper.java | 76 ++ .../StationDirectoryService.java | 105 +++ .../traingarage/TrainGarageMapper.java | 76 ++ .../traingarage/TrainGarageService.java | 107 +++ src/main/resources/application-ci.yml | 5 + src/main/resources/application-dev.yml | 5 + src/main/resources/application-test.yml | 5 + src/main/resources/application.yml | 29 + src/main/resources/db/migration/.gitkeep | 0 .../migration/V0001__directory-and-garage.sql | 50 ++ src/main/resources/log4j-spring.xml | 36 + .../acceptance/WebIntegrationTest.java | 45 + .../acceptance/actuator/ActuatorInfoDTO.java | 51 ++ .../acceptance/actuator/List_Info_GET.java | 82 ++ .../acceptance/helper/HelperPage.java | 56 ++ .../acceptance/openapi/OpenApiDocs_GET.java | 62 ++ .../acceptance/openapi/SwaggerUI_GET.java | 87 ++ .../acceptance/stationdirectory/Common.java | 49 ++ .../stationdirectory/Detail_DELETE.java | 98 +++ .../stationdirectory/Detail_GET.java | 100 +++ .../stationdirectory/Detail_PUT.java | 134 +++ .../acceptance/stationdirectory/List_GET.java | 142 ++++ .../stationdirectory/List_POST.java | 106 +++ .../StationDirectoryTestFixtures.java | 90 ++ .../acceptance/traingarage/Common.java | 49 ++ .../acceptance/traingarage/Detail_DELETE.java | 98 +++ .../acceptance/traingarage/Detail_GET.java | 97 +++ .../acceptance/traingarage/Detail_PUT.java | 134 +++ .../acceptance/traingarage/List_GET.java | 142 ++++ .../acceptance/traingarage/List_POST.java | 106 +++ .../traingarage/TrainGarageTestFixtures.java | 90 ++ 64 files changed, 4950 insertions(+) create mode 100644 .dockerignore create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/code-style.yml create mode 100644 .github/workflows/security.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 checkstyle.xml create mode 100644 pom.xml create mode 100644 src/main/java/org/fairdatatrain/trainhandler/Application.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/error/ErrorDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryChangeDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationInfoDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageChangeDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainInfoDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/config/PropertiesConfig.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/config/WebConfig.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/exception/NotFoundException.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/exception/NotImplementedException.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/model/StationDirectory.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/model/TrainGarage.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/model/base/BaseEntity.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/repository/StationDirectoryRepository.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/repository/TrainGarageRepository.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/repository/base/BaseRepository.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/actuator/AppInfoContributor.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/fixtures/StationDirectoryFixtures.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/fixtures/TrainGarageFixtures.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java create mode 100644 src/main/resources/application-ci.yml create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-test.yml create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/db/migration/.gitkeep create mode 100644 src/main/resources/db/migration/V0001__directory-and-garage.sql create mode 100644 src/main/resources/log4j-spring.xml create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/WebIntegrationTest.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/ActuatorInfoDTO.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/List_Info_GET.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/helper/HelperPage.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/openapi/OpenApiDocs_GET.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/openapi/SwaggerUI_GET.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Common.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_DELETE.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_GET.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_PUT.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_GET.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_POST.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/StationDirectoryTestFixtures.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Common.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_DELETE.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_GET.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_PUT.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_GET.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_POST.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/TrainGarageTestFixtures.java 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..d35393c --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,142 @@ +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:13.6 + ports: + - 5432:5432 + env: + POSTGRES_DB: train-handler-test + POSTGRES_USER: train-handler + 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: + needs: [test] + name: Docker Build & Push + runs-on: ubuntu-latest + + env: + PUBLIC_IMAGE: fairdata/trainhandler-server + PRIVATE_IMAGE: ${{ secrets.PRIVATE_REGISTRY_URL }}/trainhandler-server + DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} + PRIVATE_REGISTRY_URL: ${{ secrets.PRIVATE_REGISTRY_URL }} + TAG_DEVELOP: develop + TAG_LATEST: latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Docker build + run: | + docker pull $PUBLIC_IMAGE:$TAG_DEVELOP + docker build --cache-from $PUBLIC_IMAGE:$TAG_DEVELOP -t ${PRIVATE_IMAGE#/}:$GITHUB_SHA . + + - name: Docker login (private) + if: github.event_name == 'push' && env.PRIVATE_REGISTRY_URL != '' + run: | + docker login -u "$PRIVATE_REGISTRY_USERNAME" -p "$PRIVATE_REGISTRY_PASSWORD" "$PRIVATE_REGISTRY_URL" + env: + PRIVATE_REGISTRY_URL: ${{ secrets.PRIVATE_REGISTRY_URL }} + PRIVATE_REGISTRY_USERNAME: ${{ secrets.PRIVATE_REGISTRY_USERNAME }} + PRIVATE_REGISTRY_PASSWORD: ${{ secrets.PRIVATE_REGISTRY_PASSWORD }} + + - name: Docker login (public) + if: github.event_name == 'push' && env.DOCKER_HUB_USERNAME != '' + run: | + docker login -u "$DOCKER_HUB_USERNAME" -p "$DOCKER_HUB_PASSWORD" + env: + DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} + DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} + + - name: Docker push - commit SHA (private) + if: github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/') && env.PRIVATE_REGISTRY_URL != '' + run: | + docker push $PRIVATE_IMAGE:$GITHUB_SHA + + - name: Docker tag and push - branch (private) + if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/') && !contains(github.ref, 'release') && env.PRIVATE_REGISTRY_URL != '' + run: | + GITHUB_BRANCH=`echo $GITHUB_REF | cut -d/ -f3- | sed 's#/#-#g'` + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PRIVATE_IMAGE:$GITHUB_BRANCH + docker push $PRIVATE_IMAGE:$GITHUB_BRANCH + + - name: Docker tag and push - develop (public) + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + run: | + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PUBLIC_IMAGE:$TAG_DEVELOP + docker push $PUBLIC_IMAGE:$TAG_DEVELOP + + - name: Docker tag and push - latest (public) + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + run: | + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PUBLIC_IMAGE:$TAG_LATEST + docker push $PUBLIC_IMAGE:$TAG_LATEST + + - name: Docker tag and push - version tag (public) + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + run: | + GITHUB_TAG=`echo $GITHUB_REF | cut -d/ -f3` + # Release vX.Y.Z + if [[ $GITHUB_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + IMAGE_TAG_MAJOR="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v(.*)\..*\..*/\1/g"` + IMAGE_TAG_MINOR="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v(.*)\..*/\1/g"` + IMAGE_TAG_PATCH="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v//g"` + echo "Publishing release: $IMAGE_TAG_PATCH"; + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_MAJOR && docker push $IMAGE_TAG_MAJOR; + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_MINOR && docker push $IMAGE_TAG_MINOR; + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_PATCH && docker push $IMAGE_TAG_PATCH; + fi + # Release candidate vX.Y.Z-rc.R + if [[ $GITHUB_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then + IMAGE_TAG_RC="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v//g"` + echo "Publishing release candidate: $IMAGE_TAG_RC"; + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_RC && docker push $IMAGE_TAG_RC; + fi 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..8eb02d2 --- /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@v1 + with: + languages: 'java' + + - name: Build package + run: | + mvn --quiet -B -U --fail-fast -DskipTests package + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 + + 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=high + + 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=high diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +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/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 19d61e9..45a46ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added - Initiated Train Handler server project +- Setup CI, code style checks, and security audits [Unreleased]: /../../compare/master...develop diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9aa1c4c --- /dev/null +++ b/Dockerfile @@ -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. +# + +FROM maven:3-eclipse-temurin-17-alpine as builder + +WORKDIR /builder + +ADD . /builder + +RUN mvn --quiet -B -U --fail-fast -DskipTests package + +################################################################################ +# RUN STAGE +FROM eclipse-temurin:17-alpine + +WORKDIR /app + +# 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=production --spring.config.location=classpath:/application.yml,file:/app/application.yml diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 0000000..393f991 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,786 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5e7b8d0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,219 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.6.4 + + + + org.fairdatatrain + trainhandler + 0.0.1-SNAPSHOT + + 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.6 + 42.3.2 + 1.18.22 + + + 4.1 + 3.1.2 + 4.5.3.0 + 5.0.0 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-actuator + + + 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 + + + + + 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 + 8.45.1 + + + io.spring.javaformat + spring-javaformat-checkstyle + 0.0.31 + + + + + 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 + + + + + false + + +
+
+ + + 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..995aaff --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/Application.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; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@SpringBootApplication +@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..6883f7d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.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.controller; + +import org.fairdatatrain.trainhandler.api.dto.error.ErrorDTO; +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 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); + } +} 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..35f992e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java @@ -0,0 +1,94 @@ +/** + * 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.api.dto.stationdirectory.StationInfoDTO; +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.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +@Tag(name = "Station Directory") +@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, + 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) { + return stationDirectoryService.create(reqDto); + } + + @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 { + return stationDirectoryService.update(uuid, reqDto); + } + + @DeleteMapping(path = "/{uuid}") + @ResponseStatus(code = HttpStatus.NO_CONTENT) + public void delete(@PathVariable UUID uuid) throws NotFoundException { + stationDirectoryService.delete(uuid); + } + + @GetMapping( + path = "/search", + produces = MediaType.APPLICATION_JSON_VALUE + ) + @ResponseStatus(code = HttpStatus.CREATED) + public List search( + @RequestParam(value = "query", required = false, defaultValue = "") String query + ) { + return stationDirectoryService.search(query); + } +} 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..93dacd0 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java @@ -0,0 +1,94 @@ +/** + * 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.api.dto.traingarage.TrainInfoDTO; +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.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +@Tag(name = "Train Garage") +@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, + 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) { + return trainGarageService.create(reqDto); + } + + @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 { + return trainGarageService.update(uuid, reqDto); + } + + @DeleteMapping(path = "/{uuid}") + @ResponseStatus(code = HttpStatus.NO_CONTENT) + public void delete(@PathVariable UUID uuid) throws NotFoundException { + trainGarageService.delete(uuid); + } + + @GetMapping( + path = "/search", + produces = MediaType.APPLICATION_JSON_VALUE + ) + @ResponseStatus(code = HttpStatus.CREATED) + public List search( + @RequestParam(value = "query", required = false, defaultValue = "") String query + ) { + return trainGarageService.search(query); + } +} 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..97004f4 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/error/ErrorDTO.java @@ -0,0 +1,40 @@ +/** + * 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; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class ErrorDTO { + + private String code; + + private String message; + +} 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..1da620f --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.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.stationdirectory; + +import lombok.*; + +import java.time.Instant; +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 String status; + + private Instant lastContact; + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationInfoDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationInfoDTO.java new file mode 100644 index 0000000..9435b5b --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationInfoDTO.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.api.dto.stationdirectory; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class StationInfoDTO { + + private String uri; + + private String displayName; +} 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..2216278 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.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.traingarage; +import lombok.*; + +import java.time.Instant; +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 String status; + + private Instant lastContact; + +} + diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainInfoDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainInfoDTO.java new file mode 100644 index 0000000..a74ffdd --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainInfoDTO.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.api.dto.traingarage; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class TrainInfoDTO { + + private String uri; + + private String displayName; +} 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..b667899 --- /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 = "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/WebConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/WebConfig.java new file mode 100644 index 0000000..6e08d5a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/WebConfig.java @@ -0,0 +1,37 @@ +/** + * 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.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**"); + } + +} 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/model/StationDirectory.java b/src/main/java/org/fairdatatrain/trainhandler/model/StationDirectory.java new file mode 100644 index 0000000..7cee9fd --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/model/StationDirectory.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.model; + +import lombok.*; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.model.base.BaseEntity; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; + +@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; + + @Column(name = "status") + private String status; + + @Column(name = "last_contact") + private Timestamp lastContact; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/model/TrainGarage.java b/src/main/java/org/fairdatatrain/trainhandler/model/TrainGarage.java new file mode 100644 index 0000000..a98c1eb --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/model/TrainGarage.java @@ -0,0 +1,70 @@ +/** + * 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.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.fairdatatrain.trainhandler.model.base.BaseEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; + +@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; + + @Column(name = "status") + private String status; + + @Column(name = "last_contact") + private Timestamp lastContact; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/model/base/BaseEntity.java b/src/main/java/org/fairdatatrain/trainhandler/model/base/BaseEntity.java new file mode 100644 index 0000000..653e77f --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/model/base/BaseEntity.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.model.base; + +import lombok.*; +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 +@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/repository/StationDirectoryRepository.java b/src/main/java/org/fairdatatrain/trainhandler/repository/StationDirectoryRepository.java new file mode 100644 index 0000000..7df3904 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/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.repository; + +import org.fairdatatrain.trainhandler.model.StationDirectory; +import org.fairdatatrain.trainhandler.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/repository/TrainGarageRepository.java b/src/main/java/org/fairdatatrain/trainhandler/repository/TrainGarageRepository.java new file mode 100644 index 0000000..768f3d3 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/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.repository; + +import org.fairdatatrain.trainhandler.model.TrainGarage; +import org.fairdatatrain.trainhandler.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/repository/base/BaseRepository.java b/src/main/java/org/fairdatatrain/trainhandler/repository/base/BaseRepository.java new file mode 100644 index 0000000..b70137f --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/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.repository.base; + +import org.springframework.data.repository.NoRepositoryBean; +import org.springframework.data.repository.PagingAndSortingRepository; + +import java.util.UUID; + +@NoRepositoryBean +public interface BaseRepository extends PagingAndSortingRepository { +} 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/fixtures/StationDirectoryFixtures.java b/src/main/java/org/fairdatatrain/trainhandler/service/fixtures/StationDirectoryFixtures.java new file mode 100644 index 0000000..beecd91 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/fixtures/StationDirectoryFixtures.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.service.fixtures; + +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationInfoDTO; + +import java.util.Arrays; +import java.util.List; + +public class StationDirectoryFixtures { + + public static final StationInfoDTO STATION_A = + new StationInfoDTO("https://example.com/fdt/station/a", "Station A: Cancer Data CZ"); + public static final StationInfoDTO STATION_B = + new StationInfoDTO("https://example.com/fdt/station/b", "Station B: Cancer Data NL"); + public static final StationInfoDTO STATION_C = + new StationInfoDTO("https://example.com/fdt/station/c", "Station C: COVID Data EU"); + public static final StationInfoDTO STATION_D = + new StationInfoDTO("https://example.com/fdt/station/d", "Station D: COVID Data NL"); + public static final StationInfoDTO STATION_E = + new StationInfoDTO("https://example.com/fdt/station/e", "Station E: Random Data"); + + public static final List STATIONS = + Arrays.asList(STATION_A, STATION_B, STATION_C, STATION_D, STATION_E); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/fixtures/TrainGarageFixtures.java b/src/main/java/org/fairdatatrain/trainhandler/service/fixtures/TrainGarageFixtures.java new file mode 100644 index 0000000..36dff99 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/fixtures/TrainGarageFixtures.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.service.fixtures; + +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainInfoDTO; + +import java.util.Arrays; +import java.util.List; + +public class TrainGarageFixtures { + + public static final TrainInfoDTO TRAIN_A = + new TrainInfoDTO("https://example.com/fdt/train/a", "Train A: Cancer SPARQL Express"); + public static final TrainInfoDTO TRAIN_B = + new TrainInfoDTO("https://example.com/fdt/train/b", "Train B: Cancer SPARQL Slow"); + public static final TrainInfoDTO TRAIN_C = + new TrainInfoDTO("https://example.com/fdt/train/c", "Train C: COVID Portal Analysis"); + public static final TrainInfoDTO TRAIN_D = + new TrainInfoDTO("https://example.com/fdt/train/d", "Train D: COVID SPARQL Simple"); + + public static final List TRAINS = + Arrays.asList(TRAIN_A, TRAIN_B, TRAIN_C, TRAIN_D); +} 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..ca13c92 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.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.stationdirectory; + +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.model.StationDirectory; +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 new StationDirectoryDTO( + stationDirectory.getUuid(), + stationDirectory.getUri(), + stationDirectory.getDisplayName(), + stationDirectory.getNote(), + stationDirectory.getMetadata(), + stationDirectory.getStatus(), + Optional.ofNullable(stationDirectory.getLastContact()) + .map(Timestamp::toInstant) + .orElse(null) + ); + } + + 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("NEW") + .metadata(null) + .lastContact(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.setUpdatedAt(now); + return stationDirectory; + } +} 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..2b3ffb8 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.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.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.api.dto.stationdirectory.StationInfoDTO; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.model.StationDirectory; +import org.fairdatatrain.trainhandler.repository.StationDirectoryRepository; +import org.fairdatatrain.trainhandler.service.fixtures.StationDirectoryFixtures; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Locale; +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 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); + } + + public StationDirectoryDTO create(StationDirectoryChangeDTO reqDto) { + // TODO: validate? + final StationDirectory newStationDirectory = + stationDirectoryRepository.save(stationDirectoryMapper.fromCreateDTO(reqDto)); + return this.stationDirectoryMapper.toDTO(newStationDirectory); + } + + public StationDirectoryDTO update(UUID uuid, StationDirectoryChangeDTO reqDto) + throws NotFoundException { + // TODO: validate? + final StationDirectory stationDirectory = getByIdOrThrow(uuid); + final StationDirectory updatedStationDirectory = + stationDirectoryRepository.save( + stationDirectoryMapper.fromUpdateDTO(reqDto, stationDirectory)); + return this.stationDirectoryMapper.toDTO(updatedStationDirectory); + } + + public List search(String query) { + // Dummy + final String finalQuery = query.toLowerCase(Locale.ROOT); + return StationDirectoryFixtures.STATIONS.stream() + .filter( + station -> { + return station.getDisplayName() + .toLowerCase(Locale.ROOT) + .contains(finalQuery); + }) + .toList(); + } +} 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..88ec59c --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.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.traingarage; + +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.model.TrainGarage; +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 new TrainGarageDTO( + trainGarage.getUuid(), + trainGarage.getUri(), + trainGarage.getDisplayName(), + trainGarage.getNote(), + trainGarage.getMetadata(), + trainGarage.getStatus(), + Optional.ofNullable(trainGarage.getLastContact()) + .map(Timestamp::toInstant) + .orElse(null) + ); + } + + 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("NEW") + .metadata(null) + .lastContact(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; + } +} 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..3eee1e5 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java @@ -0,0 +1,107 @@ +/** + * 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.SneakyThrows; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainInfoDTO; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.model.TrainGarage; +import org.fairdatatrain.trainhandler.repository.TrainGarageRepository; +import org.fairdatatrain.trainhandler.service.fixtures.TrainGarageFixtures; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Locale; +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 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); + } + + public TrainGarageDTO create(TrainGarageChangeDTO reqDto) { + // TODO: validate? + final TrainGarage newTrainGarage = + trainGarageRepository.save(trainGarageMapper.fromCreateDTO(reqDto)); + return this.trainGarageMapper.toDTO(newTrainGarage); + } + + public TrainGarageDTO update(UUID uuid, TrainGarageChangeDTO reqDto) + throws NotFoundException { + // TODO: validate? + final TrainGarage trainGarage = getByIdOrThrow(uuid); + final TrainGarage updatedTrainGarage = + trainGarageRepository.save( + trainGarageMapper.fromUpdateDTO(reqDto, trainGarage)); + return this.trainGarageMapper.toDTO(updatedTrainGarage); + } + + @SneakyThrows + public List search(String query) { + // Dummy + final String finalQuery = query.toLowerCase(Locale.ROOT); + return TrainGarageFixtures.TRAINS.stream() + .filter( + garage -> { + return garage.getDisplayName() + .toLowerCase(Locale.ROOT) + .contains(finalQuery); + }) + .toList(); + } +} 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..89a1cba --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,5 @@ +spring: + datasource: + url: jdbc:postgresql://localhost/train-handler + username: train-handler + password: password diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml new file mode 100644 index 0000000..604bf29 --- /dev/null +++ b/src/main/resources/application-test.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.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..f72548c --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,29 @@ +spring: + datasource: + url: jdbc:postgresql://postgres/train-handler + username: train-handler + password: password + flyway: + locations: classpath:db/migration + jpa: + properties: + hibernate: + ddl-auto: validate + dialect: org.hibernate.dialect.PostgreSQLDialect + +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..564032b --- /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_pkey 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_pkey 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/log4j-spring.xml b/src/main/resources/log4j-spring.xml new file mode 100644 index 0000000..54d9a89 --- /dev/null +++ b/src/main/resources/log4j-spring.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/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..314ea95 --- /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.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..487fba9 --- /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.api.dto.stationdirectory.StationDirectoryDTO; +import org.fairdatatrain.trainhandler.model.StationDirectory; +import org.fairdatatrain.trainhandler.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.*; + +@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..6bde47a --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_GET.java @@ -0,0 +1,100 @@ +/** + * 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.model.StationDirectory; +import org.fairdatatrain.trainhandler.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.UUID; +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/: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..9de5343 --- /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.model.StationDirectory; +import org.fairdatatrain.trainhandler.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..a1e8abb --- /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.model.StationDirectory; +import org.fairdatatrain.trainhandler.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..ab08577 --- /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.model.StationDirectory; +import org.fairdatatrain.trainhandler.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..590c6d5 --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/StationDirectoryTestFixtures.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.acceptance.stationdirectory; + +import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; +import org.fairdatatrain.trainhandler.model.StationDirectory; + +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("UNKNOWN") + .lastContact(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("UNKNOWN") + .lastContact(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("UNKNOWN") + .lastContact(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..82be9ca --- /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.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..51f8b41 --- /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.model.TrainGarage; +import org.fairdatatrain.trainhandler.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..1b26d4b --- /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.model.TrainGarage; +import org.fairdatatrain.trainhandler.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..ad0b44c --- /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.model.TrainGarage; +import org.fairdatatrain.trainhandler.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..a1dd4d4 --- /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.model.TrainGarage; +import org.fairdatatrain.trainhandler.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..a7c1c85 --- /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.model.TrainGarage; +import org.fairdatatrain.trainhandler.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..3bdf4bf --- /dev/null +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/TrainGarageTestFixtures.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.acceptance.traingarage; + +import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; +import org.fairdatatrain.trainhandler.model.TrainGarage; + +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("UNKNOWN") + .lastContact(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("UNKNOWN") + .lastContact(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("UNKNOWN") + .lastContact(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); +} From 16f4dc1288ae93a6a817b7f428ee8ea5146f31cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 17 Mar 2022 10:26:07 +0100 Subject: [PATCH 02/97] Fix CORS headers --- .../trainhandler/api/filter/CorsFilter.java | 79 +++++++++++++++++++ .../trainhandler/config/WebConfig.java | 7 -- .../acceptance/actuator/CorsTest.java | 77 ++++++++++++++++++ 3 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/filter/CorsFilter.java create mode 100644 src/test/java/org/fairdatatrain/trainhandler/acceptance/actuator/CorsTest.java 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..cac24b6 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/filter/CorsFilter.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.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 { + 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/config/WebConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/WebConfig.java index 6e08d5a..458a816 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/config/WebConfig.java +++ b/src/main/java/org/fairdatatrain/trainhandler/config/WebConfig.java @@ -23,15 +23,8 @@ package org.fairdatatrain.trainhandler.config; import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { - - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**"); - } - } 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"))); + } +} From 77f61278013aaffffd2b5918f29bec144bda8bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 17 Mar 2022 14:15:24 +0100 Subject: [PATCH 03/97] Fix Git info --- pom.xml | 4 ++++ .../fairdatatrain/trainhandler/config/PropertiesConfig.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5e7b8d0..56705f9 100644 --- a/pom.xml +++ b/pom.xml @@ -187,10 +187,14 @@ revision + initialize false + true + ${project.build.outputDirectory}/META-INF/git.properties + full diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/PropertiesConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/PropertiesConfig.java index b667899..f177734 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/config/PropertiesConfig.java +++ b/src/main/java/org/fairdatatrain/trainhandler/config/PropertiesConfig.java @@ -30,7 +30,7 @@ @Configuration public class PropertiesConfig { - private static final String GIT_FILE = "git.properties"; + private static final String GIT_FILE = "META-INF/git.properties"; private static final String BUILD_INFO_FILE = "META-INF/build-info.properties"; From 77fb6a63d4eadc12ef2a30f9df84e2b7509501c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Apr 2022 19:21:55 +0000 Subject: [PATCH 04/97] Bump spring-boot-starter-parent from 2.6.4 to 2.6.6 Bumps [spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 2.6.4 to 2.6.6. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.6.4...v2.6.6) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-parent dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 56705f9..eda1397 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.6.4 + 2.6.6 From 2977cbb688316a665077015e68accfe80effe3bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Apr 2022 10:20:04 +0000 Subject: [PATCH 05/97] Bump spotbugs-maven-plugin from 4.5.3.0 to 4.6.0.0 Bumps [spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.5.3.0 to 4.6.0.0. - [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases) - [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.5.3.0...spotbugs-maven-plugin-4.6.0.0) --- updated-dependencies: - dependency-name: com.github.spotbugs:spotbugs-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index eda1397..23f134f 100644 --- a/pom.xml +++ b/pom.xml @@ -41,7 +41,7 @@ 4.1 3.1.2 - 4.5.3.0 + 4.6.0.0 5.0.0 From 7f5260fad45e1724b1b30dbd7f01228e461e2746 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Apr 2022 10:20:08 +0000 Subject: [PATCH 06/97] Bump checkstyle from 8.45.1 to 10.1 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 8.45.1 to 10.1. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-8.45.1...checkstyle-10.1) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 23f134f..c219b78 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ com.puppycrawl.tools checkstyle - 8.45.1 + 10.1 io.spring.javaformat From 5bb0d18a4c58b9830904355f7c95e775a5846c6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Apr 2022 10:20:35 +0000 Subject: [PATCH 07/97] Bump postgresql from 42.3.2 to 42.3.3 Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.2 to 42.3.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.2...REL42.3.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c219b78..767f54e 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.6.6 - 42.3.2 + 42.3.3 1.18.22 From 535373a0c0f3031f65ba01285a41a41583b5c9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 19 Apr 2022 18:51:34 +0200 Subject: [PATCH 08/97] Update Dockerfile --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 9aa1c4c..0a67ba5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,6 +34,7 @@ RUN mvn --quiet -B -U --fail-fast -DskipTests package FROM eclipse-temurin:17-alpine WORKDIR /app +EXPOSE 8080 # Mount point for rolling log files RUN mkdir /app/logs From 8ff0d1ba60eb7fb79fc3307a20d238b8f3e410a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Apr 2022 19:22:34 +0000 Subject: [PATCH 09/97] Bump postgresql from 42.3.3 to 42.3.4 Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.3 to 42.3.4. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.3...REL42.3.4) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 767f54e..a1323ea 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.6.6 - 42.3.3 + 42.3.4 1.18.22 From 852850e8f635d53fdeac89c4d8115bc9bc494ed0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Apr 2022 10:05:12 +0000 Subject: [PATCH 10/97] Bump springdoc-openapi-ui from 1.6.6 to 1.6.7 Bumps [springdoc-openapi-ui](https://github.com/springdoc/springdoc-openapi) from 1.6.6 to 1.6.7. - [Release notes](https://github.com/springdoc/springdoc-openapi/releases) - [Changelog](https://github.com/springdoc/springdoc-openapi/blob/master/CHANGELOG.md) - [Commits](https://github.com/springdoc/springdoc-openapi/compare/v1.6.6...v1.6.7) --- updated-dependencies: - dependency-name: org.springdoc:springdoc-openapi-ui dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a1323ea..c47b887 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 17 - 1.6.6 + 1.6.7 42.3.4 1.18.22 From 8ed807eb361f58ccddc8de8f04e70f6c397df0e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Apr 2022 10:05:12 +0000 Subject: [PATCH 11/97] Bump lombok from 1.18.22 to 1.18.24 Bumps [lombok](https://github.com/projectlombok/lombok) from 1.18.22 to 1.18.24. - [Release notes](https://github.com/projectlombok/lombok/releases) - [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/projectlombok/lombok/compare/v1.18.22...v1.18.24) --- updated-dependencies: - dependency-name: org.projectlombok:lombok dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c47b887..40a3ef3 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ 1.6.7 42.3.4 - 1.18.22 + 1.18.24 4.1 From d9c00cc7cd2f460041155bf301caa6c20cad19dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Apr 2022 19:23:28 +0000 Subject: [PATCH 12/97] Bump checkstyle from 10.1 to 10.2 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.1 to 10.2. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.1...checkstyle-10.2) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 40a3ef3..88b30d0 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ com.puppycrawl.tools checkstyle - 10.1 + 10.2 io.spring.javaformat From b5f06a5953b1768f725d8e9436665e00d5efd890 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Apr 2022 19:23:37 +0000 Subject: [PATCH 13/97] Bump springdoc-openapi-ui from 1.6.7 to 1.6.8 Bumps [springdoc-openapi-ui](https://github.com/springdoc/springdoc-openapi) from 1.6.7 to 1.6.8. - [Release notes](https://github.com/springdoc/springdoc-openapi/releases) - [Changelog](https://github.com/springdoc/springdoc-openapi/blob/master/CHANGELOG.md) - [Commits](https://github.com/springdoc/springdoc-openapi/compare/v1.6.7...v1.6.8) --- updated-dependencies: - dependency-name: org.springdoc:springdoc-openapi-ui dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 88b30d0..ad15dad 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 17 - 1.6.7 + 1.6.8 42.3.4 1.18.24 From 741a2e2594f710ed28c4270e2035b36ff6545484 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Apr 2022 19:23:43 +0000 Subject: [PATCH 14/97] Bump spring-boot-starter-parent from 2.6.6 to 2.6.7 Bumps [spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 2.6.6 to 2.6.7. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.6.6...v2.6.7) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-parent dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad15dad..355b96c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.6.6 + 2.6.7 From d372d46effb296389c28695d018aed17ae5a7583 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Apr 2022 19:23:51 +0000 Subject: [PATCH 15/97] Bump github/codeql-action from 1 to 2 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v1...v2) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/security.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 8eb02d2..8d443bf 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -39,7 +39,7 @@ jobs: mvn --version - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: 'java' @@ -48,7 +48,7 @@ jobs: mvn --quiet -B -U --fail-fast -DskipTests package - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 snyk: name: Snyk (Maven) From 5ddac62e1de741f55cae152601fe051b05a6b0b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 9 May 2022 20:24:11 +0200 Subject: [PATCH 16/97] Add stations, trains, and runs (#9) --- Dockerfile | 4 +- checkstyle.xml | 3 +- pom.xml | 6 + .../api/controller/ApiExceptionHandler.java | 14 ++ .../api/controller/JobController.java | 121 ++++++++++++ .../api/controller/PlanController.java | 95 +++++++++ .../api/controller/RunController.java | 72 +++++++ .../api/controller/StationController.java | 71 +++++++ .../StationDirectoryController.java | 15 +- .../api/controller/TrainController.java | 71 +++++++ .../api/controller/TrainGarageController.java | 15 +- .../api/controller/TrainTypeController.java | 81 ++++++++ .../trainhandler/api/dto/error/ErrorDTO.java | 9 + .../dto/job/JobDTO.java} | 45 +++-- .../api/dto/job/JobEventCreateDTO.java | 59 ++++++ .../trainhandler/api/dto/job/JobEventDTO.java | 54 ++++++ .../api/dto/job/JobSimpleDTO.java | 52 +++++ .../api/dto/plan/PlanCreateDTO.java | 52 +++++ .../trainhandler/api/dto/plan/PlanDTO.java | 53 ++++++ .../api/dto/plan/PlanSimpleDTO.java | 44 +++++ .../api/dto/plan/PlanUpdateDTO.java | 52 +++++ .../api/dto/run/RunCreateDTO.java | 51 +++++ .../trainhandler/api/dto/run/RunDTO.java | 62 ++++++ .../api/dto/run/RunSimpleDTO.java | 59 ++++++ .../RunUpdateDTO.java} | 15 +- .../api/dto/station/StationDTO.java | 64 +++++++ .../api/dto/station/StationSimpleDTO.java | 53 ++++++ .../stationdirectory/StationDirectoryDTO.java | 8 +- .../StationDirectorySimpleDTO.java | 44 +++++ .../trainhandler/api/dto/train/TrainDTO.java | 64 +++++++ .../api/dto/train/TrainSimpleDTO.java | 53 ++++++ .../api/dto/traingarage/TrainGarageDTO.java | 8 +- ...InfoDTO.java => TrainGarageSimpleDTO.java} | 15 +- .../api/dto/traintype/TrainTypeChangeDTO.java | 44 +++++ .../api/dto/traintype/TrainTypeDTO.java | 48 +++++ .../api/dto/traintype/TrainTypeSimpleDTO.java | 41 ++++ .../trainhandler/data/model/Job.java | 76 ++++++++ .../trainhandler/data/model/JobEvent.java | 75 ++++++++ .../trainhandler/data/model/Plan.java | 65 +++++++ .../trainhandler/data/model/PlanTarget.java | 56 ++++++ .../trainhandler/data/model/Run.java | 77 ++++++++ .../trainhandler/data/model/Station.java | 87 +++++++++ .../{ => data}/model/StationDirectory.java | 23 ++- .../trainhandler/data/model/Train.java | 87 +++++++++ .../{ => data}/model/TrainGarage.java | 22 ++- .../trainhandler/data/model/TrainType.java | 63 ++++++ .../{ => data}/model/base/BaseEntity.java | 7 +- .../data/model/enums/JobEventType.java | 29 +++ .../data/model/enums/JobStatus.java | 34 ++++ .../data/model/enums/RunStatus.java | 34 ++++ .../data/model/enums/SyncItemStatus.java | 28 +++ .../data/model/enums/SyncServiceStatus.java | 31 +++ .../data/repository/JobEventRepository.java | 39 ++++ .../data/repository/JobRepository.java | 37 ++++ .../data/repository/PlanRepository.java | 35 ++++ .../data/repository/PlanTargetRepository.java | 31 +++ .../data/repository/RunRepository.java | 37 ++++ .../StationDirectoryRepository.java | 6 +- .../data/repository/StationRepository.java | 46 +++++ .../repository/TrainGarageRepository.java | 6 +- .../data/repository/TrainRepository.java | 46 +++++ .../data/repository/TrainTypeRepository.java | 35 ++++ .../repository/base/BaseRepository.java | 2 +- .../exception/CannotPerformException.java | 46 +++++ .../exception/JobSecurityException.java | 33 ++++ .../service/async/AsyncEventPublisher.java | 46 +++++ .../service/async/JobEventNotification.java | 41 ++++ .../async/JobEventNotificationListener.java | 59 ++++++ .../fixtures/StationDirectoryFixtures.java | 45 ----- .../service/job/JobEventMapper.java | 65 +++++++ .../service/job/JobEventService.java | 145 ++++++++++++++ .../trainhandler/service/job/JobMapper.java | 105 ++++++++++ .../trainhandler/service/job/JobService.java | 67 +++++++ .../trainhandler/service/plan/PlanMapper.java | 97 ++++++++++ .../service/plan/PlanService.java | 180 ++++++++++++++++++ .../service/plan/PlanTargetMapper.java | 46 +++++ .../trainhandler/service/run/RunMapper.java | 127 ++++++++++++ .../trainhandler/service/run/RunService.java | 105 ++++++++++ .../service/station/StationMapper.java | 79 ++++++++ .../service/station/StationService.java | 88 +++++++++ .../StationDirectoryMapper.java | 43 +++-- .../StationDirectoryService.java | 21 +- .../service/train/TrainMapper.java | 79 ++++++++ .../service/train/TrainService.java | 88 +++++++++ .../traingarage/TrainGarageMapper.java | 44 +++-- .../traingarage/TrainGarageService.java | 23 +-- .../service/traintype/TrainTypeMapper.java | 76 ++++++++ .../service/traintype/TrainTypeService.java | 86 +++++++++ .../trainhandler/utils/CompareUtils.java | 36 ++++ .../trainhandler/utils/RandomUtils.java | 31 +++ .../trainhandler/utils/TimeUtils.java | 33 ++++ .../migration/V0001__directory-and-garage.sql | 6 +- .../db/migration/V0002.0__trains-stations.sql | 108 +++++++++++ .../db/migration/V0002.1__dev_data.sql | 115 +++++++++++ .../db/migration/V0003.0__plans-runs.sql | 52 +++++ .../migration/V0003.1__sync-status-enums.sql | 59 ++++++ .../migration/V0003.2__runs_jobs_events.sql | 115 +++++++++++ .../db/migration/V0003.3__dev_data.sql | 79 ++++++++ .../acceptance/stationdirectory/Common.java | 2 +- .../stationdirectory/Detail_DELETE.java | 8 +- .../stationdirectory/Detail_GET.java | 7 +- .../stationdirectory/Detail_PUT.java | 4 +- .../acceptance/stationdirectory/List_GET.java | 4 +- .../stationdirectory/List_POST.java | 4 +- .../StationDirectoryTestFixtures.java | 75 ++++---- .../acceptance/traingarage/Common.java | 2 +- .../acceptance/traingarage/Detail_DELETE.java | 4 +- .../acceptance/traingarage/Detail_GET.java | 4 +- .../acceptance/traingarage/Detail_PUT.java | 4 +- .../acceptance/traingarage/List_GET.java | 4 +- .../acceptance/traingarage/List_POST.java | 4 +- .../traingarage/TrainGarageTestFixtures.java | 75 ++++---- 112 files changed, 5095 insertions(+), 305 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java rename src/main/java/org/fairdatatrain/trainhandler/{service/fixtures/TrainGarageFixtures.java => api/dto/job/JobDTO.java} (56%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventCreateDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobSimpleDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanCreateDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanSimpleDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanUpdateDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunCreateDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunSimpleDTO.java rename src/main/java/org/fairdatatrain/trainhandler/api/dto/{stationdirectory/StationInfoDTO.java => run/RunUpdateDTO.java} (85%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationSimpleDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectorySimpleDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainSimpleDTO.java rename src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/{TrainInfoDTO.java => TrainGarageSimpleDTO.java} (84%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeChangeDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeSimpleDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/JobEvent.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/Plan.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/PlanTarget.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java rename src/main/java/org/fairdatatrain/trainhandler/{ => data}/model/StationDirectory.java (73%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java rename src/main/java/org/fairdatatrain/trainhandler/{ => data}/model/TrainGarage.java (77%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/TrainType.java rename src/main/java/org/fairdatatrain/trainhandler/{ => data}/model/base/BaseEntity.java (93%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobEventType.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobStatus.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/enums/RunStatus.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/enums/SyncItemStatus.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/enums/SyncServiceStatus.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/repository/JobEventRepository.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/repository/JobRepository.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/repository/PlanRepository.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/repository/PlanTargetRepository.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java rename src/main/java/org/fairdatatrain/trainhandler/{ => data}/repository/StationDirectoryRepository.java (88%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/repository/StationRepository.java rename src/main/java/org/fairdatatrain/trainhandler/{ => data}/repository/TrainGarageRepository.java (88%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainRepository.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java rename src/main/java/org/fairdatatrain/trainhandler/{ => data}/repository/base/BaseRepository.java (95%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/exception/CannotPerformException.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/exception/JobSecurityException.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotification.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotificationListener.java delete mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/fixtures/StationDirectoryFixtures.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventService.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanTargetMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/utils/CompareUtils.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/utils/RandomUtils.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/utils/TimeUtils.java create mode 100644 src/main/resources/db/migration/V0002.0__trains-stations.sql create mode 100644 src/main/resources/db/migration/V0002.1__dev_data.sql create mode 100644 src/main/resources/db/migration/V0003.0__plans-runs.sql create mode 100644 src/main/resources/db/migration/V0003.1__sync-status-enums.sql create mode 100644 src/main/resources/db/migration/V0003.2__runs_jobs_events.sql create mode 100644 src/main/resources/db/migration/V0003.3__dev_data.sql diff --git a/Dockerfile b/Dockerfile index 0a67ba5..44d352f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,10 +36,12 @@ FROM eclipse-temurin:17-alpine 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=production --spring.config.location=classpath:/application.yml,file:/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/checkstyle.xml b/checkstyle.xml index 393f991..13ed85d 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -339,8 +339,7 @@
diff --git a/pom.xml b/pom.xml index 355b96c..e55f2a8 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,7 @@ 1.6.8 42.3.4 1.18.24 + 2.14.1 4.1 @@ -76,6 +77,11 @@ springdoc-openapi-ui ${springdoc.version} + + com.vladmihalcea + hibernate-types-52 + ${hibernate-types.version} + org.postgresql diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java index 6883f7d..460198c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java @@ -23,6 +23,7 @@ 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; @@ -52,4 +53,17 @@ public ResponseEntity handleNotFoundException(NotFoundException except exception.getEntityName(), exception.getFields())), HttpStatus.NOT_FOUND); } + + @ExceptionHandler(CannotPerformException.class) + public ResponseEntity handleCannotDeleteException(CannotPerformException exception) { + return new ResponseEntity<>( + new ErrorDTO( + "HTTP-400", + format( + "Cannot perform %s on entity %s (with %s)", + exception.getOperation(), + exception.getEntityName(), + exception.getFields())), + HttpStatus.BAD_REQUEST); + } } 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..d48d13e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java @@ -0,0 +1,121 @@ +/** + * 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.JobDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobEventCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobEventDTO; +import org.fairdatatrain.trainhandler.api.dto.job.JobSimpleDTO; +import org.fairdatatrain.trainhandler.exception.JobSecurityException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.job.JobEventService; +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.web.bind.annotation.*; +import org.springframework.web.context.request.async.DeferredResult; + +import javax.validation.Valid; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +@Tag(name = "Runs") +@RestController +@RequestMapping("/runs") +@RequiredArgsConstructor +public class JobController { + private final JobService jobService; + + private final JobEventService jobEventService; + + @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 JobDTO getJobs( + @PathVariable UUID runUuid, @PathVariable UUID jobUuid + ) throws NotFoundException { + return jobService.getSingle(runUuid, jobUuid); + } + + @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); + } + + @GetMapping( + path = "/{runUuid}/jobs/{jobUuid}/events/poll", + produces = MediaType.APPLICATION_JSON_VALUE + ) + public DeferredResult> pollNewerJobEvents( + @PathVariable UUID runUuid, + @PathVariable UUID jobUuid, + @RequestParam(required = false) UUID afterEventUuid + ) { + // TODO: configurable timeout + final DeferredResult> events = new DeferredResult<>( + 10 * 1000L, Collections.emptyList() + ); + CompletableFuture.runAsync(() -> { + try { + events.setResult(jobEventService.pollEvents(runUuid, jobUuid, afterEventUuid)); + } + catch (Exception ex) { + ex.printStackTrace(); + events.setResult(Collections.emptyList()); + // TODO: better error handling + } + }); + return events; + } + + @PostMapping( + path = "/{runUuid}/jobs/{jobUuid}/events", + 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..9e1c606 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.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.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.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.UUID; + +@Tag(name = "Plans") +@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, + 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/RunController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java new file mode 100644 index 0000000..ac30964 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.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.run.RunCreateDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunDTO; +import org.fairdatatrain.trainhandler.api.dto.run.RunUpdateDTO; +import org.fairdatatrain.trainhandler.exception.CannotPerformException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.run.RunService; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.UUID; + +@Tag(name = "Runs") +@RestController +@RequestMapping("/runs") +@RequiredArgsConstructor +public class RunController { + + private final RunService runService; + + @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 RunDTO getSingle(@PathVariable UUID uuid) throws NotFoundException { + return runService.getSingle(uuid); + } + + @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 { + // TODO: abort? duplicate? + return runService.update(uuid, reqDto); + } +} 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..98ea78a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java @@ -0,0 +1,71 @@ +/** + * 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.StationDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +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.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@Tag(name = "Stations") +@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, + 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); + } + + @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); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java index 35f992e..38c18bf 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java @@ -26,7 +26,6 @@ import lombok.RequiredArgsConstructor; import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; -import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationInfoDTO; import org.fairdatatrain.trainhandler.exception.NotFoundException; import org.fairdatatrain.trainhandler.service.stationdirectory.StationDirectoryService; import org.springframework.data.domain.Page; @@ -36,10 +35,9 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; -import java.util.List; import java.util.UUID; -@Tag(name = "Station Directory") +@Tag(name = "Station Directories") @RestController @RequestMapping("/station-directories") @RequiredArgsConstructor @@ -80,15 +78,4 @@ public StationDirectoryDTO update( public void delete(@PathVariable UUID uuid) throws NotFoundException { stationDirectoryService.delete(uuid); } - - @GetMapping( - path = "/search", - produces = MediaType.APPLICATION_JSON_VALUE - ) - @ResponseStatus(code = HttpStatus.CREATED) - public List search( - @RequestParam(value = "query", required = false, defaultValue = "") String query - ) { - return stationDirectoryService.search(query); - } } 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..0c1fbf5 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java @@ -0,0 +1,71 @@ +/** + * 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.TrainDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; +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.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@Tag(name = "Trains") +@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, + 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); + } + + @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); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java index 93dacd0..e7598c8 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java @@ -26,7 +26,6 @@ import lombok.RequiredArgsConstructor; import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; -import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainInfoDTO; import org.fairdatatrain.trainhandler.exception.NotFoundException; import org.fairdatatrain.trainhandler.service.traingarage.TrainGarageService; import org.springframework.data.domain.Page; @@ -36,10 +35,9 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; -import java.util.List; import java.util.UUID; -@Tag(name = "Train Garage") +@Tag(name = "Train Garages") @RestController @RequestMapping("/train-garages") @RequiredArgsConstructor @@ -80,15 +78,4 @@ public TrainGarageDTO update( public void delete(@PathVariable UUID uuid) throws NotFoundException { trainGarageService.delete(uuid); } - - @GetMapping( - path = "/search", - produces = MediaType.APPLICATION_JSON_VALUE - ) - @ResponseStatus(code = HttpStatus.CREATED) - public List search( - @RequestParam(value = "query", required = false, defaultValue = "") String query - ) { - return trainGarageService.search(query); - } } 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..c911eb6 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.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.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.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.traintype.TrainTypeService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.UUID; + +@Tag(name = "Train Types") +@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, + Pageable pageable) { + return trainTypeService.getPaged(query, pageable); + } + + @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 index 97004f4..2135093 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/error/ErrorDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/error/ErrorDTO.java @@ -27,6 +27,9 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.util.Collections; +import java.util.Map; + @NoArgsConstructor @AllArgsConstructor @Getter @@ -37,4 +40,10 @@ public class ErrorDTO { 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/service/fixtures/TrainGarageFixtures.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java similarity index 56% rename from src/main/java/org/fairdatatrain/trainhandler/service/fixtures/TrainGarageFixtures.java rename to src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java index 36dff99..930c448 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/fixtures/TrainGarageFixtures.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java @@ -20,24 +20,41 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.service.fixtures; +package org.fairdatatrain.trainhandler.api.dto.job; -import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainInfoDTO; +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.Arrays; +import java.time.Instant; import java.util.List; +import java.util.UUID; -public class TrainGarageFixtures { +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class JobDTO { - public static final TrainInfoDTO TRAIN_A = - new TrainInfoDTO("https://example.com/fdt/train/a", "Train A: Cancer SPARQL Express"); - public static final TrainInfoDTO TRAIN_B = - new TrainInfoDTO("https://example.com/fdt/train/b", "Train B: Cancer SPARQL Slow"); - public static final TrainInfoDTO TRAIN_C = - new TrainInfoDTO("https://example.com/fdt/train/c", "Train C: COVID Portal Analysis"); - public static final TrainInfoDTO TRAIN_D = - new TrainInfoDTO("https://example.com/fdt/train/d", "Train D: COVID SPARQL Simple"); + private UUID uuid; - public static final List TRAINS = - Arrays.asList(TRAIN_A, TRAIN_B, TRAIN_C, TRAIN_D); + private String remoteId; + + private JobStatus status; + + private Instant startedAt; + + private Instant finishedAt; + + private StationSimpleDTO target; + + private RunSimpleDTO run; + + private List events; + + private Instant createdAt; + + private Instant updatedAt; } 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..9f8910a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventCreateDTO.java @@ -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. + */ +package org.fairdatatrain.trainhandler.api.dto.job; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.fairdatatrain.trainhandler.data.model.enums.JobEventType; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; + +import javax.validation.constraints.NotNull; +import java.time.Instant; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class JobEventCreateDTO { + + @NotNull + private JobEventType type; + + private JobStatus resultStatus; + + @NotNull + private String message; + + private String payload; + + @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..c72bbe6 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventDTO.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.job; + +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.JobEventType; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; + +import java.time.Instant; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class JobEventDTO { + + private UUID uuid; + + private JobEventType type; + + private JobStatus resultStatus; + + private String message; + + private String payload; + + private Instant occurredAt; + + private Instant createdAt; + + private Instant 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..fbe12fe --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobSimpleDTO.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.job; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; + +import java.time.Instant; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class JobSimpleDTO { + + private UUID uuid; + + private String remoteId; + + private JobStatus status; + + private Instant startedAt; + + private Instant finishedAt; + + private StationSimpleDTO target; + + private UUID runUuid; +} 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..bed4984 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanCreateDTO.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.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 stationUuids; + + @NotBlank + private String displayName; + + @NotNull + private String note; +} 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..fab3e68 --- /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.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainDTO; + +import java.time.Instant; +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 Instant createdAt; + + private Instant 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..a199491 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanSimpleDTO.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.plan; + +import lombok.*; +import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; + +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class PlanSimpleDTO { + + private UUID uuid; + + private String displayName; + + private String note; + + private TrainSimpleDTO train; +} 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..d7c1fd1 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanUpdateDTO.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.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 stationUuids; + + @NotBlank + private String displayName; + + @NotNull + private String note; +} 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..7dd8051 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunDTO.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.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.time.Instant; +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 Instant shouldStartAt; + + private Instant startedAt; + + private Instant finishedAt; + + private Instant createdAt; + + private Instant updatedAt; +} 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..0acadf2 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunSimpleDTO.java @@ -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. + */ +package org.fairdatatrain.trainhandler.api.dto.run; + +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; + +import java.time.Instant; +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 Instant shouldStartAt; + + private Instant startedAt; + + private Instant finishedAt; + + private Instant createdAt; + + private Instant updatedAt; +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationInfoDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunUpdateDTO.java similarity index 85% rename from src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationInfoDTO.java rename to src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunUpdateDTO.java index 9435b5b..2018ebe 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationInfoDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunUpdateDTO.java @@ -20,20 +20,25 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.api.dto.stationdirectory; +package org.fairdatatrain.trainhandler.api.dto.run; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -@NoArgsConstructor +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + @AllArgsConstructor +@NoArgsConstructor @Getter @Setter -public class StationInfoDTO { - - private String uri; +public class RunUpdateDTO { + @NotBlank private String displayName; + + @NotNull + private String note; } 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..47ba1ee --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.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 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.time.Instant; +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 SyncItemStatus status; + + private String metadata; + + private StationDirectorySimpleDTO directory; + + private List types; + + private Instant lastContactAt; + + private Instant createdAt; + + private Instant 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..1029563 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationSimpleDTO.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.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 SyncItemStatus status; + + private StationDirectorySimpleDTO directory; + + private List types; +} 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 index 1da620f..978bcaf 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java @@ -23,6 +23,7 @@ package org.fairdatatrain.trainhandler.api.dto.stationdirectory; import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; import java.time.Instant; import java.util.UUID; @@ -44,8 +45,11 @@ public class StationDirectoryDTO { private String metadata; - private String status; + private SyncServiceStatus status; - private Instant lastContact; + private Instant lastContactAt; + private Instant createdAt; + + private Instant 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/TrainDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.java new file mode 100644 index 0000000..0133ac8 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.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.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.time.Instant; +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 TrainGarageSimpleDTO garage; + + private List types; + + private Instant lastContactAt; + + private Instant createdAt; + + private Instant 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/traingarage/TrainGarageDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java index 2216278..e3df91a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java @@ -22,6 +22,7 @@ */ package org.fairdatatrain.trainhandler.api.dto.traingarage; import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; import java.time.Instant; import java.util.UUID; @@ -43,9 +44,12 @@ public class TrainGarageDTO { private String metadata; - private String status; + private SyncServiceStatus status; - private Instant lastContact; + private Instant lastContactAt; + private Instant createdAt; + + private Instant updatedAt; } diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainInfoDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageSimpleDTO.java similarity index 84% rename from src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainInfoDTO.java rename to src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageSimpleDTO.java index a74ffdd..7843b57 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainInfoDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageSimpleDTO.java @@ -22,18 +22,23 @@ */ package org.fairdatatrain.trainhandler.api.dto.traingarage; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; + +import java.util.UUID; @NoArgsConstructor @AllArgsConstructor @Getter @Setter -public class TrainInfoDTO { +@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..20bc300 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeDTO.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.traintype; + +import lombok.*; + +import java.time.Instant; +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 Instant createdAt; + + private Instant 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/data/model/Job.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java new file mode 100644 index 0000000..4608c3d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.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.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; + + @NotNull + @ManyToOne + @JoinColumn(name = "plan_target_id") + private PlanTarget target; + + @NotNull + @ManyToOne + @JoinColumn(name = "run_id") + private Run run; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "job") + private List events; +} 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..90d8547 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/JobEvent.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.data.model; + +import com.vladmihalcea.hibernate.type.json.JsonBinaryType; +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.JobEventType; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.sql.Timestamp; + +@Entity(name = "JobEvent") +@Table(name = "job_event") +@TypeDef(name = "json", typeClass = JsonBinaryType.class) +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class JobEvent extends BaseEntity { + + @Enumerated(EnumType.STRING) + @Column(name = "type", columnDefinition = "job_event_type", nullable = false) + private JobEventType type; + + @Enumerated(EnumType.STRING) + @Column(name = "result_status", columnDefinition = "job_status") + private JobStatus resultStatus; + + @NotNull + @Column(name = "occurred_at") + private Timestamp occurredAt; + + @NotNull + @Column(name = "message", nullable = false) + private String message; + + @Column(name = "payload", columnDefinition = "json") + @Type(type = "json") + private String payload; + + @NotNull + @ManyToOne + @JoinColumn(name = "job_id") + 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..0f9e0ed --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Plan.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.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 + @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..109b58d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/PlanTarget.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.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.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; + +@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; +} 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..85168f3 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.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.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; + + @NotNull + @ManyToOne + @JoinColumn(name = "plan_id") + private Plan plan; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "run") + private List jobs; +} 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..63d8a57 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.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.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 +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; + + @Column(name = "metadata") + private String metadata; + + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "sync_item_status", nullable = false) + private SyncItemStatus status; + + @Column(name = "last_contact_at") + private Timestamp lastContactAt; + + @NotNull + @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/model/StationDirectory.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java similarity index 73% rename from src/main/java/org/fairdatatrain/trainhandler/model/StationDirectory.java rename to src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java index 7cee9fd..af400b0 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/model/StationDirectory.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java @@ -20,16 +20,21 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.model; +package org.fairdatatrain.trainhandler.data.model; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import lombok.experimental.SuperBuilder; -import org.fairdatatrain.trainhandler.model.base.BaseEntity; +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.List; @Entity(name = "StationDirectory") @Table(name = "station_directory") @@ -57,9 +62,13 @@ public class StationDirectory extends BaseEntity { @Column(name = "metadata") private String metadata; - @Column(name = "status") - private String status; + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "sync_service_status", nullable = false) + private SyncServiceStatus status; - @Column(name = "last_contact") - private Timestamp lastContact; + @Column(name = "last_contact_at") + private Timestamp lastContactAt; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "directory") + private List stations; } 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..69dc0d7 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.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.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 +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; + + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "sync_item_status", nullable = false) + private SyncItemStatus status; + + @NotNull + @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/model/TrainGarage.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java similarity index 77% rename from src/main/java/org/fairdatatrain/trainhandler/model/TrainGarage.java rename to src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java index a98c1eb..a3635ab 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/model/TrainGarage.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java @@ -20,21 +20,21 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.model; +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.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Table; +import javax.persistence.*; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.sql.Timestamp; +import java.util.List; @Entity(name = "TrainGarage") @Table(name = "train_garage") @@ -62,9 +62,13 @@ public class TrainGarage extends BaseEntity { @Column(name = "metadata") private String metadata; - @Column(name = "status") - private String status; + @Enumerated(EnumType.STRING) + @Column(name = "status", columnDefinition = "sync_service_status", nullable = false) + private SyncServiceStatus status; - @Column(name = "last_contact") - private Timestamp lastContact; + @Column(name = "last_contact_at") + private Timestamp lastContactAt; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "garage") + private List trains; } 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/model/base/BaseEntity.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/base/BaseEntity.java similarity index 93% rename from src/main/java/org/fairdatatrain/trainhandler/model/base/BaseEntity.java rename to src/main/java/org/fairdatatrain/trainhandler/data/model/base/BaseEntity.java index 653e77f..30e19aa 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/model/base/BaseEntity.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/base/BaseEntity.java @@ -20,9 +20,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.model.base; +package org.fairdatatrain.trainhandler.data.model.base; -import lombok.*; +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; diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobEventType.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobEventType.java new file mode 100644 index 0000000..c800861 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobEventType.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 JobEventType { + ARTEFACT, + INIT, + INFO +} 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/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..88ab17c --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobRepository.java @@ -0,0 +1,37 @@ +/** + * 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..e1ce7ee --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java @@ -0,0 +1,37 @@ +/** + * 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.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface RunRepository extends BaseRepository { + + Page findAllByPlanUuid(UUID planUuid, Pageable pageable); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/repository/StationDirectoryRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationDirectoryRepository.java similarity index 88% rename from src/main/java/org/fairdatatrain/trainhandler/repository/StationDirectoryRepository.java rename to src/main/java/org/fairdatatrain/trainhandler/data/repository/StationDirectoryRepository.java index 7df3904..cc7e656 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/repository/StationDirectoryRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationDirectoryRepository.java @@ -20,10 +20,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.repository; +package org.fairdatatrain.trainhandler.data.repository; -import org.fairdatatrain.trainhandler.model.StationDirectory; -import org.fairdatatrain.trainhandler.repository.base.BaseRepository; +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; 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..140d7da --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationRepository.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.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 findByTitleContainingIgnoreCase(String query, Pageable pageable); + + @Query(""" + SELECT s + FROM Station s + WHERE LOWER(s.title) LIKE %:query% + ORDER BY s.title""") + List findByTitleContainingIgnoreCase(@Param("query") String query); +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/repository/TrainGarageRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainGarageRepository.java similarity index 88% rename from src/main/java/org/fairdatatrain/trainhandler/repository/TrainGarageRepository.java rename to src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainGarageRepository.java index 768f3d3..7aa0638 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/repository/TrainGarageRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainGarageRepository.java @@ -20,10 +20,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.repository; +package org.fairdatatrain.trainhandler.data.repository; -import org.fairdatatrain.trainhandler.model.TrainGarage; -import org.fairdatatrain.trainhandler.repository.base.BaseRepository; +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; 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..d263b6b --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainRepository.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.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 findByTitleContainingIgnoreCase(String query, Pageable pageable); + + @Query(""" + SELECT t + FROM Train t + WHERE LOWER(t.title) LIKE %:query% + 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/repository/base/BaseRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/base/BaseRepository.java similarity index 95% rename from src/main/java/org/fairdatatrain/trainhandler/repository/base/BaseRepository.java rename to src/main/java/org/fairdatatrain/trainhandler/data/repository/base/BaseRepository.java index b70137f..66e06cd 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/repository/base/BaseRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/base/BaseRepository.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.repository.base; +package org.fairdatatrain.trainhandler.data.repository.base; import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.PagingAndSortingRepository; 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/service/async/AsyncEventPublisher.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java new file mode 100644 index 0000000..5adfcc8 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.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.service.async; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +import static java.lang.String.format; + +@Component +@AllArgsConstructor +@Slf4j +public class AsyncEventPublisher { + + private final ApplicationEventPublisher publisher; + + public void publishNewJobEventNotification(final UUID jobUuid) { + log.info(format("Publishing new job event notification for job %s", jobUuid)); + publisher.publishEvent(new JobEventNotification(this, jobUuid)); + } + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotification.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotification.java new file mode 100644 index 0000000..2e915e9 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotification.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.service.async; + +import org.springframework.context.ApplicationEvent; + +import java.util.UUID; + +public class JobEventNotification extends ApplicationEvent { + + private final UUID jobUuid; + + JobEventNotification(Object source, UUID jobUuid) { + super(source); + this.jobUuid = jobUuid; + } + + public UUID getJobUuid() { + return jobUuid; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotificationListener.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotificationListener.java new file mode 100644 index 0000000..9c8de86 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotificationListener.java @@ -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. + */ +package org.fairdatatrain.trainhandler.service.async; + +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Component +public class JobEventNotificationListener { + + private final Map locks = new HashMap<>(); + + @EventListener + public void handleJobEventNotification(JobEventNotification notification) { + if (locks.containsKey(notification.getJobUuid())) { + synchronized (locks.get(notification.getJobUuid())) { + final Object lock = locks.remove(notification.getJobUuid()); + lock.notifyAll(); + } + } + } + + private void prepare(UUID jobUuid) { + if (!locks.containsKey(jobUuid)) { + locks.put(jobUuid, new Object()); + } + } + + public void wait(UUID jobUuid) throws InterruptedException { + prepare(jobUuid); + synchronized (locks.get(jobUuid)) { + locks.get(jobUuid).wait(); + } + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/fixtures/StationDirectoryFixtures.java b/src/main/java/org/fairdatatrain/trainhandler/service/fixtures/StationDirectoryFixtures.java deleted file mode 100644 index beecd91..0000000 --- a/src/main/java/org/fairdatatrain/trainhandler/service/fixtures/StationDirectoryFixtures.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * 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.fixtures; - -import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationInfoDTO; - -import java.util.Arrays; -import java.util.List; - -public class StationDirectoryFixtures { - - public static final StationInfoDTO STATION_A = - new StationInfoDTO("https://example.com/fdt/station/a", "Station A: Cancer Data CZ"); - public static final StationInfoDTO STATION_B = - new StationInfoDTO("https://example.com/fdt/station/b", "Station B: Cancer Data NL"); - public static final StationInfoDTO STATION_C = - new StationInfoDTO("https://example.com/fdt/station/c", "Station C: COVID Data EU"); - public static final StationInfoDTO STATION_D = - new StationInfoDTO("https://example.com/fdt/station/d", "Station D: COVID Data NL"); - public static final StationInfoDTO STATION_E = - new StationInfoDTO("https://example.com/fdt/station/e", "Station E: Random Data"); - - public static final List STATIONS = - Arrays.asList(STATION_A, STATION_B, STATION_C, STATION_D, STATION_E); -} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventMapper.java new file mode 100644 index 0000000..392b9e5 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventMapper.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.service.job; + +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.time.Instant; +import java.util.UUID; + +@Component +public class JobEventMapper { + public JobEventDTO toDTO(JobEvent jobEvent) { + return JobEventDTO + .builder() + .uuid(jobEvent.getUuid()) + .type(jobEvent.getType()) + .message(jobEvent.getMessage()) + .payload(jobEvent.getPayload()) + .resultStatus(jobEvent.getResultStatus()) + .createdAt(jobEvent.getCreatedAt().toInstant()) + .occurredAt(jobEvent.getOccurredAt().toInstant()) + .build(); + } + + public JobEvent fromCreateDTO(JobEventCreateDTO reqDto, Job job) { + final Timestamp now = Timestamp.from(Instant.now()); + return JobEvent + .builder() + .uuid(UUID.randomUUID()) + .message(reqDto.getMessage()) + .payload(reqDto.getPayload()) + .resultStatus(reqDto.getResultStatus()) + .type(reqDto.getType()) + .occurredAt(Timestamp.from(reqDto.getOccurredAt())) + .job(job) + .createdAt(now) + .updatedAt(now) + .build(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventService.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventService.java new file mode 100644 index 0000000..f99eec8 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventService.java @@ -0,0 +1,145 @@ +/** + * 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.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.fairdatatrain.trainhandler.data.repository.JobEventRepository; +import org.fairdatatrain.trainhandler.data.repository.JobRepository; +import org.fairdatatrain.trainhandler.exception.JobSecurityException; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.async.AsyncEventPublisher; +import org.fairdatatrain.trainhandler.service.async.JobEventNotificationListener; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +@Slf4j +public class JobEventService { + + public static final String ENTITY_NAME = "JobEvent"; + + private final JobRepository jobRepository; + + private final JobService jobService; + + private final JobEventRepository jobEventRepository; + + private final JobEventMapper jobEventMapper; + + private final AsyncEventPublisher asyncEventPublisher; + + private final JobEventNotificationListener jobEventNotificationListener; + + @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() != runUuid) { + throw new NotFoundException(JobService.ENTITY_NAME, jobUuid); + }*/ + return jobEventRepository + .findAllByJobOrderByOccurredAtAsc(job) + .parallelStream() + .map(jobEventMapper::toDTO) + .toList(); + } + + private List getEventsAfter( + UUID runUuid, UUID jobUuid, UUID afterEventUuid + ) throws NotFoundException { + if (afterEventUuid == null) { + return getEvents(runUuid, jobUuid); + } + final JobEvent event = getByIdOrThrow(afterEventUuid); + return jobEventRepository + .findAllByJobAndOccurredAtAfterOrderByOccurredAtAsc( + event.getJob(), event.getOccurredAt() + ) + .parallelStream() + .map(jobEventMapper::toDTO) + .toList(); + } + + @Transactional + public List pollEvents( + UUID runUuid, UUID jobUuid, UUID afterEventUuid + ) throws NotFoundException, InterruptedException { + List events = getEventsAfter(runUuid, jobUuid, afterEventUuid); + if (events.isEmpty()) { + log.info("No events at this point"); + log.info("Starting to wait"); + jobEventNotificationListener.wait(jobUuid); + log.info("Finished to wait"); + entityManager.flush(); + events = getEventsAfter(runUuid, jobUuid, afterEventUuid); + } + return events; + } + + @Transactional + public JobEventDTO createEvent( + UUID runUuid, UUID jobUuid, JobEventCreateDTO reqDto + ) throws NotFoundException, JobSecurityException { + final Job job = jobService.getByIdOrThrow(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()); + jobRepository.save(job); + } + else if (!Objects.equals(job.getRemoteId(), reqDto.getRemoteId())) { + throw new JobSecurityException("Incorrect remote ID for creating job event"); + } + final JobEvent jobEvent = jobEventRepository.save( + jobEventMapper.fromCreateDTO(reqDto, job) + ); + entityManager.flush(); + entityManager.refresh(jobEvent); + return jobEventMapper.toDTO(jobEvent); + } + + public void notify(UUID jobUuid) { + asyncEventPublisher.publishNewJobEventNotification(jobUuid); + } +} 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..e0d2224 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.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.service.job; + +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.model.PlanTarget; +import org.fairdatatrain.trainhandler.data.model.Run; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; +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.util.Optional; +import java.util.UUID; + +import static org.fairdatatrain.trainhandler.utils.RandomUtils.randomSecret; +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Component +public class JobMapper { + + private final StationMapper stationMapper; + + private final RunMapper runMapper; + + public JobMapper(StationMapper stationMapper, @Lazy RunMapper runMapper) { + this.stationMapper = stationMapper; + this.runMapper = runMapper; + } + + 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) + .orElse(null)) + .finishedAt( + Optional.ofNullable(job.getStartedAt()) + .map(Timestamp::toInstant) + .orElse(null)) + .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) + .runUuid(job.getRun().getUuid()) + .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) + .orElse(null)) + .finishedAt( + Optional.ofNullable(job.getStartedAt()) + .map(Timestamp::toInstant) + .orElse(null)) + .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) + .run(runMapper.toSimpleDTO(job.getRun())) + .createdAt(job.getCreatedAt().toInstant()) + .updatedAt(job.getUpdatedAt().toInstant()) + .build(); + } + + public Job fromTarget(Run run, PlanTarget target) { + final Timestamp now = now(); + return Job.builder() + .uuid(UUID.randomUUID()) + .status(JobStatus.PREPARED) + .target(target) + .run(run) + .secret(randomSecret()) + .createdAt(now) + .updatedAt(now) + .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..ff2029a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.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.service.job; + +import lombok.RequiredArgsConstructor; +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.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class JobService { + + public static final String ENTITY_NAME = "Job"; + + private final JobRepository jobRepository; + + private final JobMapper jobMapper; + + 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() != runUuid) { + throw new NotFoundException(ENTITY_NAME, jobUuid); + }*/ + return jobMapper.toDTO(job); + } +} 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..d1b4921 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.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.service.plan; + +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.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.UUID; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Component +@RequiredArgsConstructor +public class PlanMapper { + + 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(PlanTarget::getStation) + .map(stationMapper::toSimpleDTO) + .toList()) + .createdAt(plan.getCreatedAt().toInstant()) + .updatedAt(plan.getUpdatedAt().toInstant()) + .build(); + } + + public PlanSimpleDTO toSimpleDTO(Plan plan) { + return PlanSimpleDTO.builder() + .uuid(plan.getUuid()) + .displayName(plan.getDisplayName()) + .note(plan.getNote()) + .train(trainMapper.toSimpleDTO(plan.getTrain())) + .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()) + .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); + return plan; + } +} 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..b2028d3 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java @@ -0,0 +1,180 @@ +/** + * 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.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.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.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 { + // TODO: validate? (empty list of stations) + final Train train = trainService.getByIdOrThrow(reqDto.getTrainUuid()); + final List stations = new ArrayList<>(); + for (UUID stationUuid : reqDto.getStationUuids()) { + stations.add(stationService.getByIdOrThrow(stationUuid)); + } + final Plan newPlan = planRepository.save(planMapper.fromCreateDTO(reqDto, train)); + entityManager.flush(); + entityManager.refresh(newPlan); + final List targets = + stations.stream() + .map(station -> planTargetMapper.forPlan(newPlan, station)) + .toList(); + newPlan.setTargets(targets); + planTargetRepository.saveAll(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 Set newStationUuids = new HashSet<>(reqDto.getStationUuids()); + final boolean planExecuted = !plan.getRuns().isEmpty(); + final boolean changeTrain = reqDto.getTrainUuid() != plan.getTrain().getUuid(); + final boolean changeTargets = + compareListContents(reqDto.getStationUuids(), 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 stations = new ArrayList<>(); + for (UUID stationUuid : reqDto.getStationUuids()) { + if (!oldStationUuids.contains(stationUuid)) { + stations.add(stationService.getByIdOrThrow(stationUuid)); + } + } + for (PlanTarget target : plan.getTargets()) { + if (!newStationUuids.contains(target.getStation().getUuid())) { + planTargetRepository.delete(target); + } + } + final Plan updatedPlan = planRepository.save(planMapper.fromUpdateDTO(reqDto, plan, train)); + entityManager.flush(); + entityManager.refresh(updatedPlan); + final List targets = + stations.stream() + .map(station -> planTargetMapper.forPlan(updatedPlan, station)) + .toList(); + updatedPlan.setTargets(targets); + planTargetRepository.saveAll(targets); + 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..1265c2a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanTargetMapper.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.service.plan; + +import lombok.RequiredArgsConstructor; +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, Station station) { + return PlanTarget.builder() + .uuid(UUID.randomUUID()) + .plan(newPlan) + .station(station) + .createdAt(newPlan.getCreatedAt()) + .updatedAt(newPlan.getUpdatedAt()) + .build(); + } +} 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..452cb11 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.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.run; + +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.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.util.Optional; +import java.util.UUID; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; + +@Component +@RequiredArgsConstructor +public class RunMapper { + + 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) + .orElse(null)) + .startedAt( + Optional.ofNullable(run.getStartedAt()) + .map(Timestamp::toInstant) + .orElse(null)) + .finishedAt( + Optional.ofNullable(run.getFinishedAt()) + .map(Timestamp::toInstant) + .orElse(null)) + .createdAt(run.getCreatedAt().toInstant()) + .updatedAt(run.getUpdatedAt().toInstant()) + .build(); + } + + public RunDTO toDTO(Run run) { + return RunDTO.builder() + .uuid(run.getUuid()) + .displayName(run.getDisplayName()) + .note(run.getNote()) + .status(run.getStatus()) + .plan(planMapper.toSimpleDTO(run.getPlan())) + .jobs(run.getJobs().stream().map(jobMapper::toSimpleDTO).toList()) + .shouldStartAt( + Optional.ofNullable(run.getShouldStartAt()) + .map(Timestamp::toInstant) + .orElse(null)) + .startedAt( + Optional.ofNullable(run.getStartedAt()) + .map(Timestamp::toInstant) + .orElse(null)) + .finishedAt( + Optional.ofNullable(run.getFinishedAt()) + .map(Timestamp::toInstant) + .orElse(null)) + .createdAt(run.getCreatedAt().toInstant()) + .updatedAt(run.getUpdatedAt().toInstant()) + .build(); + } + + public Run fromCreateDTO(RunCreateDTO reqDto, Plan plan) { + final Timestamp now = now(); + return Run.builder() + .uuid(UUID.randomUUID()) + .displayName(reqDto.getDisplayName()) + .note(reqDto.getNote()) + .status(RunStatus.PREPARED) + .plan(plan) + .shouldStartAt( + Optional.ofNullable(reqDto.getShouldStartAt()) + .map(Timestamp::from) + .orElse(null)) + .startedAt(null) + .finishedAt(null) + .createdAt(now) + .updatedAt(now) + .build(); + } + + public Run fromUpdateDTO(RunUpdateDTO reqDto, Run run) { + final Timestamp now = now(); + run.setDisplayName(reqDto.getDisplayName()); + run.setNote(reqDto.getNote()); + run.setUpdatedAt(now); + 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..6368457 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.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.service.run; + +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.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.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 javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class RunService { + + private 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; + + @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.saveAll(jobs); + entityManager.flush(); + entityManager.refresh(newRun); + // TODO: schedule the run / dispatch it in async + 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.save(runMapper.fromUpdateDTO(reqDto, run)); + return runMapper.toDTO(updatedRun); + } +} 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..3f4c3d5 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.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.service.station; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.station.StationDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.Station; +import org.fairdatatrain.trainhandler.service.stationdirectory.StationDirectoryMapper; +import org.fairdatatrain.trainhandler.service.traintype.TrainTypeMapper; +import org.springframework.stereotype.Component; + +import java.util.Arrays; + +@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) + .toList()) + .status(station.getStatus()) + .metadata(station.getMetadata()) + .directory(stationDirectoryMapper.toSimpleDTO(station.getDirectory())) + .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) + .lastContactAt(station.getLastContactAt().toInstant()) + .createdAt(station.getCreatedAt().toInstant()) + .updatedAt(station.getUpdatedAt().toInstant()) + .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) + .toList()) + .status(station.getStatus()) + .directory(stationDirectoryMapper.toSimpleDTO(station.getDirectory())) + .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) + .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..942d610 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.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.service.station; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.station.StationDTO; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +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.train.TrainMapper; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class StationService { + + private static final String ENTITY_NAME = "Station"; + + private final StationRepository stationRepository; + + private final StationMapper stationMapper; + + private final TrainMapper trainMapper; + + 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.findAll(pageable).map(stationMapper::toSimpleDTO); + } + return stationRepository + .findByTitleContainingIgnoreCase(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(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java index ca13c92..7f3299c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java @@ -24,7 +24,9 @@ import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; -import org.fairdatatrain.trainhandler.model.StationDirectory; +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; @@ -34,29 +36,30 @@ @Component public class StationDirectoryMapper { public StationDirectoryDTO toDTO(StationDirectory stationDirectory) { - return new StationDirectoryDTO( - stationDirectory.getUuid(), - stationDirectory.getUri(), - stationDirectory.getDisplayName(), - stationDirectory.getNote(), - stationDirectory.getMetadata(), - stationDirectory.getStatus(), - Optional.ofNullable(stationDirectory.getLastContact()) - .map(Timestamp::toInstant) - .orElse(null) - ); + return StationDirectoryDTO.builder() + .uuid(stationDirectory.getUuid()) + .uri(stationDirectory.getUri()) + .displayName(stationDirectory.getDisplayName()) + .note(stationDirectory.getNote()) + .status(stationDirectory.getStatus()) + .lastContactAt( + Optional.ofNullable(stationDirectory.getLastContactAt()) + .map(Timestamp::toInstant) + .orElse(null)) + .createdAt(stationDirectory.getCreatedAt().toInstant()) + .updatedAt(stationDirectory.getUpdatedAt().toInstant()) + .build(); } public StationDirectory fromCreateDTO(StationDirectoryChangeDTO reqDto) { final Timestamp now = Timestamp.from(Instant.now()); - return StationDirectory - .builder() + return StationDirectory.builder() .uri(reqDto.getUri()) .displayName(reqDto.getDisplayName()) .note(reqDto.getNote()) - .status("NEW") + .status(SyncServiceStatus.SYNCING) .metadata(null) - .lastContact(null) + .lastContactAt(null) .createdAt(now) .updatedAt(now) .build(); @@ -73,4 +76,12 @@ public StationDirectory fromUpdateDTO( 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 index 2b3ffb8..f30261e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java @@ -25,17 +25,13 @@ import lombok.RequiredArgsConstructor; import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; -import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationInfoDTO; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.repository.StationDirectoryRepository; import org.fairdatatrain.trainhandler.exception.NotFoundException; -import org.fairdatatrain.trainhandler.model.StationDirectory; -import org.fairdatatrain.trainhandler.repository.StationDirectoryRepository; -import org.fairdatatrain.trainhandler.service.fixtures.StationDirectoryFixtures; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Locale; import java.util.UUID; @Service @@ -89,17 +85,4 @@ public StationDirectoryDTO update(UUID uuid, StationDirectoryChangeDTO reqDto) stationDirectoryMapper.fromUpdateDTO(reqDto, stationDirectory)); return this.stationDirectoryMapper.toDTO(updatedStationDirectory); } - - public List search(String query) { - // Dummy - final String finalQuery = query.toLowerCase(Locale.ROOT); - return StationDirectoryFixtures.STATIONS.stream() - .filter( - station -> { - return station.getDisplayName() - .toLowerCase(Locale.ROOT) - .contains(finalQuery); - }) - .toList(); - } } 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..32a3b49 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.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.service.train; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.train.TrainDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; +import org.fairdatatrain.trainhandler.data.model.Train; +import org.fairdatatrain.trainhandler.service.traingarage.TrainGarageMapper; +import org.fairdatatrain.trainhandler.service.traintype.TrainTypeMapper; +import org.springframework.stereotype.Component; + +import java.util.Arrays; + +@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) + .toList()) + .status(train.getStatus()) + .metadata(train.getMetadata()) + .garage(trainGarageMapper.toSimpleDTO(train.getGarage())) + .types(train.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) + .lastContactAt(train.getLastContactAt().toInstant()) + .createdAt(train.getCreatedAt().toInstant()) + .updatedAt(train.getUpdatedAt().toInstant()) + .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) + .toList()) + .status(train.getStatus()) + .garage(trainGarageMapper.toSimpleDTO(train.getGarage())) + .types(train.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) + .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..face69a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.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.service.train; + +import lombok.RequiredArgsConstructor; +import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; +import org.fairdatatrain.trainhandler.api.dto.train.TrainDTO; +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.TrainRepository; +import org.fairdatatrain.trainhandler.exception.NotFoundException; +import org.fairdatatrain.trainhandler.service.station.StationMapper; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +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; + + 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.findAll(pageable).map(trainMapper::toSimpleDTO); + } + return trainRepository + .findByTitleContainingIgnoreCase(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(); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java index 88ec59c..5389634 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java @@ -24,7 +24,9 @@ import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; -import org.fairdatatrain.trainhandler.model.TrainGarage; +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; @@ -34,29 +36,31 @@ @Component public class TrainGarageMapper { public TrainGarageDTO toDTO(TrainGarage trainGarage) { - return new TrainGarageDTO( - trainGarage.getUuid(), - trainGarage.getUri(), - trainGarage.getDisplayName(), - trainGarage.getNote(), - trainGarage.getMetadata(), - trainGarage.getStatus(), - Optional.ofNullable(trainGarage.getLastContact()) - .map(Timestamp::toInstant) - .orElse(null) - ); + return TrainGarageDTO.builder() + .uuid(trainGarage.getUuid()) + .uri(trainGarage.getUri()) + .displayName(trainGarage.getDisplayName()) + .note(trainGarage.getNote()) + .metadata(trainGarage.getMetadata()) + .status(trainGarage.getStatus()) + .lastContactAt( + Optional.ofNullable(trainGarage.getLastContactAt()) + .map(Timestamp::toInstant) + .orElse(null)) + .createdAt(trainGarage.getCreatedAt().toInstant()) + .updatedAt(trainGarage.getCreatedAt().toInstant()) + .build(); } public TrainGarage fromCreateDTO(TrainGarageChangeDTO reqDto) { final Timestamp now = Timestamp.from(Instant.now()); - return TrainGarage - .builder() + return TrainGarage.builder() .uri(reqDto.getUri()) .displayName(reqDto.getDisplayName()) .note(reqDto.getNote()) - .status("NEW") + .status(SyncServiceStatus.SYNCING) .metadata(null) - .lastContact(null) + .lastContactAt(null) .createdAt(now) .updatedAt(now) .build(); @@ -73,4 +77,12 @@ public TrainGarage fromUpdateDTO( 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 index 3eee1e5..0f053aa 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java @@ -23,20 +23,15 @@ package org.fairdatatrain.trainhandler.service.traingarage; import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; -import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainInfoDTO; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.repository.TrainGarageRepository; import org.fairdatatrain.trainhandler.exception.NotFoundException; -import org.fairdatatrain.trainhandler.model.TrainGarage; -import org.fairdatatrain.trainhandler.repository.TrainGarageRepository; -import org.fairdatatrain.trainhandler.service.fixtures.TrainGarageFixtures; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Locale; import java.util.UUID; @Service @@ -90,18 +85,4 @@ public TrainGarageDTO update(UUID uuid, TrainGarageChangeDTO reqDto) trainGarageMapper.fromUpdateDTO(reqDto, trainGarage)); return this.trainGarageMapper.toDTO(updatedTrainGarage); } - - @SneakyThrows - public List search(String query) { - // Dummy - final String finalQuery = query.toLowerCase(Locale.ROOT); - return TrainGarageFixtures.TRAINS.stream() - .filter( - garage -> { - return garage.getDisplayName() - .toLowerCase(Locale.ROOT) - .contains(finalQuery); - }) - .toList(); - } } 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..ef57528 --- /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()) + .updatedAt(trainType.getUpdatedAt().toInstant()) + .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..a321c0a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.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.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.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 java.util.UUID; + +@Service +@RequiredArgsConstructor +public class TrainTypeService { + + private static final String ENTITY_NAME = "TrainType"; + + private final TrainTypeRepository trainTypeRepository; + + private final TrainTypeMapper trainTypeMapper; + + private TrainType getByIdOrThrow(UUID uuid) throws NotFoundException { + return trainTypeRepository + .findById(uuid) + .orElseThrow(() -> new NotFoundException(ENTITY_NAME, uuid)); + } + + 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); + } + + public TrainTypeDTO create(TrainTypeChangeDTO reqDto) { + // TODO: validate? + final TrainType newTrainType = + trainTypeRepository.save(trainTypeMapper.fromCreateDTO(reqDto)); + return trainTypeMapper.toDTO(newTrainType); + } + + public TrainTypeDTO update(UUID uuid, TrainTypeChangeDTO reqDto) throws NotFoundException { + // TODO: validate? + final TrainType trainType = getByIdOrThrow(uuid); + final TrainType updatedTrainType = + trainTypeRepository.save(trainTypeMapper.fromUpdateDTO(reqDto, trainType)); + return trainTypeMapper.toDTO(updatedTrainType); + } +} 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..63c137e --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/utils/CompareUtils.java @@ -0,0 +1,36 @@ +/** + * 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; +import java.util.List; + +public class CompareUtils { + + public static boolean compareListContents(List listA, Collection listB) { + if (listA.size() != listB.size()) { + return false; + } + return listA.retainAll(listB); + } +} 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/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/resources/db/migration/V0001__directory-and-garage.sql b/src/main/resources/db/migration/V0001__directory-and-garage.sql index 564032b..311a55e 100644 --- a/src/main/resources/db/migration/V0001__directory-and-garage.sql +++ b/src/main/resources/db/migration/V0001__directory-and-garage.sql @@ -24,7 +24,7 @@ CREATE TABLE IF NOT EXISTS station_directory ( uuid UUID NOT NULL - CONSTRAINT station_directory_pkey PRIMARY KEY, + CONSTRAINT station_directory_pk PRIMARY KEY, uri TEXT NOT NULL, display_name VARCHAR(255) NOT NULL, note TEXT NOT NULL, @@ -38,11 +38,11 @@ CREATE TABLE IF NOT EXISTS station_directory CREATE TABLE IF NOT EXISTS train_garage ( uuid UUID NOT NULL - CONSTRAINT train_garage_pkey PRIMARY KEY, + CONSTRAINT train_garage_pk PRIMARY KEY, uri TEXT NOT NULL, display_name VARCHAR(255) NOT NULL, note TEXT NOT NULL, - metadata TEXT , + metadata TEXT, status VARCHAR(50), last_contact TIMESTAMP, created_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/V0002.1__dev_data.sql b/src/main/resources/db/migration/V0002.1__dev_data.sql new file mode 100644 index 0000000..5b1c838 --- /dev/null +++ b/src/main/resources/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-18e15c8e0751', '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-7d4955ded0bc', '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-aad0edd1639a', '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-18e15c8e0751', '9b2f99bb-6ca4-4326-82c1-bba34fb39abc'); +INSERT INTO station_train_type (train_type_id, station_id) +VALUES ('32d36066-dbf6-4ed3-b4da-aad0edd1639a', '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-18e15c8e0751', '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-18e15c8e0751', 'f41417ab-ef19-408f-ba69-5d3a1bc42e23'); +INSERT INTO station_train_type (train_type_id, station_id) +VALUES ('8b4acd34-5738-49d4-918f-7d4955ded0bc', '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-18e15c8e0751', '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-aad0edd1639a', '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-18e15c8e0751', 'a1eea8ce-e332-4e7b-b41d-880b53d709f4'); 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.3__dev_data.sql b/src/main/resources/db/migration/V0003.3__dev_data.sql new file mode 100644 index 0000000..61a00e4 --- /dev/null +++ b/src/main/resources/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/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Common.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Common.java index 314ea95..25d0df0 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Common.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Common.java @@ -24,7 +24,7 @@ import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; -import org.fairdatatrain.trainhandler.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; 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 index 487fba9..f354854 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_DELETE.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_DELETE.java @@ -23,9 +23,8 @@ package org.fairdatatrain.trainhandler.acceptance.stationdirectory; import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; -import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryDTO; -import org.fairdatatrain.trainhandler.model.StationDirectory; -import org.fairdatatrain.trainhandler.repository.StationDirectoryRepository; +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; @@ -40,7 +39,8 @@ import static java.lang.String.format; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; @DisplayName("DELETE /station-directories/:uuid") public class Detail_DELETE extends WebIntegrationTest { 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 index 6bde47a..fff0777 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_GET.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_GET.java @@ -23,10 +23,9 @@ 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.model.StationDirectory; -import org.fairdatatrain.trainhandler.repository.StationDirectoryRepository; +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; @@ -36,9 +35,7 @@ import org.springframework.http.ResponseEntity; import java.net.URI; -import java.util.List; import java.util.UUID; -import java.util.stream.StreamSupport; import static java.lang.String.format; import static org.hamcrest.MatcherAssert.assertThat; 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 index 9de5343..867220b 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_PUT.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/Detail_PUT.java @@ -25,8 +25,8 @@ 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.model.StationDirectory; -import org.fairdatatrain.trainhandler.repository.StationDirectoryRepository; +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; 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 index a1e8abb..601a180 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_GET.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_GET.java @@ -25,8 +25,8 @@ 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.model.StationDirectory; -import org.fairdatatrain.trainhandler.repository.StationDirectoryRepository; +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; 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 index ab08577..eb9820e 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_POST.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/List_POST.java @@ -25,8 +25,8 @@ 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.model.StationDirectory; -import org.fairdatatrain.trainhandler.repository.StationDirectoryRepository; +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; diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/StationDirectoryTestFixtures.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/StationDirectoryTestFixtures.java index 590c6d5..abe0b8c 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/StationDirectoryTestFixtures.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/stationdirectory/StationDirectoryTestFixtures.java @@ -23,7 +23,8 @@ package org.fairdatatrain.trainhandler.acceptance.stationdirectory; import org.fairdatatrain.trainhandler.api.dto.stationdirectory.StationDirectoryChangeDTO; -import org.fairdatatrain.trainhandler.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.model.StationDirectory; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; import java.sql.Timestamp; import java.time.Instant; @@ -33,44 +34,44 @@ 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("UNKNOWN") - .lastContact(Timestamp.from(Instant.now())) - .build(); + 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("UNKNOWN") - .lastContact(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("UNKNOWN") - .lastContact(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() diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Common.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Common.java index 82be9ca..bf3c94f 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Common.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Common.java @@ -24,7 +24,7 @@ import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; -import org.fairdatatrain.trainhandler.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; 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 index 51f8b41..2ce2f37 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_DELETE.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_DELETE.java @@ -23,8 +23,8 @@ package org.fairdatatrain.trainhandler.acceptance.traingarage; import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; -import org.fairdatatrain.trainhandler.model.TrainGarage; -import org.fairdatatrain.trainhandler.repository.TrainGarageRepository; +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; 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 index 1b26d4b..282ca55 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_GET.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_GET.java @@ -24,8 +24,8 @@ import org.fairdatatrain.trainhandler.acceptance.WebIntegrationTest; import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageDTO; -import org.fairdatatrain.trainhandler.model.TrainGarage; -import org.fairdatatrain.trainhandler.repository.TrainGarageRepository; +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; 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 index ad0b44c..71cd8b2 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_PUT.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/Detail_PUT.java @@ -25,8 +25,8 @@ 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.model.TrainGarage; -import org.fairdatatrain.trainhandler.repository.TrainGarageRepository; +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; 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 index a1dd4d4..a7c0cb4 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_GET.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_GET.java @@ -25,8 +25,8 @@ 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.model.TrainGarage; -import org.fairdatatrain.trainhandler.repository.TrainGarageRepository; +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; 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 index a7c1c85..2ac669f 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_POST.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/List_POST.java @@ -25,8 +25,8 @@ 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.model.TrainGarage; -import org.fairdatatrain.trainhandler.repository.TrainGarageRepository; +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; diff --git a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/TrainGarageTestFixtures.java b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/TrainGarageTestFixtures.java index 3bdf4bf..55eb786 100644 --- a/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/TrainGarageTestFixtures.java +++ b/src/test/java/org/fairdatatrain/trainhandler/acceptance/traingarage/TrainGarageTestFixtures.java @@ -23,7 +23,8 @@ package org.fairdatatrain.trainhandler.acceptance.traingarage; import org.fairdatatrain.trainhandler.api.dto.traingarage.TrainGarageChangeDTO; -import org.fairdatatrain.trainhandler.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.model.TrainGarage; +import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; import java.sql.Timestamp; import java.time.Instant; @@ -33,44 +34,44 @@ 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("UNKNOWN") - .lastContact(Timestamp.from(Instant.now())) - .build(); + 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("UNKNOWN") - .lastContact(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("UNKNOWN") - .lastContact(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() From 9e53040b34484941a168364af8a6889c4d43d3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 25 May 2022 11:15:24 +0200 Subject: [PATCH 17/97] Dispatch runs and jobs (#21) --- checkstyle.xml | 1 - pom.xml | 5 - .../trainhandler/Application.java | 4 + .../api/controller/ApiExceptionHandler.java | 29 +++- .../api/controller/JobArtifactController.java | 105 ++++++++++++ .../api/controller/JobController.java | 74 ++------ .../api/controller/JobEventController.java | 73 ++++++++ .../api/controller/RunController.java | 34 +++- .../api/dto/job/JobArtifactCreateDTO.java | 65 +++++++ .../api/dto/job/JobArtifactDTO.java | 52 ++++++ .../trainhandler/api/dto/job/JobDTO.java | 4 + .../api/dto/job/JobEventCreateDTO.java | 6 - .../trainhandler/api/dto/job/JobEventDTO.java | 5 - .../api/dto/job/JobSimpleDTO.java | 5 + .../trainhandler/api/dto/run/RunDTO.java | 2 + .../trainhandler/config/AsyncConfig.java | 40 +++++ .../trainhandler/config/HttpClientConfig.java | 65 +++++++ .../trainhandler/data/model/Job.java | 8 +- .../trainhandler/data/model/JobArtifact.java | 86 ++++++++++ .../trainhandler/data/model/JobEvent.java | 17 +- .../trainhandler/data/model/Run.java | 5 +- ...JobEventType.java => ArtifactStorage.java} | 8 +- .../repository/JobArtifactRepository.java | 31 ++++ .../data/repository/JobRepository.java | 1 + .../data/repository/RunRepository.java | 14 ++ .../service/async/AsyncEventPublisher.java | 25 ++- ...Notification.java => JobNotification.java} | 21 ++- .../async/JobNotificationListener.java | 108 ++++++++++++ ...cationListener.java => PollContainer.java} | 42 ++--- .../async/RunNotificationListener.java | 107 ++++++++++++ .../service/dispatch/DispatchMapper.java | 57 +++++++ .../service/dispatch/DispatchPayload.java | 51 ++++++ .../service/dispatch/DispatchService.java | 73 ++++++++ .../trainhandler/service/job/JobMapper.java | 31 +++- .../trainhandler/service/job/JobService.java | 35 +++- .../job/artifact/JobArtifactMapper.java | 71 ++++++++ .../job/artifact/JobArtifactService.java | 158 ++++++++++++++++++ .../job/{ => event}/JobEventMapper.java | 12 +- .../job/{ => event}/JobEventService.java | 103 +++++++----- .../service/run/RunDispatcher.java | 122 ++++++++++++++ .../trainhandler/service/run/RunMapper.java | 16 +- .../trainhandler/service/run/RunService.java | 31 +++- .../trainhandler/utils/HashUtils.java | 39 +++++ src/main/resources/application.yml | 5 + .../db/migration/V0003.4__job-artifacts.sql | 56 +++++++ .../db/migration/V0003.5__dev_data.sql | 26 +++ .../db/migration/V0003.6__run-job-version.sql | 28 ++++ .../db/migration/V0003.7__dev_data.sql | 28 ++++ 48 files changed, 1766 insertions(+), 218 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactCreateDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/config/AsyncConfig.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/config/HttpClientConfig.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/model/JobArtifact.java rename src/main/java/org/fairdatatrain/trainhandler/data/model/enums/{JobEventType.java => ArtifactStorage.java} (94%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/data/repository/JobArtifactRepository.java rename src/main/java/org/fairdatatrain/trainhandler/service/async/{JobEventNotification.java => JobNotification.java} (74%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java rename src/main/java/org/fairdatatrain/trainhandler/service/async/{JobEventNotificationListener.java => PollContainer.java} (54%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchPayload.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactMapper.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactService.java rename src/main/java/org/fairdatatrain/trainhandler/service/job/{ => event}/JobEventMapper.java (88%) rename src/main/java/org/fairdatatrain/trainhandler/service/job/{ => event}/JobEventService.java (62%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/utils/HashUtils.java create mode 100644 src/main/resources/db/migration/V0003.4__job-artifacts.sql create mode 100644 src/main/resources/db/migration/V0003.5__dev_data.sql create mode 100644 src/main/resources/db/migration/V0003.6__run-job-version.sql create mode 100644 src/main/resources/db/migration/V0003.7__dev_data.sql diff --git a/checkstyle.xml b/checkstyle.xml index 13ed85d..827a206 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -321,7 +321,6 @@ - diff --git a/pom.xml b/pom.xml index e55f2a8..f92ade7 100644 --- a/pom.xml +++ b/pom.xml @@ -77,11 +77,6 @@ springdoc-openapi-ui ${springdoc.version} - - com.vladmihalcea - hibernate-types-52 - ${hibernate-types.version} - org.postgresql diff --git a/src/main/java/org/fairdatatrain/trainhandler/Application.java b/src/main/java/org/fairdatatrain/trainhandler/Application.java index 995aaff..93b2411 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/Application.java +++ b/src/main/java/org/fairdatatrain/trainhandler/Application.java @@ -25,9 +25,13 @@ 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 { diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java index 460198c..680ffea 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/ApiExceptionHandler.java @@ -31,6 +31,8 @@ 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 @@ -50,20 +52,37 @@ public ResponseEntity handleNotFoundException(NotFoundException except "HTTP-404", format( "Cannot find entity %s with %s", - exception.getEntityName(), exception.getFields())), - HttpStatus.NOT_FOUND); + exception.getEntityName(), exception.getFields() + ) + ), + HttpStatus.NOT_FOUND + ); } @ExceptionHandler(CannotPerformException.class) public ResponseEntity handleCannotDeleteException(CannotPerformException exception) { return new ResponseEntity<>( new ErrorDTO( - "HTTP-400", + "HTTP-400-DeletionError", format( "Cannot perform %s on entity %s (with %s)", exception.getOperation(), exception.getEntityName(), - exception.getFields())), - HttpStatus.BAD_REQUEST); + 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..51e291b --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.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.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.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +import static java.lang.String.format; + +@Tag(name = "Runs") +@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", + produces = MediaType.APPLICATION_JSON_VALUE + ) + 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, runUuid); + 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 index d48d13e..db49348 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java @@ -24,13 +24,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -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.job.JobSimpleDTO; -import org.fairdatatrain.trainhandler.exception.JobSecurityException; +import org.fairdatatrain.trainhandler.api.dto.job.*; import org.fairdatatrain.trainhandler.exception.NotFoundException; -import org.fairdatatrain.trainhandler.service.job.JobEventService; import org.fairdatatrain.trainhandler.service.job.JobService; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -38,20 +33,17 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; -import javax.validation.Valid; -import java.util.Collections; -import java.util.List; import java.util.UUID; -import java.util.concurrent.CompletableFuture; @Tag(name = "Runs") @RestController @RequestMapping("/runs") @RequiredArgsConstructor public class JobController { + private final JobService jobService; - private final JobEventService jobEventService; + private final Long pollTimeout; @GetMapping(path = "/{runUuid}/jobs", produces = MediaType.APPLICATION_JSON_VALUE) public Page getJobs(@PathVariable UUID runUuid, Pageable pageable) { @@ -62,60 +54,16 @@ public Page getJobs(@PathVariable UUID runUuid, Pageable pageable) path = "/{runUuid}/jobs/{jobUuid}", produces = MediaType.APPLICATION_JSON_VALUE ) - public JobDTO getJobs( - @PathVariable UUID runUuid, @PathVariable UUID jobUuid - ) throws NotFoundException { - return jobService.getSingle(runUuid, jobUuid); - } - - @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); - } - - @GetMapping( - path = "/{runUuid}/jobs/{jobUuid}/events/poll", - produces = MediaType.APPLICATION_JSON_VALUE - ) - public DeferredResult> pollNewerJobEvents( + public DeferredResult pollJob( @PathVariable UUID runUuid, @PathVariable UUID jobUuid, - @RequestParam(required = false) UUID afterEventUuid - ) { - // TODO: configurable timeout - final DeferredResult> events = new DeferredResult<>( - 10 * 1000L, Collections.emptyList() + @RequestParam(required = false, defaultValue = "0") Long after + ) throws NotFoundException { + final JobDTO currentJob = jobService.getSingle(runUuid, jobUuid); + final DeferredResult result = new DeferredResult<>( + pollTimeout, currentJob ); - CompletableFuture.runAsync(() -> { - try { - events.setResult(jobEventService.pollEvents(runUuid, jobUuid, afterEventUuid)); - } - catch (Exception ex) { - ex.printStackTrace(); - events.setResult(Collections.emptyList()); - // TODO: better error handling - } - }); - return events; - } - - @PostMapping( - path = "/{runUuid}/jobs/{jobUuid}/events", - 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; + 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..6e75ca5 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java @@ -0,0 +1,73 @@ +/** + * 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.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +@Tag(name = "Runs") +@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, runUuid); + return dto; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java index ac30964..1c8fc88 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java @@ -29,10 +29,12 @@ import org.fairdatatrain.trainhandler.api.dto.run.RunUpdateDTO; 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.web.bind.annotation.*; +import org.springframework.web.context.request.async.DeferredResult; import javax.validation.Valid; import java.util.UUID; @@ -45,28 +47,46 @@ public class RunController { private final RunService runService; + private final AsyncEventPublisher asyncEventPublisher; + + private final Long pollTimeout; + @PostMapping( path = "", consumes = MediaType.APPLICATION_JSON_VALUE, - produces = 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 RunDTO getSingle(@PathVariable UUID uuid) throws NotFoundException { - return runService.getSingle(uuid); + @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<>( + pollTimeout, currentRun + ); + runService.poll(uuid, result, after, currentRun); + return result; } @PutMapping( path = "/{uuid}", consumes = MediaType.APPLICATION_JSON_VALUE, - produces = MediaType.APPLICATION_JSON_VALUE) + produces = MediaType.APPLICATION_JSON_VALUE + ) public RunDTO update( @PathVariable UUID uuid, @Valid @RequestBody RunUpdateDTO reqDto ) throws NotFoundException, CannotPerformException { - // TODO: abort? duplicate? - return runService.update(uuid, reqDto); + final RunDTO run = runService.update(uuid, reqDto); + asyncEventPublisher.publishNewJobEventNotification(run); + return run; } } 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..f1102f2 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.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.job; + +import lombok.*; + +import java.time.Instant; +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 hash; + + private Instant occurredAt; + + private Instant createdAt; + + private Instant 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 index 930c448..4001d1f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java @@ -54,7 +54,11 @@ public class JobDTO { private List events; + private List artifacts; + private Instant createdAt; private Instant 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 index 9f8910a..c0bca5b 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventCreateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventCreateDTO.java @@ -26,7 +26,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.fairdatatrain.trainhandler.data.model.enums.JobEventType; import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; import javax.validation.constraints.NotNull; @@ -38,16 +37,11 @@ @Setter public class JobEventCreateDTO { - @NotNull - private JobEventType type; - private JobStatus resultStatus; @NotNull private String message; - private String payload; - @NotNull private Instant occurredAt; 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 index c72bbe6..f50e206 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventDTO.java @@ -23,7 +23,6 @@ package org.fairdatatrain.trainhandler.api.dto.job; import lombok.*; -import org.fairdatatrain.trainhandler.data.model.enums.JobEventType; import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; import java.time.Instant; @@ -38,14 +37,10 @@ public class JobEventDTO { private UUID uuid; - private JobEventType type; - private JobStatus resultStatus; private String message; - private String payload; - private Instant occurredAt; private Instant createdAt; 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 index fbe12fe..473d38c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobSimpleDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobSimpleDTO.java @@ -27,6 +27,7 @@ import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; import java.time.Instant; +import java.util.List; import java.util.UUID; @AllArgsConstructor @@ -48,5 +49,9 @@ public class JobSimpleDTO { private StationSimpleDTO target; + private List artifacts; + private UUID runUuid; + + private Long version; } 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 index 7dd8051..9e2c5bc 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunDTO.java @@ -59,4 +59,6 @@ public class RunDTO { private Instant createdAt; private Instant updatedAt; + + private Long version; } diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/AsyncConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/AsyncConfig.java new file mode 100644 index 0000000..b611e93 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/AsyncConfig.java @@ -0,0 +1,40 @@ +/** + * 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.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AsyncConfig { + + // TODO: custom config properties + @Value("${poll.timeout:10000}") + private final Long pollTimeout = 10000L; + + @Bean("pollTimeout") + public Long getPollTimeout() { + return pollTimeout; + } +} 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..7ee6860 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/HttpClientConfig.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.config; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +import java.net.http.HttpClient; +import java.time.Duration; + +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; + +@Configuration +public class HttpClientConfig { + private static final long TIMEOUT = 5; + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { + return restTemplateBuilder + .setConnectTimeout(Duration.ofSeconds(TIMEOUT)) + .setReadTimeout(Duration.ofSeconds(TIMEOUT)) + .build(); + } + + @Bean + public HttpClient httpClient() { + return HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .followRedirects(HttpClient.Redirect.ALWAYS) + .build(); + } + + @Bean + public ObjectMapper objectMapper() { + final ObjectMapper mapper = new ObjectMapper(); + mapper.findAndRegisterModules(); + mapper.setSerializationInclusion(NON_NULL); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + return mapper; + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java index 4608c3d..d6f4e62 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java @@ -61,6 +61,9 @@ public class Job extends BaseEntity { @Column(name = "finished_at") private Timestamp finishedAt; + @Column(name = "version", nullable = false) + private Long version; + @NotNull @ManyToOne @JoinColumn(name = "plan_target_id") @@ -68,9 +71,12 @@ public class Job extends BaseEntity { @NotNull @ManyToOne - @JoinColumn(name = "run_id") + @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; } 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 index 90d8547..9fda6a6 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/JobEvent.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/JobEvent.java @@ -22,17 +22,13 @@ */ package org.fairdatatrain.trainhandler.data.model; -import com.vladmihalcea.hibernate.type.json.JsonBinaryType; 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.JobEventType; import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -40,7 +36,6 @@ @Entity(name = "JobEvent") @Table(name = "job_event") -@TypeDef(name = "json", typeClass = JsonBinaryType.class) @Getter @Setter @AllArgsConstructor @@ -48,28 +43,20 @@ @SuperBuilder public class JobEvent extends BaseEntity { - @Enumerated(EnumType.STRING) - @Column(name = "type", columnDefinition = "job_event_type", nullable = false) - private JobEventType type; - @Enumerated(EnumType.STRING) @Column(name = "result_status", columnDefinition = "job_status") private JobStatus resultStatus; @NotNull - @Column(name = "occurred_at") + @Column(name = "occurred_at", nullable = false) private Timestamp occurredAt; @NotNull @Column(name = "message", nullable = false) private String message; - @Column(name = "payload", columnDefinition = "json") - @Type(type = "json") - private String payload; - @NotNull @ManyToOne - @JoinColumn(name = "job_id") + @JoinColumn(name = "job_id", nullable = false) private Job job; } diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java index 85168f3..e4599aa 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java @@ -67,11 +67,14 @@ public class Run extends BaseEntity { @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.LAZY, mappedBy = "run") + @OneToMany(fetch = FetchType.EAGER, mappedBy = "run") private List jobs; } diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobEventType.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/ArtifactStorage.java similarity index 94% rename from src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobEventType.java rename to src/main/java/org/fairdatatrain/trainhandler/data/model/enums/ArtifactStorage.java index c800861..b9cf6e9 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/JobEventType.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/enums/ArtifactStorage.java @@ -22,8 +22,8 @@ */ package org.fairdatatrain.trainhandler.data.model.enums; -public enum JobEventType { - ARTEFACT, - INIT, - INFO +public enum ArtifactStorage { + POSTGRES, + S3, + LOCALFS } 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..d214b67 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobArtifactRepository.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.JobArtifact; +import org.fairdatatrain.trainhandler.data.repository.base.BaseRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface JobArtifactRepository extends BaseRepository { +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobRepository.java index 88ab17c..e870830 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobRepository.java @@ -34,4 +34,5 @@ public interface JobRepository extends BaseRepository { Page findAllByRunUuid(UUID runUuid, Pageable pageable); + } diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java index e1ce7ee..767c0c6 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java @@ -26,12 +26,26 @@ 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.Optional; 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 + ORDER BY r.shouldStartAt ASC + """) + Optional findRunToDispatch(@Param("timestamp") Timestamp timestamp); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java index 5adfcc8..0e62955 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java @@ -24,11 +24,11 @@ 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 java.util.UUID; - import static java.lang.String.format; @Component @@ -38,9 +38,24 @@ public class AsyncEventPublisher { private final ApplicationEventPublisher publisher; - public void publishNewJobEventNotification(final UUID jobUuid) { - log.info(format("Publishing new job event notification for job %s", jobUuid)); - publisher.publishEvent(new JobEventNotification(this, jobUuid)); + 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/JobEventNotification.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotification.java similarity index 74% rename from src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotification.java rename to src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotification.java index 2e915e9..89379dd 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotification.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotification.java @@ -22,20 +22,27 @@ */ 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; -import java.util.UUID; +public class JobNotification extends ApplicationEvent { -public class JobEventNotification extends ApplicationEvent { + private final RunDTO run; - private final UUID jobUuid; + private final JobDTO job; - JobEventNotification(Object source, UUID jobUuid) { + JobNotification(Object source, RunDTO run, JobDTO job) { super(source); - this.jobUuid = jobUuid; + this.run = run; + this.job = job; } - public UUID getJobUuid() { - return jobUuid; + 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..dbc1a5d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java @@ -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. + */ +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.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.async.DeferredResult; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.*; + +import static java.lang.String.format; + +@Component +@Slf4j +@RequiredArgsConstructor +public class JobNotificationListener { + + private final Long pollTimeout; + + private final Map>> queues = new HashMap<>(); + + @EventListener + public void handleJobEventNotification(JobNotification notification) { + if (notification.getJob() != null) { + updateResults(notification.getJob()); + } + } + + @Synchronized + public void updateResults(JobDTO job) { + log.info(format( + "Updating results for job '%s' (version '%s')", + job.getUuid(), job.getVersion() + )); + final Instant now = Instant.now(); + if (queues.containsKey(job.getUuid())) { + final List> remainings = 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 { + remainings.add(container); + } + }); + queues.put(job.getUuid(), remainings); + } + 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) { + final Instant now = Instant.now(); + if (!queues.containsKey(jobUuid)) { + queues.put(jobUuid, new ArrayList<>()); + } + else { + final List> remainings = new ArrayList<>(); + queues.get(jobUuid).forEach(container -> { + if (container.getTimeoutsAt().isAfter(now)) { + remainings.add(container); + } + }); + queues.put(jobUuid, remainings); + } + queues.get(jobUuid).add( + new PollContainer<>( + version, + Instant.now().plus(pollTimeout, ChronoUnit.MILLIS), + result + ) + ); + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotificationListener.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/PollContainer.java similarity index 54% rename from src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotificationListener.java rename to src/main/java/org/fairdatatrain/trainhandler/service/async/PollContainer.java index 9c8de86..903c5ca 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/async/JobEventNotificationListener.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/PollContainer.java @@ -22,38 +22,26 @@ */ package org.fairdatatrain.trainhandler.service.async; -import org.springframework.context.event.EventListener; -import org.springframework.stereotype.Component; +import lombok.*; +import org.springframework.web.context.request.async.DeferredResult; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.time.Instant; -@Component -public class JobEventNotificationListener { +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder +public class PollContainer implements Comparable> { - private final Map locks = new HashMap<>(); + private Long version; - @EventListener - public void handleJobEventNotification(JobEventNotification notification) { - if (locks.containsKey(notification.getJobUuid())) { - synchronized (locks.get(notification.getJobUuid())) { - final Object lock = locks.remove(notification.getJobUuid()); - lock.notifyAll(); - } - } - } + private Instant timeoutsAt; - private void prepare(UUID jobUuid) { - if (!locks.containsKey(jobUuid)) { - locks.put(jobUuid, new Object()); - } - } + private DeferredResult result; - public void wait(UUID jobUuid) throws InterruptedException { - prepare(jobUuid); - synchronized (locks.get(jobUuid)) { - locks.get(jobUuid).wait(); - } + @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..78206cf --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java @@ -0,0 +1,107 @@ +/** + * 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.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.async.DeferredResult; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.*; + +import static java.lang.String.format; + +@Component +@Slf4j +@RequiredArgsConstructor +public class RunNotificationListener { + + private final Long pollTimeout; + + private final Map>> queues = new HashMap<>(); + + @EventListener + public void handleJobEventNotification(JobNotification 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> remainings = 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 { + remainings.add(container); + } + }); + queues.put(run.getUuid(), remainings); + } + 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) { + final Instant now = Instant.now(); + if (!queues.containsKey(runUuid)) { + queues.put(runUuid, new ArrayList<>()); + } + else { + final List> remainings = new ArrayList<>(); + queues.get(runUuid).forEach(container -> { + if (container.getTimeoutsAt().isAfter(now)) { + remainings.add(container); + } + }); + queues.put(runUuid, remainings); + } + queues.get(runUuid).add( + new PollContainer<>( + version, + Instant.now().plus(pollTimeout, ChronoUnit.MILLIS), + result + ) + ); + } + +} 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..2435469 --- /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("${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..e40b731 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java @@ -0,0 +1,73 @@ +/** + * 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 com.fasterxml.jackson.databind.ObjectMapper; +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.client.RestTemplate; + +import static java.lang.String.format; + +@Slf4j +@Service +@RequiredArgsConstructor +public class DispatchService { + + private final DispatchMapper dispatchMapper; + + private final RestTemplate client; + + private final ObjectMapper objectMapper; + + 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)); + final HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + final String payloadJson = objectMapper.writeValueAsString(payload); + final HttpEntity entity = new HttpEntity<>(payloadJson, headers); + final ResponseEntity response = client.postForEntity(uri, entity, String.class); + if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { + log.info(format( + "Dispatching job %s failed: %s", job.getUuid(), response.getStatusCode() + )); + throw new RuntimeException( + "Station responded with status: " + response.getStatusCode() + ); + } + log.info(format("Dispatching job %s accepted", job.getUuid())); + } + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java index e0d2224..a541dc3 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java @@ -24,10 +24,10 @@ 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.model.PlanTarget; -import org.fairdatatrain.trainhandler.data.model.Run; +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; @@ -38,7 +38,6 @@ import java.util.UUID; import static org.fairdatatrain.trainhandler.utils.RandomUtils.randomSecret; -import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; @Component public class JobMapper { @@ -47,9 +46,20 @@ public class JobMapper { private final RunMapper runMapper; - public JobMapper(StationMapper stationMapper, @Lazy 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) { @@ -66,7 +76,9 @@ public JobSimpleDTO toSimpleDTO(Job job) { .map(Timestamp::toInstant) .orElse(null)) .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) + .artifacts(job.getArtifacts().stream().map(jobArtifactMapper::toDTO).toList()) .runUuid(job.getRun().getUuid()) + .version(job.getVersion()) .build(); } @@ -85,21 +97,24 @@ public JobDTO toDTO(Job job) { .orElse(null)) .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) .run(runMapper.toSimpleDTO(job.getRun())) + .events(job.getEvents().stream().map(jobEventMapper::toDTO).toList()) + .artifacts(job.getArtifacts().stream().map(jobArtifactMapper::toDTO).toList()) .createdAt(job.getCreatedAt().toInstant()) .updatedAt(job.getUpdatedAt().toInstant()) + .version(job.getVersion()) .build(); } public Job fromTarget(Run run, PlanTarget target) { - final Timestamp now = now(); return Job.builder() .uuid(UUID.randomUUID()) .status(JobStatus.PREPARED) .target(target) .run(run) .secret(randomSecret()) - .createdAt(now) - .updatedAt(now) + .createdAt(run.getCreatedAt()) + .updatedAt(run.getCreatedAt()) + .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 index ff2029a..4042042 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java @@ -23,19 +23,28 @@ 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 javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; import java.util.UUID; +import static java.lang.String.format; + @Service @RequiredArgsConstructor +@Slf4j public class JobService { public static final String ENTITY_NAME = "Job"; @@ -44,6 +53,11 @@ public class JobService { private final JobMapper jobMapper; + private final JobNotificationListener jobNotificationListener; + + @PersistenceContext + private final EntityManager entityManager; + public Job getByIdOrThrow(UUID uuid) throws NotFoundException { return jobRepository .findById(uuid) @@ -58,10 +72,25 @@ public Page getJobsForRun(UUID runUuid, Pageable pageable) { public JobDTO getSingle(UUID runUuid, UUID jobUuid) throws NotFoundException { final Job job = getByIdOrThrow(jobUuid); - /* - if (job.getRun().getUuid() != runUuid) { + 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); + } + 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..6fe5965 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactMapper.java @@ -0,0 +1,71 @@ +/** + * 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()) + .hash(artifact.getHash()) + .occurredAt(artifact.getOccurredAt().toInstant()) + .createdAt(artifact.getCreatedAt().toInstant()) + .updatedAt(artifact.getUpdatedAt().toInstant()) + .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..e2da313 --- /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.save( + jobArtifactMapper.fromCreateDTO(reqDto, job, data) + ); + job.setVersion(jobArtifact.getUpdatedAt().toInstant().toEpochMilli()); + jobRepository.save(job); + job.getRun().setVersion(job.getVersion()); + runRepository.save(job.getRun()); + entityManager.flush(); + entityManager.refresh(jobArtifact); + return jobArtifactMapper.toDTO(jobArtifact); + } + + private void validate(JobArtifactCreateDTO reqDto, byte[] data) { + MessageDigest digest = null; + 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/JobEventMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventMapper.java similarity index 88% rename from src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventMapper.java rename to src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventMapper.java index 392b9e5..395774d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventMapper.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.service.job; +package org.fairdatatrain.trainhandler.service.job.event; import org.fairdatatrain.trainhandler.api.dto.job.JobEventCreateDTO; import org.fairdatatrain.trainhandler.api.dto.job.JobEventDTO; @@ -29,33 +29,31 @@ import org.springframework.stereotype.Component; import java.sql.Timestamp; -import java.time.Instant; 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()) - .type(jobEvent.getType()) .message(jobEvent.getMessage()) - .payload(jobEvent.getPayload()) .resultStatus(jobEvent.getResultStatus()) .createdAt(jobEvent.getCreatedAt().toInstant()) + .updatedAt(jobEvent.getUpdatedAt().toInstant()) .occurredAt(jobEvent.getOccurredAt().toInstant()) .build(); } public JobEvent fromCreateDTO(JobEventCreateDTO reqDto, Job job) { - final Timestamp now = Timestamp.from(Instant.now()); + final Timestamp now = now(); return JobEvent .builder() .uuid(UUID.randomUUID()) .message(reqDto.getMessage()) - .payload(reqDto.getPayload()) .resultStatus(reqDto.getResultStatus()) - .type(reqDto.getType()) .occurredAt(Timestamp.from(reqDto.getOccurredAt())) .job(job) .createdAt(now) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventService.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java similarity index 62% rename from src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventService.java rename to src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java index f99eec8..fbb370b 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobEventService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java @@ -20,28 +20,32 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.service.job; +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.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.async.JobEventNotificationListener; +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 java.util.List; -import java.util.Objects; -import java.util.UUID; +import java.util.*; @Service @RequiredArgsConstructor @@ -50,8 +54,12 @@ public class JobEventService { public static final String ENTITY_NAME = "JobEvent"; + private final RunRepository runRepository; + private final JobRepository jobRepository; + private final RunService runService; + private final JobService jobService; private final JobEventRepository jobEventRepository; @@ -60,8 +68,6 @@ public class JobEventService { private final AsyncEventPublisher asyncEventPublisher; - private final JobEventNotificationListener jobEventNotificationListener; - @PersistenceContext private final EntityManager entityManager; @@ -73,73 +79,82 @@ public JobEvent getByIdOrThrow(UUID uuid) throws NotFoundException { public List getEvents(UUID runUuid, UUID jobUuid) throws NotFoundException { final Job job = jobService.getByIdOrThrow(jobUuid); - /* - if (job.getRun().getUuid() != runUuid) { + if (!job.getRun().getUuid().equals(runUuid)) { throw new NotFoundException(JobService.ENTITY_NAME, jobUuid); - }*/ - return jobEventRepository - .findAllByJobOrderByOccurredAtAsc(job) - .parallelStream() - .map(jobEventMapper::toDTO) - .toList(); - } - - private List getEventsAfter( - UUID runUuid, UUID jobUuid, UUID afterEventUuid - ) throws NotFoundException { - if (afterEventUuid == null) { - return getEvents(runUuid, jobUuid); } - final JobEvent event = getByIdOrThrow(afterEventUuid); return jobEventRepository - .findAllByJobAndOccurredAtAfterOrderByOccurredAtAsc( - event.getJob(), event.getOccurredAt() - ) + .findAllByJobOrderByOccurredAtAsc(job) .parallelStream() .map(jobEventMapper::toDTO) .toList(); } - @Transactional - public List pollEvents( - UUID runUuid, UUID jobUuid, UUID afterEventUuid - ) throws NotFoundException, InterruptedException { - List events = getEventsAfter(runUuid, jobUuid, afterEventUuid); - if (events.isEmpty()) { - log.info("No events at this point"); - log.info("Starting to wait"); - jobEventNotificationListener.wait(jobUuid); - log.info("Finished to wait"); - entityManager.flush(); - events = getEventsAfter(runUuid, jobUuid, afterEventUuid); - } - return events; - } - @Transactional public JobEventDTO createEvent( UUID runUuid, UUID jobUuid, JobEventCreateDTO 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()); + job.getRun().setStatus(getNextRunStatus(job, reqDto)); jobRepository.save(job); } 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()); + + } final JobEvent jobEvent = jobEventRepository.save( jobEventMapper.fromCreateDTO(reqDto, job) ); + job.setVersion(jobEvent.getUpdatedAt().toInstant().toEpochMilli()); + jobRepository.save(job); + job.getRun().setVersion(job.getVersion()); + runRepository.save(job.getRun()); entityManager.flush(); entityManager.refresh(jobEvent); return jobEventMapper.toDTO(jobEvent); } - public void notify(UUID jobUuid) { - asyncEventPublisher.publishNewJobEventNotification(jobUuid); + @Transactional + public void notify(UUID jobUuid, UUID runUuid) throws NotFoundException { + final RunDTO run = runService.getSingle(runUuid); + final JobDTO job = jobService.getSingle(runUuid, jobUuid); + asyncEventPublisher.publishNewJobEventNotification(run, job); + } + + 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/run/RunDispatcher.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java new file mode 100644 index 0000000..e8770b4 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java @@ -0,0 +1,122 @@ +/** + * 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.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.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.HashSet; +import java.util.Optional; +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; + + @Async + @Transactional + public void dispatchNewRun(Run run) { + if (run.getShouldStartAt() != null || !run.getStatus().equals(RunStatus.PREPARED)) { + return; + } + dispatchRun(run); + } + + @Scheduled( + initialDelayString = "${dispatch.initDelay:PT1M}", + fixedRateString = "${dispatch.interval:PT1M}" + ) + public void dispatchScheduledRuns() { + log.info("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.info("Dispatched run: " + dispatchedRun); + } + else { + log.info("No more runs to be dispatched now"); + } + } + } + + @Transactional + public UUID tryDispatchRun() { + final Optional optionalRun = runRepository.findRunToDispatch(now()); + if (optionalRun.isEmpty()) { + return null; + } + final Run run = optionalRun.get(); + log.info("Run selected for dispatching: " + run.getUuid()); + dispatchRun(run); + return run.getUuid(); + } + + private void dispatchRun(Run run) { + run.setStartedAt(now()); + run.getJobs().forEach(this::dispatchJob); + run.setStatus(RunStatus.RUNNING); + runRepository.save(run); + } + + private void dispatchJob(Job job) { + job.setStartedAt(now()); + try { + dispatchService.dispatch(job); + job.setStatus(JobStatus.RUNNING); + } + catch (Exception ex) { + log.warn(format("Failed to dispatch job %s: %s", job.getUuid(), ex.getMessage())); + // TODO add event (?) + job.setStatus(JobStatus.ERRORED); + } + finally { + jobRepository.save(job); + } + } +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java index 452cb11..ad8192e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java @@ -23,6 +23,7 @@ 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; @@ -35,6 +36,7 @@ import org.springframework.stereotype.Component; import java.sql.Timestamp; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -74,13 +76,17 @@ public RunSimpleDTO toSimpleDTO(Run run) { } public RunDTO toDTO(Run run) { + final List jobs = run.getJobs().stream() + .map(jobMapper::toSimpleDTO) + .toList(); return RunDTO.builder() .uuid(run.getUuid()) .displayName(run.getDisplayName()) .note(run.getNote()) .status(run.getStatus()) .plan(planMapper.toSimpleDTO(run.getPlan())) - .jobs(run.getJobs().stream().map(jobMapper::toSimpleDTO).toList()) + .jobs(jobs) + .version(run.getVersion()) .shouldStartAt( Optional.ofNullable(run.getShouldStartAt()) .map(Timestamp::toInstant) @@ -100,11 +106,14 @@ public RunDTO toDTO(Run run) { 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(RunStatus.PREPARED) + .status(reqDto.getShouldStartAt() == null + ? RunStatus.PREPARED + : RunStatus.SCHEDULED) .plan(plan) .shouldStartAt( Optional.ofNullable(reqDto.getShouldStartAt()) @@ -114,14 +123,17 @@ public Run fromCreateDTO(RunCreateDTO reqDto, Plan plan) { .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 index 6368457..69b9d6f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java @@ -23,6 +23,7 @@ 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; @@ -33,23 +34,28 @@ 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 { - private static final String ENTITY_NAME = "Run"; + public static final String ENTITY_NAME = "Run"; private final RunRepository runRepository; @@ -61,6 +67,10 @@ public class RunService { private final JobRepository jobRepository; + private final RunDispatcher runDispatcher; + + private final RunNotificationListener runNotificationListener; + @PersistenceContext private final EntityManager entityManager; @@ -91,7 +101,8 @@ public RunDTO create(RunCreateDTO reqDto) throws NotFoundException { jobRepository.saveAll(jobs); entityManager.flush(); entityManager.refresh(newRun); - // TODO: schedule the run / dispatch it in async + newRun.getJobs().forEach(entityManager::refresh); + runDispatcher.dispatchNewRun(newRun); return runMapper.toDTO(newRun); } @@ -102,4 +113,20 @@ public RunDTO update(UUID uuid, RunUpdateDTO reqDto) throws NotFoundException { final Run updatedRun = runRepository.save(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/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/resources/application.yml b/src/main/resources/application.yml index f72548c..a33f9d4 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -11,6 +11,11 @@ spring: ddl-auto: validate dialect: org.hibernate.dialect.PostgreSQLDialect +dispatch: + initDelay: PT1M + interval: PT1M + root: http://localhost:8080 + springdoc: swagger-ui: disable-swagger-default-url: true 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.5__dev_data.sql b/src/main/resources/db/migration/V0003.5__dev_data.sql new file mode 100644 index 0000000..662afc6 --- /dev/null +++ b/src/main/resources/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/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/V0003.7__dev_data.sql b/src/main/resources/db/migration/V0003.7__dev_data.sql new file mode 100644 index 0000000..8e43df7 --- /dev/null +++ b/src/main/resources/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'; From aa435e14bac25dcea0a4bbf3d925800de89335e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 19:31:03 +0000 Subject: [PATCH 18/97] Bump spring-boot-starter-parent from 2.6.7 to 2.7.0 Bumps [spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 2.6.7 to 2.7.0. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.6.7...v2.7.0) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-parent dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f92ade7..f2f239e 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.6.7 + 2.7.0 From 378a06e6b0046e4a3cf575f97a0f73dad86cfba1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 May 2022 09:16:20 +0000 Subject: [PATCH 19/97] Bump postgresql from 42.3.4 to 42.3.6 Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.4 to 42.3.6. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.4...REL42.3.6) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f2f239e..23c8e6e 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.6.8 - 42.3.4 + 42.3.6 1.18.24 2.14.1 From 80f3043067c771b5a70fe36d31d1ff23688edf91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 May 2022 09:17:28 +0000 Subject: [PATCH 20/97] Bump spotbugs-maven-plugin from 4.6.0.0 to 4.7.0.0 Bumps [spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.6.0.0 to 4.7.0.0. - [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases) - [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.6.0.0...spotbugs-maven-plugin-4.7.0.0) --- updated-dependencies: - dependency-name: com.github.spotbugs:spotbugs-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 23c8e6e..844abad 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 4.1 3.1.2 - 4.6.0.0 + 4.7.0.0 5.0.0 From 536bd0d585fc0fd3a110b4db69d87bfee9cf1af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 26 May 2022 11:29:13 +0200 Subject: [PATCH 21/97] Improve polling and dispatch config --- README.md | 40 ++++++++++++++- pom.xml | 4 ++ .../api/controller/JobController.java | 5 +- .../api/controller/RunController.java | 5 +- .../trainhandler/config/DispatcherConfig.java | 47 ++++++++++++++++++ .../DispatchProperties.java} | 24 +++++---- .../config/properties/PollingProperties.java | 49 +++++++++++++++++++ .../async/JobNotificationListener.java | 6 +-- .../async/RunNotificationListener.java | 6 +-- .../service/run/RunDispatcher.java | 4 +- ...itional-spring-configuration-metadata.json | 24 +++++++++ src/main/resources/application.yml | 13 +++-- 12 files changed, 195 insertions(+), 32 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/config/DispatcherConfig.java rename src/main/java/org/fairdatatrain/trainhandler/config/{AsyncConfig.java => properties/DispatchProperties.java} (70%) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/config/properties/PollingProperties.java create mode 100644 src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/README.md b/README.md index 2319cea..afaaf65 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,47 @@ ## 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). + +*To be done: repository with docker-compose and configuration* ## 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/pom.xml b/pom.xml index 844abad..9f315cf 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,10 @@ org.springframework.boot spring-boot-starter-actuator + + org.springframework.boot + spring-boot-configuration-processor + org.flywaydb flyway-core diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java index db49348..087a573 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java @@ -25,6 +25,7 @@ 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; @@ -43,7 +44,7 @@ public class JobController { private final JobService jobService; - private final Long pollTimeout; + private final DispatcherConfig config; @GetMapping(path = "/{runUuid}/jobs", produces = MediaType.APPLICATION_JSON_VALUE) public Page getJobs(@PathVariable UUID runUuid, Pageable pageable) { @@ -61,7 +62,7 @@ public DeferredResult pollJob( ) throws NotFoundException { final JobDTO currentJob = jobService.getSingle(runUuid, jobUuid); final DeferredResult result = new DeferredResult<>( - pollTimeout, currentJob + config.getPolling().getTimeoutMs(), currentJob ); jobService.poll(jobUuid, result, after, currentJob); return result; diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java index 1c8fc88..310419f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java @@ -27,6 +27,7 @@ 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; @@ -49,7 +50,7 @@ public class RunController { private final AsyncEventPublisher asyncEventPublisher; - private final Long pollTimeout; + private final DispatcherConfig dispatcherConfig; @PostMapping( path = "", @@ -71,7 +72,7 @@ public DeferredResult pollRun( ) throws NotFoundException { final RunDTO currentRun = runService.getSingle(uuid); final DeferredResult result = new DeferredResult<>( - pollTimeout, currentRun + dispatcherConfig.getPolling().getTimeoutMs(), currentRun ); runService.poll(uuid, result, after, currentRun); return result; 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/AsyncConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/properties/DispatchProperties.java similarity index 70% rename from src/main/java/org/fairdatatrain/trainhandler/config/AsyncConfig.java rename to src/main/java/org/fairdatatrain/trainhandler/config/properties/DispatchProperties.java index b611e93..784f8d7 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/config/AsyncConfig.java +++ b/src/main/java/org/fairdatatrain/trainhandler/config/properties/DispatchProperties.java @@ -20,21 +20,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.fairdatatrain.trainhandler.config; +package org.fairdatatrain.trainhandler.config.properties; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; -@Configuration -public class AsyncConfig { +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class DispatchProperties { - // TODO: custom config properties - @Value("${poll.timeout:10000}") - private final Long pollTimeout = 10000L; + private String callbackRoot; - @Bean("pollTimeout") - public Long getPollTimeout() { - return pollTimeout; - } } 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/service/async/JobNotificationListener.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java index dbc1a5d..384cb2c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java @@ -26,12 +26,12 @@ 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.time.temporal.ChronoUnit; import java.util.*; import static java.lang.String.format; @@ -41,7 +41,7 @@ @RequiredArgsConstructor public class JobNotificationListener { - private final Long pollTimeout; + private final DispatcherConfig config; private final Map>> queues = new HashMap<>(); @@ -100,7 +100,7 @@ public void enqueue(UUID jobUuid, Long version, DeferredResult result) { queues.get(jobUuid).add( new PollContainer<>( version, - Instant.now().plus(pollTimeout, ChronoUnit.MILLIS), + config.getPolling().getTimeoutForCurrentPoll(), result ) ); diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java index 78206cf..30f962f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java @@ -26,12 +26,12 @@ 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.time.temporal.ChronoUnit; import java.util.*; import static java.lang.String.format; @@ -41,7 +41,7 @@ @RequiredArgsConstructor public class RunNotificationListener { - private final Long pollTimeout; + private final DispatcherConfig config; private final Map>> queues = new HashMap<>(); @@ -98,7 +98,7 @@ public void enqueue(UUID runUuid, Long version, DeferredResult result) { queues.get(runUuid).add( new PollContainer<>( version, - Instant.now().plus(pollTimeout, ChronoUnit.MILLIS), + config.getPolling().getTimeoutForCurrentPoll(), result ) ); diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java index e8770b4..6aa586d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java @@ -65,8 +65,8 @@ public void dispatchNewRun(Run run) { } @Scheduled( - initialDelayString = "${dispatch.initDelay:PT1M}", - fixedRateString = "${dispatch.interval:PT1M}" + initialDelayString = "${dispatcher.dispatch.initDelay:PT1M}", + fixedRateString = "${dispatcher.dispatch.interval:PT1M}" ) public void dispatchScheduledRuns() { log.info("Dispatching scheduled runs"); 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.yml b/src/main/resources/application.yml index a33f9d4..7537ccb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,11 @@ +dispatcher: + polling: + timeout: PT2M + dispatch: + root: http://localhost:8080 + initDelay: PT1M + interval: PT1M + spring: datasource: url: jdbc:postgresql://postgres/train-handler @@ -11,11 +19,6 @@ spring: ddl-auto: validate dialect: org.hibernate.dialect.PostgreSQLDialect -dispatch: - initDelay: PT1M - interval: PT1M - root: http://localhost:8080 - springdoc: swagger-ui: disable-swagger-default-url: true From 4a192ab612e1d0070ac5494ce1e89d6b0fe49a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 26 May 2022 12:19:35 +0200 Subject: [PATCH 22/97] Improve logging --- pom.xml | 10 +++ .../trainhandler/api/filter/CorsFilter.java | 1 + .../api/filter/LoggingFilter.java | 66 +++++++++++++++++++ .../service/async/AsyncEventPublisher.java | 20 +++--- .../async/JobNotificationListener.java | 37 ++++++++--- .../async/RunNotificationListener.java | 35 +++++++--- .../service/dispatch/DispatchService.java | 2 +- .../job/artifact/JobArtifactService.java | 2 +- src/main/resources/application.yml | 2 + .../{log4j-spring.xml => log4j2.xml} | 0 10 files changed, 144 insertions(+), 31 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/filter/LoggingFilter.java rename src/main/resources/{log4j-spring.xml => log4j2.xml} (100%) diff --git a/pom.xml b/pom.xml index 9f315cf..22da740 100644 --- a/pom.xml +++ b/pom.xml @@ -50,6 +50,16 @@ org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-log4j2 org.springframework.boot diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/filter/CorsFilter.java b/src/main/java/org/fairdatatrain/trainhandler/api/filter/CorsFilter.java index cac24b6..b55ed77 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/filter/CorsFilter.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/filter/CorsFilter.java @@ -68,6 +68,7 @@ public void doFilterInternal( 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); 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/service/async/AsyncEventPublisher.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java index 0e62955..1c958e0 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/AsyncEventPublisher.java @@ -39,22 +39,18 @@ 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() - ) - ); + 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() - ) - ); + 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/JobNotificationListener.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java index 384cb2c..6a28e4a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/JobNotificationListener.java @@ -48,6 +48,7 @@ public class JobNotificationListener { @EventListener public void handleJobEventNotification(JobNotification notification) { if (notification.getJob() != null) { + log.debug("Handling new job notification"); updateResults(notification.getJob()); } } @@ -55,12 +56,12 @@ public void handleJobEventNotification(JobNotification notification) { @Synchronized public void updateResults(JobDTO job) { log.info(format( - "Updating results for job '%s' (version '%s')", + "Updating results for job '%s' (version '%s'): start", job.getUuid(), job.getVersion() )); final Instant now = Instant.now(); if (queues.containsKey(job.getUuid())) { - final List> remainings = new ArrayList<>(); + final List> remaining = new ArrayList<>(); queues.get(job.getUuid()) .stream() .filter(container -> container.getTimeoutsAt().isAfter(now)) @@ -71,31 +72,45 @@ public void updateResults(JobDTO job) { container.getResult().setResult(job); } else { - remainings.add(container); + remaining.add(container); } }); - queues.put(job.getUuid(), remainings); + 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()) - ); + 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 { - final List> remainings = new ArrayList<>(); + log.debug("Cleaning up existing job queue"); + final List> remaining = new ArrayList<>(); queues.get(jobUuid).forEach(container -> { if (container.getTimeoutsAt().isAfter(now)) { - remainings.add(container); + remaining.add(container); } }); - queues.put(jobUuid, remainings); + 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<>( @@ -104,5 +119,9 @@ public void enqueue(UUID jobUuid, Long version, DeferredResult result) { 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/RunNotificationListener.java b/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java index 30f962f..427fbb5 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/async/RunNotificationListener.java @@ -47,6 +47,7 @@ public class RunNotificationListener { @EventListener public void handleJobEventNotification(JobNotification notification) { + log.debug("Handling new run notification"); updateResults(notification.getRun()); } @@ -58,7 +59,7 @@ public void updateResults(RunDTO run) { ); final Instant now = Instant.now(); if (queues.containsKey(run.getUuid())) { - final List> remainings = new ArrayList<>(); + final List> remaining = new ArrayList<>(); queues.get(run.getUuid()) .stream() .filter(container -> container.getTimeoutsAt().isAfter(now)) @@ -69,31 +70,45 @@ public void updateResults(RunDTO run) { container.getResult().setResult(run); } else { - remainings.add(container); + remaining.add(container); } }); - queues.put(run.getUuid(), remainings); + 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()) - ); + 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 { - final List> remainings = new ArrayList<>(); + log.debug("Cleaning up existing job queue"); + final List> remaining = new ArrayList<>(); queues.get(runUuid).forEach(container -> { if (container.getTimeoutsAt().isAfter(now)) { - remainings.add(container); + remaining.add(container); } }); - queues.put(runUuid, remainings); + 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<>( @@ -102,6 +117,10 @@ public void enqueue(UUID runUuid, Long version, DeferredResult result) { 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/DispatchService.java b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java index e40b731..33d461e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java @@ -60,7 +60,7 @@ public void dispatch(Job job) throws JsonProcessingException { final HttpEntity entity = new HttpEntity<>(payloadJson, headers); final ResponseEntity response = client.postForEntity(uri, entity, String.class); if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { - log.info(format( + log.warn(format( "Dispatching job %s failed: %s", job.getUuid(), response.getStatusCode() )); throw new RuntimeException( 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 index e2da313..0740aec 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactService.java @@ -140,7 +140,7 @@ else if (!Objects.equals(job.getRemoteId(), reqDto.getRemoteId())) { } private void validate(JobArtifactCreateDTO reqDto, byte[] data) { - MessageDigest digest = null; + final MessageDigest digest; try { digest = MessageDigest.getInstance("SHA-256"); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7537ccb..3867f92 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -7,6 +7,8 @@ dispatcher: interval: PT1M spring: + main: + banner-mode: off datasource: url: jdbc:postgresql://postgres/train-handler username: train-handler diff --git a/src/main/resources/log4j-spring.xml b/src/main/resources/log4j2.xml similarity index 100% rename from src/main/resources/log4j-spring.xml rename to src/main/resources/log4j2.xml From d14fd2af620c7e9bc4de79df6924516c0a3c24be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 19:12:18 +0000 Subject: [PATCH 23/97] Bump springdoc-openapi-ui from 1.6.8 to 1.6.9 Bumps [springdoc-openapi-ui](https://github.com/springdoc/springdoc-openapi) from 1.6.8 to 1.6.9. - [Release notes](https://github.com/springdoc/springdoc-openapi/releases) - [Changelog](https://github.com/springdoc/springdoc-openapi/blob/master/CHANGELOG.md) - [Commits](https://github.com/springdoc/springdoc-openapi/compare/v1.6.8...v1.6.9) --- updated-dependencies: - dependency-name: org.springdoc:springdoc-openapi-ui dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 22da740..8d5609c 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 17 - 1.6.8 + 1.6.9 42.3.6 1.18.24 2.14.1 From 63bc7c2cdec235ba182c8a8609baa312eccf5d22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 19:12:08 +0000 Subject: [PATCH 24/97] Bump checkstyle from 10.2 to 10.3 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.2 to 10.3. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.2...checkstyle-10.3) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8d5609c..ee90d51 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,7 @@ com.puppycrawl.tools checkstyle - 10.2 + 10.3 io.spring.javaformat From 52097227375b0c083005a96d4c678e52bc6dce1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 19:12:11 +0000 Subject: [PATCH 25/97] Bump spring-javaformat-checkstyle from 0.0.31 to 0.0.33 Bumps [spring-javaformat-checkstyle](https://github.com/spring-io/spring-javaformat) from 0.0.31 to 0.0.33. - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.31...v0.0.33) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ee90d51..31b70d6 100644 --- a/pom.xml +++ b/pom.xml @@ -183,7 +183,7 @@ io.spring.javaformat spring-javaformat-checkstyle - 0.0.31 + 0.0.33 From 2e8f3013aad7cda5b547a33f8ddc6531cbb644fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 6 Jun 2022 12:16:37 +0200 Subject: [PATCH 26/97] Add events on dispatch --- .gitignore | 3 + .../api/controller/JobArtifactController.java | 2 +- .../api/controller/JobEventController.java | 2 +- .../api/dto/job/JobEventCreateDTO.java | 6 +- .../data/repository/RunRepository.java | 16 ++-- .../service/job/event/JobEventService.java | 26 ++++--- .../service/run/RunDispatcher.java | 74 ++++++++++++------- .../trainhandler/service/run/RunService.java | 3 - src/main/resources/application.yml | 4 +- 9 files changed, 82 insertions(+), 54 deletions(-) diff --git a/.gitignore b/.gitignore index 549e00a..273ae66 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ build/ ### VS Code ### .vscode/ + +### Custom ### +logs/ diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java index 51e291b..9dacdc3 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java @@ -99,7 +99,7 @@ public JobArtifactDTO addJobArtifact( @RequestBody @Valid JobArtifactCreateDTO reqDto ) throws NotFoundException, JobSecurityException { final JobArtifactDTO dto = jobArtifactService.createArtifact(runUuid, jobUuid, reqDto); - jobEventService.notify(jobUuid, runUuid); + jobEventService.notify(jobUuid); return dto; } } diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java index 6e75ca5..272100e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java @@ -67,7 +67,7 @@ public JobEventDTO addJobEvent( @RequestBody @Valid JobEventCreateDTO reqDto ) throws NotFoundException, JobSecurityException { final JobEventDTO dto = jobEventService.createEvent(runUuid, jobUuid, reqDto); - jobEventService.notify(jobUuid, runUuid); + jobEventService.notify(jobUuid); return dto; } } 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 index c0bca5b..0b80f7e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventCreateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventCreateDTO.java @@ -22,10 +22,7 @@ */ package org.fairdatatrain.trainhandler.api.dto.job; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; import javax.validation.constraints.NotNull; @@ -35,6 +32,7 @@ @NoArgsConstructor @Getter @Setter +@Builder public class JobEventCreateDTO { private JobStatus resultStatus; diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java index 767c0c6..3047e4d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/RunRepository.java @@ -31,7 +31,6 @@ import org.springframework.stereotype.Repository; import java.sql.Timestamp; -import java.util.Optional; import java.util.UUID; @Repository @@ -42,10 +41,17 @@ public interface RunRepository extends BaseRepository { @Query(""" SELECT r FROM Run r - WHERE r.status = 'SCHEDULED' - AND r.shouldStartAt IS NOT NULL - AND r.shouldStartAt < :timestamp + 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 """) - Optional findRunToDispatch(@Param("timestamp") Timestamp timestamp); + Page findRunToDispatch(@Param("timestamp") Timestamp timestamp, Pageable pageable); } 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 index fbb370b..0e1bd73 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java @@ -30,6 +30,7 @@ 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; @@ -38,8 +39,9 @@ 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.RunService; +import org.fairdatatrain.trainhandler.service.run.RunMapper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -58,7 +60,9 @@ public class JobEventService { private final JobRepository jobRepository; - private final RunService runService; + private final JobMapper jobMapper; + + private final RunMapper runMapper; private final JobService jobService; @@ -94,7 +98,8 @@ public JobEventDTO createEvent( UUID runUuid, UUID jobUuid, JobEventCreateDTO reqDto ) throws NotFoundException, JobSecurityException { final Job job = jobService.getByIdOrThrow(jobUuid); - if (!job.getRun().getUuid().equals(runUuid)) { + final Run run = job.getRun(); + if (!run.getUuid().equals(runUuid)) { throw new NotFoundException(JobService.ENTITY_NAME, jobUuid); } if (!Objects.equals(job.getSecret(), reqDto.getSecret())) { @@ -102,15 +107,13 @@ public JobEventDTO createEvent( } if (job.getRemoteId() == null) { job.setRemoteId(reqDto.getRemoteId()); - job.getRun().setStatus(getNextRunStatus(job, reqDto)); - jobRepository.save(job); } 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()); - + run.setStatus(getNextRunStatus(job, reqDto)); } final JobEvent jobEvent = jobEventRepository.save( jobEventMapper.fromCreateDTO(reqDto, job) @@ -118,17 +121,18 @@ else if (!Objects.equals(job.getRemoteId(), reqDto.getRemoteId())) { job.setVersion(jobEvent.getUpdatedAt().toInstant().toEpochMilli()); jobRepository.save(job); job.getRun().setVersion(job.getVersion()); - runRepository.save(job.getRun()); + runRepository.save(run); entityManager.flush(); entityManager.refresh(jobEvent); return jobEventMapper.toDTO(jobEvent); } @Transactional - public void notify(UUID jobUuid, UUID runUuid) throws NotFoundException { - final RunDTO run = runService.getSingle(runUuid); - final JobDTO job = jobService.getSingle(runUuid, jobUuid); - asyncEventPublisher.publishNewJobEventNotification(run, job); + 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) { diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java index 6aa586d..03d84e3 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunDispatcher.java @@ -23,7 +23,9 @@ 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; @@ -31,13 +33,15 @@ import org.fairdatatrain.trainhandler.data.repository.JobRepository; import org.fairdatatrain.trainhandler.data.repository.RunRepository; import org.fairdatatrain.trainhandler.service.dispatch.DispatchService; -import org.springframework.scheduling.annotation.Async; +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.Optional; import java.util.Set; import java.util.UUID; @@ -55,21 +59,14 @@ public class RunDispatcher { private final RunRepository runRepository; - @Async - @Transactional - public void dispatchNewRun(Run run) { - if (run.getShouldStartAt() != null || !run.getStatus().equals(RunStatus.PREPARED)) { - return; - } - dispatchRun(run); - } + private final JobEventService jobEventService; @Scheduled( initialDelayString = "${dispatcher.dispatch.initDelay:PT1M}", fixedRateString = "${dispatcher.dispatch.interval:PT1M}" ) public void dispatchScheduledRuns() { - log.info("Dispatching scheduled runs"); + log.debug("Dispatching scheduled runs"); final Set dispatchedRuns = new HashSet<>(); boolean dispatching = true; while (dispatching) { @@ -77,46 +74,69 @@ public void dispatchScheduledRuns() { dispatching = dispatchedRun != null && !dispatchedRuns.contains(dispatchedRun); if (dispatching) { dispatchedRuns.add(dispatchedRun); - log.info("Dispatched run: " + dispatchedRun); + log.debug("Dispatched run: " + dispatchedRun); } else { - log.info("No more runs to be dispatched now"); + log.debug("No more runs to be dispatched now"); } } } - @Transactional public UUID tryDispatchRun() { - final Optional optionalRun = runRepository.findRunToDispatch(now()); - if (optionalRun.isEmpty()) { + final Page runs = runRepository.findRunToDispatch( + now(), + Pageable.ofSize(1).withPage(0) + ); + if (runs.isEmpty()) { return null; } - final Run run = optionalRun.get(); + final Run run = runs.getContent().get(0); log.info("Run selected for dispatching: " + run.getUuid()); dispatchRun(run); return run.getUuid(); } - private void dispatchRun(Run run) { + @Transactional + protected void dispatchRun(Run run) { run.setStartedAt(now()); - run.getJobs().forEach(this::dispatchJob); + 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)); } - private void dispatchJob(Job job) { - job.setStartedAt(now()); + @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); - job.setStatus(JobStatus.RUNNING); } catch (Exception ex) { log.warn(format("Failed to dispatch job %s: %s", job.getUuid(), ex.getMessage())); - // TODO add event (?) - job.setStatus(JobStatus.ERRORED); - } - finally { - jobRepository.save(job); + 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/RunService.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java index 69b9d6f..6226585 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java @@ -67,8 +67,6 @@ public class RunService { private final JobRepository jobRepository; - private final RunDispatcher runDispatcher; - private final RunNotificationListener runNotificationListener; @PersistenceContext @@ -102,7 +100,6 @@ public RunDTO create(RunCreateDTO reqDto) throws NotFoundException { entityManager.flush(); entityManager.refresh(newRun); newRun.getJobs().forEach(entityManager::refresh); - runDispatcher.dispatchNewRun(newRun); return runMapper.toDTO(newRun); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3867f92..27d6b25 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -3,8 +3,8 @@ dispatcher: timeout: PT2M dispatch: root: http://localhost:8080 - initDelay: PT1M - interval: PT1M + initDelay: PT30S + interval: PT30S spring: main: From c2a8773dde6fe87351dcfd962eabef7dda027c67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 19:25:59 +0000 Subject: [PATCH 27/97] Bump spring-boot-starter-parent from 2.7.0 to 2.7.1 Bumps [spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 2.7.0 to 2.7.1. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.7.0...v2.7.1) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-parent dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 31b70d6..7e91cf1 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.7.0 + 2.7.1 From fc866fc84ed93f0ce2ff3166ae765f937d4fb58b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 19:25:49 +0000 Subject: [PATCH 28/97] Bump checkstyle from 10.3 to 10.3.1 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.3 to 10.3.1. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.3...checkstyle-10.3.1) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7e91cf1..5d9c313 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,7 @@ com.puppycrawl.tools checkstyle - 10.3 + 10.3.1 io.spring.javaformat From 85a951a71d6dd2843e009a5a6ee6d35678fb3e32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 19:19:40 +0000 Subject: [PATCH 29/97] Bump postgresql from 42.3.6 to 42.4.0 Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.6 to 42.4.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.6...REL42.4.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5d9c313..151a52a 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.6.9 - 42.3.6 + 42.4.0 1.18.24 2.14.1 From 2a058ef3b59c8e5344ee1716231d4e1b9ccd63ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 19:25:53 +0000 Subject: [PATCH 30/97] Bump spring-javaformat-checkstyle from 0.0.33 to 0.0.34 Bumps [spring-javaformat-checkstyle](https://github.com/spring-io/spring-javaformat) from 0.0.33 to 0.0.34. - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.33...v0.0.34) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 151a52a..0178df7 100644 --- a/pom.xml +++ b/pom.xml @@ -183,7 +183,7 @@ io.spring.javaformat spring-javaformat-checkstyle - 0.0.33 + 0.0.34 From 4bb7c4e313469baa720858a8eabaf202877b80b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Jul 2022 19:30:00 +0000 Subject: [PATCH 31/97] Bump spring-boot-starter-parent from 2.7.1 to 2.7.2 Bumps [spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 2.7.1 to 2.7.2. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.7.1...v2.7.2) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-parent dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0178df7..54221b1 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.7.1 + 2.7.2 From 20f90033f718ab54968bb04f522fca902cfef9a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Jul 2022 19:29:50 +0000 Subject: [PATCH 32/97] Bump spotbugs-maven-plugin from 4.7.0.0 to 4.7.1.1 Bumps [spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.7.0.0 to 4.7.1.1. - [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases) - [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.7.0.0...spotbugs-maven-plugin-4.7.1.1) --- updated-dependencies: - dependency-name: com.github.spotbugs:spotbugs-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 54221b1..f2c6ca0 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 4.1 3.1.2 - 4.7.0.0 + 4.7.1.1 5.0.0 From 1a0d72fb54f22425d197ef837be730d5ea01e34c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 19:21:04 +0000 Subject: [PATCH 33/97] Bump checkstyle from 10.3.1 to 10.3.2 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.3.1 to 10.3.2. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.3.1...checkstyle-10.3.2) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f2c6ca0..f2feeca 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,7 @@ com.puppycrawl.tools checkstyle - 10.3.1 + 10.3.2 io.spring.javaformat From adf383f0b5210e6f4764122eab971adf38b4cbc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 1 Aug 2022 11:09:28 +0200 Subject: [PATCH 34/97] Add train/station soft delete --- .../api/controller/StationController.java | 19 ++++++++++ .../api/controller/TrainController.java | 19 ++++++++++ .../api/dto/station/StationDTO.java | 2 ++ .../api/dto/station/StationUpdateDTO.java | 36 +++++++++++++++++++ .../trainhandler/api/dto/train/TrainDTO.java | 2 ++ .../api/dto/train/TrainUpdateDTO.java | 36 +++++++++++++++++++ .../trainhandler/data/model/Station.java | 5 ++- .../trainhandler/data/model/Train.java | 5 ++- .../data/model/base/BaseEntity.java | 2 +- .../data/repository/StationRepository.java | 7 +++- .../data/repository/TrainRepository.java | 7 +++- .../service/station/StationMapper.java | 7 ++++ .../service/station/StationService.java | 24 +++++++++++-- .../service/train/TrainMapper.java | 7 ++++ .../service/train/TrainService.java | 23 ++++++++++-- 15 files changed, 190 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java index 98ea78a..31c028d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java @@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor; 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; @@ -34,6 +35,7 @@ import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; +import javax.validation.Valid; import java.util.List; import java.util.UUID; @@ -68,4 +70,21 @@ 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/TrainController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java index 0c1fbf5..cf7a312 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java @@ -27,6 +27,7 @@ import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; 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; @@ -34,6 +35,7 @@ import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; +import javax.validation.Valid; import java.util.List; import java.util.UUID; @@ -68,4 +70,21 @@ 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/dto/station/StationDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java index 47ba1ee..e3b2d33 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java @@ -52,6 +52,8 @@ public class StationDTO { private String metadata; + private Boolean softDeleted; + 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..3eae56a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java @@ -0,0 +1,36 @@ +/** + * 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.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class StationUpdateDTO { + + private Boolean softDeleted; + +} 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 index 0133ac8..ddcf3fa 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.java @@ -52,6 +52,8 @@ public class TrainDTO { private String metadata; + private Boolean softDeleted; + 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..8d44bbc --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java @@ -0,0 +1,36 @@ +/** + * 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.*; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainUpdateDTO { + + private Boolean softDeleted; + +} diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java index 63d8a57..b773322 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java @@ -42,7 +42,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -@SuperBuilder +@SuperBuilder(toBuilder = true) public class Station extends BaseEntity { @NotBlank @@ -66,6 +66,9 @@ public class Station extends BaseEntity { @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; diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java index 69dc0d7..43f0f65 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java @@ -42,7 +42,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -@SuperBuilder +@SuperBuilder(toBuilder = true) public class Train extends BaseEntity { @NotBlank @@ -66,6 +66,9 @@ public class Train extends BaseEntity { @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; 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 index 30e19aa..649c14a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/base/BaseEntity.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/base/BaseEntity.java @@ -37,7 +37,7 @@ import java.util.UUID; @MappedSuperclass -@SuperBuilder +@SuperBuilder(toBuilder = true) @Getter @Setter @AllArgsConstructor diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationRepository.java index 140d7da..2d26f3b 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/StationRepository.java @@ -35,12 +35,17 @@ @Repository public interface StationRepository extends BaseRepository { - Page findByTitleContainingIgnoreCase(String query, Pageable pageable); + 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/TrainRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainRepository.java index d263b6b..b9fac9a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainRepository.java @@ -35,12 +35,17 @@ @Repository public interface TrainRepository extends BaseRepository { - Page findByTitleContainingIgnoreCase(String query, Pageable pageable); + 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/service/station/StationMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java index 3f4c3d5..93c371e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java @@ -25,6 +25,7 @@ import lombok.RequiredArgsConstructor; 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.service.stationdirectory.StationDirectoryMapper; import org.fairdatatrain.trainhandler.service.traintype.TrainTypeMapper; @@ -76,4 +77,10 @@ public StationSimpleDTO toSimpleDTO(Station station) { .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) .build(); } + + public Station fromUpdateDTO(StationUpdateDTO dto, Station station) { + return station.toBuilder() + .softDeleted(dto.getSoftDeleted()) + .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 index 942d610..6baff2c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java @@ -25,6 +25,7 @@ import lombok.RequiredArgsConstructor; 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; @@ -61,10 +62,12 @@ public Station getByIdOrThrow(UUID uuid) throws NotFoundException { public Page getPaged(String query, Pageable pageable) { if (query.isBlank()) { - return stationRepository.findAll(pageable).map(stationMapper::toSimpleDTO); + return stationRepository + .findAllBySoftDeletedIsFalse(pageable) + .map(stationMapper::toSimpleDTO); } return stationRepository - .findByTitleContainingIgnoreCase(query, pageable) + .findByTitleContainingIgnoreCaseAndSoftDeletedIsFalse(query, pageable) .map(stationMapper::toSimpleDTO); } @@ -74,7 +77,9 @@ public StationDTO getSingle(UUID uuid) throws NotFoundException { } public List getAll(String query) { - return stationRepository.findByTitleContainingIgnoreCase(query).stream() + return stationRepository + .findByTitleContainingIgnoreCase(query) + .stream() .map(stationMapper::toSimpleDTO) .toList(); } @@ -85,4 +90,17 @@ public List getSuitableStations(UUID uuid) throws NotFoundExcept station.getTypes().stream().map(TrainType::getTrains).forEach(suitableTrains::addAll); return suitableTrains.stream().map(trainMapper::toSimpleDTO).toList(); } + + public StationDTO update(UUID uuid, StationUpdateDTO dto) throws NotFoundException { + final Station station = getByIdOrThrow(uuid); + final Station newStation = stationRepository + .save(stationMapper.fromUpdateDTO(dto, station)); + return stationMapper.toDTO(newStation); + } + + public StationDTO softDelete(UUID uuid) throws NotFoundException { + final Station station = getByIdOrThrow(uuid); + station.setSoftDeleted(true); + return stationMapper.toDTO(stationRepository.save(station)); + } } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java index 32a3b49..db9a693 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java @@ -25,6 +25,7 @@ import lombok.RequiredArgsConstructor; 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.service.traingarage.TrainGarageMapper; import org.fairdatatrain.trainhandler.service.traintype.TrainTypeMapper; @@ -76,4 +77,10 @@ public TrainSimpleDTO toSimpleDTO(Train train) { .types(train.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) .build(); } + + public Train fromUpdateDTO(TrainUpdateDTO dto, Train train) { + return train.toBuilder() + .softDeleted(dto.getSoftDeleted()) + .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 index face69a..d9352ca 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java @@ -26,6 +26,7 @@ import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; 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; @@ -61,10 +62,12 @@ public Train getByIdOrThrow(UUID uuid) throws NotFoundException { public Page getPaged(String query, Pageable pageable) { if (query.isBlank()) { - return trainRepository.findAll(pageable).map(trainMapper::toSimpleDTO); + return trainRepository + .findAllBySoftDeletedIsFalse(pageable) + .map(trainMapper::toSimpleDTO); } return trainRepository - .findByTitleContainingIgnoreCase(query, pageable) + .findByTitleContainingIgnoreCaseAndSoftDeletedIsFalse(query, pageable) .map(trainMapper::toSimpleDTO); } @@ -74,7 +77,9 @@ public TrainDTO getSingle(UUID uuid) throws NotFoundException { } public List getAll(String query) { - return trainRepository.findByTitleContainingIgnoreCase(query).stream() + return trainRepository + .findByTitleContainingIgnoreCase(query) + .stream() .map(trainMapper::toSimpleDTO) .toList(); } @@ -85,4 +90,16 @@ public List getSuitableStations(UUID uuid) throws NotFoundExce train.getTypes().stream().map(TrainType::getStations).forEach(suitableStations::addAll); return suitableStations.stream().map(stationMapper::toSimpleDTO).toList(); } + + public TrainDTO update(UUID uuid, TrainUpdateDTO dto) throws NotFoundException { + final Train train = getByIdOrThrow(uuid); + final Train newTrain = trainRepository.save(trainMapper.fromUpdateDTO(dto, train)); + return trainMapper.toDTO(newTrain); + } + + public TrainDTO softDelete(UUID uuid) throws NotFoundException { + final Train train = getByIdOrThrow(uuid); + train.setSoftDeleted(true); + return trainMapper.toDTO(trainRepository.save(train)); + } } From 394895607f521d7cf6b4d431f2d95f22acc21e48 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 6 Aug 2022 06:08:35 +0000 Subject: [PATCH 35/97] Bump postgresql from 42.4.0 to 42.4.1 Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.0 to 42.4.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.0...REL42.4.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f2feeca..32b7ec1 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.6.9 - 42.4.0 + 42.4.1 1.18.24 2.14.1 From e415713c4f578455a2be0c066864d66bcef80d4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 15:30:21 +0000 Subject: [PATCH 36/97] Bump springdoc-openapi-ui from 1.6.9 to 1.6.10 Bumps [springdoc-openapi-ui](https://github.com/springdoc/springdoc-openapi) from 1.6.9 to 1.6.10. - [Release notes](https://github.com/springdoc/springdoc-openapi/releases) - [Changelog](https://github.com/springdoc/springdoc-openapi/blob/master/CHANGELOG.md) - [Commits](https://github.com/springdoc/springdoc-openapi/compare/v1.6.9...v1.6.10) --- updated-dependencies: - dependency-name: org.springdoc:springdoc-openapi-ui dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 32b7ec1..7c3005f 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 17 - 1.6.9 + 1.6.10 42.4.1 1.18.24 2.14.1 From f1929bdf8fd90c6ee62f8c4a422ef9491299c61f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Aug 2022 19:17:09 +0000 Subject: [PATCH 37/97] Bump spring-boot-starter-parent from 2.7.2 to 2.7.3 Bumps [spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 2.7.2 to 2.7.3. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.7.2...v2.7.3) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-parent dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7c3005f..b8c7aef 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.7.2 + 2.7.3 From 78181d19487e386d03e81b57c5ca55f6a03e3c72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Aug 2022 19:17:04 +0000 Subject: [PATCH 38/97] Bump springdoc-openapi-ui from 1.6.10 to 1.6.11 Bumps [springdoc-openapi-ui](https://github.com/springdoc/springdoc-openapi) from 1.6.10 to 1.6.11. - [Release notes](https://github.com/springdoc/springdoc-openapi/releases) - [Changelog](https://github.com/springdoc/springdoc-openapi/blob/master/CHANGELOG.md) - [Commits](https://github.com/springdoc/springdoc-openapi/compare/v1.6.10...v1.6.11) --- updated-dependencies: - dependency-name: org.springdoc:springdoc-openapi-ui dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b8c7aef..f8ee307 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 17 - 1.6.10 + 1.6.11 42.4.1 1.18.24 2.14.1 From c45d5efdd9c1d644423825c6e966d5942f9fc98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sat, 24 Sep 2022 07:26:39 +0200 Subject: [PATCH 39/97] Update snakeyaml to 1.31 for security --- pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pom.xml b/pom.xml index f8ee307..3729999 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,10 @@ 3.1.2 4.7.1.1 5.0.0 + 0.2.0 + + + 1.31 From b4537d9b2f6e68d14d2b714402c3d219bf00f14a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Sep 2022 05:32:43 +0000 Subject: [PATCH 40/97] Bump maven-checkstyle-plugin from 3.1.2 to 3.2.0 Bumps [maven-checkstyle-plugin](https://github.com/apache/maven-checkstyle-plugin) from 3.1.2 to 3.2.0. - [Release notes](https://github.com/apache/maven-checkstyle-plugin/releases) - [Commits](https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.1.2...maven-checkstyle-plugin-3.2.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-checkstyle-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3729999..386bd70 100644 --- a/pom.xml +++ b/pom.xml @@ -41,7 +41,7 @@ 4.1 - 3.1.2 + 3.2.0 4.7.1.1 5.0.0 0.2.0 From 2e60cd9bb1b20fa0167336fd37a965bf1edf5649 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Sep 2022 05:32:34 +0000 Subject: [PATCH 41/97] Bump checkstyle from 10.3.2 to 10.3.3 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.3.2 to 10.3.3. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.3.2...checkstyle-10.3.3) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 386bd70..8752618 100644 --- a/pom.xml +++ b/pom.xml @@ -182,7 +182,7 @@ com.puppycrawl.tools checkstyle - 10.3.2 + 10.3.3 io.spring.javaformat From 9d1bdd21e60da1e93b1b5d2c9571aa3ce03a2eac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Sep 2022 05:32:17 +0000 Subject: [PATCH 42/97] Bump postgresql from 42.4.1 to 42.5.0 Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.1 to 42.5.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.1...REL42.5.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8752618..f890b84 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.6.11 - 42.4.1 + 42.5.0 1.18.24 2.14.1 From bad24ed66710edc04e9581cc86cf2639c56fc324 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Sep 2022 05:38:16 +0000 Subject: [PATCH 43/97] Bump spotbugs-maven-plugin from 4.7.1.1 to 4.7.2.0 Bumps [spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.7.1.1 to 4.7.2.0. - [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases) - [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.7.1.1...spotbugs-maven-plugin-4.7.2.0) --- updated-dependencies: - dependency-name: com.github.spotbugs:spotbugs-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f890b84..edb15f1 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 4.1 3.2.0 - 4.7.1.1 + 4.7.2.0 5.0.0 0.2.0 From a5a562b14642b5112ed35535e4f82f886ba5cddf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Sep 2022 05:40:16 +0000 Subject: [PATCH 44/97] Bump spring-boot-starter-parent from 2.7.3 to 2.7.4 Bumps [spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 2.7.3 to 2.7.4. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v2.7.3...v2.7.4) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-parent dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index edb15f1..dc20f48 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.7.3 + 2.7.4 From bde6570f537a74712346b6cd99ea7c071587ee88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 3 Oct 2022 12:02:18 +0200 Subject: [PATCH 45/97] Fix soft-delete missing db migration --- .../service/station/StationMapper.java | 1 + .../service/train/TrainMapper.java | 1 + .../db/migration/V0004.0__add-soft-delete.sql | 28 +++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 src/main/resources/db/migration/V0004.0__add-soft-delete.sql diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java index 93c371e..f91d994 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java @@ -54,6 +54,7 @@ public StationDTO toDTO(Station station) { .map(String::trim) .toList()) .status(station.getStatus()) + .softDeleted(station.getSoftDeleted()) .metadata(station.getMetadata()) .directory(stationDirectoryMapper.toSimpleDTO(station.getDirectory())) .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java index db9a693..04f9795 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java @@ -54,6 +54,7 @@ public TrainDTO toDTO(Train train) { .map(String::trim) .toList()) .status(train.getStatus()) + .softDeleted(train.getSoftDeleted()) .metadata(train.getMetadata()) .garage(trainGarageMapper.toSimpleDTO(train.getGarage())) .types(train.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) 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; From 15becb91cbe9b00d679719f434b786fc097c9bea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Sep 2022 19:17:19 +0000 Subject: [PATCH 46/97] Bump checkstyle from 10.3.3 to 10.3.4 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.3.3 to 10.3.4. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.3.3...checkstyle-10.3.4) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dc20f48..90d98f8 100644 --- a/pom.xml +++ b/pom.xml @@ -182,7 +182,7 @@ com.puppycrawl.tools checkstyle - 10.3.3 + 10.3.4 io.spring.javaformat From bf37acf6a188a70113a00918c3c3109d3da0b08f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 19:18:36 +0000 Subject: [PATCH 47/97] Bump springdoc-openapi-ui from 1.6.11 to 1.6.12 Bumps [springdoc-openapi-ui](https://github.com/springdoc/springdoc-openapi) from 1.6.11 to 1.6.12. - [Release notes](https://github.com/springdoc/springdoc-openapi/releases) - [Changelog](https://github.com/springdoc/springdoc-openapi/blob/master/CHANGELOG.md) - [Commits](https://github.com/springdoc/springdoc-openapi/compare/v1.6.11...v1.6.12) --- updated-dependencies: - dependency-name: org.springdoc:springdoc-openapi-ui dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 90d98f8..3fb395c 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 17 - 1.6.11 + 1.6.12 42.5.0 1.18.24 2.14.1 From c5ca2377f3d99a3c638485de5da4a631c0a3a026 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:38:00 +0000 Subject: [PATCH 48/97] Bump spotbugs-maven-plugin from 4.7.2.0 to 4.7.2.1 Bumps [spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.7.2.0 to 4.7.2.1. - [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases) - [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.7.2.0...spotbugs-maven-plugin-4.7.2.1) --- updated-dependencies: - dependency-name: com.github.spotbugs:spotbugs-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3fb395c..9036fff 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 4.1 3.2.0 - 4.7.2.0 + 4.7.2.1 5.0.0 0.2.0 From 891b021fc6060ffec44ab8e237f2dbd0412f782e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:37:53 +0000 Subject: [PATCH 49/97] Bump spring-javaformat-checkstyle from 0.0.34 to 0.0.35 Bumps [spring-javaformat-checkstyle](https://github.com/spring-io/spring-javaformat) from 0.0.34 to 0.0.35. - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.34...v0.0.35) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9036fff..838b0df 100644 --- a/pom.xml +++ b/pom.xml @@ -187,7 +187,7 @@ io.spring.javaformat spring-javaformat-checkstyle - 0.0.34 + 0.0.35 From ab4e4289c7f2edf2b3ae14aa858cf67c3a291a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 5 Jul 2022 11:17:14 +0200 Subject: [PATCH 50/97] Fetch trains and stations --- pom.xml | 57 ++++ .../StationDirectoryController.java | 6 + .../api/controller/TrainGarageController.java | 6 + .../trainhandler/config/HttpClientConfig.java | 36 +-- .../data/model/StationDirectory.java | 8 + .../trainhandler/data/model/TrainGarage.java | 8 + .../data/repository/TrainTypeRepository.java | 4 + .../service/dispatch/DispatchService.java | 28 +- .../service/indexing/BaseIndexer.java | 84 ++++++ .../StationDirectoryIndexer.java | 260 ++++++++++++++++++ .../StationDirectoryMapper.java | 1 + .../StationDirectoryService.java | 13 + .../traingarage/TrainGarageIndexer.java | 225 +++++++++++++++ .../traingarage/TrainGarageService.java | 17 +- .../trainhandler/utils/RdfIOUtils.java | 81 ++++++ .../trainhandler/utils/RdfUtils.java | 49 ++++ .../trainhandler/utils/ValueFactoryUtils.java | 91 ++++++ 17 files changed, 932 insertions(+), 42 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/indexing/BaseIndexer.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/utils/RdfIOUtils.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/utils/RdfUtils.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/utils/ValueFactoryUtils.java diff --git a/pom.xml b/pom.xml index 838b0df..2f88cc8 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,7 @@ 42.5.0 1.18.24 2.14.1 + 4.2.0 4.1 @@ -81,6 +82,11 @@ org.springframework.boot spring-boot-configuration-processor + + org.springframework.boot + spring-boot-starter-webflux + + org.flywaydb flyway-core @@ -108,6 +114,29 @@ spring-boot-starter-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} + @@ -216,6 +245,34 @@ 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 + + + + diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java index 38c18bf..f041422 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java @@ -78,4 +78,10 @@ public StationDirectoryDTO update( 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/TrainGarageController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java index e7598c8..49d9f4f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java @@ -78,4 +78,10 @@ public TrainGarageDTO update( 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/config/HttpClientConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/HttpClientConfig.java index 7ee6860..05c1e70 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/config/HttpClientConfig.java +++ b/src/main/java/org/fairdatatrain/trainhandler/config/HttpClientConfig.java @@ -22,44 +22,26 @@ */ package org.fairdatatrain.trainhandler.config; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.netty.http.client.HttpClient; -import java.net.http.HttpClient; import java.time.Duration; -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; - @Configuration public class HttpClientConfig { private static final long TIMEOUT = 5; @Bean - public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { - return restTemplateBuilder - .setConnectTimeout(Duration.ofSeconds(TIMEOUT)) - .setReadTimeout(Duration.ofSeconds(TIMEOUT)) - .build(); - } + public WebClient webClient() { + final HttpClient client = HttpClient.create() + .followRedirect(true) + .responseTimeout(Duration.ofSeconds(TIMEOUT)); - @Bean - public HttpClient httpClient() { - return HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .followRedirects(HttpClient.Redirect.ALWAYS) + return WebClient.builder() + .clientConnector(new ReactorClientHttpConnector(client)) .build(); } - - @Bean - public ObjectMapper objectMapper() { - final ObjectMapper mapper = new ObjectMapper(); - mapper.findAndRegisterModules(); - mapper.setSerializationInclusion(NON_NULL); - mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - return mapper; - } } diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java index af400b0..0c82b35 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java @@ -34,6 +34,7 @@ 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") @@ -71,4 +72,11 @@ public class StationDirectory extends BaseEntity { @OneToMany(fetch = FetchType.LAZY, mappedBy = "directory") private List stations; + + public List getStations() { + if (stations == null) { + stations = new ArrayList<>(); + } + return stations; + } } diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java index a3635ab..b60f2ca 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java @@ -34,6 +34,7 @@ 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") @@ -71,4 +72,11 @@ public class TrainGarage extends BaseEntity { @OneToMany(fetch = FetchType.LAZY, mappedBy = "garage") private List trains; + + public List getTrains() { + if (trains == null) { + trains = new ArrayList<>(); + } + return trains; + } } diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java index 9641abc..02fc929 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java @@ -28,8 +28,12 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface TrainTypeRepository extends BaseRepository { + List findAllBy(); + Page findByTitleContainingIgnoreCase(String query, Pageable pageable); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java index 33d461e..3f4335d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java @@ -23,14 +23,14 @@ package org.fairdatatrain.trainhandler.service.dispatch; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; 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.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientException; import static java.lang.String.format; @@ -41,9 +41,7 @@ public class DispatchService { private final DispatchMapper dispatchMapper; - private final RestTemplate client; - - private final ObjectMapper objectMapper; + private final WebClient webClient; public void dispatch(Job job) throws JsonProcessingException { if (!job.getStatus().equals(JobStatus.PREPARED)) { @@ -54,17 +52,21 @@ public void dispatch(Job job) throws JsonProcessingException { // 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)); - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - final String payloadJson = objectMapper.writeValueAsString(payload); - final HttpEntity entity = new HttpEntity<>(payloadJson, headers); - final ResponseEntity response = client.postForEntity(uri, entity, String.class); - if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { + try { + final String response = webClient + .post() + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(payload) + .retrieve() + .bodyToMono(String.class) + .block(); + } + catch (WebClientException exception) { log.warn(format( - "Dispatching job %s failed: %s", job.getUuid(), response.getStatusCode() + "Dispatching job %s failed: %s", job.getUuid(), exception.getMessage() )); throw new RuntimeException( - "Station responded with status: " + response.getStatusCode() + "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/stationdirectory/StationDirectoryIndexer.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java new file mode 100644 index 0000000..dc0cbd8 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java @@ -0,0 +1,260 @@ +/** + * 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.scheduling.annotation.Async; +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)); + } + + @Async + @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.findAllBy(); + + 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); + } + + private void updateDirectory(StationDirectory stationDirectory, Model model) { + stationDirectory.setMetadata(""); + stationDirectory.setLastContactAt(now()); + stationDirectory.setStatus(SyncServiceStatus.SYNCED); + stationDirectoryRepository.save(stationDirectory); + } + + private void updateFaultyDirectory(StationDirectory stationDirectory) { + stationDirectory.setStatus(SyncServiceStatus.UNREACHABLE); + stationDirectoryRepository.save(stationDirectory); + } + + private void updateStations(StationDirectory stationDirectory, List stations) { + 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); + } + }); + existingStations.forEach((uri, station) -> { + if (!currentStations.containsKey(uri)) { + deprecateStation(station); + } + }); + + stationRepository.saveAll(stationDirectory.getStations()); + } + + 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 List keywords = getObjectsBy(model, resource, DCAT.KEYWORD) + .stream() + .map(Value::stringValue) + .toList(); + + final Set interactionMechanisms = + getObjectsBy(model, resource, FDT.INTERACTIONMECHANISM) + .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)", 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)) + .metadata(write(model.filter(resource, null, null))) + .types(matchingTrainTypes) + .directory(stationDirectory) + .status(SyncItemStatus.SYNCED) + .lastContactAt(now()) + .createdAt(now()) + .updatedAt(now()) + .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 index 7f3299c..e730a77 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java @@ -73,6 +73,7 @@ public StationDirectory fromUpdateDTO( stationDirectory.setUri(reqDto.getUri()); stationDirectory.setDisplayName(reqDto.getDisplayName()); stationDirectory.setNote(reqDto.getNote()); + stationDirectory.setStatus(SyncServiceStatus.SYNCING); stationDirectory.setUpdatedAt(now); return stationDirectory; } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java index f30261e..6d5bcb4 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java @@ -26,6 +26,7 @@ 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; @@ -44,6 +45,8 @@ public class StationDirectoryService { private final StationDirectoryMapper stationDirectoryMapper; + private final StationDirectoryIndexer stationDirectoryIndexer; + private StationDirectory getByIdOrThrow(UUID uuid) throws NotFoundException { return stationDirectoryRepository .findById(uuid) @@ -73,6 +76,7 @@ public StationDirectoryDTO create(StationDirectoryChangeDTO reqDto) { // TODO: validate? final StationDirectory newStationDirectory = stationDirectoryRepository.save(stationDirectoryMapper.fromCreateDTO(reqDto)); + stationDirectoryIndexer.indexDirectory(newStationDirectory); return this.stationDirectoryMapper.toDTO(newStationDirectory); } @@ -83,6 +87,15 @@ public StationDirectoryDTO update(UUID uuid, StationDirectoryChangeDTO reqDto) final StationDirectory updatedStationDirectory = stationDirectoryRepository.save( stationDirectoryMapper.fromUpdateDTO(reqDto, stationDirectory)); + stationDirectoryIndexer.indexDirectory(updatedStationDirectory); return this.stationDirectoryMapper.toDTO(updatedStationDirectory); } + + public void reindex(UUID uuid) throws NotFoundException { + final StationDirectory stationDirectory = getByIdOrThrow(uuid); + stationDirectory.setStatus(SyncServiceStatus.SYNCING); + final StationDirectory updatedStationDirectory = + stationDirectoryRepository.save(stationDirectory); + stationDirectoryIndexer.indexDirectory(updatedStationDirectory); + } } 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..077182d --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java @@ -0,0 +1,225 @@ +/** + * 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.scheduling.annotation.Async; +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; + + @Async + @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.findAllBy(); + + 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("Skipping %s (exception: %s)", uri, exception)); + } + } + + updateTrains(trainGarage, trains); + } + + private void updateGarage(TrainGarage trainGarage, Model model) { + trainGarage.setMetadata(""); + trainGarage.setLastContactAt(now()); + trainGarage.setStatus(SyncServiceStatus.SYNCED); + trainGarageRepository.save(trainGarage); + } + + private void updateFaultyGarage(TrainGarage trainGarage) { + trainGarage.setStatus(SyncServiceStatus.UNREACHABLE); + trainGarageRepository.save(trainGarage); + } + + private void updateTrains(TrainGarage trainGarage, List trains) { + 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); + } + }); + existingTrains.forEach((uri, train) -> { + if (!currentTrains.containsKey(uri)) { + deprecateTrain(train); + } + }); + + trainRepository.saveAll(trainGarage.getTrains()); + } + + 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.filter(resource, null, null))) + .types(matchingTrainTypes) + .garage(trainGarage) + .status(SyncItemStatus.SYNCED) + .lastContactAt(now()) + .createdAt(now()) + .updatedAt(now()) + .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 index 0f053aa..a10342c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java @@ -26,6 +26,7 @@ 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; @@ -44,6 +45,8 @@ public class TrainGarageService { private final TrainGarageMapper trainGarageMapper; + private final TrainGarageIndexer trainGarageIndexer; + private TrainGarage getByIdOrThrow(UUID uuid) throws NotFoundException { return trainGarageRepository .findById(uuid) @@ -73,7 +76,8 @@ public TrainGarageDTO create(TrainGarageChangeDTO reqDto) { // TODO: validate? final TrainGarage newTrainGarage = trainGarageRepository.save(trainGarageMapper.fromCreateDTO(reqDto)); - return this.trainGarageMapper.toDTO(newTrainGarage); + trainGarageIndexer.indexGarage(newTrainGarage); + return trainGarageMapper.toDTO(newTrainGarage); } public TrainGarageDTO update(UUID uuid, TrainGarageChangeDTO reqDto) @@ -83,6 +87,15 @@ public TrainGarageDTO update(UUID uuid, TrainGarageChangeDTO reqDto) final TrainGarage updatedTrainGarage = trainGarageRepository.save( trainGarageMapper.fromUpdateDTO(reqDto, trainGarage)); - return this.trainGarageMapper.toDTO(updatedTrainGarage); + trainGarageIndexer.indexGarage(updatedTrainGarage); + return trainGarageMapper.toDTO(updatedTrainGarage); + } + + public void reindex(UUID uuid) throws NotFoundException { + final TrainGarage trainGarage = getByIdOrThrow(uuid); + trainGarage.setStatus(SyncServiceStatus.SYNCING); + final TrainGarage updatedTrainGarage = + trainGarageRepository.save(trainGarage); + trainGarageIndexer.indexGarage(updatedTrainGarage); } } 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/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); + } +} From 439af6cf9acb18333c58a916f4b361cc988ee6bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 24 Oct 2022 09:49:08 +0200 Subject: [PATCH 51/97] Add flag deletable for directories and garages --- .../api/dto/stationdirectory/StationDirectoryDTO.java | 2 ++ .../trainhandler/api/dto/traingarage/TrainGarageDTO.java | 2 ++ .../trainhandler/data/model/StationDirectory.java | 7 +++++++ .../fairdatatrain/trainhandler/data/model/TrainGarage.java | 7 +++++++ .../service/stationdirectory/StationDirectoryMapper.java | 1 + .../service/traingarage/TrainGarageMapper.java | 1 + 6 files changed, 20 insertions(+) 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 index 978bcaf..b36b440 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java @@ -47,6 +47,8 @@ public class StationDirectoryDTO { private SyncServiceStatus status; + private Boolean deletable; + private Instant lastContactAt; private Instant createdAt; 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 index e3df91a..edd6710 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java @@ -46,6 +46,8 @@ public class TrainGarageDTO { private SyncServiceStatus status; + private Boolean deletable; + private Instant lastContactAt; private Instant createdAt; diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java index 0c82b35..ef1b673 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/StationDirectory.java @@ -79,4 +79,11 @@ public List getStations() { } 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/TrainGarage.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java index b60f2ca..7073bc1 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/TrainGarage.java @@ -79,4 +79,11 @@ public List getTrains() { } return trains; } + + public Boolean isDeletable() { + if (getStatus().equals(SyncServiceStatus.SYNCING)) { + return false; + } + return getTrains().isEmpty(); + } } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java index e730a77..16170ce 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java @@ -42,6 +42,7 @@ public StationDirectoryDTO toDTO(StationDirectory stationDirectory) { .displayName(stationDirectory.getDisplayName()) .note(stationDirectory.getNote()) .status(stationDirectory.getStatus()) + .deletable(stationDirectory.isDeletable()) .lastContactAt( Optional.ofNullable(stationDirectory.getLastContactAt()) .map(Timestamp::toInstant) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java index 5389634..cc85c57 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java @@ -43,6 +43,7 @@ public TrainGarageDTO toDTO(TrainGarage trainGarage) { .note(trainGarage.getNote()) .metadata(trainGarage.getMetadata()) .status(trainGarage.getStatus()) + .deletable(trainGarage.isDeletable()) .lastContactAt( Optional.ofNullable(trainGarage.getLastContactAt()) .map(Timestamp::toInstant) From fe7f5e1c0a43a5e9634755ed5ad380439692ac48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 25 Oct 2022 07:44:29 +0200 Subject: [PATCH 52/97] Change default database configs --- .github/workflows/build.yml | 4 ++-- src/main/resources/application-dev.yml | 4 ++-- src/main/resources/application-test.yml | 4 ++-- src/main/resources/application.yml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d35393c..79e3683 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,8 +20,8 @@ jobs: ports: - 5432:5432 env: - POSTGRES_DB: train-handler-test - POSTGRES_USER: train-handler + POSTGRES_DB: train_handler_test + POSTGRES_USER: postgres POSTGRES_PASSWORD: password # Set health checks to wait until postgres has started options: >- diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 89a1cba..7195c54 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -1,5 +1,5 @@ spring: datasource: - url: jdbc:postgresql://localhost/train-handler - username: train-handler + url: jdbc:postgresql://localhost/train_handler + username: postgres password: password diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml index 604bf29..7ecff2a 100644 --- a/src/main/resources/application-test.yml +++ b/src/main/resources/application-test.yml @@ -1,5 +1,5 @@ spring: datasource: - url: jdbc:postgresql://localhost/train-handler-test - username: train-handler + url: jdbc:postgresql://localhost/train_handler_test + username: postgres password: password diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 27d6b25..a0d08cd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -10,8 +10,8 @@ spring: main: banner-mode: off datasource: - url: jdbc:postgresql://postgres/train-handler - username: train-handler + url: jdbc:postgresql://postgres/train_handler + username: postgres password: password flyway: locations: classpath:db/migration From 13bb2c083813af86f6e646ed6a8485a4234b055d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 25 Oct 2022 07:45:32 +0200 Subject: [PATCH 53/97] Fix missing content type for artifact --- .../fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.java | 2 ++ .../trainhandler/service/job/artifact/JobArtifactMapper.java | 1 + 2 files changed, 3 insertions(+) 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 index f1102f2..6020dc1 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.java @@ -42,6 +42,8 @@ public class JobArtifactDTO { private Long bytesize; + private String contentType; + private String hash; private Instant occurredAt; 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 index 6fe5965..115a926 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactMapper.java @@ -43,6 +43,7 @@ public JobArtifactDTO toDTO(JobArtifact artifact) { .displayName(artifact.getDisplayName()) .filename(artifact.getFilename()) .bytesize(artifact.getBytesize()) + .contentType(artifact.getContentType()) .hash(artifact.getHash()) .occurredAt(artifact.getOccurredAt().toInstant()) .createdAt(artifact.getCreatedAt().toInstant()) From 603b50f5a3e96a22bdf90649086643cb43678b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 25 Oct 2022 07:46:41 +0200 Subject: [PATCH 54/97] Fix timestamps mapping for jobs --- .../fairdatatrain/trainhandler/service/job/JobMapper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java index a541dc3..860361d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java @@ -72,7 +72,7 @@ public JobSimpleDTO toSimpleDTO(Job job) { .map(Timestamp::toInstant) .orElse(null)) .finishedAt( - Optional.ofNullable(job.getStartedAt()) + Optional.ofNullable(job.getFinishedAt()) .map(Timestamp::toInstant) .orElse(null)) .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) @@ -92,7 +92,7 @@ public JobDTO toDTO(Job job) { .map(Timestamp::toInstant) .orElse(null)) .finishedAt( - Optional.ofNullable(job.getStartedAt()) + Optional.ofNullable(job.getFinishedAt()) .map(Timestamp::toInstant) .orElse(null)) .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) @@ -113,7 +113,7 @@ public Job fromTarget(Run run, PlanTarget target) { .run(run) .secret(randomSecret()) .createdAt(run.getCreatedAt()) - .updatedAt(run.getCreatedAt()) + .updatedAt(run.getUpdatedAt()) .version(run.getVersion()) .build(); } From a28561521e8ec3f26bfa8d0efa20e50a0bd3daf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Fri, 28 Oct 2022 15:13:35 +0200 Subject: [PATCH 55/97] Fix DB migrations for dev and tests --- .../service/stationdirectory/StationDirectoryMapper.java | 1 + src/main/resources/application-dev.yml | 2 ++ src/main/resources/{ => dev}/db/migration/V0002.1__dev_data.sql | 0 src/main/resources/{ => dev}/db/migration/V0003.3__dev_data.sql | 0 src/main/resources/{ => dev}/db/migration/V0003.5__dev_data.sql | 0 src/main/resources/{ => dev}/db/migration/V0003.7__dev_data.sql | 0 6 files changed, 3 insertions(+) rename src/main/resources/{ => dev}/db/migration/V0002.1__dev_data.sql (100%) rename src/main/resources/{ => dev}/db/migration/V0003.3__dev_data.sql (100%) rename src/main/resources/{ => dev}/db/migration/V0003.5__dev_data.sql (100%) rename src/main/resources/{ => dev}/db/migration/V0003.7__dev_data.sql (100%) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java index 16170ce..64bcb35 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java @@ -40,6 +40,7 @@ public StationDirectoryDTO toDTO(StationDirectory stationDirectory) { .uuid(stationDirectory.getUuid()) .uri(stationDirectory.getUri()) .displayName(stationDirectory.getDisplayName()) + .metadata(stationDirectory.getMetadata()) .note(stationDirectory.getNote()) .status(stationDirectory.getStatus()) .deletable(stationDirectory.isDeletable()) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 7195c54..2c19bbf 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -3,3 +3,5 @@ spring: url: jdbc:postgresql://localhost/train_handler username: postgres password: password + flyway: + locations: classpath:db/migration,classpath:dev/db/migration diff --git a/src/main/resources/db/migration/V0002.1__dev_data.sql b/src/main/resources/dev/db/migration/V0002.1__dev_data.sql similarity index 100% rename from src/main/resources/db/migration/V0002.1__dev_data.sql rename to src/main/resources/dev/db/migration/V0002.1__dev_data.sql diff --git a/src/main/resources/db/migration/V0003.3__dev_data.sql b/src/main/resources/dev/db/migration/V0003.3__dev_data.sql similarity index 100% rename from src/main/resources/db/migration/V0003.3__dev_data.sql rename to src/main/resources/dev/db/migration/V0003.3__dev_data.sql diff --git a/src/main/resources/db/migration/V0003.5__dev_data.sql b/src/main/resources/dev/db/migration/V0003.5__dev_data.sql similarity index 100% rename from src/main/resources/db/migration/V0003.5__dev_data.sql rename to src/main/resources/dev/db/migration/V0003.5__dev_data.sql diff --git a/src/main/resources/db/migration/V0003.7__dev_data.sql b/src/main/resources/dev/db/migration/V0003.7__dev_data.sql similarity index 100% rename from src/main/resources/db/migration/V0003.7__dev_data.sql rename to src/main/resources/dev/db/migration/V0003.7__dev_data.sql From 7ba4e014b778346022e430eb1812c374502805c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 13 Nov 2022 12:54:26 +0100 Subject: [PATCH 56/97] Bump rdf4j from 4.2.0 to 4.2.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2f88cc8..ca3b9fe 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 42.5.0 1.18.24 2.14.1 - 4.2.0 + 4.2.1 4.1 From c3e80bb386f7afdd618c6b16cd99375306ee3275 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Oct 2022 19:18:57 +0000 Subject: [PATCH 57/97] Bump checkstyle from 10.3.4 to 10.4 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.3.4 to 10.4. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.3.4...checkstyle-10.4) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ca3b9fe..6db0872 100644 --- a/pom.xml +++ b/pom.xml @@ -211,7 +211,7 @@ com.puppycrawl.tools checkstyle - 10.3.4 + 10.4 io.spring.javaformat From c4383f27d95c8eb06d7997eebcb6e885f313b4e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Nov 2022 19:02:07 +0000 Subject: [PATCH 58/97] Bump spotbugs-maven-plugin from 4.7.2.1 to 4.7.2.2 Bumps [spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.7.2.1 to 4.7.2.2. - [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases) - [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.7.2.1...spotbugs-maven-plugin-4.7.2.2) --- updated-dependencies: - dependency-name: com.github.spotbugs:spotbugs-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6db0872..35137b6 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ 4.1 3.2.0 - 4.7.2.1 + 4.7.2.2 5.0.0 0.2.0 From 3063b9533d4b2251d3049f882964cff84e2bbdba Mon Sep 17 00:00:00 2001 From: Jan Slifka Date: Thu, 27 Oct 2022 09:02:07 +0200 Subject: [PATCH 59/97] Add keycloak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Slifka Co-authored-by: Marek Suchánek --- checkstyle.xml | 2 +- pom.xml | 36 ++++++++++- .../api/controller/JobArtifactController.java | 2 + .../api/controller/JobController.java | 2 + .../api/controller/JobEventController.java | 2 + .../api/controller/PlanController.java | 2 + .../api/controller/RunController.java | 2 + .../api/controller/StationController.java | 2 + .../StationDirectoryController.java | 2 + .../api/controller/TrainController.java | 2 + .../api/controller/TrainGarageController.java | 2 + .../api/controller/TrainTypeController.java | 2 + .../config/SecurityDisabledConfig.java | 46 +++++++++++++ .../config/SecurityKeycloakConfig.java | 64 +++++++++++++++++++ src/main/resources/application-dev.yml | 7 ++ src/main/resources/application-test.yml | 3 + 16 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/config/SecurityDisabledConfig.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/config/SecurityKeycloakConfig.java diff --git a/checkstyle.xml b/checkstyle.xml index 827a206..3bdffe8 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -189,7 +189,7 @@
- + diff --git a/pom.xml b/pom.xml index 35137b6..e735b98 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.7.4 + 2.7.5 @@ -39,6 +39,7 @@ 1.18.24 2.14.1 4.2.1 + 19.0.3 4.1 @@ -49,6 +50,7 @@ 1.31 + 5.7.5 @@ -86,6 +88,10 @@ org.springframework.boot spring-boot-starter-webflux + + org.springframework.boot + spring-boot-starter-security + org.flywaydb @@ -114,6 +120,11 @@ spring-boot-starter-test test + + org.springframework.security + spring-security-test + test + org.eclipse.rdf4j @@ -137,8 +148,31 @@ 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 diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java index 9dacdc3..9bb0d5a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java @@ -35,6 +35,7 @@ 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; @@ -44,6 +45,7 @@ import static java.lang.String.format; @Tag(name = "Runs") +@PreAuthorize("hasRole('user')") @RestController @RequestMapping("/runs") @RequiredArgsConstructor diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java index 087a573..6682ebb 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobController.java @@ -31,12 +31,14 @@ 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 diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java index 272100e..20a0654 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobEventController.java @@ -29,6 +29,7 @@ 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; @@ -36,6 +37,7 @@ import java.util.UUID; @Tag(name = "Runs") +@PreAuthorize("hasRole('user')") @RestController @RequestMapping("/runs") @RequiredArgsConstructor diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java index 9e1c606..c02b4d4 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java @@ -37,12 +37,14 @@ import org.springframework.data.domain.Pageable; 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 diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java index 310419f..a7c80d5 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/RunController.java @@ -34,6 +34,7 @@ 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; @@ -41,6 +42,7 @@ import java.util.UUID; @Tag(name = "Runs") +@PreAuthorize("hasRole('user')") @RestController @RequestMapping("/runs") @RequiredArgsConstructor diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java index 31c028d..65a28a8 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java @@ -33,6 +33,7 @@ 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 javax.validation.Valid; @@ -40,6 +41,7 @@ import java.util.UUID; @Tag(name = "Stations") +@PreAuthorize("hasRole('user')") @RestController @RequestMapping("/stations") @RequiredArgsConstructor diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java index f041422..dc3e9da 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java @@ -32,12 +32,14 @@ import org.springframework.data.domain.Pageable; 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 diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java index cf7a312..2c81f11 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java @@ -33,6 +33,7 @@ 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 javax.validation.Valid; @@ -40,6 +41,7 @@ import java.util.UUID; @Tag(name = "Trains") +@PreAuthorize("hasRole('user')") @RestController @RequestMapping("/trains") @RequiredArgsConstructor diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java index 49d9f4f..8b8507f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java @@ -32,12 +32,14 @@ import org.springframework.data.domain.Pageable; 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 diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java index c911eb6..e927ae7 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java @@ -32,12 +32,14 @@ import org.springframework.data.domain.Pageable; 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 Types") +@PreAuthorize("hasRole('user')") @RestController @RequestMapping("/train-types") @RequiredArgsConstructor 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..dc33c0a --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/config/SecurityKeycloakConfig.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.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.EnableGlobalMethodSecurity; +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) +@EnableGlobalMethodSecurity(prePostEnabled = true) +@Import(KeycloakSpringBootConfigResolver.class) +public class SecurityKeycloakConfig extends KeycloakWebSecurityConfigurerAdapter { + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + 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.authorizeRequests(); + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 2c19bbf..59a3e74 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -5,3 +5,10 @@ spring: password: password flyway: locations: classpath:db/migration,classpath:dev/db/migration + +keycloak: + realm: myrealm + auth-server-url: http://localhost:8000 + resource: myapi + public-client: true + bearer-only: true diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml index 7ecff2a..df22c71 100644 --- a/src/main/resources/application-test.yml +++ b/src/main/resources/application-test.yml @@ -3,3 +3,6 @@ spring: url: jdbc:postgresql://localhost/train_handler_test username: postgres password: password + +keycloak: + enabled: false From f1aef94372eb69a474ad8bdf934efec4ae92dde3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 13 Nov 2022 17:25:11 +0100 Subject: [PATCH 60/97] Fix communication and use ISO timestamps --- .../trainhandler/api/dto/job/JobArtifactDTO.java | 7 +++---- .../trainhandler/api/dto/job/JobDTO.java | 9 ++++----- .../trainhandler/api/dto/job/JobEventDTO.java | 7 +++---- .../trainhandler/api/dto/job/JobSimpleDTO.java | 5 ++--- .../trainhandler/api/dto/plan/PlanDTO.java | 5 ++--- .../trainhandler/api/dto/run/RunDTO.java | 11 +++++------ .../trainhandler/api/dto/run/RunSimpleDTO.java | 11 +++++------ .../trainhandler/api/dto/station/StationDTO.java | 7 +++---- .../dto/stationdirectory/StationDirectoryDTO.java | 7 +++---- .../trainhandler/api/dto/train/TrainDTO.java | 7 +++---- .../api/dto/traingarage/TrainGarageDTO.java | 8 ++++---- .../api/dto/traintype/TrainTypeDTO.java | 5 ++--- .../service/dispatch/DispatchMapper.java | 2 +- .../service/dispatch/DispatchService.java | 2 ++ .../trainhandler/service/job/JobMapper.java | 9 +++++++-- .../trainhandler/service/job/JobService.java | 6 ++++-- .../service/job/artifact/JobArtifactMapper.java | 6 +++--- .../service/job/event/JobEventMapper.java | 6 +++--- .../trainhandler/service/plan/PlanMapper.java | 4 ++-- .../trainhandler/service/run/RunMapper.java | 15 +++++++++++---- .../service/station/StationMapper.java | 6 +++--- .../stationdirectory/StationDirectoryMapper.java | 5 +++-- .../trainhandler/service/train/TrainMapper.java | 6 +++--- .../service/traingarage/TrainGarageMapper.java | 5 +++-- .../service/traintype/TrainTypeMapper.java | 4 ++-- src/main/resources/application-dev.yml | 5 +++++ 26 files changed, 91 insertions(+), 79 deletions(-) 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 index 6020dc1..4b9e7cd 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobArtifactDTO.java @@ -24,7 +24,6 @@ import lombok.*; -import java.time.Instant; import java.util.UUID; @AllArgsConstructor @@ -46,9 +45,9 @@ public class JobArtifactDTO { private String hash; - private Instant occurredAt; + private String occurredAt; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + 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 index 4001d1f..fb2577d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobDTO.java @@ -27,7 +27,6 @@ import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; -import java.time.Instant; import java.util.List; import java.util.UUID; @@ -44,9 +43,9 @@ public class JobDTO { private JobStatus status; - private Instant startedAt; + private String startedAt; - private Instant finishedAt; + private String finishedAt; private StationSimpleDTO target; @@ -56,9 +55,9 @@ public class JobDTO { private List artifacts; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + private String updatedAt; private Long version; } 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 index f50e206..451c13a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobEventDTO.java @@ -25,7 +25,6 @@ import lombok.*; import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; -import java.time.Instant; import java.util.UUID; @AllArgsConstructor @@ -41,9 +40,9 @@ public class JobEventDTO { private String message; - private Instant occurredAt; + private String occurredAt; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + 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 index 473d38c..3893b79 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobSimpleDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/job/JobSimpleDTO.java @@ -26,7 +26,6 @@ import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; -import java.time.Instant; import java.util.List; import java.util.UUID; @@ -43,9 +42,9 @@ public class JobSimpleDTO { private JobStatus status; - private Instant startedAt; + private String startedAt; - private Instant finishedAt; + private String finishedAt; private StationSimpleDTO target; 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 index fab3e68..08effde 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanDTO.java @@ -26,7 +26,6 @@ import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; import org.fairdatatrain.trainhandler.api.dto.train.TrainDTO; -import java.time.Instant; import java.util.List; import java.util.UUID; @@ -47,7 +46,7 @@ public class PlanDTO { private List targets; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + private String updatedAt; } 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 index 9e2c5bc..3c2b24c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunDTO.java @@ -27,7 +27,6 @@ import org.fairdatatrain.trainhandler.api.dto.plan.PlanSimpleDTO; import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; -import java.time.Instant; import java.util.List; import java.util.UUID; @@ -50,15 +49,15 @@ public class RunDTO { private List jobs; - private Instant shouldStartAt; + private String shouldStartAt; - private Instant startedAt; + private String startedAt; - private Instant finishedAt; + private String finishedAt; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + 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 index 0acadf2..ab47fd4 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunSimpleDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/run/RunSimpleDTO.java @@ -25,7 +25,6 @@ import lombok.*; import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; -import java.time.Instant; import java.util.UUID; @AllArgsConstructor @@ -47,13 +46,13 @@ public class RunSimpleDTO { private UUID planUuid; - private Instant shouldStartAt; + private String shouldStartAt; - private Instant startedAt; + private String startedAt; - private Instant finishedAt; + private String finishedAt; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + private String updatedAt; } 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 index e3b2d33..5420406 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java @@ -27,7 +27,6 @@ import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeSimpleDTO; import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; -import java.time.Instant; import java.util.List; import java.util.UUID; @@ -58,9 +57,9 @@ public class StationDTO { private List types; - private Instant lastContactAt; + private String lastContactAt; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + private String updatedAt; } 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 index b36b440..3d3d635 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/stationdirectory/StationDirectoryDTO.java @@ -25,7 +25,6 @@ import lombok.*; import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; -import java.time.Instant; import java.util.UUID; @NoArgsConstructor @@ -49,9 +48,9 @@ public class StationDirectoryDTO { private Boolean deletable; - private Instant lastContactAt; + private String lastContactAt; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + private String updatedAt; } 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 index ddcf3fa..828de4d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainDTO.java @@ -27,7 +27,6 @@ import org.fairdatatrain.trainhandler.api.dto.traintype.TrainTypeSimpleDTO; import org.fairdatatrain.trainhandler.data.model.enums.SyncItemStatus; -import java.time.Instant; import java.util.List; import java.util.UUID; @@ -58,9 +57,9 @@ public class TrainDTO { private List types; - private Instant lastContactAt; + private String lastContactAt; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + private String updatedAt; } 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 index edd6710..8f40aac 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traingarage/TrainGarageDTO.java @@ -21,10 +21,10 @@ * THE SOFTWARE. */ package org.fairdatatrain.trainhandler.api.dto.traingarage; + import lombok.*; import org.fairdatatrain.trainhandler.data.model.enums.SyncServiceStatus; -import java.time.Instant; import java.util.UUID; @NoArgsConstructor @@ -48,10 +48,10 @@ public class TrainGarageDTO { private Boolean deletable; - private Instant lastContactAt; + private String lastContactAt; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + private String updatedAt; } 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 index 20bc300..2040b62 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/traintype/TrainTypeDTO.java @@ -24,7 +24,6 @@ import lombok.*; -import java.time.Instant; import java.util.UUID; @AllArgsConstructor @@ -42,7 +41,7 @@ public class TrainTypeDTO { private String note; - private Instant createdAt; + private String createdAt; - private Instant updatedAt; + private String updatedAt; } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchMapper.java index 2435469..4dde076 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchMapper.java @@ -31,7 +31,7 @@ @Component public class DispatchMapper { - @Value("${dispatch.root}") + @Value("${dispatcher.dispatch.root}") private String dispatchRoot; public DispatchPayload toPayload(Job job) { diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java index 3f4335d..4cb146c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/dispatch/DispatchService.java @@ -55,6 +55,7 @@ public void dispatch(Job job) throws JsonProcessingException { try { final String response = webClient .post() + .uri(uri) .contentType(MediaType.APPLICATION_JSON) .bodyValue(payload) .retrieve() @@ -62,6 +63,7 @@ public void dispatch(Job job) throws JsonProcessingException { .block(); } catch (WebClientException exception) { + exception.printStackTrace(); log.warn(format( "Dispatching job %s failed: %s", job.getUuid(), exception.getMessage() )); diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java index 860361d..853bbf0 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java @@ -34,6 +34,7 @@ import org.springframework.stereotype.Component; import java.sql.Timestamp; +import java.time.Instant; import java.util.Optional; import java.util.UUID; @@ -70,10 +71,12 @@ public JobSimpleDTO toSimpleDTO(Job job) { .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().map(jobArtifactMapper::toDTO).toList()) @@ -90,17 +93,19 @@ public JobDTO toDTO(Job job) { .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().map(jobEventMapper::toDTO).toList()) .artifacts(job.getArtifacts().stream().map(jobArtifactMapper::toDTO).toList()) - .createdAt(job.getCreatedAt().toInstant()) - .updatedAt(job.getUpdatedAt().toInstant()) + .createdAt(job.getCreatedAt().toInstant().toString()) + .updatedAt(job.getUpdatedAt().toInstant().toString()) .version(job.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 index 4042042..61b0188 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java @@ -90,7 +90,9 @@ public void poll( if (version < currentJob.getVersion()) { result.setResult(currentJob); } - log.info("No job update at this point, enqueueing..."); - jobNotificationListener.enqueue(jobUuid, version, result); + 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 index 115a926..d291a6b 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactMapper.java @@ -45,9 +45,9 @@ public JobArtifactDTO toDTO(JobArtifact artifact) { .bytesize(artifact.getBytesize()) .contentType(artifact.getContentType()) .hash(artifact.getHash()) - .occurredAt(artifact.getOccurredAt().toInstant()) - .createdAt(artifact.getCreatedAt().toInstant()) - .updatedAt(artifact.getUpdatedAt().toInstant()) + .occurredAt(artifact.getOccurredAt().toInstant().toString()) + .createdAt(artifact.getCreatedAt().toInstant().toString()) + .updatedAt(artifact.getUpdatedAt().toInstant().toString()) .build(); } 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 index 395774d..9c4ff06 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventMapper.java @@ -41,9 +41,9 @@ public JobEventDTO toDTO(JobEvent jobEvent) { .uuid(jobEvent.getUuid()) .message(jobEvent.getMessage()) .resultStatus(jobEvent.getResultStatus()) - .createdAt(jobEvent.getCreatedAt().toInstant()) - .updatedAt(jobEvent.getUpdatedAt().toInstant()) - .occurredAt(jobEvent.getOccurredAt().toInstant()) + .createdAt(jobEvent.getCreatedAt().toInstant().toString()) + .updatedAt(jobEvent.getUpdatedAt().toInstant().toString()) + .occurredAt(jobEvent.getOccurredAt().toInstant().toString()) .build(); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java index d1b4921..a9da0d4 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java @@ -59,8 +59,8 @@ public PlanDTO toDTO(Plan plan) { .map(PlanTarget::getStation) .map(stationMapper::toSimpleDTO) .toList()) - .createdAt(plan.getCreatedAt().toInstant()) - .updatedAt(plan.getUpdatedAt().toInstant()) + .createdAt(plan.getCreatedAt().toInstant().toString()) + .updatedAt(plan.getUpdatedAt().toInstant().toString()) .build(); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java index ad8192e..dfd640e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java @@ -36,6 +36,7 @@ import org.springframework.stereotype.Component; import java.sql.Timestamp; +import java.time.Instant; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -61,17 +62,20 @@ public RunSimpleDTO toSimpleDTO(Run run) { .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()) - .updatedAt(run.getUpdatedAt().toInstant()) + .createdAt(run.getCreatedAt().toInstant().toString()) + .updatedAt(run.getUpdatedAt().toInstant().toString()) .build(); } @@ -90,17 +94,20 @@ public RunDTO toDTO(Run run) { .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()) - .updatedAt(run.getUpdatedAt().toInstant()) + .createdAt(run.getCreatedAt().toInstant().toString()) + .updatedAt(run.getUpdatedAt().toInstant().toString()) .build(); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java index f91d994..58967c1 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java @@ -58,9 +58,9 @@ public StationDTO toDTO(Station station) { .metadata(station.getMetadata()) .directory(stationDirectoryMapper.toSimpleDTO(station.getDirectory())) .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) - .lastContactAt(station.getLastContactAt().toInstant()) - .createdAt(station.getCreatedAt().toInstant()) - .updatedAt(station.getUpdatedAt().toInstant()) + .lastContactAt(station.getLastContactAt().toInstant().toString()) + .createdAt(station.getCreatedAt().toInstant().toString()) + .updatedAt(station.getUpdatedAt().toInstant().toString()) .build(); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java index 64bcb35..ffd532b 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryMapper.java @@ -47,9 +47,10 @@ public StationDirectoryDTO toDTO(StationDirectory stationDirectory) { .lastContactAt( Optional.ofNullable(stationDirectory.getLastContactAt()) .map(Timestamp::toInstant) + .map(Instant::toString) .orElse(null)) - .createdAt(stationDirectory.getCreatedAt().toInstant()) - .updatedAt(stationDirectory.getUpdatedAt().toInstant()) + .createdAt(stationDirectory.getCreatedAt().toInstant().toString()) + .updatedAt(stationDirectory.getUpdatedAt().toInstant().toString()) .build(); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java index 04f9795..acee33b 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java @@ -58,9 +58,9 @@ public TrainDTO toDTO(Train train) { .metadata(train.getMetadata()) .garage(trainGarageMapper.toSimpleDTO(train.getGarage())) .types(train.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) - .lastContactAt(train.getLastContactAt().toInstant()) - .createdAt(train.getCreatedAt().toInstant()) - .updatedAt(train.getUpdatedAt().toInstant()) + .lastContactAt(train.getLastContactAt().toInstant().toString()) + .createdAt(train.getCreatedAt().toInstant().toString()) + .updatedAt(train.getUpdatedAt().toInstant().toString()) .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 index cc85c57..80e1fd3 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageMapper.java @@ -47,9 +47,10 @@ public TrainGarageDTO toDTO(TrainGarage trainGarage) { .lastContactAt( Optional.ofNullable(trainGarage.getLastContactAt()) .map(Timestamp::toInstant) + .map(Instant::toString) .orElse(null)) - .createdAt(trainGarage.getCreatedAt().toInstant()) - .updatedAt(trainGarage.getCreatedAt().toInstant()) + .createdAt(trainGarage.getCreatedAt().toInstant().toString()) + .updatedAt(trainGarage.getCreatedAt().toInstant().toString()) .build(); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeMapper.java index ef57528..fc04153 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeMapper.java @@ -40,8 +40,8 @@ public TrainTypeDTO toDTO(TrainType trainType) { .title(trainType.getTitle()) .uri(trainType.getUri()) .note(trainType.getNote()) - .createdAt(trainType.getCreatedAt().toInstant()) - .updatedAt(trainType.getUpdatedAt().toInstant()) + .createdAt(trainType.getCreatedAt().toInstant().toString()) + .updatedAt(trainType.getUpdatedAt().toInstant().toString()) .build(); } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 59a3e74..754574f 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -7,8 +7,13 @@ spring: 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 From 9007c66d91f7d7948c7dab060c8efc8462137bcb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Nov 2022 19:02:34 +0000 Subject: [PATCH 61/97] Bump spotbugs-maven-plugin from 4.7.2.2 to 4.7.3.0 Bumps [spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.7.2.2 to 4.7.3.0. - [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases) - [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.7.2.2...spotbugs-maven-plugin-4.7.3.0) --- updated-dependencies: - dependency-name: com.github.spotbugs:spotbugs-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e735b98..8dc9348 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ 4.1 3.2.0 - 4.7.2.2 + 4.7.3.0 5.0.0 0.2.0 From 6a587c2994bd9a1e4989308f0151a83b82de52e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Nov 2022 22:21:17 +0000 Subject: [PATCH 62/97] Bump postgresql from 42.5.0 to 42.5.1 Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.5.0 to 42.5.1. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.5.0...REL42.5.1) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8dc9348..d3ed80c 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.6.12 - 42.5.0 + 42.5.1 1.18.24 2.14.1 4.2.1 From 55f662ee89e844565aa6dc175b25fca9804327cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sat, 26 Nov 2022 19:15:32 +0100 Subject: [PATCH 63/97] Fix finishedAt for jobs and runs --- .../org/fairdatatrain/trainhandler/data/model/Job.java | 6 ++++++ .../org/fairdatatrain/trainhandler/data/model/Run.java | 7 +++++++ .../trainhandler/service/job/event/JobEventService.java | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java index d6f4e62..112397e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Job.java @@ -79,4 +79,10 @@ public class Job extends BaseEntity { @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/Run.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java index e4599aa..0a73caa 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java @@ -28,6 +28,7 @@ import lombok.Setter; import lombok.experimental.SuperBuilder; import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; +import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; import javax.persistence.*; @@ -77,4 +78,10 @@ public class Run extends BaseEntity { @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/service/job/event/JobEventService.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java index 0e1bd73..8d57d78 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java @@ -47,6 +47,7 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import java.sql.Timestamp; import java.util.*; @Service @@ -113,7 +114,13 @@ else if (!Objects.equals(job.getRemoteId(), reqDto.getRemoteId())) { } 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.save( jobEventMapper.fromCreateDTO(reqDto, job) From 58d224b60718d441d56a9058c587736a02190473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 27 Nov 2022 14:35:26 +0100 Subject: [PATCH 64/97] Fix artifact and event ordering --- .../trainhandler/data/model/Run.java | 1 - .../trainhandler/service/job/JobMapper.java | 25 ++++++++++++++++--- .../trainhandler/service/job/JobService.java | 5 ---- .../trainhandler/service/run/RunMapper.java | 4 ++- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java index 0a73caa..75e856e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Run.java @@ -28,7 +28,6 @@ import lombok.Setter; import lombok.experimental.SuperBuilder; import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; -import org.fairdatatrain.trainhandler.data.model.enums.JobStatus; import org.fairdatatrain.trainhandler.data.model.enums.RunStatus; import javax.persistence.*; diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java index 853bbf0..a61b637 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobMapper.java @@ -35,6 +35,7 @@ import java.sql.Timestamp; import java.time.Instant; +import java.util.Comparator; import java.util.Optional; import java.util.UUID; @@ -79,7 +80,13 @@ public JobSimpleDTO toSimpleDTO(Job job) { .map(Instant::toString) .orElse(null)) .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) - .artifacts(job.getArtifacts().stream().map(jobArtifactMapper::toDTO).toList()) + .artifacts(job + .getArtifacts() + .stream() + .sorted(Comparator.comparing(JobArtifact::getOccurredAt)) + .map(jobArtifactMapper::toDTO) + .toList() + ) .runUuid(job.getRun().getUuid()) .version(job.getVersion()) .build(); @@ -102,8 +109,20 @@ public JobDTO toDTO(Job job) { .orElse(null)) .target(stationMapper.toSimpleDTO(job.getTarget().getStation())) .run(runMapper.toSimpleDTO(job.getRun())) - .events(job.getEvents().stream().map(jobEventMapper::toDTO).toList()) - .artifacts(job.getArtifacts().stream().map(jobArtifactMapper::toDTO).toList()) + .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()) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java index 61b0188..080b47e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/JobService.java @@ -36,8 +36,6 @@ 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.UUID; import static java.lang.String.format; @@ -55,9 +53,6 @@ public class JobService { private final JobNotificationListener jobNotificationListener; - @PersistenceContext - private final EntityManager entityManager; - public Job getByIdOrThrow(UUID uuid) throws NotFoundException { return jobRepository .findById(uuid) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java index dfd640e..126e509 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java @@ -80,7 +80,9 @@ public RunSimpleDTO toSimpleDTO(Run run) { } public RunDTO toDTO(Run run) { - final List jobs = run.getJobs().stream() + final List jobs = run + .getJobs() + .stream() .map(jobMapper::toSimpleDTO) .toList(); return RunDTO.builder() From 20179de70ed46d44b1f41279e8c44c18bee229ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 19:17:46 +0000 Subject: [PATCH 65/97] Bump rdf4j.version from 4.2.1 to 4.2.2 Bumps `rdf4j.version` from 4.2.1 to 4.2.2. Updates `rdf4j-runtime` from 4.2.1 to 4.2.2 Updates `rdf4j-rio-api` from 4.2.1 to 4.2.2 Updates `rdf4j-sail-nativerdf` from 4.2.1 to 4.2.2 --- updated-dependencies: - dependency-name: org.eclipse.rdf4j:rdf4j-runtime dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.eclipse.rdf4j:rdf4j-rio-api dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.eclipse.rdf4j:rdf4j-sail-nativerdf dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d3ed80c..782a54e 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 42.5.1 1.18.24 2.14.1 - 4.2.1 + 4.2.2 19.0.3 From 5e69a5a7f5535650c159021d3db1b459f6b4874b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 19:21:46 +0000 Subject: [PATCH 66/97] Bump checkstyle from 10.4 to 10.5.0 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.4 to 10.5.0. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.4...checkstyle-10.5.0) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 782a54e..4deae9c 100644 --- a/pom.xml +++ b/pom.xml @@ -245,7 +245,7 @@ com.puppycrawl.tools checkstyle - 10.4 + 10.5.0 io.spring.javaformat From d7a4f98cb239d98536be67836814b9988c459756 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 19:21:59 +0000 Subject: [PATCH 67/97] Bump springdoc-openapi-ui from 1.6.12 to 1.6.13 Bumps [springdoc-openapi-ui](https://github.com/springdoc/springdoc-openapi) from 1.6.12 to 1.6.13. - [Release notes](https://github.com/springdoc/springdoc-openapi/releases) - [Changelog](https://github.com/springdoc/springdoc-openapi/blob/master/CHANGELOG.md) - [Commits](https://github.com/springdoc/springdoc-openapi/compare/v1.6.12...v1.6.13) --- updated-dependencies: - dependency-name: org.springdoc:springdoc-openapi-ui dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4deae9c..8572239 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 17 - 1.6.12 + 1.6.13 42.5.1 1.18.24 2.14.1 From 04d451f15190327fe04782773b6a10c1efbe82fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 21 Dec 2022 16:01:08 +0100 Subject: [PATCH 68/97] Update Security deps and checks --- .github/workflows/security.yml | 4 ++-- pom.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 8d443bf..6d6e355 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -68,7 +68,7 @@ jobs: env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: - args: --severity-threshold=high + args: --severity-threshold=critical snyk-docker: name: Snyk (Docker) @@ -99,4 +99,4 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: image: fdp:snyk-test - args: --severity-threshold=high + args: --severity-threshold=critical diff --git a/pom.xml b/pom.xml index 8572239..b49adaf 100644 --- a/pom.xml +++ b/pom.xml @@ -49,8 +49,8 @@ 0.2.0 - 1.31 - 5.7.5 + 1.33 + 5.8.1 From 250149262dbdc52ad5ed1a2e679eb8b335854e28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Dec 2022 16:28:09 +0000 Subject: [PATCH 69/97] Bump keycloak.version from 19.0.3 to 20.0.2 Bumps `keycloak.version` from 19.0.3 to 20.0.2. Updates `keycloak-spring-boot-starter` from 19.0.3 to 20.0.2 Updates `keycloak-spring-security-adapter` from 19.0.3 to 20.0.2 Updates `keycloak-adapter-bom` from 19.0.3 to 20.0.2 --- updated-dependencies: - dependency-name: org.keycloak:keycloak-spring-boot-starter dependency-type: direct:production update-type: version-update:semver-major - dependency-name: org.keycloak:keycloak-spring-security-adapter dependency-type: direct:production update-type: version-update:semver-major - dependency-name: org.keycloak.bom:keycloak-adapter-bom dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b49adaf..15af817 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 1.18.24 2.14.1 4.2.2 - 19.0.3 + 20.0.2 4.1 From d77ee800f29eee9e929e82ec91f5e9fd5a3d1530 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Dec 2022 16:28:25 +0000 Subject: [PATCH 70/97] Bump springdoc-openapi-ui from 1.6.13 to 1.6.14 Bumps [springdoc-openapi-ui](https://github.com/springdoc/springdoc-openapi) from 1.6.13 to 1.6.14. - [Release notes](https://github.com/springdoc/springdoc-openapi/releases) - [Changelog](https://github.com/springdoc/springdoc-openapi/blob/master/CHANGELOG.md) - [Commits](https://github.com/springdoc/springdoc-openapi/compare/v1.6.13...v1.6.14) --- updated-dependencies: - dependency-name: org.springdoc:springdoc-openapi-ui dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 15af817..278bb13 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 17 - 1.6.13 + 1.6.14 42.5.1 1.18.24 2.14.1 From 34a2d766a7052bb88e9f65d4f0a001f3961f071d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 21 Dec 2022 16:01:08 +0100 Subject: [PATCH 71/97] Update Security deps and checks --- src/main/resources/application-dev.yml | 4 ++++ src/main/resources/application.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 754574f..0556729 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -17,3 +17,7 @@ keycloak: dispatcher: dispatch: root: http://localhost:8080 + +logging: + level: + com.zaxxer.hikari: TRACE diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a0d08cd..0bac4ea 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -13,6 +13,10 @@ spring: url: jdbc:postgresql://postgres/train_handler username: postgres password: password + hikari: + pool-name: PGHikariPool + max-pool-size: 10 + min-idle: 5 flyway: locations: classpath:db/migration jpa: From ab00b8d1e739a7800c4ac5d2c50f6f63812c7747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 21 Dec 2022 21:34:50 +0100 Subject: [PATCH 72/97] Use Docker buildx in CI --- .github/workflows/build.yml | 159 +++++++++++++++++++++--------------- Dockerfile | 4 +- 2 files changed, 93 insertions(+), 70 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79e3683..4018763 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: services: postgres: - image: postgres:13.6 + image: postgres:15.1 ports: - 5432:5432 env: @@ -56,87 +56,110 @@ jobs: mvn --quiet -B -U --fail-fast -DskipTests package docker: - needs: [test] - name: Docker Build & Push + name: Docker build runs-on: ubuntu-latest + needs: test env: PUBLIC_IMAGE: fairdata/trainhandler-server PRIVATE_IMAGE: ${{ secrets.PRIVATE_REGISTRY_URL }}/trainhandler-server - DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} PRIVATE_REGISTRY_URL: ${{ secrets.PRIVATE_REGISTRY_URL }} - TAG_DEVELOP: develop - TAG_LATEST: latest + DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} steps: - - name: Checkout repository + - name: Checkout repo uses: actions/checkout@v3 with: fetch-depth: 0 - - name: Docker build - run: | - docker pull $PUBLIC_IMAGE:$TAG_DEVELOP - docker build --cache-from $PUBLIC_IMAGE:$TAG_DEVELOP -t ${PRIVATE_IMAGE#/}:$GITHUB_SHA . + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 - - name: Docker login (private) - if: github.event_name == 'push' && env.PRIVATE_REGISTRY_URL != '' - run: | - docker login -u "$PRIVATE_REGISTRY_USERNAME" -p "$PRIVATE_REGISTRY_PASSWORD" "$PRIVATE_REGISTRY_URL" - env: - PRIVATE_REGISTRY_URL: ${{ secrets.PRIVATE_REGISTRY_URL }} - PRIVATE_REGISTRY_USERNAME: ${{ secrets.PRIVATE_REGISTRY_USERNAME }} - PRIVATE_REGISTRY_PASSWORD: ${{ secrets.PRIVATE_REGISTRY_PASSWORD }} + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2 - - name: Docker login (public) - if: github.event_name == 'push' && env.DOCKER_HUB_USERNAME != '' - run: | - docker login -u "$DOCKER_HUB_USERNAME" -p "$DOCKER_HUB_PASSWORD" - env: - DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} - DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} - - - name: Docker push - commit SHA (private) - if: github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/') && env.PRIVATE_REGISTRY_URL != '' - run: | - docker push $PRIVATE_IMAGE:$GITHUB_SHA + - name: Check available platforms + run: echo ${{ steps.buildx.outputs.platforms }} - - name: Docker tag and push - branch (private) - if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/') && !contains(github.ref, 'release') && env.PRIVATE_REGISTRY_URL != '' - run: | - GITHUB_BRANCH=`echo $GITHUB_REF | cut -d/ -f3- | sed 's#/#-#g'` - docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PRIVATE_IMAGE:$GITHUB_BRANCH - docker push $PRIVATE_IMAGE:$GITHUB_BRANCH - - - name: Docker tag and push - develop (public) - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' - run: | - docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PUBLIC_IMAGE:$TAG_DEVELOP - docker push $PUBLIC_IMAGE:$TAG_DEVELOP + - 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@v3 + 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 tag and push - latest (public) - if: github.event_name == 'push' && github.ref == 'refs/heads/master' - run: | - docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PUBLIC_IMAGE:$TAG_LATEST - docker push $PUBLIC_IMAGE:$TAG_LATEST + - 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@v3 + 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 tag and push - version tag (public) - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - run: | - GITHUB_TAG=`echo $GITHUB_REF | cut -d/ -f3` - # Release vX.Y.Z - if [[ $GITHUB_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - IMAGE_TAG_MAJOR="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v(.*)\..*\..*/\1/g"` - IMAGE_TAG_MINOR="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v(.*)\..*/\1/g"` - IMAGE_TAG_PATCH="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v//g"` - echo "Publishing release: $IMAGE_TAG_PATCH"; - docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_MAJOR && docker push $IMAGE_TAG_MAJOR; - docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_MINOR && docker push $IMAGE_TAG_MINOR; - docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_PATCH && docker push $IMAGE_TAG_PATCH; - fi - # Release candidate vX.Y.Z-rc.R - if [[ $GITHUB_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then - IMAGE_TAG_RC="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v//g"` - echo "Publishing release candidate: $IMAGE_TAG_RC"; - docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_RC && docker push $IMAGE_TAG_RC; - fi + - 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@v3 + 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/Dockerfile b/Dockerfile index 44d352f..b3614a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ # THE SOFTWARE. # -FROM maven:3-eclipse-temurin-17-alpine as builder +FROM maven:3-eclipse-temurin-17 as builder WORKDIR /builder @@ -31,7 +31,7 @@ RUN mvn --quiet -B -U --fail-fast -DskipTests package ################################################################################ # RUN STAGE -FROM eclipse-temurin:17-alpine +FROM eclipse-temurin:17 WORKDIR /app EXPOSE 8080 From 2b42116881fbc512fe34a4b0d318796cdde3e051 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Jan 2023 19:08:12 +0000 Subject: [PATCH 73/97] Bump checkstyle from 10.5.0 to 10.6.0 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.5.0 to 10.6.0. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.5.0...checkstyle-10.6.0) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 278bb13..e5f8acd 100644 --- a/pom.xml +++ b/pom.xml @@ -245,7 +245,7 @@ com.puppycrawl.tools checkstyle - 10.5.0 + 10.6.0 io.spring.javaformat From c5a040fdc3cf8d62f09e5367d26039b68af899aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sat, 7 Jan 2023 18:00:36 +0100 Subject: [PATCH 74/97] Fix indexing stations and trains --- .../StationDirectoryController.java | 12 ++++++++--- .../api/controller/TrainGarageController.java | 16 +++++++++----- .../data/repository/base/BaseRepository.java | 4 ++-- .../job/artifact/JobArtifactService.java | 6 +++--- .../service/job/event/JobEventService.java | 6 +++--- .../service/plan/PlanService.java | 10 +++++---- .../trainhandler/service/run/RunService.java | 5 +++-- .../service/station/StationService.java | 3 +++ .../StationDirectoryIndexer.java | 13 ++++++------ .../StationDirectoryService.java | 21 +++++++++++++------ .../service/train/TrainService.java | 8 +++++-- .../traingarage/TrainGarageIndexer.java | 11 +++++----- .../traingarage/TrainGarageService.java | 20 ++++++++++++------ .../service/traintype/TrainTypeService.java | 7 +++++-- 14 files changed, 93 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java index dc3e9da..2976056 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java @@ -59,8 +59,12 @@ public Page getPaged( consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(code = HttpStatus.CREATED) - public StationDirectoryDTO create(@Valid @RequestBody StationDirectoryChangeDTO reqDto) { - return stationDirectoryService.create(reqDto); + 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) @@ -72,7 +76,9 @@ public StationDirectoryDTO getSingle(@PathVariable UUID uuid) throws NotFoundExc public StationDirectoryDTO update( @PathVariable UUID uuid, @Valid @RequestBody StationDirectoryChangeDTO reqDto) throws NotFoundException { - return stationDirectoryService.update(uuid, reqDto); + final StationDirectoryDTO dto = stationDirectoryService.update(uuid, reqDto); + stationDirectoryService.reindex(dto.getUuid()); + return dto; } @DeleteMapping(path = "/{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 index 8b8507f..10f7000 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java @@ -59,8 +59,12 @@ public Page getPaged( consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(code = HttpStatus.CREATED) - public TrainGarageDTO create(@Valid @RequestBody TrainGarageChangeDTO reqDto) { - return trainGarageService.create(reqDto); + 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) @@ -70,9 +74,11 @@ public TrainGarageDTO getSingle(@PathVariable UUID uuid) throws NotFoundExceptio @PutMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) public TrainGarageDTO update( - @PathVariable UUID uuid, @Valid @RequestBody TrainGarageChangeDTO reqDto) - throws NotFoundException { - return trainGarageService.update(uuid, reqDto); + @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}") 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 index 66e06cd..ca78e8f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/repository/base/BaseRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/base/BaseRepository.java @@ -22,11 +22,11 @@ */ package org.fairdatatrain.trainhandler.data.repository.base; +import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.NoRepositoryBean; -import org.springframework.data.repository.PagingAndSortingRepository; import java.util.UUID; @NoRepositoryBean -public interface BaseRepository extends PagingAndSortingRepository { +public interface BaseRepository extends JpaRepository { } 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 index 0740aec..94fc96b 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/artifact/JobArtifactService.java @@ -127,13 +127,13 @@ else if (!Objects.equals(job.getRemoteId(), reqDto.getRemoteId())) { } final byte[] data = Base64.getDecoder().decode(reqDto.getBase64data()); validate(reqDto, data); - final JobArtifact jobArtifact = jobArtifactRepository.save( + final JobArtifact jobArtifact = jobArtifactRepository.saveAndFlush( jobArtifactMapper.fromCreateDTO(reqDto, job, data) ); job.setVersion(jobArtifact.getUpdatedAt().toInstant().toEpochMilli()); - jobRepository.save(job); + jobRepository.saveAndFlush(job); job.getRun().setVersion(job.getVersion()); - runRepository.save(job.getRun()); + runRepository.saveAndFlush(job.getRun()); entityManager.flush(); entityManager.refresh(jobArtifact); return jobArtifactMapper.toDTO(jobArtifact); 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 index 8d57d78..4555ce5 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/job/event/JobEventService.java @@ -122,13 +122,13 @@ else if (!Objects.equals(job.getRemoteId(), reqDto.getRemoteId())) { run.setFinishedAt(Timestamp.from(reqDto.getOccurredAt())); } } - final JobEvent jobEvent = jobEventRepository.save( + final JobEvent jobEvent = jobEventRepository.saveAndFlush( jobEventMapper.fromCreateDTO(reqDto, job) ); job.setVersion(jobEvent.getUpdatedAt().toInstant().toEpochMilli()); - jobRepository.save(job); + jobRepository.saveAndFlush(job); job.getRun().setVersion(job.getVersion()); - runRepository.save(run); + runRepository.saveAndFlush(run); entityManager.flush(); entityManager.refresh(jobEvent); return jobEventMapper.toDTO(jobEvent); diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java index b2028d3..f706bb6 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java @@ -96,7 +96,8 @@ public PlanDTO create(PlanCreateDTO reqDto) throws NotFoundException { for (UUID stationUuid : reqDto.getStationUuids()) { stations.add(stationService.getByIdOrThrow(stationUuid)); } - final Plan newPlan = planRepository.save(planMapper.fromCreateDTO(reqDto, train)); + final Plan newPlan = + planRepository.saveAndFlush(planMapper.fromCreateDTO(reqDto, train)); entityManager.flush(); entityManager.refresh(newPlan); final List targets = @@ -104,7 +105,7 @@ public PlanDTO create(PlanCreateDTO reqDto) throws NotFoundException { .map(station -> planTargetMapper.forPlan(newPlan, station)) .toList(); newPlan.setTargets(targets); - planTargetRepository.saveAll(targets); + planTargetRepository.saveAllAndFlush(targets); entityManager.flush(); entityManager.refresh(newPlan); return planMapper.toDTO(newPlan); @@ -151,7 +152,8 @@ public PlanDTO update(UUID uuid, PlanUpdateDTO reqDto) planTargetRepository.delete(target); } } - final Plan updatedPlan = planRepository.save(planMapper.fromUpdateDTO(reqDto, plan, train)); + final Plan updatedPlan = + planRepository.saveAndFlush(planMapper.fromUpdateDTO(reqDto, plan, train)); entityManager.flush(); entityManager.refresh(updatedPlan); final List targets = @@ -159,7 +161,7 @@ public PlanDTO update(UUID uuid, PlanUpdateDTO reqDto) .map(station -> planTargetMapper.forPlan(updatedPlan, station)) .toList(); updatedPlan.setTargets(targets); - planTargetRepository.saveAll(targets); + planTargetRepository.saveAllAndFlush(targets); entityManager.flush(); entityManager.refresh(updatedPlan); return planMapper.toDTO(updatedPlan); diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java index 6226585..4298e00 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunService.java @@ -96,7 +96,7 @@ public RunDTO create(RunCreateDTO reqDto) throws NotFoundException { final List jobs = plan.getTargets().stream() .map(target -> jobMapper.fromTarget(newRun, target)) .toList(); - jobRepository.saveAll(jobs); + jobRepository.saveAllAndFlush(jobs); entityManager.flush(); entityManager.refresh(newRun); newRun.getJobs().forEach(entityManager::refresh); @@ -107,7 +107,8 @@ public RunDTO create(RunCreateDTO reqDto) throws NotFoundException { public RunDTO update(UUID uuid, RunUpdateDTO reqDto) throws NotFoundException { // TODO: abort (?) final Run run = getByIdOrThrow(uuid); - final Run updatedRun = runRepository.save(runMapper.fromUpdateDTO(reqDto, run)); + final Run updatedRun = + runRepository.saveAndFlush(runMapper.fromUpdateDTO(reqDto, run)); return runMapper.toDTO(updatedRun); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java index 6baff2c..4dcdd53 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java @@ -36,6 +36,7 @@ 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; @@ -91,6 +92,7 @@ public List getSuitableStations(UUID uuid) throws NotFoundExcept return suitableTrains.stream().map(trainMapper::toSimpleDTO).toList(); } + @Transactional public StationDTO update(UUID uuid, StationUpdateDTO dto) throws NotFoundException { final Station station = getByIdOrThrow(uuid); final Station newStation = stationRepository @@ -98,6 +100,7 @@ public StationDTO update(UUID uuid, StationUpdateDTO dto) throws NotFoundExcepti return stationMapper.toDTO(newStation); } + @Transactional public StationDTO softDelete(UUID uuid) throws NotFoundException { final Station station = getByIdOrThrow(uuid); station.setSoftDeleted(true); diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java index dc0cbd8..2a5b94b 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java @@ -38,7 +38,6 @@ import org.fairdatatrain.trainhandler.data.repository.*; import org.fairdatatrain.trainhandler.service.indexing.BaseIndexer; import org.fairdatatrain.trainhandler.utils.ValueFactoryUtils; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -85,7 +84,6 @@ public class StationDirectoryIndexer { MECHANISM_TRAIN_TYPES.put(FDT.RESTAPI, List.of(FDT.RESTTRAIN)); } - @Async @Transactional public void indexDirectory(StationDirectory stationDirectory) { final Set visitedUris = new HashSet<>(); @@ -131,15 +129,16 @@ private void updateDirectory(StationDirectory stationDirectory, Model model) { stationDirectory.setMetadata(""); stationDirectory.setLastContactAt(now()); stationDirectory.setStatus(SyncServiceStatus.SYNCED); - stationDirectoryRepository.save(stationDirectory); + stationDirectoryRepository.saveAndFlush(stationDirectory); } private void updateFaultyDirectory(StationDirectory stationDirectory) { stationDirectory.setStatus(SyncServiceStatus.UNREACHABLE); - stationDirectoryRepository.save(stationDirectory); + stationDirectoryRepository.saveAndFlush(stationDirectory); } private void updateStations(StationDirectory stationDirectory, List stations) { + final List stationsToSave = new ArrayList<>(); final Map existingStations = stationDirectory .getStations() .stream() @@ -155,6 +154,7 @@ private void updateStations(StationDirectory stationDirectory, List sta else { station.setDirectory(stationDirectory); stationDirectory.getStations().add(station); + stationsToSave.add(station); } }); existingStations.forEach((uri, station) -> { @@ -163,7 +163,7 @@ private void updateStations(StationDirectory stationDirectory, List sta } }); - stationRepository.saveAll(stationDirectory.getStations()); + stationRepository.saveAllAndFlush(stationsToSave); } private void deprecateStation(Station existingStation) { @@ -209,7 +209,7 @@ private Station extractStation( .toList(); final Set interactionMechanisms = - getObjectsBy(model, resource, FDT.INTERACTIONMECHANISM) + getObjectsBy(model, resource, FDT.IMPLEMENTSINTERACTIONMECHANISM) .stream() .map(Value::stringValue) .map(ValueFactoryUtils::i) @@ -250,6 +250,7 @@ private Station extractStation( .lastContactAt(now()) .createdAt(now()) .updatedAt(now()) + .softDeleted(false) .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 index 6d5bcb4..100ba57 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryService.java @@ -31,7 +31,9 @@ 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; @@ -72,30 +74,37 @@ public StationDirectoryDTO getSingle(UUID uuid) throws NotFoundException { return stationDirectoryMapper.toDTO(stationDirectory); } + @Transactional public StationDirectoryDTO create(StationDirectoryChangeDTO reqDto) { // TODO: validate? final StationDirectory newStationDirectory = - stationDirectoryRepository.save(stationDirectoryMapper.fromCreateDTO(reqDto)); - stationDirectoryIndexer.indexDirectory(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.save( + stationDirectoryRepository.saveAndFlush( stationDirectoryMapper.fromUpdateDTO(reqDto, stationDirectory)); - stationDirectoryIndexer.indexDirectory(updatedStationDirectory); 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.save(stationDirectory); - stationDirectoryIndexer.indexDirectory(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/TrainService.java b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java index d9352ca..7a39070 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java @@ -36,6 +36,7 @@ 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; @@ -91,15 +92,18 @@ public List getSuitableStations(UUID uuid) throws NotFoundExce return suitableStations.stream().map(stationMapper::toSimpleDTO).toList(); } + @Transactional public TrainDTO update(UUID uuid, TrainUpdateDTO dto) throws NotFoundException { final Train train = getByIdOrThrow(uuid); - final Train newTrain = trainRepository.save(trainMapper.fromUpdateDTO(dto, train)); + final Train newTrain = + trainRepository.saveAndFlush(trainMapper.fromUpdateDTO(dto, train)); return trainMapper.toDTO(newTrain); } + @Transactional public TrainDTO softDelete(UUID uuid) throws NotFoundException { final Train train = getByIdOrThrow(uuid); train.setSoftDeleted(true); - return trainMapper.toDTO(trainRepository.save(train)); + return trainMapper.toDTO(trainRepository.saveAndFlush(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 index 077182d..19cb22f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java @@ -38,7 +38,6 @@ import org.fairdatatrain.trainhandler.data.repository.TrainRepository; import org.fairdatatrain.trainhandler.data.repository.TrainTypeRepository; import org.fairdatatrain.trainhandler.service.indexing.BaseIndexer; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -65,7 +64,6 @@ public class TrainGarageIndexer { private final BaseIndexer baseIndexer; - @Async @Transactional public void indexGarage(TrainGarage trainGarage) { final Set visitedUris = new HashSet<>(); @@ -110,15 +108,16 @@ private void updateGarage(TrainGarage trainGarage, Model model) { trainGarage.setMetadata(""); trainGarage.setLastContactAt(now()); trainGarage.setStatus(SyncServiceStatus.SYNCED); - trainGarageRepository.save(trainGarage); + trainGarageRepository.saveAndFlush(trainGarage); } private void updateFaultyGarage(TrainGarage trainGarage) { trainGarage.setStatus(SyncServiceStatus.UNREACHABLE); - trainGarageRepository.save(trainGarage); + trainGarageRepository.saveAndFlush(trainGarage); } private void updateTrains(TrainGarage trainGarage, List trains) { + final List trainsToSave = new ArrayList<>(); final Map existingTrains = trainGarage .getTrains() .stream() @@ -134,6 +133,7 @@ private void updateTrains(TrainGarage trainGarage, List trains) { else { train.setGarage(trainGarage); trainGarage.getTrains().add(train); + trainsToSave.add(train); } }); existingTrains.forEach((uri, train) -> { @@ -142,7 +142,7 @@ private void updateTrains(TrainGarage trainGarage, List trains) { } }); - trainRepository.saveAll(trainGarage.getTrains()); + trainRepository.saveAllAndFlush(trainsToSave); } private void deprecateTrain(Train existingTrain) { @@ -220,6 +220,7 @@ private Train extractTrain( .lastContactAt(now()) .createdAt(now()) .updatedAt(now()) + .softDeleted(false) .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 index a10342c..9349e96 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageService.java @@ -31,7 +31,9 @@ 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; @@ -72,30 +74,36 @@ public TrainGarageDTO getSingle(UUID uuid) throws NotFoundException { return trainGarageMapper.toDTO(trainGarage); } + @Transactional public TrainGarageDTO create(TrainGarageChangeDTO reqDto) { // TODO: validate? final TrainGarage newTrainGarage = - trainGarageRepository.save(trainGarageMapper.fromCreateDTO(reqDto)); - trainGarageIndexer.indexGarage(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.save( + trainGarageRepository.saveAndFlush( trainGarageMapper.fromUpdateDTO(reqDto, trainGarage)); - trainGarageIndexer.indexGarage(updatedTrainGarage); 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.save(trainGarage); - trainGarageIndexer.indexGarage(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/TrainTypeService.java b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java index a321c0a..ee86d22 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java @@ -31,6 +31,7 @@ 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.UUID; @@ -69,18 +70,20 @@ public TrainTypeDTO getSingle(UUID uuid) throws NotFoundException { return trainTypeMapper.toDTO(trainType); } + @Transactional public TrainTypeDTO create(TrainTypeChangeDTO reqDto) { // TODO: validate? final TrainType newTrainType = - trainTypeRepository.save(trainTypeMapper.fromCreateDTO(reqDto)); + 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.save(trainTypeMapper.fromUpdateDTO(reqDto, trainType)); + trainTypeRepository.saveAndFlush(trainTypeMapper.fromUpdateDTO(reqDto, trainType)); return trainTypeMapper.toDTO(updatedTrainType); } } From 201bd8bcd29ea54c59531049c59a41c9143eb0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 9 Jan 2023 11:34:19 +0100 Subject: [PATCH 75/97] Add default train types to DB --- .../V0005.0__default-train-types.sql | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/main/resources/db/migration/V0005.0__default-train-types.sql 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'); + From 34796679b6f1301c7cda9a148a106ac9746da64e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jan 2023 19:02:23 +0000 Subject: [PATCH 76/97] Bump maven-checkstyle-plugin from 3.2.0 to 3.2.1 Bumps [maven-checkstyle-plugin](https://github.com/apache/maven-checkstyle-plugin) from 3.2.0 to 3.2.1. - [Release notes](https://github.com/apache/maven-checkstyle-plugin/releases) - [Commits](https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.2.0...maven-checkstyle-plugin-3.2.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-checkstyle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e5f8acd..b9f55bf 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ 4.1 - 3.2.0 + 3.2.1 4.7.3.0 5.0.0 0.2.0 From 88bf2e188c645dc1f3400f51337e5584dc0ac420 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jan 2023 19:02:17 +0000 Subject: [PATCH 77/97] Bump keycloak.version from 20.0.2 to 20.0.3 Bumps `keycloak.version` from 20.0.2 to 20.0.3. Updates `keycloak-spring-boot-starter` from 20.0.2 to 20.0.3 Updates `keycloak-spring-security-adapter` from 20.0.2 to 20.0.3 Updates `keycloak-adapter-bom` from 20.0.2 to 20.0.3 --- updated-dependencies: - dependency-name: org.keycloak:keycloak-spring-boot-starter dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.keycloak:keycloak-spring-security-adapter dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.keycloak.bom:keycloak-adapter-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b9f55bf..1099a18 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 1.18.24 2.14.1 4.2.2 - 20.0.2 + 20.0.3 4.1 From 736058dd912bd110fb6de7edf0fe8b5a001a560f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 2 Feb 2023 20:29:00 +0100 Subject: [PATCH 78/97] Support envvars for configuration --- src/main/resources/application.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0bac4ea..d3e5126 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,18 +1,18 @@ dispatcher: polling: - timeout: PT2M + timeout: ${FDT_POLLING_TIMEOUT:PT2M} dispatch: - root: http://localhost:8080 - initDelay: PT30S - interval: PT30S + 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://postgres/train_handler - username: postgres - password: password + 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 @@ -25,6 +25,14 @@ spring: 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 From ac4df231485c2a2b803c3798dd5d1c574bac7423 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Jan 2023 19:04:01 +0000 Subject: [PATCH 79/97] Bump docker/build-push-action from 3 to 4 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v3...v4) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4018763..016b37f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,7 +91,7 @@ jobs: tags: | type=sha - name: Docker build+push [test] - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . file: ./Dockerfile @@ -121,7 +121,7 @@ jobs: type=semver,pattern={{version}} - name: Docker build+push [private] - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 if: github.event_name == 'push' && env.PRIVATE_REGISTRY_URL != '' && steps.meta-private.outputs.tags != '' with: context: . @@ -154,7 +154,7 @@ jobs: type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }} - name: Docker build+push [public] - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 if: github.event_name == 'push' && env.DOCKER_HUB_USERNAME != '' && steps.meta-public.outputs.tags != '' with: context: . From bc2c60ba07285bd0563d57a223980ff169eaea93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Fri, 3 Feb 2023 21:27:43 +0100 Subject: [PATCH 80/97] Allow to create and edit stations/trains --- .../api/controller/StationController.java | 12 +++++ .../api/controller/TrainController.java | 12 +++++ .../api/dto/station/StationCreateDTO.java | 50 +++++++++++++++++++ .../api/dto/station/StationUpdateDTO.java | 17 +++++++ .../api/dto/train/TrainCreateDTO.java | 50 +++++++++++++++++++ .../api/dto/train/TrainUpdateDTO.java | 17 +++++++ .../trainhandler/data/model/Station.java | 1 - .../trainhandler/data/model/Train.java | 1 - .../service/station/StationMapper.java | 45 ++++++++++++++++- .../service/station/StationService.java | 41 ++++++++++++--- .../StationDirectoryIndexer.java | 15 ++++++ .../service/train/TrainMapper.java | 45 ++++++++++++++++- .../service/train/TrainService.java | 37 +++++++++++++- .../traingarage/TrainGarageIndexer.java | 17 ++++++- .../service/traintype/TrainTypeService.java | 18 ++++++- 15 files changed, 364 insertions(+), 14 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationCreateDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainCreateDTO.java diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java index 65a28a8..6b44525 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java @@ -24,6 +24,7 @@ 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; @@ -62,6 +63,17 @@ public List getPaged( return stationService.getAll(query); } + @PutMapping( + 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); diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java index 2c81f11..b72a3b4 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java @@ -25,6 +25,7 @@ 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; @@ -62,6 +63,17 @@ public List getPaged( 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); 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..aece874 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationCreateDTO.java @@ -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. + */ +package org.fairdatatrain.trainhandler.api.dto.station; + +import lombok.*; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class StationCreateDTO { + + private String uri; + + private String title; + + private String description; + + private List keywords; + + private String metadata; + + private List trainTypeUuids; + + private Boolean fetch = false; +} 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 index 3eae56a..551d790 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java @@ -24,6 +24,9 @@ import lombok.*; +import java.util.List; +import java.util.UUID; + @AllArgsConstructor @NoArgsConstructor @Getter @@ -31,6 +34,20 @@ @Builder(toBuilder = true) public class StationUpdateDTO { + private String uri; + + private String title; + + private String description; + + private List keywords; + + private String metadata; + + private List trainTypeUuids; + private Boolean softDeleted; + private Boolean fetch = false; + } 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..4713ada --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainCreateDTO.java @@ -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. + */ +package org.fairdatatrain.trainhandler.api.dto.train; + +import lombok.*; + +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class TrainCreateDTO { + + private String uri; + + private String title; + + private String description; + + private List keywords; + + private String metadata; + + private List trainTypeUuids; + + private Boolean fetch = false; +} 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 index 8d44bbc..9e96e7c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java @@ -24,6 +24,9 @@ import lombok.*; +import java.util.List; +import java.util.UUID; + @AllArgsConstructor @NoArgsConstructor @Getter @@ -31,6 +34,20 @@ @Builder(toBuilder = true) public class TrainUpdateDTO { + private String uri; + + private String title; + + private String description; + + private List keywords; + + private String metadata; + + private List trainTypeUuids; + private Boolean softDeleted; + private Boolean fetch = false; + } diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java index b773322..1fe87a9 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java @@ -76,7 +76,6 @@ public class Station extends BaseEntity { @Column(name = "last_contact_at") private Timestamp lastContactAt; - @NotNull @ManyToOne @JoinColumn(name = "station_directory_id") private StationDirectory directory; diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java index 43f0f65..f1c7074 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Train.java @@ -73,7 +73,6 @@ public class Train extends BaseEntity { @Column(name = "status", columnDefinition = "sync_item_status", nullable = false) private SyncItemStatus status; - @NotNull @ManyToOne @JoinColumn(name = "train_garage_id") private TrainGarage garage; diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java index 58967c1..b69e85f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java @@ -23,15 +23,22 @@ 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.util.Arrays; +import java.util.List; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; @Component @RequiredArgsConstructor @@ -79,9 +86,45 @@ public StationSimpleDTO toSimpleDTO(Station station) { .build(); } - public Station fromUpdateDTO(StationUpdateDTO dto, Station station) { + 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())) + .metadata(dto.getMetadata()) + .types(trainTypes) .softDeleted(dto.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())) + .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 index 4dcdd53..7e3cf8a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationService.java @@ -23,6 +23,7 @@ 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; @@ -32,16 +33,15 @@ 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.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; @Service @RequiredArgsConstructor @@ -55,6 +55,10 @@ public class StationService { private final TrainMapper trainMapper; + private final TrainTypeService trainTypeService; + + private final StationDirectoryIndexer stationDirectoryIndexer; + public Station getByIdOrThrow(UUID uuid) throws NotFoundException { return stationRepository .findById(uuid) @@ -95,8 +99,13 @@ public List getSuitableStations(UUID uuid) throws NotFoundExcept @Transactional public StationDTO update(UUID uuid, StationUpdateDTO dto) throws NotFoundException { final Station station = getByIdOrThrow(uuid); - final Station newStation = stationRepository - .save(stationMapper.fromUpdateDTO(dto, station)); + 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); } @@ -106,4 +115,24 @@ public StationDTO softDelete(UUID uuid) throws NotFoundException { 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 index 2a5b94b..c4f910c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java @@ -125,6 +125,21 @@ public void indexDirectory(StationDirectory stationDirectory) { updateStations(stationDirectory, stations); } + public Station tryToFetchStation(String uri) { + final List trainTypes = trainTypeRepository.findAllBy(); + 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()); diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java index acee33b..2da4657 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java @@ -23,15 +23,22 @@ 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.util.Arrays; +import java.util.List; + +import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; @Component @RequiredArgsConstructor @@ -79,9 +86,45 @@ public TrainSimpleDTO toSimpleDTO(Train train) { .build(); } - public Train fromUpdateDTO(TrainUpdateDTO dto, Train train) { + 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(dto.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 index 7a39070..1f607d6 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainService.java @@ -24,6 +24,7 @@ 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; @@ -33,6 +34,8 @@ 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; @@ -55,6 +58,10 @@ public class TrainService { private final StationMapper stationMapper; + private final TrainTypeService trainTypeService; + + private final TrainGarageIndexer trainGarageIndexer; + public Train getByIdOrThrow(UUID uuid) throws NotFoundException { return trainRepository .findById(uuid) @@ -95,8 +102,13 @@ public List getSuitableStations(UUID uuid) throws NotFoundExce @Transactional public TrainDTO update(UUID uuid, TrainUpdateDTO dto) throws NotFoundException { final Train train = getByIdOrThrow(uuid); - final Train newTrain = - trainRepository.saveAndFlush(trainMapper.fromUpdateDTO(dto, train)); + 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); } @@ -106,4 +118,25 @@ public TrainDTO softDelete(UUID uuid) throws NotFoundException { 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 index 19cb22f..08b96ca 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java @@ -97,13 +97,28 @@ public void indexGarage(TrainGarage trainGarage) { toVisitUris.addAll(baseIndexer.extractChildren(model)); } catch (Exception exception) { - log.debug(format("Skipping %s (exception: %s)", uri, exception)); + log.debug(format("Failed to fetch %s (exception: %s)", uri, exception)); } } updateTrains(trainGarage, trains); } + public Train tryToFetchTrain(String uri) { + final List trainTypes = trainTypeRepository.findAllBy(); + try { + final Model model = baseIndexer.makeRequest(uri); + final List trains = extractTrains(null, model, trainTypes); + if (trains.size() > 0) { + 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()); diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java index ee86d22..bb491c0 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java @@ -33,6 +33,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.Objects; import java.util.UUID; @Service @@ -45,12 +47,26 @@ public class TrainTypeService { private final TrainTypeMapper trainTypeMapper; - private TrainType getByIdOrThrow(UUID uuid) throws NotFoundException { + 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); From 74b080de9fcdf1905cfb1dd5664f499641d04b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 30 Jan 2023 08:41:16 +0100 Subject: [PATCH 81/97] Fix station indexing (endpoint) --- .../api/dto/station/StationCreateDTO.java | 4 ++ .../api/dto/station/StationDTO.java | 4 ++ .../api/dto/station/StationSimpleDTO.java | 4 ++ .../api/dto/station/StationUpdateDTO.java | 4 ++ .../trainhandler/data/model/Station.java | 8 ++++ .../service/station/StationMapper.java | 8 ++++ .../StationDirectoryIndexer.java | 12 ++++- .../traingarage/TrainGarageIndexer.java | 2 +- .../migration/V0006.0__station-endpoint.sql | 31 +++++++++++++ .../dev/db/migration/V0004.1__dev_data.sql | 44 +++++++++++++++++++ 10 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/db/migration/V0006.0__station-endpoint.sql create mode 100644 src/main/resources/dev/db/migration/V0004.1__dev_data.sql 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 index aece874..52a34bd 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationCreateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationCreateDTO.java @@ -40,6 +40,10 @@ public class StationCreateDTO { private String description; + private String endpointUrl; + + private String endpointDescription; + private List keywords; private String metadata; 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 index 5420406..d15ad9a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationDTO.java @@ -47,6 +47,10 @@ public class StationDTO { private List keywords; + private String endpointUrl; + + private String endpointDescription; + private SyncItemStatus status; private String metadata; 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 index 1029563..168f7e5 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationSimpleDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationSimpleDTO.java @@ -45,6 +45,10 @@ public class StationSimpleDTO { private List keywords; + private String endpointUrl; + + private String endpointDescription; + private SyncItemStatus status; private StationDirectorySimpleDTO directory; 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 index 551d790..49fb9d6 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java @@ -42,6 +42,10 @@ public class StationUpdateDTO { private List keywords; + private String endpointUrl; + + private String endpointDescription; + private String metadata; private List trainTypeUuids; diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java index 1fe87a9..6e089df 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Station.java @@ -63,6 +63,14 @@ public class Station extends BaseEntity { @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; diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java index b69e85f..6e21578 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java @@ -60,6 +60,8 @@ public StationDTO toDTO(Station station) { Arrays.stream(station.getKeywords().split(KEYWORD_SEP)) .map(String::trim) .toList()) + .endpointUrl(station.getEndpointUrl()) + .endpointDescription(station.getEndpointDescription()) .status(station.getStatus()) .softDeleted(station.getSoftDeleted()) .metadata(station.getMetadata()) @@ -80,6 +82,8 @@ public StationSimpleDTO toSimpleDTO(Station station) { Arrays.stream(station.getKeywords().split(KEYWORD_SEP)) .map(String::trim) .toList()) + .endpointUrl(station.getEndpointUrl()) + .endpointDescription(station.getEndpointDescription()) .status(station.getStatus()) .directory(stationDirectoryMapper.toSimpleDTO(station.getDirectory())) .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) @@ -92,6 +96,8 @@ public Station fromUpdateDTO(StationUpdateDTO dto, Station station, List trainTypes) { .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) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java index c4f910c..3e1eb98 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java @@ -218,6 +218,8 @@ private Station extractStation( 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) @@ -237,7 +239,11 @@ private Station extractStation( .collect(Collectors.toSet()); if (title == null) { - log.warn(format("Skipping station %s (missing required information)", resource)); + 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; } @@ -258,7 +264,9 @@ private Station extractStation( .title(title) .description(description == null ? "" : description) .keywords(String.join(",", keywords)) - .metadata(write(model.filter(resource, null, null))) + .endpointUrl(endpointUrl) + .endpointDescription(endpointDescription == null ? "" : endpointDescription) + .metadata(write(model)) .types(matchingTrainTypes) .directory(stationDirectory) .status(SyncItemStatus.SYNCED) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java index 08b96ca..32ef241 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java @@ -228,7 +228,7 @@ private Train extractTrain( .title(title) .description(description == null ? "" : description) .keywords(String.join(",", keywords)) - .metadata(write(model.filter(resource, null, null))) + .metadata(write(model)) .types(matchingTrainTypes) .garage(trainGarage) .status(SyncItemStatus.SYNCED) 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/dev/db/migration/V0004.1__dev_data.sql b/src/main/resources/dev/db/migration/V0004.1__dev_data.sql new file mode 100644 index 0000000..6538adc --- /dev/null +++ b/src/main/resources/dev/db/migration/V0004.1__dev_data.sql @@ -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. +-- + +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', '', + NOW(), NOW()); +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', '', + NOW(), NOW()); +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', '', + NOW(), NOW()); +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', '', + NOW(), NOW()); +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', '', + NOW(), NOW()); +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', '', + NOW(), NOW()); +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', '', NOW(), NOW()); \ No newline at end of file From a5af4544936379e9e4c8ee3896308095b8386963 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Feb 2023 19:07:54 +0000 Subject: [PATCH 82/97] Bump lombok from 1.18.24 to 1.18.26 Bumps [lombok](https://github.com/projectlombok/lombok) from 1.18.24 to 1.18.26. - [Release notes](https://github.com/projectlombok/lombok/releases) - [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/projectlombok/lombok/compare/v1.18.24...v1.18.26) --- updated-dependencies: - dependency-name: org.projectlombok:lombok dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1099a18..4566f5c 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ 1.6.14 42.5.1 - 1.18.24 + 1.18.26 2.14.1 4.2.2 20.0.3 From 392de08da77864431f86952aedbd5331b60f062f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Feb 2023 19:07:43 +0000 Subject: [PATCH 83/97] Bump checkstyle from 10.6.0 to 10.7.0 Bumps [checkstyle](https://github.com/checkstyle/checkstyle) from 10.6.0 to 10.7.0. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.6.0...checkstyle-10.7.0) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4566f5c..158a542 100644 --- a/pom.xml +++ b/pom.xml @@ -245,7 +245,7 @@ com.puppycrawl.tools checkstyle - 10.6.0 + 10.7.0 io.spring.javaformat From 640543248aae1c595a41d3288861032764f540a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Feb 2023 15:21:49 +0000 Subject: [PATCH 84/97] Bump postgresql from 42.5.1 to 42.5.3 Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.5.1 to 42.5.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/REL42.5.3/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.5.1...REL42.5.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 158a542..6fc356f 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.6.14 - 42.5.1 + 42.5.3 1.18.26 2.14.1 4.2.2 From 647d8963401b6d235284482ea1e3887c0dcdd162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sat, 31 Dec 2022 15:25:45 +0100 Subject: [PATCH 85/97] Support publishing artifacts --- .../api/controller/JobArtifactController.java | 3 +- .../api/controller/PlanLatestController.java | 85 +++++++++++++++++ .../api/dto/plan/PlanCreateDTO.java | 5 +- .../trainhandler/api/dto/plan/PlanDTO.java | 5 +- .../api/dto/plan/PlanSimpleDTO.java | 8 ++ .../api/dto/plan/PlanTargetChangeDTO.java | 42 +++++++++ .../api/dto/plan/PlanTargetDTO.java | 42 +++++++++ .../api/dto/plan/PlanUpdateDTO.java | 4 +- .../trainhandler/data/model/Plan.java | 4 + .../trainhandler/data/model/PlanTarget.java | 14 ++- .../repository/JobArtifactRepository.java | 32 +++++++ .../trainhandler/service/plan/PlanMapper.java | 28 ++++-- .../service/plan/PlanService.java | 68 ++++++++------ .../service/plan/PlanTargetMapper.java | 4 +- .../plan/latest/PlanLatestService.java | 91 +++++++++++++++++++ .../trainhandler/utils/CompareUtils.java | 3 +- .../V0007.0__add-public-artifacts.sql | 28 ++++++ .../dev/db/migration/V0002.1__dev_data.sql | 22 ++--- .../dev/db/migration/V0004.1__dev_data.sql | 44 --------- 19 files changed, 431 insertions(+), 101 deletions(-) create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanLatestController.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanTargetChangeDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanTargetDTO.java create mode 100644 src/main/java/org/fairdatatrain/trainhandler/service/plan/latest/PlanLatestService.java create mode 100644 src/main/resources/db/migration/V0007.0__add-public-artifacts.sql delete mode 100644 src/main/resources/dev/db/migration/V0004.1__dev_data.sql diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java index 9bb0d5a..c7e69f1 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/JobArtifactController.java @@ -68,8 +68,7 @@ public List getJobArtifacts( } @GetMapping( - path = "/{runUuid}/jobs/{jobUuid}/artifacts/{artifactUuid}/download", - produces = MediaType.APPLICATION_JSON_VALUE + path = "/{runUuid}/jobs/{jobUuid}/artifacts/{artifactUuid}/download" ) public ResponseEntity getJobArtifactData( @PathVariable UUID runUuid, 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..144cc98 --- /dev/null +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanLatestController.java @@ -0,0 +1,85 @@ +/** + * 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.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +import static java.lang.String.format; + +@Tag(name = "Plans") +@PreAuthorize("hasRole('user')") +@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/dto/plan/PlanCreateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanCreateDTO.java index bed4984..c659f4d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanCreateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanCreateDTO.java @@ -42,11 +42,14 @@ public class PlanCreateDTO { private UUID trainUuid; @NotNull - private List stationUuids; + 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 index 08effde..3cc9c48 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanDTO.java @@ -23,7 +23,6 @@ package org.fairdatatrain.trainhandler.api.dto.plan; import lombok.*; -import org.fairdatatrain.trainhandler.api.dto.station.StationSimpleDTO; import org.fairdatatrain.trainhandler.api.dto.train.TrainDTO; import java.util.List; @@ -44,7 +43,9 @@ public class PlanDTO { private TrainDTO train; - private List targets; + private List targets; + + private Boolean publishArtifacts; private String createdAt; 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 index a199491..9c05b5e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanSimpleDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanSimpleDTO.java @@ -25,6 +25,8 @@ import lombok.*; import org.fairdatatrain.trainhandler.api.dto.train.TrainSimpleDTO; +import javax.validation.constraints.NotNull; +import java.util.List; import java.util.UUID; @AllArgsConstructor @@ -40,5 +42,11 @@ public class PlanSimpleDTO { 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 index d7c1fd1..f097aae 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanUpdateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/plan/PlanUpdateDTO.java @@ -42,11 +42,13 @@ public class PlanUpdateDTO { private UUID trainUuid; @NotNull - private List stationUuids; + private List targets; @NotBlank private String displayName; @NotNull private String note; + + private Boolean publishArtifacts = false; } diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/Plan.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/Plan.java index 0f9e0ed..4aea02c 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/Plan.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/Plan.java @@ -52,6 +52,10 @@ public class Plan extends BaseEntity { @Column(name = "note", nullable = false) private String note; + @NotNull + @Column(name = "publish_artifacts", nullable = false) + private Boolean publishArtifacts; + @NotNull @ManyToOne @JoinColumn(name = "train_id") diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/model/PlanTarget.java b/src/main/java/org/fairdatatrain/trainhandler/data/model/PlanTarget.java index 109b58d..152648a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/model/PlanTarget.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/model/PlanTarget.java @@ -29,11 +29,9 @@ import lombok.experimental.SuperBuilder; import org.fairdatatrain.trainhandler.data.model.base.BaseEntity; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; +import javax.persistence.*; import javax.validation.constraints.NotNull; +import java.util.UUID; @Entity(name = "PlanTarget") @Table(name = "plan_target") @@ -53,4 +51,12 @@ public class PlanTarget extends BaseEntity { @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/repository/JobArtifactRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobArtifactRepository.java index d214b67..7ab600b 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobArtifactRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/JobArtifactRepository.java @@ -24,8 +24,40 @@ 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/service/plan/PlanMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java index a9da0d4..4a1c0fd 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java @@ -23,10 +23,7 @@ package org.fairdatatrain.trainhandler.service.plan; 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.plan.*; import org.fairdatatrain.trainhandler.data.model.Plan; import org.fairdatatrain.trainhandler.data.model.PlanTarget; import org.fairdatatrain.trainhandler.data.model.Train; @@ -55,10 +52,11 @@ public PlanDTO toDTO(Plan plan) { .note(plan.getNote()) .train(trainMapper.toDTO(plan.getTrain())) .targets( - plan.getTargets().stream() - .map(PlanTarget::getStation) - .map(stationMapper::toSimpleDTO) + plan.getTargets() + .stream() + .map(this::toPlanTargetDTO) .toList()) + .publishArtifacts(plan.getPublishArtifacts()) .createdAt(plan.getCreatedAt().toInstant().toString()) .updatedAt(plan.getUpdatedAt().toInstant().toString()) .build(); @@ -70,6 +68,13 @@ public PlanSimpleDTO toSimpleDTO(Plan plan) { .displayName(plan.getDisplayName()) .note(plan.getNote()) .train(trainMapper.toSimpleDTO(plan.getTrain())) + .targets( + plan.getTargets() + .stream() + .map(this::toPlanTargetDTO) + .toList() + ) + .publishArtifacts(plan.getPublishArtifacts()) .build(); } @@ -81,6 +86,7 @@ public Plan fromCreateDTO(PlanCreateDTO reqDto, Train train) { .note(reqDto.getNote()) .train(train) .targets(Collections.emptyList()) + .publishArtifacts(reqDto.getPublishArtifacts()) .createdAt(now) .updatedAt(now) .build(); @@ -92,6 +98,14 @@ public Plan fromUpdateDTO(PlanUpdateDTO reqDto, Plan plan, Train 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 index f706bb6..c8f9edd 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanService.java @@ -23,10 +23,7 @@ package org.fairdatatrain.trainhandler.service.plan; 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.plan.*; import org.fairdatatrain.trainhandler.data.model.Plan; import org.fairdatatrain.trainhandler.data.model.PlanTarget; import org.fairdatatrain.trainhandler.data.model.Station; @@ -45,6 +42,7 @@ 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; @@ -90,19 +88,26 @@ public PlanDTO getSingle(UUID uuid) throws NotFoundException { @Transactional public PlanDTO create(PlanCreateDTO reqDto) throws NotFoundException { - // TODO: validate? (empty list of stations) final Train train = trainService.getByIdOrThrow(reqDto.getTrainUuid()); - final List stations = new ArrayList<>(); - for (UUID stationUuid : reqDto.getStationUuids()) { - stations.add(stationService.getByIdOrThrow(stationUuid)); + 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 = - stations.stream() - .map(station -> planTargetMapper.forPlan(newPlan, station)) + reqDto.getTargets() + .stream() + .map(targetDto -> { + return planTargetMapper.forPlan( + newPlan, + targetDto, + stations.get(targetDto.getStationUuid()) + ); + }) .toList(); newPlan.setTargets(targets); planTargetRepository.saveAllAndFlush(targets); @@ -116,16 +121,25 @@ 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() + final Set oldStationUuids = plan + .getTargets() + .stream() .map(PlanTarget::getStation) .map(Station::getUuid) .collect(Collectors.toSet()); - final Set newStationUuids = new HashSet<>(reqDto.getStationUuids()); + 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(reqDto.getStationUuids(), oldStationUuids); + compareListContents(newStationUuids, oldStationUuids); if (planExecuted && changeTrain) { throw new CannotPerformException( ENTITY_NAME, @@ -141,10 +155,19 @@ public PlanDTO update(UUID uuid, PlanUpdateDTO reqDto) "It is not possible to change targets of already used plan."); } final Train train = trainService.getByIdOrThrow(reqDto.getTrainUuid()); - final List stations = new ArrayList<>(); - for (UUID stationUuid : reqDto.getStationUuids()) { - if (!oldStationUuids.contains(stationUuid)) { - stations.add(stationService.getByIdOrThrow(stationUuid)); + 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()) { @@ -152,18 +175,11 @@ public PlanDTO update(UUID uuid, PlanUpdateDTO reqDto) planTargetRepository.delete(target); } } + plan.setTargets(targets); final Plan updatedPlan = planRepository.saveAndFlush(planMapper.fromUpdateDTO(reqDto, plan, train)); entityManager.flush(); entityManager.refresh(updatedPlan); - final List targets = - stations.stream() - .map(station -> planTargetMapper.forPlan(updatedPlan, station)) - .toList(); - updatedPlan.setTargets(targets); - planTargetRepository.saveAllAndFlush(targets); - entityManager.flush(); - entityManager.refresh(updatedPlan); return planMapper.toDTO(updatedPlan); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanTargetMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanTargetMapper.java index 1265c2a..f15e32a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanTargetMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanTargetMapper.java @@ -23,6 +23,7 @@ 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; @@ -34,11 +35,12 @@ @RequiredArgsConstructor public class PlanTargetMapper { - public PlanTarget forPlan(Plan newPlan, Station station) { + 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/utils/CompareUtils.java b/src/main/java/org/fairdatatrain/trainhandler/utils/CompareUtils.java index 63c137e..fd97189 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/utils/CompareUtils.java +++ b/src/main/java/org/fairdatatrain/trainhandler/utils/CompareUtils.java @@ -23,11 +23,10 @@ package org.fairdatatrain.trainhandler.utils; import java.util.Collection; -import java.util.List; public class CompareUtils { - public static boolean compareListContents(List listA, Collection listB) { + public static boolean compareListContents(Collection listA, Collection listB) { if (listA.size() != listB.size()) { return false; } 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/dev/db/migration/V0002.1__dev_data.sql b/src/main/resources/dev/db/migration/V0002.1__dev_data.sql index 5b1c838..8bdb338 100644 --- a/src/main/resources/dev/db/migration/V0002.1__dev_data.sql +++ b/src/main/resources/dev/db/migration/V0002.1__dev_data.sql @@ -48,15 +48,15 @@ VALUES ('7c9594d1-d20e-449a-bd7f-393e1f6b87ac', 'http://example.com/fds/train-ga -- Train Type INSERT INTO train_type (uuid, uri, title, note, created_at, updated_at) -VALUES ('f5eef54f-b85c-4109-b26b-18e15c8e0751', 'https://w3id.org/fdp/fdt-o#SPARQLTrain', 'SPARQL Train', +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-7d4955ded0bc', 'https://w3id.org/fdp/fdt-o#DockerTrain', 'Docker Train', +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-aad0edd1639a', 'https://w3id.org/fdp/fdt-o#SQLTrain', 'SQL Train', +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 @@ -66,9 +66,9 @@ 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-18e15c8e0751', '9b2f99bb-6ca4-4326-82c1-bba34fb39abc'); +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-aad0edd1639a', '9b2f99bb-6ca4-4326-82c1-bba34fb39abc'); +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) @@ -76,7 +76,7 @@ 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-18e15c8e0751', 'a4d6cf81-1e7a-4666-88e7-26fbdd992674'); +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) @@ -84,9 +84,9 @@ 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-18e15c8e0751', 'f41417ab-ef19-408f-ba69-5d3a1bc42e23'); +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-7d4955ded0bc', 'f41417ab-ef19-408f-ba69-5d3a1bc42e23'); +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, @@ -96,7 +96,7 @@ VALUES ('e816b968-2663-4110-889d-7023b797c407', 'http://example.com/fds/train1', '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-18e15c8e0751', 'e816b968-2663-4110-889d-7023b797c407'); +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) @@ -104,7 +104,7 @@ VALUES ('5dd5c8d4-d084-4ade-8647-cdf0df0702c2', 'http://example.com/fds/train2', '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-aad0edd1639a', '5dd5c8d4-d084-4ade-8647-cdf0df0702c2'); +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) @@ -112,4 +112,4 @@ VALUES ('a1eea8ce-e332-4e7b-b41d-880b53d709f4', 'http://example.com/fds/train3', '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-18e15c8e0751', 'a1eea8ce-e332-4e7b-b41d-880b53d709f4'); +VALUES ('f5eef54f-b85c-4109-b26b-18e15c8e075f', 'a1eea8ce-e332-4e7b-b41d-880b53d709f4'); diff --git a/src/main/resources/dev/db/migration/V0004.1__dev_data.sql b/src/main/resources/dev/db/migration/V0004.1__dev_data.sql deleted file mode 100644 index 6538adc..0000000 --- a/src/main/resources/dev/db/migration/V0004.1__dev_data.sql +++ /dev/null @@ -1,44 +0,0 @@ --- --- 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.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', '', - NOW(), NOW()); -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', '', - NOW(), NOW()); -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', '', - NOW(), NOW()); -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', '', - NOW(), NOW()); -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', '', - NOW(), NOW()); -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', '', - NOW(), NOW()); -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', '', NOW(), NOW()); \ No newline at end of file From ad139d7c64f52886b2cfff92cfdf7ab77ce77c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 6 Feb 2023 09:56:29 +0100 Subject: [PATCH 86/97] Add get for all train types --- .../trainhandler/api/controller/TrainTypeController.java | 7 +++++++ .../trainhandler/service/traintype/TrainTypeService.java | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java index e927ae7..74e3de3 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java @@ -26,6 +26,7 @@ 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; @@ -36,6 +37,7 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; +import java.util.List; import java.util.UUID; @Tag(name = "Train Types") @@ -54,6 +56,11 @@ public Page getPaged( 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, diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java index bb491c0..4fcc2e6 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traintype/TrainTypeService.java @@ -25,6 +25,7 @@ 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; @@ -102,4 +103,12 @@ public TrainTypeDTO update(UUID uuid, TrainTypeChangeDTO reqDto) throws NotFound trainTypeRepository.saveAndFlush(trainTypeMapper.fromUpdateDTO(reqDto, trainType)); return trainTypeMapper.toDTO(updatedTrainType); } + + public List getAll() { + return trainTypeRepository + .findAll() + .stream() + .map(trainTypeMapper::toSimpleDTO) + .toList(); + } } From e2e9db82663dcb42d9a2c54503bb7e6ed1065086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 6 Feb 2023 12:45:12 +0100 Subject: [PATCH 87/97] Fix train/station creation --- .../api/controller/StationController.java | 2 +- .../api/dto/station/StationCreateDTO.java | 10 +++++++ .../api/dto/station/StationUpdateDTO.java | 10 +++++++ .../api/dto/train/TrainCreateDTO.java | 8 ++++++ .../api/dto/train/TrainUpdateDTO.java | 8 ++++++ .../service/station/StationMapper.java | 26 ++++++++++++++--- .../service/train/TrainMapper.java | 26 ++++++++++++++--- .../V0007.1__fix-garage-requirement.sql | 28 +++++++++++++++++++ 8 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 src/main/resources/db/migration/V0007.1__fix-garage-requirement.sql diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java index 6b44525..4d53832 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java @@ -63,7 +63,7 @@ public List getPaged( return stationService.getAll(query); } - @PutMapping( + @PostMapping( path = "", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE 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 index 52a34bd..ec206ce 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationCreateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationCreateDTO.java @@ -24,6 +24,7 @@ import lombok.*; +import javax.validation.constraints.NotNull; import java.util.List; import java.util.UUID; @@ -34,21 +35,30 @@ @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/StationUpdateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java index 49fb9d6..8adec9a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/station/StationUpdateDTO.java @@ -24,6 +24,7 @@ import lombok.*; +import javax.validation.constraints.NotNull; import java.util.List; import java.util.UUID; @@ -34,24 +35,33 @@ @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/train/TrainCreateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainCreateDTO.java index 4713ada..c27bd3f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainCreateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainCreateDTO.java @@ -24,6 +24,7 @@ import lombok.*; +import javax.validation.constraints.NotNull; import java.util.List; import java.util.UUID; @@ -34,17 +35,24 @@ @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/TrainUpdateDTO.java b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java index 9e96e7c..ebc4f83 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/dto/train/TrainUpdateDTO.java @@ -24,6 +24,7 @@ import lombok.*; +import javax.validation.constraints.NotNull; import java.util.List; import java.util.UUID; @@ -34,20 +35,27 @@ @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/service/station/StationMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java index 6e21578..854f113 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java @@ -35,8 +35,10 @@ 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; @@ -65,9 +67,18 @@ public StationDTO toDTO(Station station) { .status(station.getStatus()) .softDeleted(station.getSoftDeleted()) .metadata(station.getMetadata()) - .directory(stationDirectoryMapper.toSimpleDTO(station.getDirectory())) + .directory( + Optional.ofNullable(station.getDirectory()) + .map(stationDirectoryMapper::toSimpleDTO) + .orElse(null) + ) .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) - .lastContactAt(station.getLastContactAt().toInstant().toString()) + .lastContactAt( + Optional.ofNullable(station.getLastContactAt()) + .map(Timestamp::toInstant) + .map(Instant::toString) + .orElse(null) + ) .createdAt(station.getCreatedAt().toInstant().toString()) .updatedAt(station.getUpdatedAt().toInstant().toString()) .build(); @@ -85,7 +96,11 @@ public StationSimpleDTO toSimpleDTO(Station station) { .endpointUrl(station.getEndpointUrl()) .endpointDescription(station.getEndpointDescription()) .status(station.getStatus()) - .directory(stationDirectoryMapper.toSimpleDTO(station.getDirectory())) + .directory( + Optional.ofNullable(station.getDirectory()) + .map(stationDirectoryMapper::toSimpleDTO) + .orElse(null) + ) .types(station.getTypes().stream().map(trainTypeMapper::toSimpleDTO).toList()) .build(); } @@ -100,7 +115,10 @@ public Station fromUpdateDTO(StationUpdateDTO dto, Station station, List trai .keywords(String.join(KEYWORD_SEP, dto.getKeywords())) .metadata(dto.getMetadata()) .types(trainTypes) - .softDeleted(dto.getSoftDeleted()) + .softDeleted( + Optional.ofNullable(dto.getSoftDeleted()) + .orElse(train.getSoftDeleted()) + ) .updatedAt(now()) .build(); } 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; From 4a16d95bbaabafa861150e1650de5d1938d49036 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 19:59:33 +0000 Subject: [PATCH 88/97] Bump rdf4j.version from 4.2.2 to 4.2.3 Bumps `rdf4j.version` from 4.2.2 to 4.2.3. Updates `rdf4j-runtime` from 4.2.2 to 4.2.3 Updates `rdf4j-rio-api` from 4.2.2 to 4.2.3 Updates `rdf4j-sail-nativerdf` from 4.2.2 to 4.2.3 --- updated-dependencies: - dependency-name: org.eclipse.rdf4j:rdf4j-runtime dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.eclipse.rdf4j:rdf4j-rio-api dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.eclipse.rdf4j:rdf4j-sail-nativerdf dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6fc356f..174a05a 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 42.5.3 1.18.26 2.14.1 - 4.2.2 + 4.2.3 20.0.3 From 31fe70a21889e234428f1a7377955040af3acb39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Feb 2023 19:58:30 +0000 Subject: [PATCH 89/97] Bump postgresql from 42.5.3 to 42.5.4 Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.5.3 to 42.5.4. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.5.3...REL42.5.4) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 174a05a..8200682 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ 1.6.14 - 42.5.3 + 42.5.4 1.18.26 2.14.1 4.2.3 From 578cb0817f8afd1a4a9c239abced958d19610581 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Feb 2023 20:05:40 +0000 Subject: [PATCH 90/97] Bump spring-javaformat-checkstyle from 0.0.35 to 0.0.38 Bumps [spring-javaformat-checkstyle](https://github.com/spring-io/spring-javaformat) from 0.0.35 to 0.0.38. - [Release notes](https://github.com/spring-io/spring-javaformat/releases) - [Commits](https://github.com/spring-io/spring-javaformat/compare/v0.0.35...v0.0.38) --- updated-dependencies: - dependency-name: io.spring.javaformat:spring-javaformat-checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8200682..bf3ed43 100644 --- a/pom.xml +++ b/pom.xml @@ -250,7 +250,7 @@ io.spring.javaformat spring-javaformat-checkstyle - 0.0.35 + 0.0.38 From 0d4a7d95d90125ac6630d37263a33437108b6d10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Feb 2023 20:03:25 +0000 Subject: [PATCH 91/97] Bump spotbugs-maven-plugin from 4.7.3.0 to 4.7.3.2 Bumps [spotbugs-maven-plugin](https://github.com/spotbugs/spotbugs-maven-plugin) from 4.7.3.0 to 4.7.3.2. - [Release notes](https://github.com/spotbugs/spotbugs-maven-plugin/releases) - [Commits](https://github.com/spotbugs/spotbugs-maven-plugin/compare/spotbugs-maven-plugin-4.7.3.0...spotbugs-maven-plugin-4.7.3.2) --- updated-dependencies: - dependency-name: com.github.spotbugs:spotbugs-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bf3ed43..59ccec5 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ 4.1 3.2.1 - 4.7.3.0 + 4.7.3.2 5.0.0 0.2.0 From 7450f587616c052d2b77836b06533de035c2bb93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Mar 2023 08:39:59 +0000 Subject: [PATCH 92/97] Bump keycloak.version from 20.0.3 to 21.0.1 Bumps `keycloak.version` from 20.0.3 to 21.0.1. Updates `keycloak-spring-boot-starter` from 20.0.3 to 21.0.1 Updates `keycloak-spring-security-adapter` from 20.0.3 to 21.0.1 Updates `keycloak-adapter-bom` from 20.0.3 to 21.0.1 --- updated-dependencies: - dependency-name: org.keycloak:keycloak-spring-boot-starter dependency-type: direct:production update-type: version-update:semver-major - dependency-name: org.keycloak:keycloak-spring-security-adapter dependency-type: direct:production update-type: version-update:semver-major - dependency-name: org.keycloak.bom:keycloak-adapter-bom dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 59ccec5..5e2fa0f 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 1.18.26 2.14.1 4.2.3 - 20.0.3 + 21.0.1 4.1 From b0d162847820422168cacf15783f12716e9fc650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Fri, 3 Mar 2023 11:17:00 +0100 Subject: [PATCH 93/97] Add default sorting for listings --- .../trainhandler/api/controller/PlanController.java | 3 ++- .../trainhandler/api/controller/StationController.java | 3 ++- .../api/controller/StationDirectoryController.java | 3 ++- .../trainhandler/api/controller/TrainController.java | 3 ++- .../api/controller/TrainGarageController.java | 3 ++- .../trainhandler/api/controller/TrainTypeController.java | 3 ++- .../data/repository/TrainTypeRepository.java | 4 ---- .../trainhandler/service/plan/PlanMapper.java | 9 ++++++++- .../trainhandler/service/run/RunMapper.java | 5 +++++ .../stationdirectory/StationDirectoryIndexer.java | 4 ++-- .../service/traingarage/TrainGarageIndexer.java | 6 +++--- 11 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java index c02b4d4..a1870b3 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanController.java @@ -35,6 +35,7 @@ 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; @@ -57,7 +58,7 @@ public class PlanController { @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) public Page getPaged( @RequestParam(value = "query", required = false, defaultValue = "") String query, - Pageable pageable) { + @PageableDefault(sort = "displayName") Pageable pageable) { return planService.getPaged(query, pageable); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java index 4d53832..ce13268 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationController.java @@ -33,6 +33,7 @@ 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.*; @@ -53,7 +54,7 @@ public class StationController { @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) public Page getPaged( @RequestParam(value = "query", required = false, defaultValue = "") String query, - Pageable pageable) { + @PageableDefault(sort = "title") Pageable pageable) { return stationService.getPaged(query, pageable); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java index 2976056..2b2c41e 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/StationDirectoryController.java @@ -30,6 +30,7 @@ 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; @@ -50,7 +51,7 @@ public class StationDirectoryController { @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) public Page getPaged( @RequestParam(value = "query", required = false, defaultValue = "") String query, - Pageable pageable) { + @PageableDefault(sort = "displayName") Pageable pageable) { return stationDirectoryService.getPaged(query, pageable); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java index b72a3b4..9ebd2ea 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainController.java @@ -33,6 +33,7 @@ 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.*; @@ -53,7 +54,7 @@ public class TrainController { @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) public Page getPaged( @RequestParam(value = "query", required = false, defaultValue = "") String query, - Pageable pageable) { + @PageableDefault(sort = "title") Pageable pageable) { return trainService.getPaged(query, pageable); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java index 10f7000..9643a0d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainGarageController.java @@ -30,6 +30,7 @@ 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; @@ -50,7 +51,7 @@ public class TrainGarageController { @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) public Page getPaged( @RequestParam(value = "query", required = false, defaultValue = "") String query, - Pageable pageable) { + @PageableDefault(sort = "displayName") Pageable pageable) { return trainGarageService.getPaged(query, pageable); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java index 74e3de3..11049cf 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/TrainTypeController.java @@ -31,6 +31,7 @@ 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; @@ -52,7 +53,7 @@ public class TrainTypeController { @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) public Page getPaged( @RequestParam(value = "query", required = false, defaultValue = "") String query, - Pageable pageable) { + @PageableDefault(sort = "title") Pageable pageable) { return trainTypeService.getPaged(query, pageable); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java index 02fc929..9641abc 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java +++ b/src/main/java/org/fairdatatrain/trainhandler/data/repository/TrainTypeRepository.java @@ -28,12 +28,8 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; -import java.util.List; - @Repository public interface TrainTypeRepository extends BaseRepository { - List findAllBy(); - Page findByTitleContainingIgnoreCase(String query, Pageable pageable); } diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java index 4a1c0fd..d569c0d 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/plan/PlanMapper.java @@ -33,6 +33,7 @@ import java.sql.Timestamp; import java.util.Collections; +import java.util.Comparator; import java.util.UUID; import static org.fairdatatrain.trainhandler.utils.TimeUtils.now; @@ -41,6 +42,9 @@ @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; @@ -55,7 +59,9 @@ public PlanDTO toDTO(Plan plan) { plan.getTargets() .stream() .map(this::toPlanTargetDTO) - .toList()) + .sorted(TARGET_CMP) + .toList() + ) .publishArtifacts(plan.getPublishArtifacts()) .createdAt(plan.getCreatedAt().toInstant().toString()) .updatedAt(plan.getUpdatedAt().toInstant().toString()) @@ -72,6 +78,7 @@ public PlanSimpleDTO toSimpleDTO(Plan plan) { plan.getTargets() .stream() .map(this::toPlanTargetDTO) + .sorted(TARGET_CMP) .toList() ) .publishArtifacts(plan.getPublishArtifacts()) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java index 126e509..e958578 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/run/RunMapper.java @@ -37,6 +37,7 @@ import java.sql.Timestamp; import java.time.Instant; +import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -47,6 +48,9 @@ @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; @@ -84,6 +88,7 @@ public RunDTO toDTO(Run run) { .getJobs() .stream() .map(jobMapper::toSimpleDTO) + .sorted(JOB_SIMPLE_CMP) .toList(); return RunDTO.builder() .uuid(run.getUuid()) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java index 3e1eb98..7c363f2 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/stationdirectory/StationDirectoryIndexer.java @@ -89,7 +89,7 @@ public void indexDirectory(StationDirectory stationDirectory) { final Set visitedUris = new HashSet<>(); final Queue toVisitUris = new LinkedList<>(); final List stations = new ArrayList<>(); - final List trainTypes = trainTypeRepository.findAllBy(); + final List trainTypes = trainTypeRepository.findAll(); Model model; try { @@ -126,7 +126,7 @@ public void indexDirectory(StationDirectory stationDirectory) { } public Station tryToFetchStation(String uri) { - final List trainTypes = trainTypeRepository.findAllBy(); + final List trainTypes = trainTypeRepository.findAll(); try { final Model model = baseIndexer.makeRequest(uri); final List stations = extractStations(null, model, trainTypes); diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java index 32ef241..376548f 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/traingarage/TrainGarageIndexer.java @@ -69,7 +69,7 @@ public void indexGarage(TrainGarage trainGarage) { final Set visitedUris = new HashSet<>(); final Queue toVisitUris = new LinkedList<>(); final List trains = new ArrayList<>(); - final List trainTypes = trainTypeRepository.findAllBy(); + final List trainTypes = trainTypeRepository.findAll(); Model model; try { @@ -105,11 +105,11 @@ public void indexGarage(TrainGarage trainGarage) { } public Train tryToFetchTrain(String uri) { - final List trainTypes = trainTypeRepository.findAllBy(); + final List trainTypes = trainTypeRepository.findAll(); try { final Model model = baseIndexer.makeRequest(uri); final List trains = extractTrains(null, model, trainTypes); - if (trains.size() > 0) { + if (!trains.isEmpty()) { return trains.get(0); } } From 48882af02c316d5b19b6539b23727e3306bdd927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Fri, 3 Mar 2023 12:58:27 +0100 Subject: [PATCH 94/97] Fix Keycloak authentication --- .../trainhandler/config/SecurityKeycloakConfig.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/fairdatatrain/trainhandler/config/SecurityKeycloakConfig.java b/src/main/java/org/fairdatatrain/trainhandler/config/SecurityKeycloakConfig.java index dc33c0a..36bbb8a 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/config/SecurityKeycloakConfig.java +++ b/src/main/java/org/fairdatatrain/trainhandler/config/SecurityKeycloakConfig.java @@ -31,19 +31,19 @@ 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.EnableGlobalMethodSecurity; +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) -@EnableGlobalMethodSecurity(prePostEnabled = true) +@EnableMethodSecurity @Import(KeycloakSpringBootConfigResolver.class) public class SecurityKeycloakConfig extends KeycloakWebSecurityConfigurerAdapter { @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + public void configureGlobal(AuthenticationManagerBuilder auth) { final KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); @@ -59,6 +59,8 @@ protected NullAuthenticatedSessionStrategy sessionAuthenticationStrategy() { @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); - http.authorizeRequests(); + http + .csrf().disable() + .authorizeHttpRequests(); } } From e4a17466db32d48257467cf15379c7298965a43b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Fri, 3 Mar 2023 13:19:03 +0100 Subject: [PATCH 95/97] Fix keywords mapping --- .../trainhandler/service/station/StationMapper.java | 2 ++ .../fairdatatrain/trainhandler/service/train/TrainMapper.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java index 854f113..c750aee 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/station/StationMapper.java @@ -61,6 +61,7 @@ public StationDTO toDTO(Station station) { .keywords( Arrays.stream(station.getKeywords().split(KEYWORD_SEP)) .map(String::trim) + .filter(item -> !item.isBlank()) .toList()) .endpointUrl(station.getEndpointUrl()) .endpointDescription(station.getEndpointDescription()) @@ -92,6 +93,7 @@ public StationSimpleDTO toSimpleDTO(Station station) { .keywords( Arrays.stream(station.getKeywords().split(KEYWORD_SEP)) .map(String::trim) + .filter(item -> !item.isBlank()) .toList()) .endpointUrl(station.getEndpointUrl()) .endpointDescription(station.getEndpointDescription()) diff --git a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java index 95b4d76..b7f5365 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java +++ b/src/main/java/org/fairdatatrain/trainhandler/service/train/TrainMapper.java @@ -61,6 +61,7 @@ public TrainDTO toDTO(Train train) { .keywords( Arrays.stream(train.getKeywords().split(KEYWORD_SEP)) .map(String::trim) + .filter(item -> !item.isBlank()) .toList()) .status(train.getStatus()) .softDeleted(train.getSoftDeleted()) @@ -90,6 +91,7 @@ public TrainSimpleDTO toSimpleDTO(Train train) { .keywords( Arrays.stream(train.getKeywords().split(KEYWORD_SEP)) .map(String::trim) + .filter(item -> !item.isBlank()) .toList()) .status(train.getStatus()) .garage( From 512a4b86385d0387bf6c6ee3e67fe193da72bfa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Fri, 3 Mar 2023 13:28:45 +0100 Subject: [PATCH 96/97] Fix authentication for latest plan --- .../trainhandler/api/controller/PlanLatestController.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanLatestController.java b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanLatestController.java index 144cc98..f6aa533 100644 --- a/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanLatestController.java +++ b/src/main/java/org/fairdatatrain/trainhandler/api/controller/PlanLatestController.java @@ -33,7 +33,6 @@ 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 java.util.List; @@ -42,7 +41,6 @@ import static java.lang.String.format; @Tag(name = "Plans") -@PreAuthorize("hasRole('user')") @RestController @RequestMapping("/plans") @RequiredArgsConstructor From c102f9220129b416a2c12158edf697b42529065d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Fri, 3 Mar 2023 13:25:55 +0100 Subject: [PATCH 97/97] Release 0.1.0 --- CHANGELOG.md | 5 ++++- README.md | 20 +++++++++++++++++++- pom.xml | 6 +----- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45a46ef..f94f153 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +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/README.md b/README.md index afaaf65..d545786 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,25 @@ Train Handler is intended to be used together with [client](https://github.com/FAIRDataTeam/TrainHandler-client) via Docker (unless for development purposes). -*To be done: repository with docker-compose and configuration* +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 diff --git a/pom.xml b/pom.xml index 5e2fa0f..261b696 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.fairdatatrain trainhandler - 0.0.1-SNAPSHOT + 0.1.0 Train Handler FAIR Data Train Handler @@ -47,10 +47,6 @@ 4.7.3.2 5.0.0 0.2.0 - - - 1.33 - 5.8.1