diff --git a/.github/workflows/ci.executor1.yml b/.github/workflows/ci.executor1.yml
index 5d48580..708d7d4 100644
--- a/.github/workflows/ci.executor1.yml
+++ b/.github/workflows/ci.executor1.yml
@@ -37,7 +37,7 @@ jobs:
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build executorBase
- run: mvn -f executor-base/pom.xml -B verify
+ run: mvn -f executor-base/pom.xml -B install
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/ci.executor2.yml b/.github/workflows/ci.executor2.yml
index 32a59a8..5ae38f0 100644
--- a/.github/workflows/ci.executor2.yml
+++ b/.github/workflows/ci.executor2.yml
@@ -37,7 +37,7 @@ jobs:
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build executorBase
- run: mvn -f executor-base/pom.xml -B verify
+ run: mvn -f executor-base/pom.xml -B install
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/assignment/pom.xml b/assignment/pom.xml
index 43af6c3..99996b8 100644
--- a/assignment/pom.xml
+++ b/assignment/pom.xml
@@ -30,6 +30,11 @@
runtime
true
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
org.projectlombok
lombok
@@ -40,6 +45,24 @@
spring-boot-starter-test
test
+
+ javax.validation
+ validation-api
+ 1.1.0.Final
+
+
+ javax.transaction
+ javax.transaction-api
+ 1.2
+
+
+
+ org.json
+ json
+ 20210307
+
+
+
diff --git a/assignment/src/main/java/ch/unisg/assignment/TestController.java b/assignment/src/main/java/ch/unisg/assignment/TestController.java
deleted file mode 100644
index ac8e4f9..0000000
--- a/assignment/src/main/java/ch/unisg/assignment/TestController.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package ch.unisg.assignment;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-public class TestController {
- @RequestMapping("/")
- public String index() {
- return "Hello World! Assignment";
- }
-}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/ApplyForTaskController.java b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/ApplyForTaskController.java
new file mode 100644
index 0000000..1d0111d
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/ApplyForTaskController.java
@@ -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);
+
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/NewTaskController.java b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/NewTaskController.java
new file mode 100644
index 0000000..18bad8f
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/NewTaskController.java
@@ -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 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);
+
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/TaskCompletedController.java b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/TaskCompletedController.java
new file mode 100644
index 0000000..e8335ed
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/TaskCompletedController.java
@@ -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 addNewTaskTaskToTaskList(@RequestBody Task task) {
+
+ TaskCompletedCommand command = new TaskCompletedCommand(task.getTaskID(), task.getTaskType(),
+ task.getStatus(), task.getResult());
+
+ taskCompletedUseCase.taskCompleted(command);
+
+ return new ResponseEntity<>(HttpStatus.OK);
+
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/WebControllerExceptionHandler.java b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/WebControllerExceptionHandler.java
new file mode 100644
index 0000000..08a0895
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/WebControllerExceptionHandler.java
@@ -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 handleException(PortOutOfRangeException e){
+
+ ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST, e.getLocalizedMessage());
+ return new ResponseEntity<>(error, error.getHttpStatus());
+
+ }
+
+ @ExceptionHandler(InvalidIP4Exception.class)
+ public ResponseEntity handleException(InvalidIP4Exception e){
+
+ ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST, e.getLocalizedMessage());
+ return new ResponseEntity<>(error, error.getHttpStatus());
+
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishNewTaskEventAdapter.java b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishNewTaskEventAdapter.java
new file mode 100644
index 0000000..1db2b84
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishNewTaskEventAdapter.java
@@ -0,0 +1,44 @@
+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: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();
+ }
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskAssignedEventAdapter.java b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskAssignedEventAdapter.java
new file mode 100644
index 0000000..85bb9ab
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskAssignedEventAdapter.java
@@ -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:8085";
+
+ 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/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();
+ }
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskCompletedEventAdapter.java b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskCompletedEventAdapter.java
new file mode 100644
index 0000000..f9f2833
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskCompletedEventAdapter.java
@@ -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();
+ }
+
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/ApplyForTaskCommand.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/ApplyForTaskCommand.java
new file mode 100644
index 0000000..df36d58
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/ApplyForTaskCommand.java
@@ -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{
+
+ @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();
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/ApplyForTaskUseCase.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/ApplyForTaskUseCase.java
new file mode 100644
index 0000000..1e7180a
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/ApplyForTaskUseCase.java
@@ -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);
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskCommand.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskCommand.java
new file mode 100644
index 0000000..ab6838e
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskCommand.java
@@ -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 {
+
+ @NotNull
+ private final String taskID;
+
+ @NotNull
+ private final ExecutorType taskType;
+
+ public NewTaskCommand(String taskID, ExecutorType taskType) {
+ this.taskID = taskID;
+ this.taskType = taskType;
+ this.validateSelf();
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskUseCase.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskUseCase.java
new file mode 100644
index 0000000..21f084e
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskUseCase.java
@@ -0,0 +1,5 @@
+package ch.unisg.assignment.assignment.application.port.in;
+
+public interface NewTaskUseCase {
+ boolean addNewTaskToQueue(NewTaskCommand newTaskCommand);
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedCommand.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedCommand.java
new file mode 100644
index 0000000..e324e89
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedCommand.java
@@ -0,0 +1,34 @@
+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 TaskCompletedCommand extends SelfValidating{
+
+ @NotNull
+ private final String taskID;
+
+ @NotNull
+ private final ExecutorType taskType;
+
+ @NotNull
+ private final String taskStatus;
+
+ @NotNull
+ private final String taskResult;
+
+ public TaskCompletedCommand(String taskID, ExecutorType taskType, String taskStatus, String taskResult) {
+ this.taskID = taskID;
+ this.taskType = taskType;
+ this.taskStatus = taskStatus;
+ this.taskResult = taskResult;
+ this.validateSelf();
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedUseCase.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedUseCase.java
new file mode 100644
index 0000000..1902952
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedUseCase.java
@@ -0,0 +1,5 @@
+package ch.unisg.assignment.assignment.application.port.in;
+
+public interface TaskCompletedUseCase {
+ void taskCompleted(TaskCompletedCommand taskCompletedCommand);
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/NewTaskEventPort.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/NewTaskEventPort.java
new file mode 100644
index 0000000..909a9ba
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/NewTaskEventPort.java
@@ -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);
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/TaskAssignedEventPort.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/TaskAssignedEventPort.java
new file mode 100644
index 0000000..fefd4a1
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/TaskAssignedEventPort.java
@@ -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);
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/TaskCompletedEventPort.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/TaskCompletedEventPort.java
new file mode 100644
index 0000000..43a8aa5
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/TaskCompletedEventPort.java
@@ -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);
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/ApplyForTaskService.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/ApplyForTaskService.java
new file mode 100644
index 0000000..0593a30
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/ApplyForTaskService.java
@@ -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;
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/NewTaskService.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/NewTaskService.java
new file mode 100644
index 0000000..069ee29
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/NewTaskService.java
@@ -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.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;
+
+ @Override
+ public boolean addNewTaskToQueue(NewTaskCommand command) {
+
+ // TODO Get availableTaskTypes from executor pool
+ List availableTaskTypes = Arrays.asList("ADDITION", "ROBOT");
+
+ if (!availableTaskTypes.contains(command.getTaskType().getValue())) {
+ 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;
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/TaskCompletedService.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/TaskCompletedService.java
new file mode 100644
index 0000000..c8273ff
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/TaskCompletedService.java
@@ -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()));
+
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/ExecutorInfo.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/ExecutorInfo.java
new file mode 100644
index 0000000..6b19dcc
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/ExecutorInfo.java
@@ -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;
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/Roster.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/Roster.java
new file mode 100644
index 0000000..521a748
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/Roster.java
@@ -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> queues = new HashMap<>();
+
+ private HashMap 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);
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/RosterItem.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/RosterItem.java
new file mode 100644
index 0000000..2c3bb52
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/RosterItem.java
@@ -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;
+ }
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/Task.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/Task.java
new file mode 100644
index 0000000..7daa738
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/Task.java
@@ -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() {}
+
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/NewTaskEvent.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/NewTaskEvent.java
new file mode 100644
index 0000000..34e7f0b
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/NewTaskEvent.java
@@ -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;
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskAssignedEvent.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskAssignedEvent.java
new file mode 100644
index 0000000..d0178d4
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskAssignedEvent.java
@@ -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;
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskCompletedEvent.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskCompletedEvent.java
new file mode 100644
index 0000000..432a8f0
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskCompletedEvent.java
@@ -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;
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/ExecutorType.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/ExecutorType.java
new file mode 100644
index 0000000..bc5f467
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/ExecutorType.java
@@ -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();
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/IP4Adress.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/IP4Adress.java
new file mode 100644
index 0000000..cd23b6b
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/IP4Adress.java
@@ -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();
+ }
+ }
+}
+
+
+
+
+
diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/Port.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/Port.java
new file mode 100644
index 0000000..a66dbbd
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/Port.java
@@ -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();
+ }
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/common/SelfValidating.java b/assignment/src/main/java/ch/unisg/assignment/common/SelfValidating.java
new file mode 100644
index 0000000..a8d366f
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/common/SelfValidating.java
@@ -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 {
+
+ 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> violations = validator.validate((T) this);
+ if (!violations.isEmpty()) {
+ throw new ConstraintViolationException(violations);
+ }
+ }
+}
+
diff --git a/assignment/src/main/java/ch/unisg/assignment/common/exception/ErrorResponse.java b/assignment/src/main/java/ch/unisg/assignment/common/exception/ErrorResponse.java
new file mode 100644
index 0000000..2fb834e
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/common/exception/ErrorResponse.java
@@ -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;
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/common/exception/InvalidIP4Exception.java b/assignment/src/main/java/ch/unisg/assignment/common/exception/InvalidIP4Exception.java
new file mode 100644
index 0000000..fecbfcb
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/common/exception/InvalidIP4Exception.java
@@ -0,0 +1,7 @@
+package ch.unisg.assignment.common.exception;
+
+public class InvalidIP4Exception extends Exception {
+ public InvalidIP4Exception() {
+ super("IP4 is invalid");
+ }
+}
diff --git a/assignment/src/main/java/ch/unisg/assignment/common/exception/PortOutOfRangeException.java b/assignment/src/main/java/ch/unisg/assignment/common/exception/PortOutOfRangeException.java
new file mode 100644
index 0000000..2772256
--- /dev/null
+++ b/assignment/src/main/java/ch/unisg/assignment/common/exception/PortOutOfRangeException.java
@@ -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)");
+ }
+}
diff --git a/assignment/src/main/resources/application.properties b/assignment/src/main/resources/application.properties
index 4d360de..3cf12af 100644
--- a/assignment/src/main/resources/application.properties
+++ b/assignment/src/main/resources/application.properties
@@ -1 +1 @@
-server.port=8081
+server.port=8082
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 76b8af1..8c4bfcf 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -1,62 +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:8081"
- - "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:8081"
- - "5009:5005"
- volumes:
- - ./executor2/src:/opt/app/src
- - ./executor2/target:/opt/app/target
+ 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
diff --git a/executor-base/pom.xml b/executor-base/pom.xml
index 6ad675a..2acba18 100644
--- a/executor-base/pom.xml
+++ b/executor-base/pom.xml
@@ -15,8 +15,6 @@
Demo project for Spring Boot
11
- scs-asse-fs21-group1
- https://sonarcloud.io
@@ -56,23 +54,12 @@
javax.transaction-api
1.2
+
+
+ org.json
+ json
+ 20210307
+
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
- org.projectlombok
- lombok
-
-
-
-
-
-
-
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/common/SelfValidating.java b/executor-base/src/main/java/ch/unisg/executorBase/common/SelfValidating.java
index 1d4a80a..5119ac5 100644
--- a/executor-base/src/main/java/ch/unisg/executorBase/common/SelfValidating.java
+++ b/executor-base/src/main/java/ch/unisg/executorBase/common/SelfValidating.java
@@ -21,6 +21,7 @@ public class SelfValidating {
* instance.
*/
protected void validateSelf() {
+ @SuppressWarnings("unchecked")
Set> violations = validator.validate((T) this);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/in/web/TaskAvailableController.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/in/web/TaskAvailableController.java
index 75d3a02..182f2ba 100644
--- a/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/in/web/TaskAvailableController.java
+++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/in/web/TaskAvailableController.java
@@ -21,7 +21,7 @@ public class TaskAvailableController {
@GetMapping(path = "/newtask/{taskType}")
public ResponseEntity retrieveTaskFromTaskList(@PathVariable("taskType") String taskType) {
-
+
if (ExecutorType.contains(taskType.toUpperCase())) {
TaskAvailableCommand command = new TaskAvailableCommand(
ExecutorType.valueOf(taskType.toUpperCase()));
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/ExecutionFinishedEventAdapter.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/ExecutionFinishedEventAdapter.java
index 2f53a2b..fd26d47 100644
--- a/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/ExecutionFinishedEventAdapter.java
+++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/ExecutionFinishedEventAdapter.java
@@ -5,54 +5,46 @@ import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
-import java.util.HashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.core.JsonProcessingException;
+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 {
- //This is the base URI of the service interested in this event (in my setup, running locally as separate Spring Boot application)
String server = "http://127.0.0.1:8082";
+ Logger logger = Logger.getLogger(ExecutionFinishedEventAdapter.class.getName());
+
@Override
public void publishExecutionFinishedEvent(ExecutionFinishedEvent event) {
- ///Here we would need to work with DTOs in case the payload of calls becomes more complex
- var values = new HashMap() {{
- put("result",event.getResult());
- put("status",event.getStatus());
- }};
-
- var objectMapper = new ObjectMapper();
- String requestBody = null;
- try {
- requestBody = objectMapper.writeValueAsString(values);
- } catch (JsonProcessingException e) {
- e.printStackTrace();
- }
+ 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/"+event.getTaskID()))
- .PUT(HttpRequest.BodyPublishers.ofString(requestBody))
+ .header("Content-Type", "application/json")
+ .PUT(HttpRequest.BodyPublishers.ofString(body))
.build();
- /** Needs the other service running
try {
- HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
- } catch (IOException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
+ 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());
-
+
}
-
+
}
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/GetAssignmentAdapter.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/GetAssignmentAdapter.java
index b3e7875..05852fa 100644
--- a/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/GetAssignmentAdapter.java
+++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/GetAssignmentAdapter.java
@@ -1,8 +1,12 @@
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;
@@ -11,35 +15,47 @@ 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 {
- //This is the base URI of the service interested in this event (in my setup, running locally as separate Spring Boot application)
String server = "http://127.0.0.1:8082";
+ Logger logger = Logger.getLogger(GetAssignmentAdapter.class.getName());
+
@Override
- public Task getAssignment(ExecutorType executorType) {
-
+ 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+"/assignment/" + executorType))
- .GET()
+ .uri(URI.create(server+"/task/apply"))
+ .header("Content-Type", "application/json")
+ .POST(HttpRequest.BodyPublishers.ofString(body))
.build();
- /** Needs the other service running
try {
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
- } catch (IOException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
+ 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();
}
- **/
- // TODO return null or a new Task here depending on the response of the http call
-
- return new Task("123");
+ return null;
}
-
+
}
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/NotifyExecutorPoolAdapter.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/NotifyExecutorPoolAdapter.java
index feeca69..bf465f7 100644
--- a/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/NotifyExecutorPoolAdapter.java
+++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/adapter/out/web/NotifyExecutorPoolAdapter.java
@@ -3,11 +3,8 @@ package ch.unisg.executorBase.executor.adapter.out.web;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
-import java.util.HashMap;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import org.json.JSONObject;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@@ -17,31 +14,22 @@ import ch.unisg.executorBase.executor.domain.ExecutorType;
@Component
@Primary
public class NotifyExecutorPoolAdapter implements NotifyExecutorPoolPort {
-
- //This is the base URI of the service interested in this event (in my setup, running locally as separate Spring Boot application)
+
String server = "http://127.0.0.1:8083";
@Override
public boolean notifyExecutorPool(String ip, int port, ExecutorType executorType) {
- var values = new HashMap() {{
- put("ip", ip);
- put("port", Integer.toString(port));
- put("executorType", executorType.toString());
- }};
-
- var objectMapper = new ObjectMapper();
- String requestBody = null;
- try {
- requestBody = objectMapper.writeValueAsString(values);
- } catch (JsonProcessingException e) {
- e.printStackTrace();
- }
+ 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+"/executor/new/"))
- .POST(HttpRequest.BodyPublishers.ofString(requestBody))
+ .POST(HttpRequest.BodyPublishers.ofString(body))
.build();
/** Needs the other service running
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/in/TaskAvailableCommand.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/in/TaskAvailableCommand.java
index 916c8eb..cfa32bb 100644
--- a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/in/TaskAvailableCommand.java
+++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/in/TaskAvailableCommand.java
@@ -9,7 +9,7 @@ import lombok.Value;
@Value
public class TaskAvailableCommand extends SelfValidating {
-
+
@NotNull
private final ExecutorType taskType;
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/GetAssignmentPort.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/GetAssignmentPort.java
index 1f205b8..79d3a0a 100644
--- a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/GetAssignmentPort.java
+++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/GetAssignmentPort.java
@@ -4,5 +4,5 @@ import ch.unisg.executorBase.executor.domain.ExecutorType;
import ch.unisg.executorBase.executor.domain.Task;
public interface GetAssignmentPort {
- Task getAssignment(ExecutorType executorType);
+ Task getAssignment(ExecutorType executorType, String ip, int port);
}
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/service/TaskAvailableService.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/service/TaskAvailableService.java
new file mode 100644
index 0000000..a4f5e6e
--- /dev/null
+++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/service/TaskAvailableService.java
@@ -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
+ }
+}
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorBase.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorBase.java
index e639cb3..c9df1a8 100644
--- a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorBase.java
+++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorBase.java
@@ -4,13 +4,6 @@ import ch.unisg.executorBase.executor.application.port.out.ExecutionFinishedEven
import ch.unisg.executorBase.executor.application.port.out.GetAssignmentPort;
import ch.unisg.executorBase.executor.application.port.out.NotifyExecutorPoolPort;
-import java.util.concurrent.TimeUnit;
-
-import javax.transaction.Transactional;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Configurable;
-
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;
@@ -44,23 +37,19 @@ public abstract class ExecutorBase {
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 {
- System.out.println(true);
this.status = ExecutorStatus.IDLING;
getAssignment();
}
}
- // public static ExecutorBase getExecutor() {
- // return executor;
- // }
-
public void getAssignment() {
- Task newTask = getAssignmentPort.getAssignment(this.getExecutorType());
+ Task newTask = getAssignmentPort.getAssignment(this.getExecutorType(), this.getIp(),
+ this.getPort());
if (newTask != null) {
this.executeTask(newTask);
} else {
@@ -71,15 +60,16 @@ public abstract class ExecutorBase {
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"));
+ executionFinishedEventPort.publishExecutionFinishedEvent(
+ new ExecutionFinishedEvent(task.getTaskID(), task.getResult(), "SUCCESS"));
System.out.println("Finish execution");
getAssignment();
}
protected abstract String execution();
-
+
}
diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/Task.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/Task.java
index 6719613..fec330f 100644
--- a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/Task.java
+++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/Task.java
@@ -1,11 +1,10 @@
package ch.unisg.executorBase.executor.domain;
-import lombok.Data;
import lombok.Getter;
import lombok.Setter;
public class Task {
-
+
@Getter
private String taskID;
diff --git a/executor2/pom.xml b/executor2/pom.xml
index 95c67ff..1f970e0 100644
--- a/executor2/pom.xml
+++ b/executor2/pom.xml
@@ -44,6 +44,13 @@
ch.unisg
executorBase
0.0.1-SNAPSHOT
+ compile
+
+
+
+ org.json
+ json
+ 20210307
diff --git a/executor2/src/main/java/ch/unisg/executor2/executor/adapter/in/web/TaskAvailableController.java b/executor2/src/main/java/ch/unisg/executor2/executor/adapter/in/web/TaskAvailableController.java
new file mode 100644
index 0000000..a14b58f
--- /dev/null
+++ b/executor2/src/main/java/ch/unisg/executor2/executor/adapter/in/web/TaskAvailableController.java
@@ -0,0 +1,35 @@
+package ch.unisg.executor2.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 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);
+ }
+}
diff --git a/executor2/src/main/java/ch/unisg/executor2/executor/application/service/TaskAvailableService.java b/executor2/src/main/java/ch/unisg/executor2/executor/application/service/TaskAvailableService.java
index 4484ebb..6fa918d 100644
--- a/executor2/src/main/java/ch/unisg/executor2/executor/application/service/TaskAvailableService.java
+++ b/executor2/src/main/java/ch/unisg/executor2/executor/application/service/TaskAvailableService.java
@@ -20,7 +20,7 @@ public class TaskAvailableService implements TaskAvailableUseCase {
Executor executor = Executor.getExecutor();
- if (executor.getExecutorType() == command.getTaskType() &&
+ if (executor.getExecutorType() == command.getTaskType() &&
executor.getStatus() == ExecutorStatus.IDLING) {
executor.getAssignment();
}
diff --git a/executor2/src/main/java/ch/unisg/executor2/executor/domain/Executor.java b/executor2/src/main/java/ch/unisg/executor2/executor/domain/Executor.java
index bb9308b..6aa1656 100644
--- a/executor2/src/main/java/ch/unisg/executor2/executor/domain/Executor.java
+++ b/executor2/src/main/java/ch/unisg/executor2/executor/domain/Executor.java
@@ -5,7 +5,7 @@ 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.ADDITION);
public static Executor getExecutor() {
@@ -19,7 +19,7 @@ public class Executor extends ExecutorBase {
@Override
protected
String execution() {
-
+
int a = 20;
int b = 20;
try {
diff --git a/executor2/src/main/resources/application.properties b/executor2/src/main/resources/application.properties
index 4d360de..cd2d02b 100644
--- a/executor2/src/main/resources/application.properties
+++ b/executor2/src/main/resources/application.properties
@@ -1 +1 @@
-server.port=8081
+server.port=8085