Merge pull request #25 from SCS-ASSE-FS21-Group1/dev

Deployment 0.0.1
This commit is contained in:
Marcel 2021-10-17 15:49:10 +02:00 committed by GitHub
commit 3a15756faf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
176 changed files with 7660 additions and 265 deletions

View File

@ -0,0 +1,108 @@
version: "3.0"
services:
reverse-proxy:
image: traefik:v2.1.3
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker=true
- --certificatesResolvers.le.acme.httpChallenge.entryPoint=web
- --certificatesresolvers.le.acme.email=martin.eigenmann@unisg.ch
- --certificatesresolvers.le.acme.storage=/acme.json
- --providers.docker.exposedByDefault=false
- --serversTransport.insecureSkipVerify=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./acme.json:/acme.json
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
tapas-tasks:
image: openjdk
command: "java -jar /data/tapas-tasks-0.0.1-SNAPSHOT.jar"
restart: unless-stopped
volumes:
- ./:/data/
labels:
- "traefik.enable=true"
- "traefik.http.routers.tapas-tasks.rule=Host(`tapas-tasks.${PUB_IP}.nip.io`)"
- "traefik.http.routers.tapas-tasks.service=tapas-tasks"
- "traefik.http.services.tapas-tasks.loadbalancer.server.port=8081"
- "traefik.http.routers.tapas-tasks.tls=true"
- "traefik.http.routers.tapas-tasks.entryPoints=web,websecure"
- "traefik.http.routers.tapas-tasks.tls.certresolver=le"
assignment:
image: openjdk
command: "java -jar /data/assignment-0.0.1.jar"
restart: unless-stopped
volumes:
- ./:/data/
labels:
- "traefik.enable=true"
- "traefik.http.routers.assignment.rule=Host(`assignment.${PUB_IP}.nip.io`)"
- "traefik.http.routers.assignment.service=assignment"
- "traefik.http.services.assignment.loadbalancer.server.port=8082"
- "traefik.http.routers.assignment.tls=true"
- "traefik.http.routers.assignment.entryPoints=web,websecure"
- "traefik.http.routers.assignment.tls.certresolver=le"
executor-pool:
image: openjdk
command: "java -jar /data/executor-pool-0.0.1.jar"
restart: unless-stopped
volumes:
- ./:/data/
labels:
- "traefik.enable=true"
- "traefik.http.routers.executor-pool.rule=Host(`executor-pool.${PUB_IP}.nip.io`)"
- "traefik.http.routers.executor-pool.service=executor-pool"
- "traefik.http.services.executor-pool.loadbalancer.server.port=8083"
- "traefik.http.routers.executor-pool.tls=true"
- "traefik.http.routers.executor-pool.entryPoints=web,websecure"
- "traefik.http.routers.executor-pool.tls.certresolver=le"
executor1:
image: openjdk
command: "java -jar /data/executor1-0.0.1.jar"
restart: unless-stopped
depends_on:
- executor-pool
- assignment
volumes:
- ./:/data/
labels:
- "traefik.enable=true"
- "traefik.http.routers.executor1.rule=Host(`executor1.${PUB_IP}.nip.io`)"
- "traefik.http.routers.executor1.service=executor1"
- "traefik.http.services.executor1.loadbalancer.server.port=8084"
- "traefik.http.routers.executor1.tls=true"
- "traefik.http.routers.executor1.entryPoints=web,websecure"
- "traefik.http.routers.executor1.tls.certresolver=le"
executor2:
image: openjdk
command: "java -jar /data/executor2-0.0.1.jar"
restart: unless-stopped
depends_on:
- executor-pool
- assignment
volumes:
- ./:/data/
labels:
- "traefik.enable=true"
- "traefik.http.routers.executor2.rule=Host(`executor2.${PUB_IP}.nip.io`)"
- "traefik.http.routers.executor2.service=executor2"
- "traefik.http.services.executor2.loadbalancer.server.port=8085"
- "traefik.http.routers.executor2.tls=true"
- "traefik.http.routers.executor2.entryPoints=web,websecure"
- "traefik.http.routers.executor2.tls.certresolver=le"

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
end_of_line = lf
insert_final_newline = true

View File

@ -4,78 +4,97 @@
name: Build and Deploy name: Build and Deploy
on: on:
push: push:
branches: branches:
- main - main
workflow_dispatch:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: read
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Set up JDK 11 - name: Set up JDK 11
uses: actions/setup-java@v2 uses: actions/setup-java@v2
with: with:
java-version: '11' java-version: "11"
distribution: 'adopt' distribution: "adopt"
- run: mkdir ./target
- run: mkdir ./target
- name: Build with Maven - name: Cache Maven packages
run: mvn -f tapas-tasks/pom.xml --batch-mode --update-snapshots verify uses: actions/cache@v1
- run: cp ./tapas-tasks/target/tapas-tasks-0.0.1-SNAPSHOT.jar ./target with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build with Maven - name: Build with Maven
run: mvn -f app/pom.xml --batch-mode --update-snapshots verify run: mvn -f assignment/pom.xml --batch-mode --update-snapshots verify
- run: cp ./app/target/app-0.1.0.jar ./target - run: cp ./assignment/target/assignment-0.0.1-SNAPSHOT.jar ./target
- run: cp docker-compose.yml ./target - name: Build with Maven
- name: Archive artifacts run: mvn -f executor-pool/pom.xml --batch-mode --update-snapshots verify
uses: actions/upload-artifact@v1 - run: cp ./executor-pool/target/executor-pool-0.0.1.jar ./target
with:
name: app
path: ./target/
deploy:
runs-on: ubuntu-latest
needs: [build, ]
steps:
- name: Download app artifacts
uses: actions/download-artifact@v1
with:
name: app
- name: Copy host via scp
uses: appleboy/scp-action@master
env:
HOST: ${{ secrets.SSH_HOST }}
USERNAME: ${{ secrets.SSH_USER }}
PORT: 22
KEY: ${{ secrets.SSH_PRIVATE_KEY }}
with:
source: "app/*"
target: "/home/${{ secrets.SSH_USER }}/"
strip_components: 1
rm: false
overwrite: true
- name: Executing remote command - name: Build with Maven
uses: appleboy/ssh-action@master run: mvn -f executorBase/pom.xml --batch-mode --update-snapshots install
with:
host: ${{ secrets.SSH_HOST }} - name: Build with Maven
USERNAME: ${{ secrets.SSH_USER }} run: mvn -f executor1/pom.xml --batch-mode --update-snapshots verify
PORT: 22 - run: cp ./executor1/target/executor1-0.0.1.jar ./target
KEY: ${{ secrets.SSH_PRIVATE_KEY }}
script: | - name: Build with Maven
cd /home/${{ secrets.SSH_USER }}/ run: mvn -f executor2/pom.xml --batch-mode --update-snapshots verify
touch acme.json - run: cp ./executor2/target/executor2-0.0.1.jar ./target
sudo chmod 0600 acme.json
sudo echo "PUB_IP=$(wget -qO- http://ipecho.net/plain | xargs echo)" | sed -e 's/\./-/g' > .env - name: Build with Maven
sudo docker-compose up -d run: mvn -f tapas-tasks/pom.xml --batch-mode --update-snapshots verify
- run: cp ./tapas-tasks/target/tapas-tasks-0.0.1.jar ./target
- run: cp ./.deployment/docker-compose.yml ./target
- name: Archive artifacts
uses: actions/upload-artifact@v1
with:
name: app
path: ./target/
deploy:
runs-on: ubuntu-latest
needs: [build]
steps:
- name: Download app artifacts
uses: actions/download-artifact@v1
with:
name: app
- name: Copy host via scp
uses: appleboy/scp-action@master
env:
HOST: ${{ secrets.SSH_HOST }}
USERNAME: ${{ secrets.SSH_USER }}
PORT: 22
KEY: ${{ secrets.SSH_PRIVATE_KEY }}
with:
source: "app/*"
target: "/home/${{ secrets.SSH_USER }}/"
strip_components: 1
rm: false
overwrite: true
- name: Executing remote command
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
USERNAME: ${{ secrets.SSH_USER }}
PORT: 22
KEY: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /home/${{ secrets.SSH_USER }}/
touch acme.json
sudo chmod 0600 acme.json
sudo echo "PUB_IP=$(wget -qO- http://ipecho.net/plain | xargs echo)" | sed -e 's/\./-/g' > .env
sudo docker-compose up -d

41
.github/workflows/ci.assignment.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: CI Assignment
on:
push:
branches: [main, dev]
paths:
- "assignment/**"
pull_request:
branches: [main, dev]
paths:
- "assignment/**"
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v1
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v1
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -f assignment/pom.xml -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=scs-asse-fs21-group1_tapas-assignment

41
.github/workflows/ci.executor-pool.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: CI Executor Pool
on:
push:
branches: [main, dev]
paths:
- "executor-pool/**"
pull_request:
branches: [main, dev]
paths:
- "executor-pool/**"
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v1
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v1
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -f executor-pool/pom.xml -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=scs-asse-fs21-group1_tapas-executor-pool

45
.github/workflows/ci.executor1.yml vendored Normal file
View File

@ -0,0 +1,45 @@
name: CI Executor 1
on:
push:
branches: [main, dev]
paths:
- "executor-base/**"
- "executor1/**"
pull_request:
branches: [main, dev]
paths:
- "executor-base/**"
- "executor1/**"
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v1
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v1
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build executorBase
run: mvn -f executor-base/pom.xml -B install
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -f executor1/pom.xml -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=scs-asse-fs21-group1_tapas-executor1

45
.github/workflows/ci.executor2.yml vendored Normal file
View File

@ -0,0 +1,45 @@
name: CI Executor 2
on:
push:
branches: [main, dev]
paths:
- "executor-base/**"
- "executor2/**"
pull_request:
branches: [main, dev]
paths:
- "executor-base/**"
- "executor2/**"
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v1
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v1
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build executorBase
run: mvn -f executor-base/pom.xml -B install
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -f executor2/pom.xml -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=scs-asse-fs21-group1_tapas-executor2

41
.github/workflows/ci.tapas-tasks.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: CI Tasks
on:
push:
branches: [main, dev]
paths:
- "tapas-tasks/**"
pull_request:
branches: [main, dev]
paths:
- "tapas-tasks/**"
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v1
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v1
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -f tapas-tasks/pom.xml -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=scs-asse-fs21-group1_tapas-tasks

4
.gitignore vendored
View File

@ -31,3 +31,7 @@ build/
### VS Code ### ### VS Code ###
.vscode/ .vscode/
### Mac ###
.DS_Store

145
README.md
View File

@ -1,62 +1,113 @@
# TAPAS # TAPAS
This is the main GitHub project for your implementation of the TAPAS application. This is the main GitHub project for your implementation of the TAPAS application.
## Run application in developent
We use Docker & docker-compose in development to easly start all the microservices and other needed application (db's, message-broker's) at once. All microservices have hot-reloads enabled by default!
#### Start
```
docker-compose up
```
#### Rebuild container
```
docker-compose up --build
```
#### Start detached
```
docker-compose up -d
```
#### Stop detached
```
docker-compose down
```
## Available Services
Ports and debug ports of each service are listed below:
| Name | Port | Debug Port |
| ------------------ | ---- | ---------- |
| Tasklist | 8081 | 5005 |
| Assignment Service | 8082 | 5006 |
| Executor Pool | 8083 | 5007 |
| Executor 1 | 8084 | 5008 |
| Executor 2 | 8085 | 5009 |
## Project Structure ## Project Structure
This project is structured as follows: This project is structured as follows:
* [tapas-tasks](tapas-tasks): standalone project for the Tapas-Tasks micro-service (Spring Boot project)
* [tapas-tasks/src](tapas-tasks/src): source code of the project (following the Hexagonal Architecture) - [tapas-tasks](tapas-tasks): standalone project for the Tapas-Tasks micro-service (Spring Boot project)
* [tapas-tasks/pom.xml](tapas-tasks\pom.xml): Maven pom-file - [tapas-tasks/src](tapas-tasks/src): source code of the project (following the Hexagonal Architecture)
* [app](app): folder as placeholder for a second micro-service (Spring Boot project) - [tapas-tasks/pom.xml](tapas-tasks\pom.xml): Maven pom-file
* [docker-compose.yml](docker-compose.yml): Docker Compose configuration file for all services - [app](app): folder as placeholder for a second micro-service (Spring Boot project)
* [.github/workflows/build-and-deploy.yml](.github/workflows/build-and-deploy.yml): GitHub actions script (CI/CD workflow) - [docker-compose.yml](docker-compose.yml): Docker Compose configuration file for all services
- [.github/workflows/build-and-deploy.yml](.github/workflows/build-and-deploy.yml): GitHub actions script (CI/CD workflow)
## How to Add a New Service with Spring Boot ## How to Add a New Service with Spring Boot
### Create a new Spring Boot project ### Create a new Spring Boot project
* Recommended: use [Spring Initialzr](https://start.spring.io/) (Maven, Spring Boot 2.5.5, Jar, Java 11, dependencies as needed) - Recommended: use [Spring Initialzr](https://start.spring.io/) (Maven, Spring Boot 2.5.5, Jar, Java 11, dependencies as needed)
* Set the Spring application properties for your service (e.g., port of the web server) in `src/resources/application.properties` - Set the Spring application properties for your service (e.g., port of the web server) in `src/resources/application.properties`
### Update the Docker Compose file ### Update the Docker Compose file
Your TAPAS application is a multi-container Docker application ran with [Docker Compose](https://docs.docker.com/compose/). Your TAPAS application is a multi-container Docker application ran with [Docker Compose](https://docs.docker.com/compose/).
To add your newly created service to the Docker Compose configuration file, you need to create a new service To add your newly created service to the Docker Compose configuration file, you need to create a new service
definition in [docker-compose.yml](docker-compose.yml): definition in [docker-compose.yml](docker-compose.yml):
* copy and edit the `tapas-tasks` service definition from [lines 29-42](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/docker-compose.yml#L29-L42)
* change `command` (see [line 31](https://github.com/scs-asse/tapas/blob/main/docker-compose.yml#L31)) - copy and edit the `tapas-tasks` service definition from [lines 29-42](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/docker-compose.yml#L29-L42)
to use the name of the JAR file generated by Maven for your service - change `command` (see [line 31](https://github.com/scs-asse/tapas/blob/main/docker-compose.yml#L31))
* note: if you change the version of your service, you need to update this line to reflect the change to use the name of the JAR file generated by Maven for your service
* update the Traefik label names to reflect the name of your new service (see [lines 37-42](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/docker-compose.yml#L37-L42)) - note: if you change the version of your service, you need to update this line to reflect the change
* e.g., change `traefik.http.routers.tapas-tasks.rule` to `traefik.http.routers.<new-service-name>.rule` - update the Traefik label names to reflect the name of your new service (see [lines 37-42](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/docker-compose.yml#L37-L42))
* update the Traefik `rule` (see [line 37](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/docker-compose.yml#L37)) with the name of your new service: ``Host(`<new-service-name>.${PUB_IP}.nip.io`)`` - e.g., change `traefik.http.routers.tapas-tasks.rule` to `traefik.http.routers.<new-service-name>.rule`
* update the Traefik `port` (see [line 39](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/docker-compose.yml#L39)) with the port configured for your new service - update the Traefik `rule` (see [line 37](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/docker-compose.yml#L37)) with the name of your new service: `` Host(`<new-service-name>.${PUB_IP}.nip.io`) ``
- update the Traefik `port` (see [line 39](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/docker-compose.yml#L39)) with the port configured for your new service
### Update the GitHub Actions Workflow ### Update the GitHub Actions Workflow
This project uses GitHub Actions to build and deploy your TAPAS application whenever a new commit is
pushed on the `main` branch. You can add your new service to the GitHub Actions workflow defined in This project uses GitHub Actions to build and deploy your TAPAS application whenever a new commit is
pushed on the `main` branch. You can add your new service to the GitHub Actions workflow defined in
[.github/workflows/build-and-deploy.yml](.github/workflows/build-and-deploy.yml): [.github/workflows/build-and-deploy.yml](.github/workflows/build-and-deploy.yml):
* copy and edit the definition for `tapas-tasks` from [line 28-30](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/.github/workflows/build-and-deploy.yml#L28-L30)
* update the `mvn` command used to build your service to point to the `pom.xml` file of your new service (see [line 29](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/.github/workflows/build-and-deploy.yml#L29)) - copy and edit the definition for `tapas-tasks` from [line 28-30](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/.github/workflows/build-and-deploy.yml#L28-L30)
* update the `cp` command to point to the JAR file of your new service directive (see [line 30](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/.github/workflows/build-and-deploy.yml#L30)) - update the `mvn` command used to build your service to point to the `pom.xml` file of your new service (see [line 29](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/.github/workflows/build-and-deploy.yml#L29))
* note you will need to update the complete file path (folder structure and JAR name) - update the `cp` command to point to the JAR file of your new service directive (see [line 30](https://github.com/scs-asse/tapas/blob/424a5f5aa2d6524acfe95d93000571884ed9d66f/.github/workflows/build-and-deploy.yml#L30))
- note you will need to update the complete file path (folder structure and JAR name)
### How to Run Your Service Locally ### How to Run Your Service Locally
You can run and test your micro-service on your local machine just like a regular Maven project: You can run and test your micro-service on your local machine just like a regular Maven project:
* Run from IntelliJ:
* Reload *pom.xml* if necessary - Run from IntelliJ:
* Run the micro-service's main class from IntelliJ for all required projects - Reload _pom.xml_ if necessary
* Use Maven to run from the command line: - Run the micro-service's main class from IntelliJ for all required projects
- Use Maven to run from the command line:
```shell ```shell
mvn spring-boot:run mvn spring-boot:run
``` ```
## How to Deploy on your VM ## How to Deploy on your VM
1. Start your Ubuntu VM on Switch. 1. Start your Ubuntu VM on Switch.
* VM shuts down automatically at 2 AM - VM shuts down automatically at 2 AM
* Group admins can do this via https://engines.switch.ch/horizon - Group admins can do this via https://engines.switch.ch/horizon
2. Push new code to the *main* branch 2. Push new code to the _main_ branch
* Check the status of the workflow on the *Actions* page of the GitHub project - Check the status of the workflow on the _Actions_ page of the GitHub project
* We recommend to test your project locally before pushing the code to GitHub. The GitHub Organizations - We recommend to test your project locally before pushing the code to GitHub. The GitHub Organizations
used in the course are on a free tier plan, which comes with [various limits](https://github.com/pricing). used in the course are on a free tier plan, which comes with [various limits](https://github.com/pricing).
3. Open in your browser `https://app.<server-ip>.nip.io` 3. Open in your browser `https://app.<server-ip>.nip.io`
For the server IP address (see below), you should use dashes instead of dots, e.g.: `127.0.0.1` becomes `127-0-0-1`. For the server IP address (see below), you should use dashes instead of dots, e.g.: `127.0.0.1` becomes `127-0-0-1`.
@ -64,19 +115,21 @@ For the server IP address (see below), you should use dashes instead of dots, e.
## VM Configurations ## VM Configurations
Specs (we can upgrade if needed): Specs (we can upgrade if needed):
* 1 CPU
* 2 GB RAM
* 20 GB HD
* Ubuntu 20.04
| Name | Server IP | - 1 CPU
|-------|-----------| - 2 GB RAM
|SCS-ASSE-VM-Group1|86.119.35.40| - 20 GB HD
|SCS-ASSE-VM-Group2|86.119.35.213| - Ubuntu 20.04
|SCS-ASSE-VM-Group3|86.119.34.242|
|SCS-ASSE-VM-Group4|86.119.35.199| | Name | Server IP |
|SCS-ASSE-VM-Group5|86.119.35.72| | ------------------ | ------------- |
| SCS-ASSE-VM-Group1 | 86.119.35.40 |
| SCS-ASSE-VM-Group2 | 86.119.35.213 |
| SCS-ASSE-VM-Group3 | 86.119.34.242 |
| SCS-ASSE-VM-Group4 | 86.119.35.199 |
| SCS-ASSE-VM-Group5 | 86.119.35.72 |
## Architecture Decision Records ## Architecture Decision Records
We recommend you to use [adr-tools](https://github.com/npryce/adr-tools) to manage your ADRs here in
this GitHub project in a dedicated folder. The tool works best on a Mac OS or Linux machine. We recommend you to use [adr-tools](https://github.com/npryce/adr-tools) to manage your ADRs here in
this GitHub project in a dedicated folder. The tool works best on a Mac OS or Linux machine.

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dockerforjavadevelopers</groupId>
<artifactId>app</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<start-class>com.dockerforjavadevelopers.hello.Application</start-class>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,19 +0,0 @@
package com.dockerforjavadevelopers.hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}

View File

@ -1,13 +0,0 @@
package com.dockerforjavadevelopers.hello;
import static org.junit.Assert.*;
import org.junit.Test;
public class DummyTest {
@Test
public void aTest() {
assertEquals(true, true);
}
}

33
assignment/.gitignore vendored Normal file
View File

@ -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/

View File

@ -0,0 +1,117 @@
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

Binary file not shown.

View File

@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

18
assignment/Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM openjdk:11 AS development
WORKDIR /opt/app
# ENV SPRING_DATASOURCE_URL=jdbc:mysql://backend-db:3306/db
COPY .mvn/ .mvn
COPY mvnw pom.xml mvnw.cmd ./
RUN apt-get clean && apt-get update && apt-get install dos2unix
RUN dos2unix mvnw
RUN ./mvnw dependency:go-offline
COPY src /opt/app/src
COPY *target /opt/app/target
CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.jvmArguments=\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005\"", "-Dspring.devtools.restart.enabled=true"]

310
assignment/mvnw vendored Executable file
View File

@ -0,0 +1,310 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

182
assignment/mvnw.cmd vendored Normal file
View File

@ -0,0 +1,182 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

85
assignment/pom.xml Normal file
View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ch.unisg</groupId>
<artifactId>assignment</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>assignment</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<sonar.organization>scs-asse-fs21-group1</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,13 @@
package ch.unisg.assignment;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AssignmentApplication {
public static void main(String[] args) {
SpringApplication.run(AssignmentApplication.class, args);
}
}

View File

@ -0,0 +1,29 @@
package ch.unisg.assignment.assignment.adapter.in.web;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import ch.unisg.assignment.assignment.application.port.in.ApplyForTaskCommand;
import ch.unisg.assignment.assignment.application.port.in.ApplyForTaskUseCase;
import ch.unisg.assignment.assignment.domain.ExecutorInfo;
import ch.unisg.assignment.assignment.domain.Task;
@RestController
public class ApplyForTaskController {
private final ApplyForTaskUseCase applyForTaskUseCase;
public ApplyForTaskController(ApplyForTaskUseCase applyForTaskUseCase) {
this.applyForTaskUseCase = applyForTaskUseCase;
}
@PostMapping(path = "/task/apply", consumes = {"application/json"})
public Task applyForTask(@RequestBody ExecutorInfo executorInfo) {
ApplyForTaskCommand command = new ApplyForTaskCommand(executorInfo.getExecutorType(),
executorInfo.getIp(), executorInfo.getPort());
return applyForTaskUseCase.applyForTask(command);
}
}

View File

@ -0,0 +1,34 @@
package ch.unisg.assignment.assignment.adapter.in.web;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import ch.unisg.assignment.assignment.application.port.in.NewTaskCommand;
import ch.unisg.assignment.assignment.application.port.in.NewTaskUseCase;
import ch.unisg.assignment.assignment.domain.Task;
@RestController
public class NewTaskController {
private final NewTaskUseCase newTaskUseCase;
public NewTaskController(NewTaskUseCase newTaskUseCase) {
this.newTaskUseCase = newTaskUseCase;
}
@PostMapping(path = "/task", consumes = {"application/json"})
public ResponseEntity<Void> newTaskController(@RequestBody Task task) {
NewTaskCommand command = new NewTaskCommand(task.getTaskID(), task.getTaskType());
boolean success = newTaskUseCase.addNewTaskToQueue(command);
if (success) {
return new ResponseEntity<>(HttpStatus.CREATED);
}
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
}

View File

@ -0,0 +1,34 @@
package ch.unisg.assignment.assignment.adapter.in.web;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import ch.unisg.assignment.assignment.application.port.in.TaskCompletedCommand;
import ch.unisg.assignment.assignment.application.port.in.TaskCompletedUseCase;
import ch.unisg.assignment.assignment.domain.Task;
@RestController
public class TaskCompletedController {
private final TaskCompletedUseCase taskCompletedUseCase;
public TaskCompletedController(TaskCompletedUseCase taskCompletedUseCase) {
this.taskCompletedUseCase = taskCompletedUseCase;
}
@PostMapping(path = "/task/completed", consumes = {"application/json"})
public ResponseEntity<Void> addNewTaskTaskToTaskList(@RequestBody Task task) {
TaskCompletedCommand command = new TaskCompletedCommand(task.getTaskID(),
task.getStatus(), task.getResult());
taskCompletedUseCase.taskCompleted(command);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -0,0 +1,31 @@
package ch.unisg.assignment.assignment.adapter.in.web;
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 ch.unisg.assignment.common.exception.ErrorResponse;
import ch.unisg.assignment.common.exception.InvalidIP4Exception;
import ch.unisg.assignment.common.exception.PortOutOfRangeException;
@ControllerAdvice
public class WebControllerExceptionHandler {
@ExceptionHandler(PortOutOfRangeException.class)
public ResponseEntity<ErrorResponse> handleException(PortOutOfRangeException e){
ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST, e.getLocalizedMessage());
return new ResponseEntity<>(error, error.getHttpStatus());
}
@ExceptionHandler(InvalidIP4Exception.class)
public ResponseEntity<ErrorResponse> handleException(InvalidIP4Exception e){
ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST, e.getLocalizedMessage());
return new ResponseEntity<>(error, error.getHttpStatus());
}
}

View File

@ -0,0 +1,55 @@
package ch.unisg.assignment.assignment.adapter.out.web;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import ch.unisg.assignment.assignment.application.port.out.GetAllExecutorInExecutorPoolByTypePort;
import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType;
@Component
@Primary
public class GetAllExecutorInExecutorPoolByTypeAdapter implements GetAllExecutorInExecutorPoolByTypePort {
@Override
public boolean doesExecutorTypeExist(ExecutorType type) {
String server = "http://127.0.0.1:8083";
Logger logger = Logger.getLogger(PublishNewTaskEventAdapter.class.getName());
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server + "/executor-pool/GetAllExecutorInExecutorPoolByType/" + type.getValue()))
.header("Content-Type", "application/json")
.GET()
.build();
try {
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == HttpStatus.OK.value()) {
JSONArray jsonArray = new JSONArray(response.body().toString());
if (jsonArray.length() > 0) {
return true;
}
}
} catch (IOException | InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Restore interrupted state...
Thread.currentThread().interrupt();
}
return false;
}
}

View File

@ -0,0 +1,60 @@
package ch.unisg.assignment.assignment.adapter.out.web;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import ch.unisg.assignment.assignment.application.port.out.NewTaskEventPort;
import ch.unisg.assignment.assignment.domain.event.NewTaskEvent;
@Component
@Primary
public class PublishNewTaskEventAdapter implements NewTaskEventPort {
String server = "http://127.0.0.1:8084";
String server2 = "http://127.0.0.1:8085";
Logger logger = Logger.getLogger(PublishNewTaskEventAdapter.class.getName());
@Override
public void publishNewTaskEvent(NewTaskEvent event) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server + "/newtask/" + event.taskType.getValue()))
.GET()
.build();
try {
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Restore interrupted state...
Thread.currentThread().interrupt();
}
HttpClient client2 = HttpClient.newHttpClient();
HttpRequest request2 = HttpRequest.newBuilder()
.uri(URI.create(server2 + "/newtask/" + event.taskType.getValue()))
.GET()
.build();
try {
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Restore interrupted state...
Thread.currentThread().interrupt();
}
}
}

View File

@ -0,0 +1,50 @@
package ch.unisg.assignment.assignment.adapter.out.web;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONObject;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import ch.unisg.assignment.assignment.application.port.out.TaskAssignedEventPort;
import ch.unisg.assignment.assignment.domain.event.TaskAssignedEvent;
@Component
@Primary
public class PublishTaskAssignedEventAdapter implements TaskAssignedEventPort {
String server = "http://127.0.0.1:8081";
Logger logger = Logger.getLogger(PublishTaskAssignedEventAdapter.class.getName());
@Override
public void publishTaskAssignedEvent(TaskAssignedEvent event) {
String body = new JSONObject()
.put("taskId", event.taskID)
.toString();
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server + "/tasks/assignTask"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
try {
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Restore interrupted state...
Thread.currentThread().interrupt();
}
}
}

View File

@ -0,0 +1,53 @@
package ch.unisg.assignment.assignment.adapter.out.web;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONObject;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import ch.unisg.assignment.assignment.application.port.out.TaskCompletedEventPort;
import ch.unisg.assignment.assignment.domain.event.TaskCompletedEvent;
@Component
@Primary
public class PublishTaskCompletedEventAdapter implements TaskCompletedEventPort {
String server = "http://127.0.0.1:8081";
Logger logger = Logger.getLogger(PublishTaskCompletedEventAdapter.class.getName());
@Override
public void publishTaskCompleted(TaskCompletedEvent event) {
String body = new JSONObject()
.put("taskId", event.taskID)
.put("status", event.status)
.put("taskResult", event.result)
.toString();
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server + "/tasks/completeTask"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
try {
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Restore interrupted state...
Thread.currentThread().interrupt();
}
}
}

View File

@ -0,0 +1,32 @@
package ch.unisg.assignment.assignment.application.port.in;
import javax.validation.constraints.NotNull;
import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType;
import ch.unisg.assignment.assignment.domain.valueobject.IP4Adress;
import ch.unisg.assignment.assignment.domain.valueobject.Port;
import ch.unisg.assignment.common.SelfValidating;
import lombok.EqualsAndHashCode;
import lombok.Value;
@Value
@EqualsAndHashCode(callSuper=false)
public class ApplyForTaskCommand extends SelfValidating<ApplyForTaskCommand>{
@NotNull
private final ExecutorType taskType;
@NotNull
private final IP4Adress executorIP;
@NotNull
private final Port executorPort;
public ApplyForTaskCommand(ExecutorType taskType, IP4Adress executorIP, Port executorPort) {
this.taskType = taskType;
this.executorIP = executorIP;
this.executorPort = executorPort;
this.validateSelf();
}
}

View File

@ -0,0 +1,7 @@
package ch.unisg.assignment.assignment.application.port.in;
import ch.unisg.assignment.assignment.domain.Task;
public interface ApplyForTaskUseCase {
Task applyForTask(ApplyForTaskCommand applyForTaskCommand);
}

View File

@ -0,0 +1,25 @@
package ch.unisg.assignment.assignment.application.port.in;
import javax.validation.constraints.NotNull;
import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType;
import ch.unisg.assignment.common.SelfValidating;
import lombok.EqualsAndHashCode;
import lombok.Value;
@Value
@EqualsAndHashCode(callSuper=false)
public class NewTaskCommand extends SelfValidating<NewTaskCommand> {
@NotNull
private final String taskID;
@NotNull
private final ExecutorType taskType;
public NewTaskCommand(String taskID, ExecutorType taskType) {
this.taskID = taskID;
this.taskType = taskType;
this.validateSelf();
}
}

View File

@ -0,0 +1,5 @@
package ch.unisg.assignment.assignment.application.port.in;
public interface NewTaskUseCase {
boolean addNewTaskToQueue(NewTaskCommand newTaskCommand);
}

View File

@ -0,0 +1,29 @@
package ch.unisg.assignment.assignment.application.port.in;
import javax.validation.constraints.NotNull;
import ch.unisg.assignment.common.SelfValidating;
import lombok.EqualsAndHashCode;
import lombok.Value;
@Value
@EqualsAndHashCode(callSuper=false)
public class TaskCompletedCommand extends SelfValidating<TaskCompletedCommand>{
@NotNull
private final String taskID;
@NotNull
private final String taskStatus;
@NotNull
private final String taskResult;
public TaskCompletedCommand(String taskID, String taskStatus, String taskResult) {
this.taskID = taskID;
this.taskStatus = taskStatus;
this.taskResult = taskResult;
this.validateSelf();
}
}

View File

@ -0,0 +1,5 @@
package ch.unisg.assignment.assignment.application.port.in;
public interface TaskCompletedUseCase {
void taskCompleted(TaskCompletedCommand taskCompletedCommand);
}

View File

@ -0,0 +1,9 @@
package ch.unisg.assignment.assignment.application.port.out;
import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType;
public interface GetAllExecutorInExecutorPoolByTypePort {
boolean doesExecutorTypeExist(ExecutorType type);
}

View File

@ -0,0 +1,7 @@
package ch.unisg.assignment.assignment.application.port.out;
import ch.unisg.assignment.assignment.domain.event.NewTaskEvent;
public interface NewTaskEventPort {
void publishNewTaskEvent(NewTaskEvent event);
}

View File

@ -0,0 +1,7 @@
package ch.unisg.assignment.assignment.application.port.out;
import ch.unisg.assignment.assignment.domain.event.TaskAssignedEvent;
public interface TaskAssignedEventPort {
void publishTaskAssignedEvent(TaskAssignedEvent taskAssignedEvent);
}

View File

@ -0,0 +1,7 @@
package ch.unisg.assignment.assignment.application.port.out;
import ch.unisg.assignment.assignment.domain.event.TaskCompletedEvent;
public interface TaskCompletedEventPort {
void publishTaskCompleted(TaskCompletedEvent event);
}

View File

@ -0,0 +1,34 @@
package ch.unisg.assignment.assignment.application.service;
import javax.transaction.Transactional;
import org.springframework.stereotype.Component;
import ch.unisg.assignment.assignment.application.port.in.ApplyForTaskCommand;
import ch.unisg.assignment.assignment.application.port.in.ApplyForTaskUseCase;
import ch.unisg.assignment.assignment.application.port.out.TaskAssignedEventPort;
import ch.unisg.assignment.assignment.domain.Roster;
import ch.unisg.assignment.assignment.domain.Task;
import ch.unisg.assignment.assignment.domain.event.TaskAssignedEvent;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Component
@Transactional
public class ApplyForTaskService implements ApplyForTaskUseCase {
private final TaskAssignedEventPort taskAssignedEventPort;
@Override
public Task applyForTask(ApplyForTaskCommand command) {
Task task = Roster.getInstance().assignTaskToExecutor(command.getTaskType(),
command.getExecutorIP(), command.getExecutorPort());
if (task != null) {
taskAssignedEventPort.publishTaskAssignedEvent(new TaskAssignedEvent(task.getTaskID()));
}
return task;
}
}

View File

@ -0,0 +1,46 @@
package ch.unisg.assignment.assignment.application.service;
import java.util.Arrays;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.stereotype.Component;
import ch.unisg.assignment.assignment.application.port.in.NewTaskCommand;
import ch.unisg.assignment.assignment.application.port.in.NewTaskUseCase;
import ch.unisg.assignment.assignment.application.port.out.GetAllExecutorInExecutorPoolByTypePort;
import ch.unisg.assignment.assignment.application.port.out.NewTaskEventPort;
import ch.unisg.assignment.assignment.domain.Roster;
import ch.unisg.assignment.assignment.domain.Task;
import ch.unisg.assignment.assignment.domain.event.NewTaskEvent;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Component
@Transactional
public class NewTaskService implements NewTaskUseCase {
private final NewTaskEventPort newTaskEventPort;
private final GetAllExecutorInExecutorPoolByTypePort getAllExecutorInExecutorPoolByTypePort;
@Override
public boolean addNewTaskToQueue(NewTaskCommand command) {
// TODO Get availableTaskTypes from executor pool
if (!getAllExecutorInExecutorPoolByTypePort.doesExecutorTypeExist(command.getTaskType())) {
return false;
}
Task task = new Task(command.getTaskID(), command.getTaskType());
Roster.getInstance().addTaskToQueue(task);
// TODO this event should be in the roster function xyz
NewTaskEvent newTaskEvent = new NewTaskEvent(task.getTaskType());
newTaskEventPort.publishNewTaskEvent(newTaskEvent);
return true;
}
}

View File

@ -0,0 +1,31 @@
package ch.unisg.assignment.assignment.application.service;
import javax.transaction.Transactional;
import org.springframework.stereotype.Component;
import ch.unisg.assignment.assignment.application.port.in.TaskCompletedCommand;
import ch.unisg.assignment.assignment.application.port.in.TaskCompletedUseCase;
import ch.unisg.assignment.assignment.application.port.out.TaskCompletedEventPort;
import ch.unisg.assignment.assignment.domain.Roster;
import ch.unisg.assignment.assignment.domain.event.TaskCompletedEvent;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Component
@Transactional
public class TaskCompletedService implements TaskCompletedUseCase {
private final TaskCompletedEventPort taskCompletedEventPort;
@Override
public void taskCompleted(TaskCompletedCommand command) {
Roster.getInstance().taskCompleted(command.getTaskID());
taskCompletedEventPort.publishTaskCompleted(new TaskCompletedEvent(command.getTaskID(),
command.getTaskStatus(), command.getTaskResult()));
}
}

View File

@ -0,0 +1,21 @@
package ch.unisg.assignment.assignment.domain;
import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType;
import ch.unisg.assignment.assignment.domain.valueobject.IP4Adress;
import ch.unisg.assignment.assignment.domain.valueobject.Port;
import lombok.Getter;
import lombok.Setter;
public class ExecutorInfo {
@Getter
@Setter
private IP4Adress ip;
@Getter
@Setter
private Port port;
@Getter
@Setter
private ExecutorType executorType;
}

View File

@ -0,0 +1,53 @@
package ch.unisg.assignment.assignment.domain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType;
import ch.unisg.assignment.assignment.domain.valueobject.IP4Adress;
import ch.unisg.assignment.assignment.domain.valueobject.Port;
public class Roster {
private static final Roster roster = new Roster();
private HashMap<String, ArrayList<Task>> queues = new HashMap<>();
private HashMap<String, RosterItem> rosterMap = new HashMap<>();
public static Roster getInstance() {
return roster;
}
private Roster() {}
public void addTaskToQueue(Task task) {
if (queues.containsKey(task.getTaskType().getValue())) {
queues.get(task.getTaskType().getValue()).add(task);
} else {
queues.put(task.getTaskType().getValue(), new ArrayList<>(Arrays.asList(task)));
}
}
public Task assignTaskToExecutor(ExecutorType taskType, IP4Adress executorIP, Port executorPort) {
if (!queues.containsKey(taskType.getValue())) {
return null;
}
if (queues.get(taskType.getValue()).isEmpty()) {
return null;
}
Task task = queues.get(taskType.getValue()).remove(0);
rosterMap.put(task.getTaskID(), new RosterItem(task.getTaskID(),
task.getTaskType().getValue(), executorIP, executorPort));
return task;
}
public void taskCompleted(String taskID) {
rosterMap.remove(taskID);
}
}

View File

@ -0,0 +1,29 @@
package ch.unisg.assignment.assignment.domain;
import ch.unisg.assignment.assignment.domain.valueobject.IP4Adress;
import ch.unisg.assignment.assignment.domain.valueobject.Port;
import lombok.Getter;
public class RosterItem {
@Getter
private String taskID;
@Getter
private String taskType;
@Getter
private IP4Adress executorIP;
@Getter
private Port executorPort;
public RosterItem(String taskID, String taskType, IP4Adress executorIP, Port executorPort) {
this.taskID = taskID;
this.taskType = taskType;
this.executorIP = executorIP;
this.executorPort = executorPort;
}
}

View File

@ -0,0 +1,35 @@
package ch.unisg.assignment.assignment.domain;
import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType;
import lombok.Getter;
import lombok.Setter;
public class Task {
@Getter
private String taskID;
@Getter
private ExecutorType taskType;
@Getter
@Setter
private String result;
@Getter
@Setter
private String status;
public Task(String taskID, String taskType) {
this.taskID = taskID;
this.taskType = new ExecutorType(taskType);
}
public Task(String taskID, ExecutorType taskType) {
this.taskID = taskID;
this.taskType = taskType;
}
public Task() {}
}

View File

@ -0,0 +1,11 @@
package ch.unisg.assignment.assignment.domain.event;
import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType;
public class NewTaskEvent {
public final ExecutorType taskType;
public NewTaskEvent(ExecutorType taskType) {
this.taskType = taskType;
}
}

View File

@ -0,0 +1,9 @@
package ch.unisg.assignment.assignment.domain.event;
public class TaskAssignedEvent {
public final String taskID;
public TaskAssignedEvent(String taskID) {
this.taskID = taskID;
}
}

View File

@ -0,0 +1,15 @@
package ch.unisg.assignment.assignment.domain.event;
public class TaskCompletedEvent {
public final String taskID;
public final String status;
public final String result;
public TaskCompletedEvent(String taskID, String status, String result) {
this.taskID = taskID;
this.status = status;
this.result = result;
}
}

View File

@ -0,0 +1,12 @@
package ch.unisg.assignment.assignment.domain.valueobject;
import lombok.Value;
@Value
public class ExecutorType {
private String value;
public ExecutorType(String type) {
this.value = type.toUpperCase();
}
}

View File

@ -0,0 +1,23 @@
package ch.unisg.assignment.assignment.domain.valueobject;
import ch.unisg.assignment.common.exception.InvalidIP4Exception;
import lombok.Value;
@Value
public class IP4Adress {
private String value;
public IP4Adress(String ip4) throws InvalidIP4Exception {
if (ip4.equalsIgnoreCase("localhost") ||
ip4.matches("^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)(\\.(?!$)|$)){4}$")) {
this.value = ip4;
} else {
throw new InvalidIP4Exception();
}
}
}

View File

@ -0,0 +1,17 @@
package ch.unisg.assignment.assignment.domain.valueobject;
import ch.unisg.assignment.common.exception.PortOutOfRangeException;
import lombok.Value;
@Value
public class Port {
private int value;
public Port(int port) throws PortOutOfRangeException {
if (1024 <= port && port <= 65535) {
this.value = port;
} else {
throw new PortOutOfRangeException();
}
}
}

View File

@ -0,0 +1,31 @@
package ch.unisg.assignment.common;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set;
public abstract class SelfValidating<T> {
private Validator validator;
protected SelfValidating() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
/**
* Evaluates all Bean Validations on the attributes of this
* instance.
*/
protected void validateSelf() {
@SuppressWarnings("unchecked")
Set<ConstraintViolation<T>> violations = validator.validate((T) this);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
}
}

View File

@ -0,0 +1,13 @@
package ch.unisg.assignment.common.exception;
import org.springframework.http.HttpStatus;
import lombok.Data;
import lombok.RequiredArgsConstructor;
@Data
@RequiredArgsConstructor
public class ErrorResponse {
private final HttpStatus httpStatus;
private final String message;
}

View File

@ -0,0 +1,7 @@
package ch.unisg.assignment.common.exception;
public class InvalidIP4Exception extends Exception {
public InvalidIP4Exception() {
super("IP4 is invalid");
}
}

View File

@ -0,0 +1,7 @@
package ch.unisg.assignment.common.exception;
public class PortOutOfRangeException extends Exception {
public PortOutOfRangeException() {
super("Port is out of available range (1024-65535)");
}
}

View File

@ -0,0 +1 @@
server.port=8082

View File

@ -0,0 +1,13 @@
package ch.unisg.assignment;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class AssignmentApplicationTests {
@Test
void contextLoads() {
}
}

653
diagram_1.bpmn Normal file
View File

@ -0,0 +1,653 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0qxgodh" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.8.1" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:collaboration id="Collaboration_0anvhsf">
<bpmn:participant id="Participant_0q8hukc" name="Create Task" processRef="Process_0g1u0dm" />
<bpmn:participant id="Participant_143daut" name="Executor Ideling" processRef="Process_0s8woey" />
<bpmn:participant id="Participant_1q0bjfl" name="Request more executors" processRef="Process_0p5wk5x" />
<bpmn:participant id="Participant_062djli" name="Executor Requests for work" processRef="Process_1iep78l" />
<bpmn:participant id="Participant_1ova0gb" name="Executor finish task" processRef="Process_102ufh8" />
<bpmn:messageFlow id="Flow_1xo6v1g" sourceRef="Activity_0u3tts0" targetRef="Activity_1q87dyp" />
</bpmn:collaboration>
<bpmn:process id="Process_0g1u0dm" isExecutable="false">
<bpmn:laneSet id="LaneSet_1lcmyw6">
<bpmn:lane id="Lane_1qeq039" name="Assignment Service">
<bpmn:flowNodeRef>Gateway_1vd3as7</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_1jd11bs</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Gateway_1e4ckdq</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_1dl4fvt</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Gateway_1e3rabp</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_1lm6x5y</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_1ysgenb</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_00rvb9o</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0u3tts0</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0vs4eam</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0mwpp9o</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_0v7hm2z</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0paecdb</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0srcl99</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0assw9c</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_12khd4k" name="Task Service">
<bpmn:flowNodeRef>Activity_0jai885</bpmn:flowNodeRef>
<bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef>
</bpmn:lane>
</bpmn:laneSet>
<bpmn:exclusiveGateway id="Gateway_1vd3as7">
<bpmn:incoming>Flow_1hc51tx</bpmn:incoming>
<bpmn:outgoing>Flow_1sajzlx</bpmn:outgoing>
<bpmn:outgoing>Flow_1ijfkpz</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:task id="Activity_1jd11bs" name="Check if more tasks of the same are in a queue">
<bpmn:incoming>Flow_1sajzlx</bpmn:incoming>
<bpmn:outgoing>Flow_0cpd5ad</bpmn:outgoing>
</bpmn:task>
<bpmn:exclusiveGateway id="Gateway_1e4ckdq">
<bpmn:incoming>Flow_0cpd5ad</bpmn:incoming>
<bpmn:outgoing>Flow_0kwvrmc</bpmn:outgoing>
<bpmn:outgoing>Flow_1w3uh2m</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:task id="Activity_1dl4fvt" name="Add task to queue">
<bpmn:incoming>Flow_0kwvrmc</bpmn:incoming>
<bpmn:outgoing>Flow_0vpcut0</bpmn:outgoing>
</bpmn:task>
<bpmn:exclusiveGateway id="Gateway_1e3rabp">
<bpmn:incoming>Flow_0vpcut0</bpmn:incoming>
<bpmn:outgoing>Flow_179e0hl</bpmn:outgoing>
<bpmn:outgoing>Flow_12nh0g5</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:endEvent id="Event_1lm6x5y">
<bpmn:incoming>Flow_179e0hl</bpmn:incoming>
</bpmn:endEvent>
<bpmn:endEvent id="Event_1ysgenb">
<bpmn:incoming>Flow_0366zqm</bpmn:incoming>
</bpmn:endEvent>
<bpmn:endEvent id="Event_00rvb9o">
<bpmn:incoming>Flow_1n8jm89</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sendTask id="Activity_0u3tts0" name="Let executors know that there is work">
<bpmn:incoming>Flow_1w3uh2m</bpmn:incoming>
<bpmn:outgoing>Flow_1n8jm89</bpmn:outgoing>
</bpmn:sendTask>
<bpmn:task id="Activity_0jai885" name="Create Task">
<bpmn:incoming>Flow_19dbo28</bpmn:incoming>
<bpmn:outgoing>Flow_1rwgf2n</bpmn:outgoing>
</bpmn:task>
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_19dbo28</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Activity_0vs4eam" name="Request auctionshouse completion">
<bpmn:incoming>Flow_1ijfkpz</bpmn:incoming>
<bpmn:outgoing>Flow_1gvdy5x</bpmn:outgoing>
</bpmn:task>
<bpmn:task id="Activity_0mwpp9o" name="Some currently unknown Auctionhouse logic">
<bpmn:incoming>Flow_1gvdy5x</bpmn:incoming>
<bpmn:outgoing>Flow_1yxp4e8</bpmn:outgoing>
</bpmn:task>
<bpmn:endEvent id="Event_0v7hm2z">
<bpmn:incoming>Flow_1yxp4e8</bpmn:incoming>
</bpmn:endEvent>
<bpmn:task id="Activity_0paecdb" name="Checks if task can be handled internaly">
<bpmn:incoming>Flow_1rwgf2n</bpmn:incoming>
<bpmn:outgoing>Flow_1hc51tx</bpmn:outgoing>
</bpmn:task>
<bpmn:task id="Activity_0srcl99" name="(This can be checked here bc we are caching infos from the executor pool)" />
<bpmn:subProcess id="Activity_0assw9c" name="Request more executors">
<bpmn:incoming>Flow_12nh0g5</bpmn:incoming>
<bpmn:outgoing>Flow_0366zqm</bpmn:outgoing>
</bpmn:subProcess>
<bpmn:sequenceFlow id="Flow_1hc51tx" sourceRef="Activity_0paecdb" targetRef="Gateway_1vd3as7" />
<bpmn:sequenceFlow id="Flow_1sajzlx" name="Yes" sourceRef="Gateway_1vd3as7" targetRef="Activity_1jd11bs" />
<bpmn:sequenceFlow id="Flow_0cpd5ad" sourceRef="Activity_1jd11bs" targetRef="Gateway_1e4ckdq" />
<bpmn:sequenceFlow id="Flow_0kwvrmc" name="Yes" sourceRef="Gateway_1e4ckdq" targetRef="Activity_1dl4fvt" />
<bpmn:sequenceFlow id="Flow_0vpcut0" name="Are more than X tasks in queue?" sourceRef="Activity_1dl4fvt" targetRef="Gateway_1e3rabp" />
<bpmn:sequenceFlow id="Flow_179e0hl" name="No" sourceRef="Gateway_1e3rabp" targetRef="Event_1lm6x5y" />
<bpmn:sequenceFlow id="Flow_12nh0g5" name="Yes" sourceRef="Gateway_1e3rabp" targetRef="Activity_0assw9c" />
<bpmn:sequenceFlow id="Flow_0366zqm" sourceRef="Activity_0assw9c" targetRef="Event_1ysgenb" />
<bpmn:sequenceFlow id="Flow_1w3uh2m" name="No" sourceRef="Gateway_1e4ckdq" targetRef="Activity_0u3tts0" />
<bpmn:sequenceFlow id="Flow_1n8jm89" sourceRef="Activity_0u3tts0" targetRef="Event_00rvb9o" />
<bpmn:sequenceFlow id="Flow_1rwgf2n" sourceRef="Activity_0jai885" targetRef="Activity_0paecdb" />
<bpmn:sequenceFlow id="Flow_19dbo28" sourceRef="StartEvent_1" targetRef="Activity_0jai885" />
<bpmn:sequenceFlow id="Flow_1gvdy5x" sourceRef="Activity_0vs4eam" targetRef="Activity_0mwpp9o" />
<bpmn:sequenceFlow id="Flow_1ijfkpz" name="No" sourceRef="Gateway_1vd3as7" targetRef="Activity_0vs4eam" />
<bpmn:sequenceFlow id="Flow_1yxp4e8" sourceRef="Activity_0mwpp9o" targetRef="Event_0v7hm2z" />
</bpmn:process>
<bpmn:process id="Process_0s8woey" isExecutable="false">
<bpmn:receiveTask id="Activity_1q87dyp" name="Gets information about work">
<bpmn:outgoing>Flow_119ldsr</bpmn:outgoing>
</bpmn:receiveTask>
<bpmn:endEvent id="Event_170rm9y">
<bpmn:incoming>Flow_1mm9swr</bpmn:incoming>
</bpmn:endEvent>
<bpmn:subProcess id="Activity_0h1d3g9" name="Executor Requests for work">
<bpmn:incoming>Flow_119ldsr</bpmn:incoming>
<bpmn:outgoing>Flow_1mm9swr</bpmn:outgoing>
</bpmn:subProcess>
<bpmn:sequenceFlow id="Flow_119ldsr" sourceRef="Activity_1q87dyp" targetRef="Activity_0h1d3g9" />
<bpmn:sequenceFlow id="Flow_1mm9swr" sourceRef="Activity_0h1d3g9" targetRef="Event_170rm9y" />
</bpmn:process>
<bpmn:process id="Process_0p5wk5x" isExecutable="false">
<bpmn:laneSet id="LaneSet_1r5f5iw">
<bpmn:lane id="Lane_06e7su5" name="Assignment Service">
<bpmn:flowNodeRef>Event_0v73rhy</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0n8uuvk</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_1lg2d2q" name="Execturo Pool">
<bpmn:flowNodeRef>Activity_06xjrrk</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_19i1lbs" name="Executor">
<bpmn:flowNodeRef>Activity_0uxkytf</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_01nh9j2</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_1qgjnyh</bpmn:flowNodeRef>
</bpmn:lane>
</bpmn:laneSet>
<bpmn:startEvent id="Event_0v73rhy">
<bpmn:outgoing>Flow_17d0j42</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Activity_0n8uuvk" name="Request more executors">
<bpmn:incoming>Flow_17d0j42</bpmn:incoming>
<bpmn:outgoing>Flow_0opy5tp</bpmn:outgoing>
</bpmn:task>
<bpmn:task id="Activity_06xjrrk" name="Add/start new executors">
<bpmn:incoming>Flow_0opy5tp</bpmn:incoming>
<bpmn:outgoing>Flow_0sudw7l</bpmn:outgoing>
</bpmn:task>
<bpmn:task id="Activity_0uxkytf" name="Exectuor starts">
<bpmn:incoming>Flow_0sudw7l</bpmn:incoming>
<bpmn:outgoing>Flow_02uzxx3</bpmn:outgoing>
</bpmn:task>
<bpmn:endEvent id="Event_01nh9j2">
<bpmn:incoming>Flow_0rpv16j</bpmn:incoming>
</bpmn:endEvent>
<bpmn:subProcess id="Activity_1qgjnyh" name="Executor Requests for work">
<bpmn:incoming>Flow_02uzxx3</bpmn:incoming>
<bpmn:outgoing>Flow_0rpv16j</bpmn:outgoing>
</bpmn:subProcess>
<bpmn:sequenceFlow id="Flow_17d0j42" sourceRef="Event_0v73rhy" targetRef="Activity_0n8uuvk" />
<bpmn:sequenceFlow id="Flow_0opy5tp" sourceRef="Activity_0n8uuvk" targetRef="Activity_06xjrrk" />
<bpmn:sequenceFlow id="Flow_02uzxx3" sourceRef="Activity_0uxkytf" targetRef="Activity_1qgjnyh" />
<bpmn:sequenceFlow id="Flow_0sudw7l" sourceRef="Activity_06xjrrk" targetRef="Activity_0uxkytf" />
<bpmn:sequenceFlow id="Flow_0rpv16j" sourceRef="Activity_1qgjnyh" targetRef="Event_01nh9j2" />
</bpmn:process>
<bpmn:process id="Process_1iep78l" isExecutable="false">
<bpmn:laneSet id="LaneSet_03zwzb7">
<bpmn:lane id="Lane_06xhlk6" name="Executor">
<bpmn:flowNodeRef>Event_1oz3tr5</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0xk9kck</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_02fg9xj" name="Assignment service">
<bpmn:flowNodeRef>Gateway_079742h</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0umieiz</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_062x6a9</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0b6bh6v</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_1achffx</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_1mme68o</bpmn:flowNodeRef>
</bpmn:lane>
</bpmn:laneSet>
<bpmn:startEvent id="Event_1oz3tr5">
<bpmn:outgoing>Flow_0od6iot</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Activity_0xk9kck" name="Ask for work">
<bpmn:incoming>Flow_0od6iot</bpmn:incoming>
<bpmn:outgoing>Flow_0k07ofo</bpmn:outgoing>
</bpmn:task>
<bpmn:exclusiveGateway id="Gateway_079742h">
<bpmn:incoming>Flow_0k07ofo</bpmn:incoming>
<bpmn:outgoing>Flow_1fwmda3</bpmn:outgoing>
<bpmn:outgoing>Flow_050yku1</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:task id="Activity_0umieiz" name="Assign task to executor">
<bpmn:incoming>Flow_1fwmda3</bpmn:incoming>
<bpmn:outgoing>Flow_15lkkxa</bpmn:outgoing>
</bpmn:task>
<bpmn:endEvent id="Event_062x6a9">
<bpmn:incoming>Flow_15lkkxa</bpmn:incoming>
</bpmn:endEvent>
<bpmn:task id="Activity_0b6bh6v" name="Some logic to reduce amount of executors if possible???">
<bpmn:incoming>Flow_050yku1</bpmn:incoming>
<bpmn:outgoing>Flow_1lgcq8d</bpmn:outgoing>
</bpmn:task>
<bpmn:endEvent id="Event_1achffx">
<bpmn:incoming>Flow_0oqra8s</bpmn:incoming>
</bpmn:endEvent>
<bpmn:task id="Activity_1mme68o" name="Executor idle&#39;s">
<bpmn:incoming>Flow_1lgcq8d</bpmn:incoming>
<bpmn:outgoing>Flow_0oqra8s</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_0od6iot" sourceRef="Event_1oz3tr5" targetRef="Activity_0xk9kck" />
<bpmn:sequenceFlow id="Flow_0k07ofo" name="Check if tasks are in queue" sourceRef="Activity_0xk9kck" targetRef="Gateway_079742h" />
<bpmn:sequenceFlow id="Flow_1fwmda3" name="Yes" sourceRef="Gateway_079742h" targetRef="Activity_0umieiz" />
<bpmn:sequenceFlow id="Flow_15lkkxa" sourceRef="Activity_0umieiz" targetRef="Event_062x6a9" />
<bpmn:sequenceFlow id="Flow_050yku1" name="No" sourceRef="Gateway_079742h" targetRef="Activity_0b6bh6v" />
<bpmn:sequenceFlow id="Flow_1lgcq8d" sourceRef="Activity_0b6bh6v" targetRef="Activity_1mme68o" />
<bpmn:sequenceFlow id="Flow_0oqra8s" sourceRef="Activity_1mme68o" targetRef="Event_1achffx" />
</bpmn:process>
<bpmn:process id="Process_102ufh8" isExecutable="false">
<bpmn:laneSet id="LaneSet_15t2y8k">
<bpmn:lane id="Lane_0lvtv1p" name="Executor">
<bpmn:flowNodeRef>Event_1b2jt5y</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_1ikvmpl</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_0y66dbe</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_11lqrhg</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_1oownmu</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_1jghhc4" name="Assignment service">
<bpmn:flowNodeRef>Activity_1ohwol1</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_0bbqq3x</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_0k7q1xv" name="task service">
<bpmn:flowNodeRef>Activity_1e9hb9h</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_0l7ljcr</bpmn:flowNodeRef>
</bpmn:lane>
</bpmn:laneSet>
<bpmn:startEvent id="Event_1b2jt5y">
<bpmn:outgoing>Flow_046hsk4</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:task id="Activity_1ikvmpl" name="Executor finish work">
<bpmn:incoming>Flow_046hsk4</bpmn:incoming>
<bpmn:outgoing>Flow_0zoqmub</bpmn:outgoing>
</bpmn:task>
<bpmn:endEvent id="Event_0y66dbe">
<bpmn:incoming>Flow_0nyxv8e</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sendTask id="Activity_11lqrhg" name="Send finish message">
<bpmn:incoming>Flow_0zoqmub</bpmn:incoming>
<bpmn:outgoing>Flow_0ip5x3i</bpmn:outgoing>
<bpmn:outgoing>Flow_1bqiz65</bpmn:outgoing>
<bpmn:outgoing>Flow_142xsjm</bpmn:outgoing>
</bpmn:sendTask>
<bpmn:task id="Activity_1ohwol1" name="Update tasks status to finished">
<bpmn:incoming>Flow_1bqiz65</bpmn:incoming>
<bpmn:outgoing>Flow_0znvsoe</bpmn:outgoing>
</bpmn:task>
<bpmn:task id="Activity_1e9hb9h" name="Update task status to finished">
<bpmn:incoming>Flow_142xsjm</bpmn:incoming>
<bpmn:outgoing>Flow_0ue2i8v</bpmn:outgoing>
</bpmn:task>
<bpmn:endEvent id="Event_0l7ljcr">
<bpmn:incoming>Flow_0ue2i8v</bpmn:incoming>
</bpmn:endEvent>
<bpmn:endEvent id="Event_0bbqq3x">
<bpmn:incoming>Flow_0znvsoe</bpmn:incoming>
</bpmn:endEvent>
<bpmn:subProcess id="Activity_1oownmu" name="Executor Requests for work">
<bpmn:incoming>Flow_0ip5x3i</bpmn:incoming>
<bpmn:outgoing>Flow_0nyxv8e</bpmn:outgoing>
</bpmn:subProcess>
<bpmn:sequenceFlow id="Flow_046hsk4" sourceRef="Event_1b2jt5y" targetRef="Activity_1ikvmpl" />
<bpmn:sequenceFlow id="Flow_0zoqmub" sourceRef="Activity_1ikvmpl" targetRef="Activity_11lqrhg" />
<bpmn:sequenceFlow id="Flow_0ip5x3i" sourceRef="Activity_11lqrhg" targetRef="Activity_1oownmu" />
<bpmn:sequenceFlow id="Flow_0nyxv8e" sourceRef="Activity_1oownmu" targetRef="Event_0y66dbe" />
<bpmn:sequenceFlow id="Flow_1bqiz65" sourceRef="Activity_11lqrhg" targetRef="Activity_1ohwol1" />
<bpmn:sequenceFlow id="Flow_142xsjm" sourceRef="Activity_11lqrhg" targetRef="Activity_1e9hb9h" />
<bpmn:sequenceFlow id="Flow_0ue2i8v" sourceRef="Activity_1e9hb9h" targetRef="Event_0l7ljcr" />
<bpmn:sequenceFlow id="Flow_0znvsoe" sourceRef="Activity_1ohwol1" targetRef="Event_0bbqq3x" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_0anvhsf">
<bpmndi:BPMNShape id="Participant_0q8hukc_di" bpmnElement="Participant_0q8hukc" isHorizontal="true">
<dc:Bounds x="140" y="80" width="1728" height="590" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1qeq039_di" bpmnElement="Lane_1qeq039" isHorizontal="true">
<dc:Bounds x="170" y="200" width="1698" height="470" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_12khd4k_di" bpmnElement="Lane_12khd4k" isHorizontal="true">
<dc:Bounds x="170" y="80" width="1698" height="120" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1hc51tx_di" bpmnElement="Flow_1hc51tx">
<di:waypoint x="408" y="310" />
<di:waypoint x="495" y="310" />
<bpmndi:BPMNLabel>
<dc:Bounds x="405" y="576" width="83" height="27" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1sajzlx_di" bpmnElement="Flow_1sajzlx">
<di:waypoint x="545" y="310" />
<di:waypoint x="680" y="310" />
<bpmndi:BPMNLabel>
<dc:Bounds x="604" y="292" width="18" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0cpd5ad_di" bpmnElement="Flow_0cpd5ad">
<di:waypoint x="780" y="310" />
<di:waypoint x="915" y="310" />
<bpmndi:BPMNLabel>
<dc:Bounds x="839" y="592" width="18" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0kwvrmc_di" bpmnElement="Flow_0kwvrmc">
<di:waypoint x="965" y="310" />
<di:waypoint x="1070" y="310" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1009" y="292" width="18" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0vpcut0_di" bpmnElement="Flow_0vpcut0">
<di:waypoint x="1170" y="310" />
<di:waypoint x="1345" y="310" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1217" y="276" width="81" height="27" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_179e0hl_di" bpmnElement="Flow_179e0hl">
<di:waypoint x="1395" y="310" />
<di:waypoint x="1542" y="310" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1462" y="292" width="15" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_12nh0g5_di" bpmnElement="Flow_12nh0g5">
<di:waypoint x="1370" y="335" />
<di:waypoint x="1370" y="420" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1376" y="375" width="18" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0366zqm_di" bpmnElement="Flow_0366zqm">
<di:waypoint x="1420" y="460" />
<di:waypoint x="1542" y="460" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1w3uh2m_di" bpmnElement="Flow_1w3uh2m">
<di:waypoint x="940" y="335" />
<di:waypoint x="940" y="420" />
<bpmndi:BPMNLabel>
<dc:Bounds x="948" y="368" width="15" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1n8jm89_di" bpmnElement="Flow_1n8jm89">
<di:waypoint x="990" y="460" />
<di:waypoint x="1102" y="460" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1rwgf2n_di" bpmnElement="Flow_1rwgf2n">
<di:waypoint x="358" y="180" />
<di:waypoint x="358" y="270" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_19dbo28_di" bpmnElement="Flow_19dbo28">
<di:waypoint x="258" y="140" />
<di:waypoint x="308" y="140" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1gvdy5x_di" bpmnElement="Flow_1gvdy5x">
<di:waypoint x="520" y="510" />
<di:waypoint x="520" y="560" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1ijfkpz_di" bpmnElement="Flow_1ijfkpz">
<di:waypoint x="520" y="335" />
<di:waypoint x="520" y="430" />
<bpmndi:BPMNLabel>
<dc:Bounds x="532" y="368" width="15" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1yxp4e8_di" bpmnElement="Flow_1yxp4e8">
<di:waypoint x="570" y="600" />
<di:waypoint x="662" y="600" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Gateway_1vd3as7_di" bpmnElement="Gateway_1vd3as7" isMarkerVisible="true">
<dc:Bounds x="495" y="285" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1jd11bs_di" bpmnElement="Activity_1jd11bs">
<dc:Bounds x="680" y="270" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1e4ckdq_di" bpmnElement="Gateway_1e4ckdq" isMarkerVisible="true">
<dc:Bounds x="915" y="285" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1dl4fvt_di" bpmnElement="Activity_1dl4fvt">
<dc:Bounds x="1070" y="270" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1e3rabp_di" bpmnElement="Gateway_1e3rabp" isMarkerVisible="true">
<dc:Bounds x="1345" y="285" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1lm6x5y_di" bpmnElement="Event_1lm6x5y">
<dc:Bounds x="1542" y="292" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1ysgenb_di" bpmnElement="Event_1ysgenb">
<dc:Bounds x="1542" y="442" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_00rvb9o_di" bpmnElement="Event_00rvb9o">
<dc:Bounds x="1102" y="442" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_190bh4a_di" bpmnElement="Activity_0u3tts0">
<dc:Bounds x="890" y="420" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0jai885_di" bpmnElement="Activity_0jai885">
<dc:Bounds x="308" y="100" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="222" y="122" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0vs4eam_di" bpmnElement="Activity_0vs4eam">
<dc:Bounds x="470" y="430" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0mwpp9o_di" bpmnElement="Activity_0mwpp9o">
<dc:Bounds x="470" y="560" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0v7hm2z_di" bpmnElement="Event_0v7hm2z">
<dc:Bounds x="662" y="582" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0paecdb_di" bpmnElement="Activity_0paecdb">
<dc:Bounds x="308" y="270" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0srcl99_di" bpmnElement="Activity_0srcl99">
<dc:Bounds x="308" y="350" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1iyu1x2_di" bpmnElement="Activity_0assw9c">
<dc:Bounds x="1320" y="420" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_143daut_di" bpmnElement="Participant_143daut" isHorizontal="true">
<dc:Bounds x="820" y="710" width="1048" height="250" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_119ldsr_di" bpmnElement="Flow_119ldsr">
<di:waypoint x="990" y="820" />
<di:waypoint x="1110" y="820" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1mm9swr_di" bpmnElement="Flow_1mm9swr">
<di:waypoint x="1210" y="820" />
<di:waypoint x="1312" y="820" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Activity_0fc3d7o_di" bpmnElement="Activity_1q87dyp">
<dc:Bounds x="890" y="780" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_170rm9y_di" bpmnElement="Event_170rm9y">
<dc:Bounds x="1312" y="802" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0t1gk0s_di" bpmnElement="Activity_0h1d3g9">
<dc:Bounds x="1110" y="780" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_062djli_di" bpmnElement="Participant_062djli" isHorizontal="true">
<dc:Bounds x="820" y="1000" width="1048" height="470" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_06xhlk6_di" bpmnElement="Lane_06xhlk6" isHorizontal="true">
<dc:Bounds x="850" y="1000" width="1018" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_02fg9xj_di" bpmnElement="Lane_02fg9xj" isHorizontal="true">
<dc:Bounds x="850" y="1125" width="1018" height="345" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0od6iot_di" bpmnElement="Flow_0od6iot">
<di:waypoint x="948" y="1060" />
<di:waypoint x="1060" y="1060" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0k07ofo_di" bpmnElement="Flow_0k07ofo">
<di:waypoint x="1110" y="1100" />
<di:waypoint x="1110" y="1215" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1116" y="1155" width="88" height="27" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1fwmda3_di" bpmnElement="Flow_1fwmda3">
<di:waypoint x="1135" y="1240" />
<di:waypoint x="1250" y="1240" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1184" y="1222" width="18" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_15lkkxa_di" bpmnElement="Flow_15lkkxa">
<di:waypoint x="1350" y="1240" />
<di:waypoint x="1472" y="1240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_050yku1_di" bpmnElement="Flow_050yku1">
<di:waypoint x="1110" y="1265" />
<di:waypoint x="1110" y="1380" />
<di:waypoint x="1250" y="1380" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1118" y="1320" width="15" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1lgcq8d_di" bpmnElement="Flow_1lgcq8d">
<di:waypoint x="1350" y="1380" />
<di:waypoint x="1430" y="1380" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0oqra8s_di" bpmnElement="Flow_0oqra8s">
<di:waypoint x="1530" y="1380" />
<di:waypoint x="1602" y="1380" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_1oz3tr5_di" bpmnElement="Event_1oz3tr5">
<dc:Bounds x="912" y="1042" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0xk9kck_di" bpmnElement="Activity_0xk9kck">
<dc:Bounds x="1060" y="1020" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_079742h_di" bpmnElement="Gateway_079742h" isMarkerVisible="true">
<dc:Bounds x="1085" y="1215" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0umieiz_di" bpmnElement="Activity_0umieiz">
<dc:Bounds x="1250" y="1200" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_062x6a9_di" bpmnElement="Event_062x6a9">
<dc:Bounds x="1472" y="1222" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0b6bh6v_di" bpmnElement="Activity_0b6bh6v">
<dc:Bounds x="1250" y="1340" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1achffx_di" bpmnElement="Event_1achffx">
<dc:Bounds x="1602" y="1362" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1mme68o_di" bpmnElement="Activity_1mme68o">
<dc:Bounds x="1430" y="1340" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_0xytik6_di" bpmnElement="Participant_1q0bjfl" isHorizontal="true">
<dc:Bounds x="140" y="710" width="600" height="370" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_06e7su5_di" bpmnElement="Lane_06e7su5" isHorizontal="true">
<dc:Bounds x="170" y="710" width="570" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1lg2d2q_di" bpmnElement="Lane_1lg2d2q" isHorizontal="true">
<dc:Bounds x="170" y="835" width="570" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_19i1lbs_di" bpmnElement="Lane_19i1lbs" isHorizontal="true">
<dc:Bounds x="170" y="960" width="570" height="120" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_17d0j42_di" bpmnElement="Flow_17d0j42">
<di:waypoint x="268" y="770" />
<di:waypoint x="370" y="770" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0opy5tp_di" bpmnElement="Flow_0opy5tp">
<di:waypoint x="420" y="810" />
<di:waypoint x="420" y="860" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_02uzxx3_di" bpmnElement="Flow_02uzxx3">
<di:waypoint x="470" y="1020" />
<di:waypoint x="520" y="1020" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0sudw7l_di" bpmnElement="Flow_0sudw7l">
<di:waypoint x="420" y="940" />
<di:waypoint x="420" y="980" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0rpv16j_di" bpmnElement="Flow_0rpv16j">
<di:waypoint x="620" y="1020" />
<di:waypoint x="682" y="1020" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_0v73rhy_di" bpmnElement="Event_0v73rhy">
<dc:Bounds x="232" y="752" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0n8uuvk_di" bpmnElement="Activity_0n8uuvk">
<dc:Bounds x="370" y="730" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_06xjrrk_di" bpmnElement="Activity_06xjrrk">
<dc:Bounds x="370" y="860" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_00bhvrm_di" bpmnElement="Activity_0uxkytf">
<dc:Bounds x="370" y="980" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_01nh9j2_di" bpmnElement="Event_01nh9j2">
<dc:Bounds x="682" y="1002" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1r1i7hf_di" bpmnElement="Activity_1qgjnyh">
<dc:Bounds x="520" y="980" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Participant_1ova0gb_di" bpmnElement="Participant_1ova0gb" isHorizontal="true">
<dc:Bounds x="140" y="1530" width="820" height="370" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_0lvtv1p_di" bpmnElement="Lane_0lvtv1p" isHorizontal="true">
<dc:Bounds x="170" y="1530" width="790" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1jghhc4_di" bpmnElement="Lane_1jghhc4" isHorizontal="true">
<dc:Bounds x="170" y="1655" width="790" height="125" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_0k7q1xv_di" bpmnElement="Lane_0k7q1xv" isHorizontal="true">
<dc:Bounds x="170" y="1780" width="790" height="120" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_046hsk4_di" bpmnElement="Flow_046hsk4">
<di:waypoint x="268" y="1600" />
<di:waypoint x="320" y="1600" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0zoqmub_di" bpmnElement="Flow_0zoqmub">
<di:waypoint x="420" y="1600" />
<di:waypoint x="530" y="1600" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ip5x3i_di" bpmnElement="Flow_0ip5x3i">
<di:waypoint x="630" y="1600" />
<di:waypoint x="720" y="1600" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0nyxv8e_di" bpmnElement="Flow_0nyxv8e">
<di:waypoint x="820" y="1600" />
<di:waypoint x="902" y="1600" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1bqiz65_di" bpmnElement="Flow_1bqiz65">
<di:waypoint x="580" y="1640" />
<di:waypoint x="580" y="1710" />
<di:waypoint x="430" y="1710" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_142xsjm_di" bpmnElement="Flow_142xsjm">
<di:waypoint x="580" y="1640" />
<di:waypoint x="580" y="1800" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ue2i8v_di" bpmnElement="Flow_0ue2i8v">
<di:waypoint x="630" y="1840" />
<di:waypoint x="682" y="1840" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0znvsoe_di" bpmnElement="Flow_0znvsoe">
<di:waypoint x="330" y="1720" />
<di:waypoint x="268" y="1720" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_1b2jt5y_di" bpmnElement="Event_1b2jt5y">
<dc:Bounds x="232" y="1582" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1ikvmpl_di" bpmnElement="Activity_1ikvmpl">
<dc:Bounds x="320" y="1560" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0y66dbe_di" bpmnElement="Event_0y66dbe">
<dc:Bounds x="902" y="1582" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0ujophe_di" bpmnElement="Activity_11lqrhg">
<dc:Bounds x="530" y="1560" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1ohwol1_di" bpmnElement="Activity_1ohwol1">
<dc:Bounds x="330" y="1680" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1e9hb9h_di" bpmnElement="Activity_1e9hb9h">
<dc:Bounds x="530" y="1800" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0l7ljcr_di" bpmnElement="Event_0l7ljcr">
<dc:Bounds x="682" y="1822" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0bbqq3x_di" bpmnElement="Event_0bbqq3x">
<dc:Bounds x="232" y="1702" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1oownmu_di" bpmnElement="Activity_1oownmu">
<dc:Bounds x="720" y="1560" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1xo6v1g_di" bpmnElement="Flow_1xo6v1g">
<di:waypoint x="940" y="500" />
<di:waypoint x="940" y="780" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

62
docker-compose.yaml Normal file
View File

@ -0,0 +1,62 @@
version: "3.6"
services:
tapas-tasks:
container_name: tapas-tasks
build:
context: "./tapas-tasks"
dockerfile: "Dockerfile"
target: development
ports:
- "8081:8081"
- "5005:5005"
volumes:
- ./tapas-tasks/src:/opt/app/src
- ./tapas-tasks/target:/opt/app/target
assignment:
container_name: assignment
build:
context: "./assignment"
dockerfile: "Dockerfile"
target: development
ports:
- "8082:8082"
- "5006:5005"
volumes:
- ./assignment/src:/opt/app/src
- ./assignment/target:/opt/app/target
executor-pool:
container_name: executor-pool
build:
context: "./executor-pool"
dockerfile: "Dockerfile"
target: development
ports:
- "8083:8081"
- "5007:5005"
volumes:
- ./executor-pool/src:/opt/app/src
- ./executor-pool/target:/opt/app/target
executor1:
container_name: executor1
build:
context: "./executor1"
dockerfile: "Dockerfile"
target: development
ports:
- "8084:8081"
- "5008:5005"
volumes:
- ./executor1/src:/opt/app/src
- ./executor1/target:/opt/app/target
executor2:
container_name: executor2
build:
context: "./executor2"
dockerfile: "Dockerfile"
target: development
ports:
- "8085:8085"
- "5009:5005"
volumes:
- ./executor2/src:/opt/app/src
- ./executor2/target:/opt/app/target

View File

@ -1,57 +0,0 @@
version: "3.0"
services:
reverse-proxy:
image: traefik:v2.1.3
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker=true
- --certificatesResolvers.le.acme.httpChallenge.entryPoint=web
- --certificatesresolvers.le.acme.email=martin.eigenmann@unisg.ch
- --certificatesresolvers.le.acme.storage=/acme.json
- --providers.docker.exposedByDefault=false
- --serversTransport.insecureSkipVerify=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./acme.json:/acme.json
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
tapas-tasks:
image: openjdk
command: "java -jar /data/tapas-tasks-0.0.1-SNAPSHOT.jar"
restart: unless-stopped
volumes:
- ./:/data/
labels:
- "traefik.enable=true"
- "traefik.http.routers.tapas-tasks.rule=Host(`tapas-tasks.${PUB_IP}.nip.io`)"
- "traefik.http.routers.tapas-tasks.service=tapas-tasks"
- "traefik.http.services.tapas-tasks.loadbalancer.server.port=8081"
- "traefik.http.routers.tapas-tasks.tls=true"
- "traefik.http.routers.tapas-tasks.entryPoints=web,websecure"
- "traefik.http.routers.tapas-tasks.tls.certresolver=le"
app:
image: openjdk
command: "java -jar /data/app-0.1.0.jar"
restart: unless-stopped
volumes:
- ./:/data/
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`app.${PUB_IP}.nip.io`)"
- "traefik.http.routers.app.service=app"
- "traefik.http.services.app.loadbalancer.server.port=8080"
- "traefik.http.routers.app.tls=true"
- "traefik.http.routers.app.entryPoints=web,websecure"
- "traefik.http.routers.app.tls.certresolver=le"

33
executor-base/.gitignore vendored Normal file
View File

@ -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/

View File

@ -0,0 +1,117 @@
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

Binary file not shown.

View File

@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

18
executor-base/Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM openjdk:11 AS development
WORKDIR /opt/app
# ENV SPRING_DATASOURCE_URL=jdbc:mysql://backend-db:3306/db
COPY .mvn/ .mvn
COPY mvnw pom.xml mvnw.cmd ./
RUN apt-get clean && apt-get update && apt-get install dos2unix
RUN dos2unix mvnw
RUN ./mvnw dependency:go-offline
COPY src /opt/app/src
COPY *target /opt/app/target
CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.jvmArguments=\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005\"", "-Dspring.devtools.restart.enabled=true"]

310
executor-base/mvnw vendored Executable file
View File

@ -0,0 +1,310 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

182
executor-base/mvnw.cmd vendored Normal file
View File

@ -0,0 +1,182 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

65
executor-base/pom.xml Normal file
View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ch.unisg</groupId>
<artifactId>executorBase</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>executorBase</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,13 @@
package ch.unisg.executorBase;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Executor1Application {
public static void main(String[] args) {
SpringApplication.run(Executor1Application.class, args);
}
}

View File

@ -0,0 +1,30 @@
package ch.unisg.executorBase.common;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set;
public class SelfValidating<T> {
private Validator validator;
public SelfValidating() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
/**
* Evaluates all Bean Validations on the attributes of this
* instance.
*/
protected void validateSelf() {
@SuppressWarnings("unchecked")
Set<ConstraintViolation<T>> violations = validator.validate((T) this);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
}
}

View File

@ -0,0 +1,36 @@
package ch.unisg.executorBase.executor.adapter.in.web;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import ch.unisg.executorBase.executor.application.port.in.TaskAvailableCommand;
import ch.unisg.executorBase.executor.application.port.in.TaskAvailableUseCase;
import ch.unisg.executorBase.executor.domain.ExecutorType;
@RestController
public class TaskAvailableController {
private final TaskAvailableUseCase taskAvailableUseCase;
public TaskAvailableController(TaskAvailableUseCase taskAvailableUseCase) {
this.taskAvailableUseCase = taskAvailableUseCase;
}
@GetMapping(path = "/newtask/{taskType}")
public ResponseEntity<String> retrieveTaskFromTaskList(@PathVariable("taskType") String taskType) {
if (ExecutorType.contains(taskType.toUpperCase())) {
TaskAvailableCommand command = new TaskAvailableCommand(
ExecutorType.valueOf(taskType.toUpperCase()));
taskAvailableUseCase.newTaskAvailable(command);
}
// Add the content type as a response header
HttpHeaders responseHeaders = new HttpHeaders();
return new ResponseEntity<>("OK", responseHeaders, HttpStatus.OK);
}
}

View File

@ -0,0 +1,50 @@
package ch.unisg.executorBase.executor.adapter.out.web;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONObject;
import ch.unisg.executorBase.executor.application.port.out.ExecutionFinishedEventPort;
import ch.unisg.executorBase.executor.domain.ExecutionFinishedEvent;
public class ExecutionFinishedEventAdapter implements ExecutionFinishedEventPort {
String server = "http://127.0.0.1:8082";
Logger logger = Logger.getLogger(ExecutionFinishedEventAdapter.class.getName());
@Override
public void publishExecutionFinishedEvent(ExecutionFinishedEvent event) {
String body = new JSONObject()
.put("taskID", event.getTaskID())
.put("result", event.getResult())
.put("status", event.getStatus())
.toString();
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server+"/task/completed"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
try {
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Restore interrupted state...
Thread.currentThread().interrupt();
}
System.out.println("Finish execution event sent with result:" + event.getResult());
}
}

View File

@ -0,0 +1,61 @@
package ch.unisg.executorBase.executor.adapter.out.web;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import ch.unisg.executorBase.executor.application.port.out.GetAssignmentPort;
import ch.unisg.executorBase.executor.domain.ExecutorType;
import ch.unisg.executorBase.executor.domain.Task;
import org.json.JSONObject;
@Component
@Primary
public class GetAssignmentAdapter implements GetAssignmentPort {
String server = "http://127.0.0.1:8082";
Logger logger = Logger.getLogger(GetAssignmentAdapter.class.getName());
@Override
public Task getAssignment(ExecutorType executorType, String ip, int port) {
String body = new JSONObject()
.put("executorType", executorType)
.put("ip", ip)
.put("port", port)
.toString();
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server+"/task/apply"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.body().equals("")) {
return null;
}
return new Task(new JSONObject(response.body()).getString("taskID"));
} catch (IOException | InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Restore interrupted state...
Thread.currentThread().interrupt();
}
return null;
}
}

View File

@ -0,0 +1,57 @@
package ch.unisg.executorBase.executor.adapter.out.web;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONObject;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import ch.unisg.executorBase.executor.application.port.out.NotifyExecutorPoolPort;
import ch.unisg.executorBase.executor.domain.ExecutorType;
@Component
@Primary
public class NotifyExecutorPoolAdapter implements NotifyExecutorPoolPort {
String server = "http://127.0.0.1:8083";
Logger logger = Logger.getLogger(NotifyExecutorPoolAdapter.class.getName());
@Override
public boolean notifyExecutorPool(String ip, int port, ExecutorType executorType) {
String body = new JSONObject()
.put("executorTaskType", executorType)
.put("executorIp", ip)
.put("executorPort", Integer.toString(port))
.toString();
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server+"/executor-pool/AddExecutor"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == HttpStatus.CREATED.value()) {
return true;
}
} catch (IOException | InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Restore interrupted state...
Thread.currentThread().interrupt();
}
return false;
}
}

View File

@ -0,0 +1,20 @@
package ch.unisg.executorBase.executor.application.port.in;
import ch.unisg.executorBase.common.SelfValidating;
import ch.unisg.executorBase.executor.domain.ExecutorType;
import javax.validation.constraints.NotNull;
import lombok.Value;
@Value
public class TaskAvailableCommand extends SelfValidating<TaskAvailableCommand> {
@NotNull
private final ExecutorType taskType;
public TaskAvailableCommand(ExecutorType taskType) {
this.taskType = taskType;
this.validateSelf();
}
}

View File

@ -0,0 +1,5 @@
package ch.unisg.executorBase.executor.application.port.in;
public interface TaskAvailableUseCase {
void newTaskAvailable(TaskAvailableCommand command);
}

View File

@ -0,0 +1,7 @@
package ch.unisg.executorBase.executor.application.port.out;
import ch.unisg.executorBase.executor.domain.ExecutionFinishedEvent;
public interface ExecutionFinishedEventPort {
void publishExecutionFinishedEvent(ExecutionFinishedEvent event);
}

View File

@ -0,0 +1,8 @@
package ch.unisg.executorBase.executor.application.port.out;
import ch.unisg.executorBase.executor.domain.ExecutorType;
import ch.unisg.executorBase.executor.domain.Task;
public interface GetAssignmentPort {
Task getAssignment(ExecutorType executorType, String ip, int port);
}

View File

@ -0,0 +1,7 @@
package ch.unisg.executorBase.executor.application.port.out;
import ch.unisg.executorBase.executor.domain.ExecutorType;
public interface NotifyExecutorPoolPort {
boolean notifyExecutorPool(String ip, int port, ExecutorType executorType);
}

View File

@ -0,0 +1,15 @@
package ch.unisg.executorBase.executor.application.service;
import ch.unisg.executorBase.executor.application.port.out.NotifyExecutorPoolPort;
import ch.unisg.executorBase.executor.domain.ExecutorType;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class NotifyExecutorPoolService {
private final NotifyExecutorPoolPort notifyExecutorPoolPort;
public boolean notifyExecutorPool(String ip, int port, ExecutorType executorType) {
return notifyExecutorPoolPort.notifyExecutorPool(ip, port, executorType);
}
}

View File

@ -0,0 +1,20 @@
package ch.unisg.executorBase.executor.application.service;
import org.springframework.stereotype.Component;
import ch.unisg.executorBase.executor.application.port.in.TaskAvailableCommand;
import ch.unisg.executorBase.executor.application.port.in.TaskAvailableUseCase;
import lombok.RequiredArgsConstructor;
import javax.transaction.Transactional;
@RequiredArgsConstructor
@Component
@Transactional
public class TaskAvailableService implements TaskAvailableUseCase {
@Override
public void newTaskAvailable(TaskAvailableCommand command) {
// Placeholder so spring can create a bean
}
}

View File

@ -0,0 +1,21 @@
package ch.unisg.executorBase.executor.domain;
import lombok.Getter;
public class ExecutionFinishedEvent {
@Getter
private String taskID;
@Getter
private String result;
@Getter
private String status;
public ExecutionFinishedEvent(String taskID, String result, String status) {
this.taskID = taskID;
this.result = result;
this.status = status;
}
}

View File

@ -0,0 +1,75 @@
package ch.unisg.executorBase.executor.domain;
import ch.unisg.executorBase.executor.application.port.out.ExecutionFinishedEventPort;
import ch.unisg.executorBase.executor.application.port.out.GetAssignmentPort;
import ch.unisg.executorBase.executor.application.port.out.NotifyExecutorPoolPort;
import ch.unisg.executorBase.executor.adapter.out.web.ExecutionFinishedEventAdapter;
import ch.unisg.executorBase.executor.adapter.out.web.GetAssignmentAdapter;
import ch.unisg.executorBase.executor.adapter.out.web.NotifyExecutorPoolAdapter;
import ch.unisg.executorBase.executor.application.service.NotifyExecutorPoolService;
import lombok.Getter;
public abstract class ExecutorBase {
@Getter
private String ip;
@Getter
private ExecutorType executorType;
@Getter
private int port;
@Getter
private ExecutorStatus status;
// TODO Violation of the Dependency Inversion Principle?, but we havn't really got a better solutions to send a http request / access a service from a domain model
// TODO I guess we can somehow autowire this but I don't know why it's not working :D
private final NotifyExecutorPoolPort notifyExecutorPoolPort = new NotifyExecutorPoolAdapter();
private final NotifyExecutorPoolService notifyExecutorPoolService = new NotifyExecutorPoolService(notifyExecutorPoolPort);
private final GetAssignmentPort getAssignmentPort = new GetAssignmentAdapter();
private final ExecutionFinishedEventPort executionFinishedEventPort = new ExecutionFinishedEventAdapter();
public ExecutorBase(ExecutorType executorType) {
System.out.println("Starting Executor");
// TODO set this automaticly
this.ip = "localhost";
this.port = 8084;
this.executorType = executorType;
this.status = ExecutorStatus.STARTING_UP;
if(!notifyExecutorPoolService.notifyExecutorPool(this.ip, this.port, this.executorType)) {
System.exit(0);
} else {
this.status = ExecutorStatus.IDLING;
getAssignment();
}
}
public void getAssignment() {
Task newTask = getAssignmentPort.getAssignment(this.getExecutorType(), this.getIp(),
this.getPort());
if (newTask != null) {
this.executeTask(newTask);
} else {
this.status = ExecutorStatus.IDLING;
}
}
private void executeTask(Task task) {
System.out.println("Starting execution");
this.status = ExecutorStatus.EXECUTING;
task.setResult(execution());
executionFinishedEventPort.publishExecutionFinishedEvent(
new ExecutionFinishedEvent(task.getTaskID(), task.getResult(), "SUCCESS"));
System.out.println("Finish execution");
getAssignment();
}
protected abstract String execution();
}

View File

@ -0,0 +1,7 @@
package ch.unisg.executorBase.executor.domain;
public enum ExecutorStatus {
STARTING_UP,
EXECUTING,
IDLING,
}

View File

@ -0,0 +1,18 @@
package ch.unisg.executorBase.executor.domain;
public enum ExecutorType {
ADDITION, ROBOT;
public static boolean contains(String test) {
for (ExecutorType x : ExecutorType.values()) {
if (x.name().equals(test)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,19 @@
package ch.unisg.executorBase.executor.domain;
import lombok.Getter;
import lombok.Setter;
public class Task {
@Getter
private String taskID;
@Getter
@Setter
private String result;
public Task(String taskID) {
this.taskID = taskID;
}
}

View File

@ -0,0 +1 @@
server.port=8081

View File

@ -0,0 +1,13 @@
package ch.unisg.executorBase;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class executorBaseApplicationTests {
@Test
void contextLoads() {
}
}

33
executor-pool/.gitignore vendored Normal file
View File

@ -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/

View File

@ -0,0 +1,117 @@
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

Binary file not shown.

View File

@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

18
executor-pool/Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM openjdk:11 AS development
WORKDIR /opt/app
# ENV SPRING_DATASOURCE_URL=jdbc:mysql://backend-db:3306/db
COPY .mvn/ .mvn
COPY mvnw pom.xml mvnw.cmd ./
RUN apt-get clean && apt-get update && apt-get install dos2unix
RUN dos2unix mvnw
RUN ./mvnw dependency:go-offline
COPY src /opt/app/src
COPY *target /opt/app/target
CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.jvmArguments=\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005\"", "-Dspring.devtools.restart.enabled=true"]

310
executor-pool/mvnw vendored Executable file
View File

@ -0,0 +1,310 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

182
executor-pool/mvnw.cmd vendored Normal file
View File

@ -0,0 +1,182 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

81
executor-pool/pom.xml Normal file
View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ch.unisg</groupId>
<artifactId>executor-pool</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>executor-pool</name>
<description>Executor Pool</description>
<properties>
<java.version>11</java.version>
<sonar.organization>scs-asse-fs21-group1</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,30 @@
package ch.unisg.common;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set;
public class SelfValidating<T> {
private Validator validator;
public SelfValidating() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
/**
* Evaluates all Bean Validations on the attributes of this
* instance.
*/
protected void validateSelf() {
@SuppressWarnings("unchecked")
Set<ConstraintViolation<T>> violations = validator.validate((T) this);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
}
}

View File

@ -0,0 +1,13 @@
package ch.unisg.executorpool;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ExecutorPoolApplication {
public static void main(String[] args) {
SpringApplication.run(ExecutorPoolApplication.class, args);
}
}

Some files were not shown because too many files have changed in this diff Show More