executorbase restructure + improvments

This commit is contained in:
Marcel 2021-12-22 19:35:09 +01:00
parent 1153b75322
commit 88623f6327
66 changed files with 573 additions and 950 deletions

View File

@ -90,9 +90,7 @@ services:
environment: environment:
task.list.uri: http://tapas-tasks:8081 task.list.uri: http://tapas-tasks:8081
auction.house.uri: http://tapas-auction-house:8086 auction.house.uri: http://tapas-auction-house:8086
executor.robot.uri: http://executor-robot:8084 executor.pool.uri: http://executor-pool:8083
executor.computation.uri: http://executor-computation:8085
executor.humidity.uri: http://executor-humidity:8087
mqtt.broker.uri: tcp://broker.hivemq.com:1883 mqtt.broker.uri: tcp://broker.hivemq.com:1883
spring.data.mongodb.uri: mongodb://root:password@tapas-db:27017 spring.data.mongodb.uri: mongodb://root:password@tapas-db:27017
labels: labels:
@ -135,13 +133,15 @@ services:
volumes: volumes:
- ./:/data/ - ./:/data/
environment: environment:
EXECUTOR_POOL_URI: http://executor-pool:8083 executor.type: COMPUTATION
ROSTER_URI: http://roster:8082 executor.uri: http://executor-computation:8085
executor.pool.uri: http://executor-pool:8083
roster.uri: http://roster:8082
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.executor-computation.rule=Host(`executor-computation.${PUB_IP}.nip.io`)" - "traefik.http.routers.executor-computation.rule=Host(`executor-computation.${PUB_IP}.nip.io`)"
- "traefik.http.routers.executor-computation.service=executor-computation" - "traefik.http.routers.executor-computation.service=executor-computation"
- "traefik.http.services.executor-computation.loadbalancer.server.port=8084" - "traefik.http.services.executor-computation.loadbalancer.server.port=8085"
- "traefik.http.routers.executor-computation.tls=true" - "traefik.http.routers.executor-computation.tls=true"
- "traefik.http.routers.executor-computation.entryPoints=web,websecure" - "traefik.http.routers.executor-computation.entryPoints=web,websecure"
- "traefik.http.routers.executor-computation.tls.certresolver=le" - "traefik.http.routers.executor-computation.tls.certresolver=le"
@ -156,13 +156,15 @@ services:
volumes: volumes:
- ./:/data/ - ./:/data/
environment: environment:
EXECUTOR_POOL_URI: http://executor-pool:8083 executor.type: SMALLROBOT
ROSTER_URI: http://roster:8082 executor.uri: http://executor-robot:8084
executor.pool.uri: http://executor-pool:8083
roster.uri: http://roster:8082
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.executor-robot.rule=Host(`executor-robot.${PUB_IP}.nip.io`)" - "traefik.http.routers.executor-robot.rule=Host(`executor-robot.${PUB_IP}.nip.io`)"
- "traefik.http.routers.executor-robot.service=executor-robot" - "traefik.http.routers.executor-robot.service=executor-robot"
- "traefik.http.services.executor-robot.loadbalancer.server.port=8085" - "traefik.http.services.executor-robot.loadbalancer.server.port=8084"
- "traefik.http.routers.executor-robot.tls=true" - "traefik.http.routers.executor-robot.tls=true"
- "traefik.http.routers.executor-robot.entryPoints=web,websecure" - "traefik.http.routers.executor-robot.entryPoints=web,websecure"
- "traefik.http.routers.executor-robot.tls.certresolver=le" - "traefik.http.routers.executor-robot.tls.certresolver=le"
@ -177,8 +179,10 @@ services:
volumes: volumes:
- ./:/data/ - ./:/data/
environment: environment:
EXECUTOR_POOL_URI: http://executor-pool:8083 executor.type: HUMIDITY
ROSTER_URI: http://roster:8082 executor.uri: http://executor-humidity:8087
executor.pool.uri: http://executor-pool:8083
roster.uri: http://roster:8082
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.executor-computation.rule=Host(`executor-humidity.${PUB_IP}.nip.io`)" - "traefik.http.routers.executor-computation.rule=Host(`executor-humidity.${PUB_IP}.nip.io`)"

View File

@ -1,3 +0,0 @@
# Californium3 CoAP Properties file
# Wed Dec 15 21:41:00 CET 2021
#

145
README.md
View File

@ -1,125 +1,63 @@
# TAPAS # TAPAS
This is the main GitHub project for your implementation of the TAPAS application. This is the main GitHub project for the implementation of the TAPAS application from Group 1.
## 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) - [.deployment/docker-compose.yml](.deployment/docker-compose.yml): Docker Compose configuration file for all services (deployment)
- [tapas-tasks/src](tapas-tasks/src): source code of the project (following the Hexagonal Architecture) - [.experiments](.experiments): Experiment files for chaos monkey tests
- [tapas-tasks/pom.xml](tapas-tasks\pom.xml): Maven pom-file - [.github/workflows](.github/workflows): GitHub actions scripts (CI/CD workflow)
- [app](app): folder as placeholder for a second micro-service (Spring Boot project) - [common](common): common library for shared elements across the whole application
- [docker-compose.yml](docker-compose.yml): Docker Compose configuration file for all services - [common/src](common/src): source code of the library
- [.github/workflows/build-and-deploy.yml](.github/workflows/build-and-deploy.yml): GitHub actions script (CI/CD workflow) - [common/pom.xml](common/pom.xml): Maven pom-file
- [doc/architecture/decisions](doc/architecture/decisions): ADRs
- [doc/workflow.png](doc/workflow.png): Workflow diagram
- [executor-base](executor-base): library for the executors. Includes the logic for executors to connect to the system
- [executor-base/src](executor-base/src): source code of the library
- [executor-base/pom.xml](executor-base/pom.xml): Maven pom-file
- [executor-computation](executor-computation): standalone project for the computation executor micro-service (Spring Boot project)
- [executor-computation/src](executor-computation/src): source code of the project
- [executor-computation/pom.xml](executor-computation/pom.xml): Maven pom-file
- [executor-humidity](executor-humidity): standalone project for the humidity executor micro-service (Spring Boot project)
- [executor-humidity/src](executor-humidity/src): source code of the project
- [executor-humidity/pom.xml](executor-humidity/pom.xml): Maven pom-file
- [executor-pool](executor-pool): standalone project for the executor-pool micro-service (Spring Boot project)
- [executor-pool/src](executor-pool/src): source code of the project (following the Hexagonal Architecture)
- [executor-pool/pom.xml](executor-pool/pom.xml): Maven pom-file
- [executor-robot](executor-robot): standalone project for the robot executor micro-service (Spring Boot project)
## How to Add a New Service with Spring Boot - [executor-robot/src](executor-robot/src): source code of the project
- [executor-robot/pom.xml](executor-robot/pom.xml): Maven pom-file
### Create a new Spring Boot project - [mocks](mocks): some auction-house mock files to test localy
- Recommended: use [Spring Initialzr](https://start.spring.io/) (Maven, Spring Boot 2.5.5, Jar, Java 11, dependencies as needed) - [roster](roster): standalone project for the Roster micro-service (Spring Boot project)
- 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 - [roster/src](roster/src): source code of the project (following the Hexagonal Architecture)
- [roster/pom.xml](roster/pom.xml): Maven pom-file
Your TAPAS application is a multi-container Docker application ran with [Docker Compose](https://docs.docker.com/compose/). - [tapas-auction-house](tapas-auction-house): standalone project for the Tapas-Aution-House micro-service (Spring Boot project)
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):
- 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) - [tapas-auction-house/src](tapas-auction-house/src): source code of the project (following the Hexagonal Architecture)
- change `command` (see [line 31](https://github.com/scs-asse/tapas/blob/main/docker-compose.yml#L31)) - [tapas-auction-house/pom.xml](tapas-auction-house/pom.xml): Maven pom-file
to use the name of the JAR file generated by Maven for your service
- note: if you change the version of your service, you need to update this line to reflect the change
- 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))
- e.g., change `traefik.http.routers.tapas-tasks.rule` to `traefik.http.routers.<new-service-name>.rule`
- 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 - [tapas-tasks](tapas-tasks): standalone project for the Tapas-Tasks micro-service (Spring Boot project)
This project uses GitHub Actions to build and deploy your TAPAS application whenever a new commit is - [tapas-tasks/src](tapas-tasks/src): source code of the project (following the Hexagonal Architecture)
pushed on the `main` branch. You can add your new service to the GitHub Actions workflow defined in - [tapas-tasks/pom.xml](tapas-tasks/pom.xml): Maven pom-file
[.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) - [docker-compose.yml](docker-compose.yml): Docker Compose configuration file for local development
- 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))
- 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
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 the micro-service's main class from IntelliJ for all required projects
- Use Maven to run from the command line:
```shell
mvn spring-boot:run
```
## How to Deploy on your VM
1. Start your Ubuntu VM on Switch.
- VM shuts down automatically at 2 AM
- Group admins can do this via https://engines.switch.ch/horizon
2. Push new code to the _main_ branch
- 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
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`
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`.
## VM Configurations ## VM Configurations
Specs (we can upgrade if needed): Specs (we can upgrade if needed):
- 1 CPU - 1 CPU
- 2 GB RAM - 2 GB RAM
- 20 GB HD - 20 GB HD
- Ubuntu 20.04 - Ubuntu 20.04
| Name | Server IP | | Name | Server IP |
| ------------------ | ------------- | | ------------------ | ------------- |
@ -128,8 +66,3 @@ Specs (we can upgrade if needed):
| SCS-ASSE-VM-Group3 | 86.119.34.242 | | SCS-ASSE-VM-Group3 | 86.119.34.242 |
| SCS-ASSE-VM-Group4 | 86.119.35.199 | | SCS-ASSE-VM-Group4 | 86.119.35.199 |
| SCS-ASSE-VM-Group5 | 86.119.35.72 | | SCS-ASSE-VM-Group5 | 86.119.35.72 |
## 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.

View File

@ -1,13 +0,0 @@
# Dockerfile/Docker-Compose file based on an initial version authored by Alexander Lontke (ASSE, Fall Semester 2021)
FROM maven as build
COPY . /app
RUN mvn -f app/pom.xml --batch-mode --update-snapshots verify
FROM openjdk
COPY --from=build /app/target/app-0.1.0.jar ./app-0.1.0.jar
CMD java -jar app-0.1.0.jar

View File

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

View File

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

View File

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

View File

@ -1,9 +0,0 @@
package ch.unisg.executorbase.executor.application.port.out;
import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.executorbase.executor.domain.ExecutorType;
import ch.unisg.executorbase.executor.domain.Task;
public interface GetAssignmentPort {
Task getAssignment(ExecutorType executorType, ExecutorURI executorURI);
}

View File

@ -1,8 +0,0 @@
package ch.unisg.executorbase.executor.application.port.out;
import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.executorbase.executor.domain.ExecutorType;
public interface NotifyExecutorPoolPort {
boolean notifyExecutorPool(ExecutorURI executorURI, ExecutorType executorType);
}

View File

@ -1,16 +0,0 @@
package ch.unisg.executorbase.executor.application.service;
import ch.unisg.common.valueobject.ExecutorURI;
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(ExecutorURI executorURI, ExecutorType executorType) {
return notifyExecutorPoolPort.notifyExecutorPool(executorURI, executorType);
}
}

View File

@ -1,20 +0,0 @@
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, implementation of this service is inside the individual executors
}
}

View File

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

View File

@ -1,93 +0,0 @@
package ch.unisg.executorbase.executor.domain;
import java.util.logging.Level;
import java.util.logging.Logger;
import ch.unisg.common.valueobject.ExecutorURI;
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.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.application.service.NotifyExecutorPoolService;
import lombok.Getter;
public abstract class ExecutorBase {
@Getter
private ExecutorURI executorURI;
@Getter
private ExecutorType executorType;
@Getter
private ExecutorStatus status;
// TODO Violation of the Dependency Inversion Principle?,
// TODO do this with only services
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();
Logger logger = Logger.getLogger(ExecutorBase.class.getName());
protected ExecutorBase(ExecutorType executorType, String uri) {
logger.info("ExecutorBase | Starting Executor");
this.status = ExecutorStatus.STARTING_UP;
this.executorType = executorType;
this.executorURI = new ExecutorURI(uri);
// TODO do this in main
// Notify executor-pool about existence. If executor-pools response is successfull start with getting an assignment, else shut down executor.
logger.info("ExecutorBase | Notifying executor-pool about existens");
if(!notifyExecutorPoolService.notifyExecutorPool(this.executorURI, this.executorType)) {
logger.log(Level.WARNING, "ExecutorBase | Executor could not connect to executor pool! Shuting down!");
System.exit(0);
} else {
logger.info("ExecutorBase | Executor conntected to executor pool");
this.status = ExecutorStatus.IDLING;
getAssignment();
}
}
/**
* Requests a new task from the task queue
* @return void
**/
public void getAssignment() {
Task newTask = getAssignmentPort.getAssignment(this.getExecutorType(), this.getExecutorURI());
if (newTask != null) {
logger.info("ExecutorBase | Executor got a new task");
this.executeTask(newTask);
} else {
logger.info("ExecutorBase | Executor got no new task");
this.status = ExecutorStatus.IDLING;
}
}
/**
* Start the execution of a task
* @return void
**/
private void executeTask(Task task) {
logger.info("ExecutorBase | Starting execution");
this.status = ExecutorStatus.EXECUTING;
task.setOutputData(execution(task.getInputData()));
// TODO implement logic if execution was not successful
executionFinishedEventPort.publishExecutionFinishedEvent(
new ExecutionFinishedEvent(task.getTaskID(), task.getOutputData(), "SUCCESS"));
logger.info("ExecutorBase | Finish execution");
getAssignment();
}
/**
* Implementation of the actual execution method of an executor
* @return the execution result
**/
protected abstract String execution(String input);
}

View File

@ -1,22 +0,0 @@
package ch.unisg.executorbase.executor.domain;
public enum ExecutorType {
COMPUTATION, SMALLROBOT, HUMIDITY;
/**
* Checks if the give executor type exists.
* @return Whether the given executor type exists
**/
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,66 @@
package ch.unisg.executorbase;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.executorbase.services.GetAssignmentService;
import ch.unisg.executorbase.services.NotifyExecutorPoolService;
import lombok.Getter;
@Component
public class Executor {
@Getter
ExecutorStatus executorStatus = ExecutorStatus.STARTING_UP;
@Getter
@Value("${executor.type}")
String executorType;
@Getter
@Value("${executor.uri}")
ExecutorURI executorUri;
@Autowired
NotifyExecutorPoolService notifyExecutorPoolService;
@Autowired
GetAssignmentService getAssignmentService;
private Logger logger = Logger.getLogger(Executor.class.getName());
public Executor() {
executorStatus = ExecutorStatus.IDLING;
}
public void init() {
if(!notifyExecutorPoolService.executorStarted(this.executorUri, this.executorType)) {
logger.log(Level.WARNING, "ExecutorBase | Executor could not connect to executor pool! Shuting down!");
System.exit(0);
} else {
logger.info("ExecutorBase | Executor conntected to executor pool");
this.setIdling();
getAssignmentService.getAssignment();
}
}
// @PreDestroy
// public void preDestroy() {
// System.out.println("TEST");
// notifyExecutorPoolService.executorStopped(this.executorUri);
// }
public void setIdling() {
this.executorStatus = ExecutorStatus.IDLING;
}
public void setExecuting() {
this.executorStatus = ExecutorStatus.EXECUTING;
}
}

View File

@ -0,0 +1,27 @@
package ch.unisg.executorbase;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import ch.unisg.executorbase.services.NotifyExecutorPoolService;
public class ExecutorBase {
@Autowired
Executor executor;
@Autowired
NotifyExecutorPoolService notifyExecutorPoolService;
@PostConstruct
private void initialiseRoster(){
executor.init();
}
@PreDestroy
public void test() {
System.out.println("TEST");
}
}

View File

@ -1,4 +1,4 @@
package ch.unisg.executorbase.executor.domain; package ch.unisg.executorbase;
public enum ExecutorStatus { public enum ExecutorStatus {
STARTING_UP, // Executor is starting STARTING_UP, // Executor is starting

View File

@ -1,4 +1,4 @@
package ch.unisg.executorbase.executor.domain; package ch.unisg.executorbase;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;

View File

@ -1,7 +1,9 @@
package ch.unisg.executorbase.executor.adapter.in.web; package ch.unisg.executorbase.controller;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -9,17 +11,13 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import ch.unisg.executorbase.executor.application.port.in.TaskAvailableCommand; import ch.unisg.executorbase.services.TaskAvailableService;
import ch.unisg.executorbase.executor.application.port.in.TaskAvailableUseCase;
import ch.unisg.executorbase.executor.domain.ExecutorType;
@RestController @RestController
public class TaskAvailableController { public class TaskAvailableController {
private final TaskAvailableUseCase taskAvailableUseCase;
public TaskAvailableController(TaskAvailableUseCase taskAvailableUseCase) { @Autowired
this.taskAvailableUseCase = taskAvailableUseCase; private TaskAvailableService taskAvailableService;
}
Logger logger = Logger.getLogger(TaskAvailableController.class.getName()); Logger logger = Logger.getLogger(TaskAvailableController.class.getName());
@ -27,16 +25,12 @@ public class TaskAvailableController {
* Controller for notification about new events. * Controller for notification about new events.
* @return 200 OK * @return 200 OK
**/ **/
@GetMapping(path = "/newtask/{taskType}", consumes = { "application/json" }) @GetMapping(path = "/newtask/{taskType}")
public ResponseEntity<String> retrieveTaskFromTaskList(@PathVariable("taskType") String taskType) { public ResponseEntity<String> retrieveTaskFromTaskList(@PathVariable("taskType") String taskType) {
logger.info("ExecutorBase | New " + taskType + " task available"); logger.info("ExecutorBase | New " + taskType + " task available");
if (ExecutorType.contains(taskType.toUpperCase())) { CompletableFuture.runAsync(() -> taskAvailableService.newTaskAvailable(taskType.toUpperCase()));
TaskAvailableCommand command = new TaskAvailableCommand(
ExecutorType.valueOf(taskType.toUpperCase()));
taskAvailableUseCase.newTaskAvailable(command);
}
// Add the content type as a response header // Add the content type as a response header
HttpHeaders responseHeaders = new HttpHeaders(); HttpHeaders responseHeaders = new HttpHeaders();

View File

@ -0,0 +1,42 @@
package ch.unisg.executorbase.services;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import ch.unisg.executorbase.Executor;
import ch.unisg.executorbase.Task;
public abstract class ExecuteTaskServiceBase implements ExecuteTaskServiceInterface {
private Logger logger = Logger.getLogger(ExecuteTaskServiceBase.class.getName());
@Autowired
private Executor executor;
@Autowired
private GetAssignmentService getAssignmentService;
@Autowired
private ExecutionFinishedService executionFinishedService;
/**
* Start the execution of a task
* @return void
**/
public void executeTask(Task task) {
logger.info("ExecutorBase | Starting execution");
executor.setExecuting();
task.setOutputData(execution(task.getInputData()));
// TODO implement logic if execution was not successful
executionFinishedService.publishExecutionFinishedEvent(task.getTaskID(), task.getOutputData(), "SUCCESS");
logger.info("ExecutorBase | Finish execution");
getAssignmentService.getAssignment();
}
}

View File

@ -0,0 +1,13 @@
package ch.unisg.executorbase.services;
import ch.unisg.executorbase.Task;
public interface ExecuteTaskServiceInterface {
void executeTask(Task task);
/**
* Implementation of the actual execution method of an executor
* @return the execution result
**/
String execution(String input);
}

View File

@ -1,4 +1,4 @@
package ch.unisg.executorbase.executor.adapter.out.web; package ch.unisg.executorbase.services;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -9,36 +9,34 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.json.JSONObject; import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import ch.unisg.executorbase.executor.application.port.out.ExecutionFinishedEventPort; @Component
import ch.unisg.executorbase.executor.domain.ExecutionFinishedEvent; public class ExecutionFinishedService {
public class ExecutionFinishedEventAdapter implements ExecutionFinishedEventPort { @Value("${roster.uri}")
private String rosterUri;
String server = System.getenv("ROSTER_URI") == null ? private Logger logger = Logger.getLogger(ExecutionFinishedService.class.getName());
"http://localhost:8082" : System.getenv("ROSTER_URI");
Logger logger = Logger.getLogger(ExecutionFinishedEventAdapter.class.getName());
/** /**
* Publishes the execution finished event * Publishes the execution finished event
* @return void * @return void
**/ **/
@Override public void publishExecutionFinishedEvent(String taskID, String outputData, String status) {
public void publishExecutionFinishedEvent(ExecutionFinishedEvent event) {
logger.log(Level.INFO, "ExecutorBase | Sending finish execution event...."); logger.log(Level.INFO, "ExecutorBase | Sending finish execution event....");
String body = new JSONObject() String body = new JSONObject()
.put("taskID", event.getTaskID()) .put("taskID", taskID)
.put("outputData", event.getOutputData()) .put("outputData", outputData)
.put("status", event.getStatus()) .put("status", status)
.toString(); .toString();
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server+"/task/completed")) .uri(URI.create(rosterUri+"/task/completed"))
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body)) .POST(HttpRequest.BodyPublishers.ofString(body))
.build(); .build();
@ -53,7 +51,7 @@ public class ExecutionFinishedEventAdapter implements ExecutionFinishedEventPort
logger.log(Level.SEVERE, e.getLocalizedMessage(), e); logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
} }
logger.log(Level.INFO, "ExecutorBase | Finish execution event sent with result: {0}", event.getOutputData()); logger.log(Level.INFO, "ExecutorBase | Finish execution event sent with result: {0}", outputData);
} }
} }

View File

@ -1,4 +1,4 @@
package ch.unisg.executorbase.executor.adapter.out.web; package ch.unisg.executorbase.services;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -8,42 +8,57 @@ import java.net.http.HttpResponse;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.unisg.common.valueobject.ExecutorURI; import ch.unisg.executorbase.Executor;
import ch.unisg.executorbase.executor.application.port.out.GetAssignmentPort; import ch.unisg.executorbase.Task;
import ch.unisg.executorbase.executor.domain.ExecutorType;
import ch.unisg.executorbase.executor.domain.Task;
import org.json.JSONObject;
@Component @Component
@Primary @Primary
public class GetAssignmentAdapter implements GetAssignmentPort { public class GetAssignmentService {
String server = System.getenv("ROSTER_URI") == null ? @Value("${roster.uri}")
"http://localhost:8082" : System.getenv("ROSTER_URI"); String rosterUri;
Logger logger = Logger.getLogger(GetAssignmentAdapter.class.getName()); Logger logger = Logger.getLogger(GetAssignmentService.class.getName());
@Autowired
private Executor executor;
@Autowired
private ExecuteTaskServiceInterface executeTaskService;
public void getAssignment() {
Task newTask = requestAssignment();
if (newTask != null) {
logger.info("ExecutorBase | Executor got a new task");
executeTaskService.executeTask(newTask);
} else {
logger.info("ExecutorBase | Executor got no new task");
executor.setIdling();
}
}
/** /**
* Requests a new task assignment * Requests a new task assignment
* @return the assigned task * @return the assigned task
* @see Task * @see Task
**/ **/
@Override private Task requestAssignment() {
public Task getAssignment(ExecutorType executorType, ExecutorURI executorURI) {
String body = new JSONObject() String body = new JSONObject()
.put("executorType", executorType) .put("executorType", executor.getExecutorType())
.put("executorURI", executorURI.getValue()) .put("executorURI", executor.getExecutorUri().getValue())
.toString(); .toString();
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server+"/task/apply")) .uri(URI.create(rosterUri + "/task/apply"))
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body)) .POST(HttpRequest.BodyPublishers.ofString(body))
.build(); .build();
@ -72,5 +87,4 @@ public class GetAssignmentAdapter implements GetAssignmentPort {
return null; return null;
} }
} }

View File

@ -1,4 +1,4 @@
package ch.unisg.executorbase.executor.adapter.out.web; package ch.unisg.executorbase.services;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -9,29 +9,27 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.json.JSONObject; import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.unisg.common.valueobject.ExecutorURI; import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.executorbase.executor.application.port.out.NotifyExecutorPoolPort;
import ch.unisg.executorbase.executor.domain.ExecutorType;
@Component @Component
@Primary @Primary
public class NotifyExecutorPoolAdapter implements NotifyExecutorPoolPort { public class NotifyExecutorPoolService {
String server = System.getenv("EXECUTOR_POOL_URI") == null ? @Value("${executor.pool.uri}")
"http://localhost:8083" : System.getenv("EXECUTOR_POOL_URI"); String executorPoolUri;
Logger logger = Logger.getLogger(NotifyExecutorPoolAdapter.class.getName()); Logger logger = Logger.getLogger(NotifyExecutorPoolService.class.getName());
/** /**
* Notifies the executor-pool about the startup of this executor * Notifies the executor-pool about the startup of this executor
* @return if the notification was successful * @return if the notification was successful
**/ **/
@Override public boolean executorStarted(ExecutorURI executorURI, String executorType) {
public boolean notifyExecutorPool(ExecutorURI executorURI, ExecutorType executorType) {
String body = new JSONObject() String body = new JSONObject()
.put("executorTaskType", executorType) .put("executorTaskType", executorType)
@ -40,7 +38,7 @@ public class NotifyExecutorPoolAdapter implements NotifyExecutorPoolPort {
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server+"/executor-pool/executors")) .uri(URI.create(executorPoolUri + "/executor-pool/executors"))
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body)) .POST(HttpRequest.BodyPublishers.ofString(body))
.build(); .build();
@ -58,6 +56,28 @@ public class NotifyExecutorPoolAdapter implements NotifyExecutorPoolPort {
} }
return false; return false;
} }
/**
* Notifies the executor-pool about the shutdown of this executor
**/
public static void executorStopped(String executorURI) {
System.out.println("TEST");
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:8083" + "/executor-pool/executors/" + executorURI))
// .uri(URI.create(executorPoolUri + "/executor-pool/executors/" + executorURI))
.header("Content-Type", "application/json")
.DELETE()
.build();
try {
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (InterruptedException e) {
// logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Thread.currentThread().interrupt();
} catch (IOException e) {
// logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
} }

View File

@ -0,0 +1,28 @@
package ch.unisg.executorbase.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ch.unisg.executorbase.Executor;
import ch.unisg.executorbase.ExecutorStatus;
import lombok.RequiredArgsConstructor;
import javax.transaction.Transactional;
@RequiredArgsConstructor
@Component
@Transactional
public class TaskAvailableService {
@Autowired
Executor executor;
@Autowired
GetAssignmentService getAssignmentService;
public void newTaskAvailable(String taskType) {
if (executor.getExecutorStatus() == ExecutorStatus.IDLING && executor.getExecutorType().equalsIgnoreCase(taskType)) {
getAssignmentService.getAssignment();
}
}
}

View File

@ -1,6 +1,4 @@
server.port=8081 roster.uri=http://localhost:8082
roster.url=http://127.0.0.1:8082
executor.pool.url=http://127.0.0.1:8083
spring.profiles.active=chaos-monkey spring.profiles.active=chaos-monkey
chaos.monkey.enabled=false chaos.monkey.enabled=false

View File

@ -78,6 +78,12 @@
<artifactId>js-scriptengine</artifactId> <artifactId>js-scriptengine</artifactId>
<version>21.3.0</version> <version>21.3.0</version>
</dependency> </dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -0,0 +1,40 @@
package ch.unisg.executorcomputation;
import java.util.logging.Logger;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import ch.unisg.executorbase.services.ExecuteTaskServiceBase;
@Component
@Primary
public class ExecuteTaskService extends ExecuteTaskServiceBase {
Logger executorLogger = Logger.getLogger(ExecuteTaskService.class.getName());
@Override
public String execution(String input) {
executorLogger.info("Executor | Starting execution with inputData: " + input);
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String result = "";
try {
result = engine.eval(input).toString();
} catch (ScriptException e1) {
// TODO some logic if execution fails
executorLogger.severe(e1.getMessage());
return result;
}
executorLogger.info("Executor | Finish execution");
return result;
}
}

View File

@ -1,22 +1,30 @@
package ch.unisg.executorcomputation; package ch.unisg.executorcomputation;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import ch.unisg.executorcomputation.executor.domain.Executor; import ch.unisg.executorbase.ExecutorBase;
import ch.unisg.executorbase.services.NotifyExecutorPoolService;
@SpringBootApplication @SpringBootApplication
public class ExecutorcomputationApplication { @ComponentScan({"ch.unisg.executorbase", "ch.unisg.executorcomputation"})
public class ExecutorcomputationApplication extends ExecutorBase {
static Logger logger = Logger.getLogger(ExecutorcomputationApplication.class.getName()); static Logger logger = Logger.getLogger(ExecutorcomputationApplication.class.getName());
public static void main(String[] args) { public static void main(String[] args) {
/**
* This is not a nice solution but I didn't get the @PreDestroy hook to work... This is the
* only solution which was working so I had to make the executorStopped function static
* for now.
*/
Thread printingHook = new Thread(() -> NotifyExecutorPoolService.executorStopped("http://executor-computation:8085"));
Runtime.getRuntime().addShutdownHook(printingHook);
SpringApplication.run(ExecutorcomputationApplication.class, args); SpringApplication.run(ExecutorcomputationApplication.class, args);
Executor.getExecutor();
} }
} }

View File

@ -1,35 +0,0 @@
package ch.unisg.executorcomputation.executor.adapter.in.web;
import java.util.concurrent.CompletableFuture;
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()));
CompletableFuture.runAsync(() -> taskAvailableUseCase.newTaskAvailable(command));
}
return new ResponseEntity<>("OK", new HttpHeaders(), HttpStatus.OK);
}
}

View File

@ -1,28 +0,0 @@
package ch.unisg.executorcomputation.executor.application.service;
import org.springframework.stereotype.Component;
import ch.unisg.executorcomputation.executor.domain.Executor;
import ch.unisg.executorbase.executor.application.port.in.TaskAvailableCommand;
import ch.unisg.executorbase.executor.application.port.in.TaskAvailableUseCase;
import ch.unisg.executorbase.executor.domain.ExecutorStatus;
import lombok.RequiredArgsConstructor;
import javax.transaction.Transactional;
@RequiredArgsConstructor
@Component
@Transactional
public class TaskAvailableService implements TaskAvailableUseCase {
@Override
public void newTaskAvailable(TaskAvailableCommand command) {
Executor executor = Executor.getExecutor();
if (executor.getExecutorType() == command.getTaskType() &&
executor.getStatus() == ExecutorStatus.IDLING) {
executor.getAssignment();
}
}
}

View File

@ -1,57 +0,0 @@
package ch.unisg.executorcomputation.executor.domain;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import ch.unisg.executorbase.executor.domain.ExecutorBase;
import ch.unisg.executorbase.executor.domain.ExecutorType;
public class Executor extends ExecutorBase {
private static Logger executorLogger = Logger.getLogger(Executor.class.getName());
private static final Executor executor = new Executor(ExecutorType.COMPUTATION, "http://localhost:8085");
public static Executor getExecutor() {
return executor;
}
private Executor(ExecutorType executorType, String uri) {
super(executorType, uri);
}
@Override
protected
String execution(String inputData) {
executorLogger.info("Executor | Starting execution with inputData: " + inputData);
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String result = "";
try {
result = engine.eval(inputData).toString();
} catch (ScriptException e1) {
// TODO some logic if execution fails
executorLogger.severe(e1.getMessage());
return result;
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
return result;
// executorLogger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Thread.currentThread().interrupt();
}
executorLogger.info("Executor | Finish execution");
return result;
}
}

View File

@ -1,5 +1,10 @@
server.port=8085 server.port=8085
executor.type=COMPUTATION
executor.uri=http://localhost:8085
roster.uri=http://localhost:8082
executor.pool.uri=http://localhost:8083
spring.profiles.active=chaos-monkey spring.profiles.active=chaos-monkey
chaos.monkey.enabled=false chaos.monkey.enabled=false
management.endpoint.chaosmonkey.enabled=true management.endpoint.chaosmonkey.enabled=true

View File

@ -0,0 +1,27 @@
package ch.unisg.executorhumidity;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import ch.unisg.executorbase.services.ExecuteTaskServiceBase;
@Component
@Primary
public class ExecuteTaskService extends ExecuteTaskServiceBase {
@Autowired
GetHumidityService getHumidityService;
private Logger executorLogger = Logger.getLogger(ExecuteTaskService.class.getName());
@Override
public String execution(String input) {
executorLogger.info("Executor | Starting execution with inputData: " + input);
return getHumidityService.getHumidity();
}
}

View File

@ -2,15 +2,24 @@ package ch.unisg.executorhumidity;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import ch.unisg.executorhumidity.executor.domain.Executor; import ch.unisg.executorbase.ExecutorBase;
import ch.unisg.executorbase.services.NotifyExecutorPoolService;
@SpringBootApplication @SpringBootApplication
public class ExecutorhumidityApplication { @ComponentScan({"ch.unisg.executorbase", "ch.unisg.executorhumidity"})
public class ExecutorhumidityApplication extends ExecutorBase {
public static void main(String[] args) { public static void main(String[] args) {
/**
* This is not a nice solution but I didn't get the @PreDestroy hook to work... This is the
* only solution which was working so I had to make the executorStopped function static
* for now.
*/
Thread printingHook = new Thread(() -> NotifyExecutorPoolService.executorStopped("http://executor-humidity:8087"));
Runtime.getRuntime().addShutdownHook(printingHook);
SpringApplication.run(ExecutorhumidityApplication.class, args); SpringApplication.run(ExecutorhumidityApplication.class, args);
Executor.getExecutor();
} }
} }

View File

@ -1,23 +1,4 @@
package ch.unisg.executorhumidity.executor.adapter.out; package ch.unisg.executorhumidity;
import ch.unisg.executorhumidity.executor.application.port.out.GetHumidityPort;
import ch.unisg.ics.interactions.wot.td.ThingDescription;
import ch.unisg.ics.interactions.wot.td.affordances.Form;
import ch.unisg.ics.interactions.wot.td.affordances.PropertyAffordance;
import ch.unisg.ics.interactions.wot.td.clients.TDCoapRequest;
import ch.unisg.ics.interactions.wot.td.clients.TDCoapResponse;
import ch.unisg.ics.interactions.wot.td.io.TDGraphReader;
import ch.unisg.ics.interactions.wot.td.schemas.ObjectSchema;
import ch.unisg.ics.interactions.wot.td.vocabularies.TD;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
@ -32,15 +13,29 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import ch.unisg.ics.interactions.wot.td.ThingDescription;
import ch.unisg.ics.interactions.wot.td.affordances.Form;
import ch.unisg.ics.interactions.wot.td.affordances.PropertyAffordance;
import ch.unisg.ics.interactions.wot.td.clients.TDCoapRequest;
import ch.unisg.ics.interactions.wot.td.clients.TDCoapResponse;
import ch.unisg.ics.interactions.wot.td.io.TDGraphReader;
import ch.unisg.ics.interactions.wot.td.schemas.ObjectSchema;
import ch.unisg.ics.interactions.wot.td.vocabularies.TD;
@Component @Component
@Primary public class GetHumidityService {
public class GetHumidityAdapter implements GetHumidityPort {
String endpoint = System.getenv("SEARCH_ENGINE_URI") == null ? @Value("${search.engine.uri}")
"https://api.interactions.ics.unisg.ch/search/searchEngine" : System.getenv("SEARCH_ENGINE_URI"); String endpoint;
@Override
public String getHumidity() { public String getHumidity() {
String input = "@prefix dct: <http://purl.org/dc/terms/> . select ?title where { ?title dct:title 'Mirogate' }"; String input = "@prefix dct: <http://purl.org/dc/terms/> . select ?title where { ?title dct:title 'Mirogate' }";
@ -83,18 +78,14 @@ public class GetHumidityAdapter implements GetHumidityPort {
if (humidity.isPresent()) { if (humidity.isPresent()) {
Optional<Form> form = humidity.get().getFirstFormForOperationType(TD.readProperty); Optional<Form> form = humidity.get().getFirstFormForOperationType(TD.readProperty);
// System.out.println(humidity.get().getDataSchema().getDatatype());
if (form.isPresent()) { if (form.isPresent()) {
TDCoapRequest request = new TDCoapRequest(form.get(), TD.readProperty); TDCoapRequest request = new TDCoapRequest(form.get(), TD.readProperty);
try {
TDCoapResponse response = request.execute();
Map<String, Object> payload = response.getPayloadAsObject((ObjectSchema) humidity.get().getDataSchema());
Object result = payload.get("https://interactions.ics.unisg.ch/mirogate#HumidityValue");
return result.toString();
} catch (IOException e) { TDCoapResponse response = request.execute();
e.printStackTrace(); Map<String, Object> payload = response.getPayloadAsObject((ObjectSchema) humidity.get().getDataSchema());
} Object result = payload.get("https://interactions.ics.unisg.ch/mirogate#HumidityValue");
return result.toString();
} }
} }

View File

@ -1,38 +0,0 @@
package ch.unisg.executorhumidity.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;
import java.util.concurrent.CompletableFuture;
@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()));
CompletableFuture.runAsync(() -> taskAvailableUseCase.newTaskAvailable(command));
}
// Add the content type as a response header
HttpHeaders responseHeaders = new HttpHeaders();
return new ResponseEntity<>("OK", responseHeaders, HttpStatus.OK);
}
}

View File

@ -1,9 +0,0 @@
package ch.unisg.executorhumidity.executor.application.port.out;
import org.eclipse.californium.elements.exception.ConnectorException;
import java.io.IOException;
public interface GetHumidityPort {
String getHumidity();
}

View File

@ -1,27 +0,0 @@
package ch.unisg.executorhumidity.executor.application.service;
import ch.unisg.executorbase.executor.domain.ExecutorStatus;
import ch.unisg.executorhumidity.executor.domain.Executor;
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) {
Executor executor = Executor.getExecutor();
if(executor.getExecutorType() == command.getTaskType() &&
executor.getStatus() == ExecutorStatus.IDLING) {
executor.getAssignment();
}
}
}

View File

@ -1,28 +0,0 @@
package ch.unisg.executorhumidity.executor.domain;
import ch.unisg.executorbase.executor.domain.ExecutorBase;
import ch.unisg.executorbase.executor.domain.ExecutorType;
import ch.unisg.executorhumidity.executor.adapter.out.GetHumidityAdapter;
import ch.unisg.executorhumidity.executor.application.port.out.GetHumidityPort;
public class Executor extends ExecutorBase {
private static final Executor executor = new Executor(ExecutorType.HUMIDITY, "http://localhost:8087");
private final GetHumidityPort getHumidityPort = new GetHumidityAdapter();
private Executor(ExecutorType executorType, String uri) {
super(executorType, uri);
}
public static Executor getExecutor() {return executor;}
@Override
protected
String execution(String input) {
String result = getHumidityPort.getHumidity();
return result;
}
}

View File

@ -1,6 +1,10 @@
server.port=8087 server.port=8087
search.engine.uri=https://api.interactions.ics.unisg.ch/search/searchEngine search.engine.uri=https://api.interactions.ics.unisg.ch/search/searchEngine
executor.type=HUMIDITY
executor.uri=http://localhost:8087
roster.uri=http://localhost:8082
executor.pool.uri=http://localhost:8083
spring.profiles.active=chaos-monkey spring.profiles.active=chaos-monkey
chaos.monkey.enabled=false chaos.monkey.enabled=false

View File

@ -1,7 +1,5 @@
package ch.unisg.executorpool.adapter.common.clients; package ch.unisg.executorpool.adapter.common.clients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.paho.client.mqttv3.*; import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
@ -9,7 +7,6 @@ import java.nio.charset.StandardCharsets;
import java.util.UUID; import java.util.UUID;
public class TapasMqttClient { public class TapasMqttClient {
private static final Logger LOGGER = LogManager.getLogger(TapasMqttClient.class);
private static TapasMqttClient tapasClient = null; private static TapasMqttClient tapasClient = null;

View File

@ -1,6 +1,5 @@
package ch.unisg.executorpool.adapter.in.web; package ch.unisg.executorpool.adapter.in.web;
import ch.unisg.executorpool.adapter.common.clients.TapasMqttClient;
import ch.unisg.executorpool.adapter.common.formats.ExecutorJsonRepresentation; import ch.unisg.executorpool.adapter.common.formats.ExecutorJsonRepresentation;
import ch.unisg.executorpool.application.port.in.AddNewExecutorToExecutorPoolUseCase; import ch.unisg.executorpool.application.port.in.AddNewExecutorToExecutorPoolUseCase;
import ch.unisg.executorpool.application.port.in.AddNewExecutorToExecutorPoolCommand; import ch.unisg.executorpool.application.port.in.AddNewExecutorToExecutorPoolCommand;
@ -14,10 +13,6 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ResponseStatusException;
import javax.validation.ConstraintViolationException; import javax.validation.ConstraintViolationException;
import java.net.URI; import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import org.eclipse.paho.client.mqttv3.*;
@RestController @RestController
public class AddNewExecutorToExecutorPoolWebController { public class AddNewExecutorToExecutorPoolWebController {

View File

@ -1,6 +1,5 @@
package ch.unisg.executorpool.adapter.out.messaging; package ch.unisg.executorpool.adapter.out.messaging;
import ch.unisg.common.ConfigProperties;
import ch.unisg.executorpool.adapter.common.clients.TapasMqttClient; import ch.unisg.executorpool.adapter.common.clients.TapasMqttClient;
import ch.unisg.executorpool.adapter.common.formats.ExecutorJsonRepresentation; import ch.unisg.executorpool.adapter.common.formats.ExecutorJsonRepresentation;
import ch.unisg.executorpool.application.port.out.ExecutorAddedEventPort; import ch.unisg.executorpool.application.port.out.ExecutorAddedEventPort;
@ -13,20 +12,12 @@ import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.net.URI;
@Component @Component
@Primary @Primary
public class PublishExecutorAddedEventAdapter implements ExecutorAddedEventPort { public class PublishExecutorAddedEventAdapter implements ExecutorAddedEventPort {
private static final Logger LOGGER = LogManager.getLogger(PublishExecutorAddedEventAdapter.class); private static final Logger LOGGER = LogManager.getLogger(PublishExecutorAddedEventAdapter.class);
// TODO Can't autowire. Find fix
/*
@Autowired
private ConfigProperties config;
*/
@Autowired @Autowired
private Environment environment; private Environment environment;

View File

@ -1,13 +1,14 @@
package ch.unisg.executorpool.application.port.in; package ch.unisg.executorpool.application.port.in;
import ch.unisg.common.SelfValidating; import ch.unisg.common.SelfValidating;
import ch.unisg.executorpool.domain.ExecutorPool;
import ch.unisg.executorpool.domain.ExecutorClass.ExecutorUri; import ch.unisg.executorpool.domain.ExecutorClass.ExecutorUri;
import ch.unisg.executorpool.domain.ExecutorClass.ExecutorTaskType; import ch.unisg.executorpool.domain.ExecutorClass.ExecutorTaskType;
import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@Value @Value
@EqualsAndHashCode(callSuper=false)
public class AddNewExecutorToExecutorPoolCommand extends SelfValidating<AddNewExecutorToExecutorPoolCommand> { public class AddNewExecutorToExecutorPoolCommand extends SelfValidating<AddNewExecutorToExecutorPoolCommand> {
@NotNull @NotNull
private final ExecutorUri executorUri; private final ExecutorUri executorUri;

View File

@ -1,7 +1,6 @@
package ch.unisg.executorpool.application.port.in; package ch.unisg.executorpool.application.port.in;
import ch.unisg.executorpool.domain.ExecutorClass; import ch.unisg.executorpool.domain.ExecutorClass;
import ch.unisg.executorpool.domain.ExecutorPool;
import java.util.List; import java.util.List;

View File

@ -16,7 +16,6 @@ import static org.assertj.core.api.BDDAssertions.*;
import ch.unisg.executorpool.adapter.common.formats.ExecutorJsonRepresentation; import ch.unisg.executorpool.adapter.common.formats.ExecutorJsonRepresentation;
import ch.unisg.executorpool.application.port.out.AddExecutorPort; import ch.unisg.executorpool.application.port.out.AddExecutorPort;
import ch.unisg.executorpool.domain.ExecutorPool; import ch.unisg.executorpool.domain.ExecutorPool;
import ch.unisg.executorpool.domain.ExecutorClass;
import ch.unisg.executorpool.domain.ExecutorClass.ExecutorTaskType; import ch.unisg.executorpool.domain.ExecutorClass.ExecutorTaskType;
import ch.unisg.executorpool.domain.ExecutorClass.ExecutorUri; import ch.unisg.executorpool.domain.ExecutorClass.ExecutorUri;
@ -27,16 +26,13 @@ public class AddNewExecutorToExecutorPoolSystemTest {
@Autowired @Autowired
private TestRestTemplate restTemplate; private TestRestTemplate restTemplate;
@Autowired
private AddExecutorPort addExecutorPort;
@Test @Test
void AddNewExecutorToExecutorPool() throws JSONException { void AddNewExecutorToExecutorPool() throws JSONException {
ExecutorTaskType executorTaskType = new ExecutorTaskType("system-integration-test-type"); ExecutorTaskType executorTaskType = new ExecutorTaskType("system-integration-test-type");
ExecutorUri executorUri = new ExecutorUri(java.net.URI.create("example.org")); ExecutorUri executorUri = new ExecutorUri(java.net.URI.create("example.org"));
ResponseEntity response = whenAddNewExecutorToEmptyPool(executorTaskType, executorUri); ResponseEntity<String> response = whenAddNewExecutorToEmptyPool(executorTaskType, executorUri);
JSONObject responseJson = new JSONObject(response.getBody().toString()); JSONObject responseJson = new JSONObject(response.getBody().toString());
String respExecutorUri = responseJson.getString("executorUri"); String respExecutorUri = responseJson.getString("executorUri");
@ -50,7 +46,7 @@ public class AddNewExecutorToExecutorPoolSystemTest {
} }
private ResponseEntity whenAddNewExecutorToEmptyPool(ExecutorTaskType executorTaskType, private ResponseEntity whenAddNewExecutorToEmptyPool(ExecutorTaskType executorTaskType,
ExecutorUri executorUri) throws JSONException { ExecutorUri executorUri) throws JSONException {
ExecutorPool.getExecutorPool().getListOfExecutors().getValue().clear(); ExecutorPool.getExecutorPool().getListOfExecutors().getValue().clear();

View File

@ -1,9 +1,6 @@
package ch.unisg.executorpool; package ch.unisg.executorpool;
import java.util.Optional;
import ch.unisg.executorpool.application.port.out.LoadExecutorPort; import ch.unisg.executorpool.application.port.out.LoadExecutorPort;
import org.bson.json.JsonObject;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import static org.mockito.BDDMockito.eq; import static org.mockito.BDDMockito.eq;

View File

@ -1,7 +1,6 @@
package ch.unisg.executorpool; package ch.unisg.executorpool;
import java.net.URI; import java.net.URI;
import java.util.Optional;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@ -0,0 +1,27 @@
package ch.unisg.executorrobot;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import ch.unisg.executorbase.services.ExecuteTaskServiceBase;
@Component
@Primary
public class ExecuteTaskService extends ExecuteTaskServiceBase {
@Autowired
RobotService robotService;
private Logger executorLogger = Logger.getLogger(ExecuteTaskService.class.getName());
@Override
public String execution(String input) {
executorLogger.info("Executor | Starting execution with inputData: " + input);
robotService.executeRobotTask();
return "";
}
}

View File

@ -1,18 +1,26 @@
package ch.unisg.executorrobot; package ch.unisg.executorrobot;
import java.util.concurrent.TimeUnit;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import ch.unisg.executorrobot.executor.domain.Executor; import ch.unisg.executorbase.ExecutorBase;
import ch.unisg.executorbase.services.NotifyExecutorPoolService;
@SpringBootApplication @SpringBootApplication
public class ExecutorrobotApplication { @ComponentScan({"ch.unisg.executorbase", "ch.unisg.executorrobot"})
public class ExecutorrobotApplication extends ExecutorBase {
public static void main(String[] args) { public static void main(String[] args) {
/**
* This is not a nice solution but I didn't get the @PreDestroy hook to work... This is the
* only solution which was working so I had to make the executorStopped function static
* for now.
*/
// Thread printingHook = new Thread(() -> NotifyExecutorPoolService.executorStopped("http://localhost:8084"));
Thread printingHook = new Thread(() -> NotifyExecutorPoolService.executorStopped("http://executor-robot:8084"));
Runtime.getRuntime().addShutdownHook(printingHook);
SpringApplication.run(ExecutorrobotApplication.class, args); SpringApplication.run(ExecutorrobotApplication.class, args);
Executor.getExecutor();
} }
} }

View File

@ -1,4 +1,5 @@
package ch.unisg.executorrobot.executor.adapter.out; package ch.unisg.executorrobot;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.net.URI; import java.net.URI;
@ -9,11 +10,20 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import ch.unisg.ics.interactions.wot.td.ThingDescription; import ch.unisg.ics.interactions.wot.td.ThingDescription;
import ch.unisg.ics.interactions.wot.td.affordances.ActionAffordance; import ch.unisg.ics.interactions.wot.td.affordances.ActionAffordance;
import ch.unisg.ics.interactions.wot.td.affordances.Form; import ch.unisg.ics.interactions.wot.td.affordances.Form;
@ -27,25 +37,15 @@ import ch.unisg.ics.interactions.wot.td.security.SecurityScheme;
import ch.unisg.ics.interactions.wot.td.vocabularies.TD; import ch.unisg.ics.interactions.wot.td.vocabularies.TD;
import ch.unisg.ics.interactions.wot.td.vocabularies.WoTSec; import ch.unisg.ics.interactions.wot.td.vocabularies.WoTSec;
import org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import ch.unisg.executorrobot.executor.application.port.out.UserToRobotPort;
@Component @Component
@Primary public class RobotService {
public class UserToRobotAdapter implements UserToRobotPort {
@Override @Value("${search.engine.uri}")
public String userToRobot() { String endpoint;
String endpoint = "https://api.interactions.ics.unisg.ch/search/searchEngine"; private Logger logger = Logger.getLogger(RobotService.class.getName());
public String executeRobotTask() {
String input = "@prefix dct: <http://purl.org/dc/terms/> . select ?title where { ?title dct:title 'leubot1' }"; String input = "@prefix dct: <http://purl.org/dc/terms/> . select ?title where { ?title dct:title 'leubot1' }";
@ -83,10 +83,10 @@ public class UserToRobotAdapter implements UserToRobotPort {
ThingDescription td = TDGraphReader.readFromURL(ThingDescription.TDFormat.RDF_TURTLE, leubot1Uri); ThingDescription td = TDGraphReader.readFromURL(ThingDescription.TDFormat.RDF_TURTLE, leubot1Uri);
String apiUrl = getAPIKey(td); String apiUrl = getAPIKey(td);
System.out.println("FOUND API URL " + apiUrl); logger.info("Executor | FOUND API URL " + apiUrl);
String apiKey = apiUrl.split("/")[apiUrl.split("/").length-1].split("]")[0]; String apiKey = apiUrl.split("/")[apiUrl.split("/").length-1].split("]")[0];
System.out.println("FOUND KEY " + apiKey); logger.info("Executor | FOUND KEY " + apiKey);
if(apiKey == null) { if(apiKey == null) {
// TODO implement logic if execution failed // TODO implement logic if execution failed
@ -160,7 +160,7 @@ public class UserToRobotAdapter implements UserToRobotPort {
try { try {
TDHttpResponse response = request.execute(); TDHttpResponse response = request.execute();
System.out.println("Received response with status code: " + response.getStatusCode()); logger.info("Executor | Received response with status code: " + response.getStatusCode());
String url = response.getHeaders().get("Location"); String url = response.getHeaders().get("Location");
return url; return url;
@ -210,7 +210,7 @@ public class UserToRobotAdapter implements UserToRobotPort {
try { try {
TDHttpResponse response = request.execute(); TDHttpResponse response = request.execute();
System.out.println("Received response with status code: " + response.getStatusCode()); logger.info("Executor | Received response with status code: " + response.getStatusCode());
return true; return true;
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -230,12 +230,11 @@ public class UserToRobotAdapter implements UserToRobotPort {
try { try {
var response = client.send(request, HttpResponse.BodyHandlers.ofString()); var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); logger.info("Executor | Delete user from robot response code: " + response.statusCode());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }

View File

@ -1,38 +0,0 @@
package ch.unisg.executorrobot.executor.adapter.in.web;
import java.util.concurrent.CompletableFuture;
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()));
CompletableFuture.runAsync(() -> taskAvailableUseCase.newTaskAvailable(command));
}
// Add the content type as a response header
HttpHeaders responseHeaders = new HttpHeaders();
return new ResponseEntity<>("OK", responseHeaders, HttpStatus.OK);
}
}

View File

@ -1,7 +0,0 @@
package ch.unisg.executorrobot.executor.application.port.out;
import ch.unisg.executorbase.executor.domain.ExecutorType;
public interface UserToRobotPort {
String userToRobot();
}

View File

@ -1,28 +0,0 @@
package ch.unisg.executorrobot.executor.application.service;
import org.springframework.stereotype.Component;
import ch.unisg.executorrobot.executor.domain.Executor;
import ch.unisg.executorbase.executor.application.port.in.TaskAvailableCommand;
import ch.unisg.executorbase.executor.application.port.in.TaskAvailableUseCase;
import ch.unisg.executorbase.executor.domain.ExecutorStatus;
import lombok.RequiredArgsConstructor;
import javax.transaction.Transactional;
@RequiredArgsConstructor
@Component
@Transactional
public class TaskAvailableService implements TaskAvailableUseCase {
@Override
public void newTaskAvailable(TaskAvailableCommand command) {
Executor executor = Executor.getExecutor();
if (executor.getExecutorType() == command.getTaskType() &&
executor.getStatus() == ExecutorStatus.IDLING) {
executor.getAssignment();
}
}
}

View File

@ -1,28 +0,0 @@
package ch.unisg.executorrobot.executor.domain;
import ch.unisg.executorrobot.executor.adapter.out.UserToRobotAdapter;
import ch.unisg.executorrobot.executor.application.port.out.UserToRobotPort;
import ch.unisg.executorbase.executor.domain.ExecutorBase;
import ch.unisg.executorbase.executor.domain.ExecutorType;
public class Executor extends ExecutorBase {
private static final Executor executor = new Executor(ExecutorType.SMALLROBOT, "http://localhost:8084");
private final UserToRobotPort userToRobotPort = new UserToRobotAdapter();
public static Executor getExecutor() {
return executor;
}
private Executor(ExecutorType executorType, String uri) {
super(executorType, uri);
}
@Override
protected
String execution(String input) {
userToRobotPort.userToRobot();
return "";
}
}

View File

@ -1 +1,19 @@
server.port=8084 server.port=8084
executor.type=SMALLROBOT
executor.uri=http://localhost:8084
roster.uri=http://localhost:8082
executor.pool.uri=http://localhost:8083
search.engine.uri=https://api.interactions.ics.unisg.ch/search/searchEngine
spring.profiles.active=chaos-monkey
chaos.monkey.enabled=false
management.endpoint.chaosmonkey.enabled=true
management.endpoint.chaosmonkeyjmx.enabled=true
# include specific endpoints
management.endpoints.web.exposure.include=health,info,chaosmonkey
chaos.monkey.watcher.controller=true
chaos.monkey.watcher.restController=true
chaos.monkey.watcher.service=true
chaos.monkey.watcher.repository=true
chaos.monkey.watcher.component=true

View File

@ -9,7 +9,6 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.function.ServerRequest.Headers;
import ch.unisg.roster.roster.application.port.in.NewTaskCommand; import ch.unisg.roster.roster.application.port.in.NewTaskCommand;
import ch.unisg.roster.roster.application.port.in.NewTaskUseCase; import ch.unisg.roster.roster.application.port.in.NewTaskUseCase;

View File

@ -4,7 +4,10 @@ import ch.unisg.roster.roster.domain.ExecutorInfo;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -15,11 +18,12 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@Component
@Primary
public class GetExecutorsInExecutorPoolWebAdapter { public class GetExecutorsInExecutorPoolWebAdapter {
private static final Logger LOGGER = LogManager.getLogger(GetExecutorsInExecutorPoolWebAdapter.class); private static final Logger LOGGER = LogManager.getLogger(GetExecutorsInExecutorPoolWebAdapter.class);
// TODO get from config @Value("${executor.pool.uri}")
String server = "http://localhost:8083"; String server = "http://localhost:8083";
public List<ExecutorInfo> getExecutorsInExecutorPool(){ public List<ExecutorInfo> getExecutorsInExecutorPool(){

View File

@ -5,29 +5,22 @@ import java.net.URI;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.roster.roster.application.port.out.NewTaskEventPort; import ch.unisg.roster.roster.application.port.out.NewTaskEventPort;
import ch.unisg.roster.roster.domain.ExecutorRegistry;
import ch.unisg.roster.roster.domain.event.NewTaskEvent; import ch.unisg.roster.roster.domain.event.NewTaskEvent;
@Component @Component
@Primary @Primary
public class PublishNewTaskEventAdapter implements NewTaskEventPort { public class PublishNewTaskEventAdapter implements NewTaskEventPort {
@Value("${executor.robot.uri}")
private String server;
@Value("${executor.computation.uri}")
private String server2;
@Value("${executor.humidity.uri}")
private String server3;
Logger logger = Logger.getLogger(PublishNewTaskEventAdapter.class.getName()); Logger logger = Logger.getLogger(PublishNewTaskEventAdapter.class.getName());
/** /**
@ -37,53 +30,26 @@ public class PublishNewTaskEventAdapter implements NewTaskEventPort {
@Override @Override
public void publishNewTaskEvent(NewTaskEvent event) { public void publishNewTaskEvent(NewTaskEvent event) {
HttpClient client = HttpClient.newHttpClient(); Set<ExecutorURI> executors = ExecutorRegistry.getInstance().getExecutorsByType(event.taskType.getValue());
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server + "/newtask/" + event.taskType.getValue())) for (ExecutorURI uri : executors) {
.GET() HttpClient client = HttpClient.newHttpClient();
.build(); HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri.getValue() + "/newtask/" + event.taskType.getValue()))
.GET()
.build();
try { try {
client.send(request, HttpResponse.BodyHandlers.ofString()); client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e); logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e); logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
} }
HttpClient client2 = HttpClient.newHttpClient();
HttpRequest request2 = HttpRequest.newBuilder()
.uri(URI.create(server2 + "/newtask/" + event.taskType.getValue()))
.GET()
.build();
try {
client2.send(request2, HttpResponse.BodyHandlers.ofString());
} catch (InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
Thread.currentThread().interrupt();
} catch (IOException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
HttpClient client3 = HttpClient.newHttpClient();
HttpRequest request3 = HttpRequest.newBuilder()
.uri(URI.create(server3 + "/newtask/" + event.taskType.getValue()))
.GET()
.build();
try {
client3.send(request3, HttpResponse.BodyHandlers.ofString());
} catch (InterruptedException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
Thread.currentThread().interrupt();
} catch (IOException e) {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
} }
} }

View File

@ -45,7 +45,7 @@ public class PublishTaskAssignedEventAdapter implements TaskAssignedEventPort {
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server + "/tasks/" + event.taskID)) .uri(URI.create(server + "/tasks/" + event.taskID))
.header("Content-Type", "application/task+json") .header("Content-Type", "application/json-patch+json")
.method("PATCH", HttpRequest.BodyPublishers.ofString(body)) .method("PATCH", HttpRequest.BodyPublishers.ofString(body))
.build(); .build();
@ -57,27 +57,6 @@ public class PublishTaskAssignedEventAdapter implements TaskAssignedEventPort {
logger.log(Level.SEVERE, e.getLocalizedMessage(), e); logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
} }
// 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/task+json")
// .POST(HttpRequest.BodyPublishers.ofString(body))
// .build();
// try {
// client.send(request, HttpResponse.BodyHandlers.ofString());
// } catch (InterruptedException e) {
// logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Thread.currentThread().interrupt();
// } catch (IOException e) {
// logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// }
} }
} }

View File

@ -38,10 +38,10 @@ public class PublishTaskCompletedEventAdapter implements TaskCompletedEventPort
JSONObject op1 = new JSONObject() JSONObject op1 = new JSONObject()
.put("op", "replace") .put("op", "replace")
.put("path", "/taskStatus") .put("path", "/taskStatus")
.put("value", event.status); .put("value", "EXECUTED");
JSONObject op2 = new JSONObject() JSONObject op2 = new JSONObject()
.put("op", "replace") .put("op", "add")
.put("path", "/outputData") .put("path", "/outputData")
.put("value", event.result); .put("value", event.result);
@ -50,7 +50,7 @@ public class PublishTaskCompletedEventAdapter implements TaskCompletedEventPort
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(server + "/tasks/" + event.taskID)) .uri(URI.create(server + "/tasks/" + event.taskID))
.header("Content-Type", "application/task+json") .header("Content-Type", "application/json-patch+json")
.method("PATCH", HttpRequest.BodyPublishers.ofString(body)) .method("PATCH", HttpRequest.BodyPublishers.ofString(body))
.build(); .build();
@ -62,29 +62,6 @@ public class PublishTaskCompletedEventAdapter implements TaskCompletedEventPort
logger.log(Level.SEVERE, e.getLocalizedMessage(), e); logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
} }
// String body = new JSONObject()
// .put("taskId", event.taskID)
// .put("status", event.status)
// .put("outputData", event.result)
// .toString();
// HttpClient client = HttpClient.newHttpClient();
// HttpRequest request = HttpRequest.newBuilder()
// .uri(URI.create(server + "/tasks/completeTask/"))
// .header("Content-Type", "application/task+json")
// .POST(HttpRequest.BodyPublishers.ofString(body))
// .build();
// try {
// client.send(request, HttpResponse.BodyHandlers.ofString());
// } catch (InterruptedException e) {
// logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// Thread.currentThread().interrupt();
// } catch (IOException e) {
// logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
// }
} }
} }

View File

@ -5,8 +5,6 @@ import ch.unisg.common.valueobject.ExecutorURI;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.net.URI;
public class ExecutorInfo { public class ExecutorInfo {
@Getter @Getter
@Setter @Setter

View File

@ -4,6 +4,7 @@ import java.util.*;
import ch.unisg.common.valueobject.ExecutorURI; import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.roster.roster.domain.valueobject.ExecutorType; import ch.unisg.roster.roster.domain.valueobject.ExecutorType;
import lombok.Getter;
/** /**
* Registry that keeps a track of executors internal to the TAPAS application and the types of tasks * Registry that keeps a track of executors internal to the TAPAS application and the types of tasks
@ -98,4 +99,8 @@ public class ExecutorRegistry {
this.executors.putAll(executors); this.executors.putAll(executors);
} }
public Set<ExecutorURI> getExecutorsByType(String executorType) {
return this.executors.get(new ExecutorType(executorType));
}
} }

View File

@ -1,9 +1,8 @@
server.port=8082 server.port=8082
executor.robot.uri=http://127.0.0.1:8084
executor.computation.uri=http://127.0.0.1:8085
executor.humidity.uri=http://127.0.0.1:8087
auction.house.uri=http://127.0.0.1:8086 auction.house.uri=http://127.0.0.1:8086
task.list.uri=http://127.0.0.1:8081 task.list.uri=http://127.0.0.1:8081
executor.pool.uri=http://localhost:8083
# mqtt.broker.uri=tcp://localhost:1883 # mqtt.broker.uri=tcp://localhost:1883
mqtt.broker.uri=tcp://broker.hivemq.com mqtt.broker.uri=tcp://broker.hivemq.com

View File

@ -20,11 +20,14 @@ import java.util.Optional;
public class TaskExecutedEventListenerHttpAdapter extends TaskEventListener { public class TaskExecutedEventListenerHttpAdapter extends TaskEventListener {
public Task handleTaskEvent(String taskId, JsonNode payload) { public Task handleTaskEvent(String taskId, JsonNode payload) {
System.out.println(payload);
TaskJsonPatchRepresentation representation = new TaskJsonPatchRepresentation(payload); TaskJsonPatchRepresentation representation = new TaskJsonPatchRepresentation(payload);
Optional<Task.ServiceProvider> serviceProvider = representation.extractFirstServiceProviderChange(); Optional<Task.ServiceProvider> serviceProvider = representation.extractFirstServiceProviderChange();
Optional<Task.OutputData> outputData = representation.extractFirstOutputDataAddition(); Optional<Task.OutputData> outputData = representation.extractFirstOutputDataAddition();
System.out.println(outputData);
TaskExecutedEvent taskExecutedEvent = new TaskExecutedEvent(new Task.TaskId(taskId), TaskExecutedEvent taskExecutedEvent = new TaskExecutedEvent(new Task.TaskId(taskId),
serviceProvider, outputData); serviceProvider, outputData);
TaskExecutedEventHandler taskExecutedEventHandler = new TaskExecutedHandler(); TaskExecutedEventHandler taskExecutedEventHandler = new TaskExecutedHandler();