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 deleted file mode 100644 index 08a0895..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/WebControllerExceptionHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -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/application/port/in/ApplyForTaskCommand.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/ApplyForTaskCommand.java deleted file mode 100644 index df36d58..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/ApplyForTaskCommand.java +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index 1e7180a..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/ApplyForTaskUseCase.java +++ /dev/null @@ -1,7 +0,0 @@ -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/out/GetAllExecutorInExecutorPoolByTypePort.java b/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/GetAllExecutorInExecutorPoolByTypePort.java deleted file mode 100644 index e751727..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/GetAllExecutorInExecutorPoolByTypePort.java +++ /dev/null @@ -1,9 +0,0 @@ -package ch.unisg.assignment.assignment.application.port.out; - -import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType; - -public interface GetAllExecutorInExecutorPoolByTypePort { - boolean doesExecutorTypeExist(ExecutorType type); -} - - 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 deleted file mode 100644 index 909a9ba..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/NewTaskEventPort.java +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index fefd4a1..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/TaskAssignedEventPort.java +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 43a8aa5..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/out/TaskCompletedEventPort.java +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 0593a30..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/ApplyForTaskService.java +++ /dev/null @@ -1,34 +0,0 @@ -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 deleted file mode 100644 index 7d7de5c..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/NewTaskService.java +++ /dev/null @@ -1,46 +0,0 @@ -package ch.unisg.assignment.assignment.application.service; - -import java.util.Arrays; -import java.util.List; - -import javax.transaction.Transactional; - -import org.springframework.stereotype.Component; - -import ch.unisg.assignment.assignment.application.port.in.NewTaskCommand; -import ch.unisg.assignment.assignment.application.port.in.NewTaskUseCase; -import ch.unisg.assignment.assignment.application.port.out.GetAllExecutorInExecutorPoolByTypePort; -import ch.unisg.assignment.assignment.application.port.out.NewTaskEventPort; -import ch.unisg.assignment.assignment.domain.Roster; -import ch.unisg.assignment.assignment.domain.Task; -import ch.unisg.assignment.assignment.domain.event.NewTaskEvent; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Component -@Transactional -public class NewTaskService implements NewTaskUseCase { - - private final NewTaskEventPort newTaskEventPort; - private final GetAllExecutorInExecutorPoolByTypePort getAllExecutorInExecutorPoolByTypePort; - - @Override - public boolean addNewTaskToQueue(NewTaskCommand command) { - - // TODO Get availableTaskTypes from executor pool - if (!getAllExecutorInExecutorPoolByTypePort.doesExecutorTypeExist(command.getTaskType())) { - return false; - } - - Task task = new Task(command.getTaskID(), command.getTaskType()); - - Roster.getInstance().addTaskToQueue(task); - - // TODO this event should be in the roster function xyz - NewTaskEvent newTaskEvent = new NewTaskEvent(task.getTaskType()); - newTaskEventPort.publishNewTaskEvent(newTaskEvent); - - return true; - } - -} 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 deleted file mode 100644 index 6b19dcc..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/ExecutorInfo.java +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 521a748..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/Roster.java +++ /dev/null @@ -1,53 +0,0 @@ -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 deleted file mode 100644 index 2c3bb52..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/RosterItem.java +++ /dev/null @@ -1,29 +0,0 @@ -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/valueobject/IP4Adress.java b/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/IP4Adress.java deleted file mode 100644 index cd23b6b..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/IP4Adress.java +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index a66dbbd..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/Port.java +++ /dev/null @@ -1,17 +0,0 @@ -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/exception/InvalidIP4Exception.java b/assignment/src/main/java/ch/unisg/assignment/common/exception/InvalidIP4Exception.java deleted file mode 100644 index fecbfcb..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/common/exception/InvalidIP4Exception.java +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 2772256..0000000 --- a/assignment/src/main/java/ch/unisg/assignment/common/exception/PortOutOfRangeException.java +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 3cf12af..0000000 --- a/assignment/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -server.port=8082 diff --git a/assignment/.mvn/wrapper/MavenWrapperDownloader.java b/common/.mvn/wrapper/MavenWrapperDownloader.java similarity index 100% rename from assignment/.mvn/wrapper/MavenWrapperDownloader.java rename to common/.mvn/wrapper/MavenWrapperDownloader.java diff --git a/assignment/.mvn/wrapper/maven-wrapper.jar b/common/.mvn/wrapper/maven-wrapper.jar similarity index 100% rename from assignment/.mvn/wrapper/maven-wrapper.jar rename to common/.mvn/wrapper/maven-wrapper.jar diff --git a/assignment/.mvn/wrapper/maven-wrapper.properties b/common/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from assignment/.mvn/wrapper/maven-wrapper.properties rename to common/.mvn/wrapper/maven-wrapper.properties diff --git a/assignment/mvnw b/common/mvnw similarity index 100% rename from assignment/mvnw rename to common/mvnw diff --git a/assignment/mvnw.cmd b/common/mvnw.cmd similarity index 100% rename from assignment/mvnw.cmd rename to common/mvnw.cmd diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 0000000..f4e8342 --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,72 @@ + + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.5 + + + + ch.unisg + common + 0.0.1-SNAPSHOT + + common + + http://www.example.com + + + 11 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-starter-validation + + + org.projectlombok + lombok + true + + + org.springframework.boot + 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/common/exception/ErrorResponse.java b/common/src/main/java/ch/unisg/common/exception/ErrorResponse.java similarity index 84% rename from assignment/src/main/java/ch/unisg/assignment/common/exception/ErrorResponse.java rename to common/src/main/java/ch/unisg/common/exception/ErrorResponse.java index 2fb834e..aeef41c 100644 --- a/assignment/src/main/java/ch/unisg/assignment/common/exception/ErrorResponse.java +++ b/common/src/main/java/ch/unisg/common/exception/ErrorResponse.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.common.exception; +package ch.unisg.common.exception; import org.springframework.http.HttpStatus; diff --git a/common/src/main/java/ch/unisg/common/exception/InvalidExecutorURIException.java b/common/src/main/java/ch/unisg/common/exception/InvalidExecutorURIException.java new file mode 100644 index 0000000..1d619e9 --- /dev/null +++ b/common/src/main/java/ch/unisg/common/exception/InvalidExecutorURIException.java @@ -0,0 +1,7 @@ +package ch.unisg.common.exception; + +public class InvalidExecutorURIException extends Exception { + public InvalidExecutorURIException() { + super("URI is invalid"); + } +} diff --git a/assignment/src/main/java/ch/unisg/assignment/common/SelfValidating.java b/common/src/main/java/ch/unisg/common/validation/SelfValidating.java similarity index 95% rename from assignment/src/main/java/ch/unisg/assignment/common/SelfValidating.java rename to common/src/main/java/ch/unisg/common/validation/SelfValidating.java index a8d366f..bb2d0fe 100644 --- a/assignment/src/main/java/ch/unisg/assignment/common/SelfValidating.java +++ b/common/src/main/java/ch/unisg/common/validation/SelfValidating.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.common; +package ch.unisg.common.validation; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; diff --git a/common/src/main/java/ch/unisg/common/valueobject/ExecutorURI.java b/common/src/main/java/ch/unisg/common/valueobject/ExecutorURI.java new file mode 100644 index 0000000..627104e --- /dev/null +++ b/common/src/main/java/ch/unisg/common/valueobject/ExecutorURI.java @@ -0,0 +1,13 @@ +package ch.unisg.common.valueobject; + +import java.net.URI; +import lombok.Value; + +@Value +public class ExecutorURI { + private URI value; + + public ExecutorURI(String uri) { + this.value = URI.create(uri); + } +} diff --git a/diagram_1.bpmn b/diagram_1.bpmn deleted file mode 100644 index 313a860..0000000 --- a/diagram_1.bpmn +++ /dev/null @@ -1,653 +0,0 @@ - - - - - - - - - - - - - - Gateway_1vd3as7 - Activity_1jd11bs - Gateway_1e4ckdq - Activity_1dl4fvt - Gateway_1e3rabp - Event_1lm6x5y - Event_1ysgenb - Event_00rvb9o - Activity_0u3tts0 - Activity_0vs4eam - Activity_0mwpp9o - Event_0v7hm2z - Activity_0paecdb - Activity_0srcl99 - Activity_0assw9c - - - Activity_0jai885 - StartEvent_1 - - - - Flow_1hc51tx - Flow_1sajzlx - Flow_1ijfkpz - - - Flow_1sajzlx - Flow_0cpd5ad - - - Flow_0cpd5ad - Flow_0kwvrmc - Flow_1w3uh2m - - - Flow_0kwvrmc - Flow_0vpcut0 - - - Flow_0vpcut0 - Flow_179e0hl - Flow_12nh0g5 - - - Flow_179e0hl - - - Flow_0366zqm - - - Flow_1n8jm89 - - - Flow_1w3uh2m - Flow_1n8jm89 - - - Flow_19dbo28 - Flow_1rwgf2n - - - Flow_19dbo28 - - - Flow_1ijfkpz - Flow_1gvdy5x - - - Flow_1gvdy5x - Flow_1yxp4e8 - - - Flow_1yxp4e8 - - - Flow_1rwgf2n - Flow_1hc51tx - - - - Flow_12nh0g5 - Flow_0366zqm - - - - - - - - - - - - - - - - - - - - Flow_119ldsr - - - Flow_1mm9swr - - - Flow_119ldsr - Flow_1mm9swr - - - - - - - - Event_0v73rhy - Activity_0n8uuvk - - - Activity_06xjrrk - - - Activity_0uxkytf - Event_01nh9j2 - Activity_1qgjnyh - - - - Flow_17d0j42 - - - Flow_17d0j42 - Flow_0opy5tp - - - Flow_0opy5tp - Flow_0sudw7l - - - Flow_0sudw7l - Flow_02uzxx3 - - - Flow_0rpv16j - - - Flow_02uzxx3 - Flow_0rpv16j - - - - - - - - - - - Event_1oz3tr5 - Activity_0xk9kck - - - Gateway_079742h - Activity_0umieiz - Event_062x6a9 - Activity_0b6bh6v - Event_1achffx - Activity_1mme68o - - - - Flow_0od6iot - - - Flow_0od6iot - Flow_0k07ofo - - - Flow_0k07ofo - Flow_1fwmda3 - Flow_050yku1 - - - Flow_1fwmda3 - Flow_15lkkxa - - - Flow_15lkkxa - - - Flow_050yku1 - Flow_1lgcq8d - - - Flow_0oqra8s - - - Flow_1lgcq8d - Flow_0oqra8s - - - - - - - - - - - - - Event_1b2jt5y - Activity_1ikvmpl - Event_0y66dbe - Activity_11lqrhg - Activity_1oownmu - - - Activity_1ohwol1 - Event_0bbqq3x - - - Activity_1e9hb9h - Event_0l7ljcr - - - - Flow_046hsk4 - - - Flow_046hsk4 - Flow_0zoqmub - - - Flow_0nyxv8e - - - Flow_0zoqmub - Flow_0ip5x3i - Flow_1bqiz65 - Flow_142xsjm - - - Flow_1bqiz65 - Flow_0znvsoe - - - Flow_142xsjm - Flow_0ue2i8v - - - Flow_0ue2i8v - - - Flow_0znvsoe - - - Flow_0ip5x3i - Flow_0nyxv8e - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/workflow.bpmn b/doc/workflow.bpmn new file mode 100644 index 0000000..6d68a24 --- /dev/null +++ b/doc/workflow.bpmn @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Flow_1rie16h + Flow_159tlyd + Flow_01pbz6s + + + Flow_159tlyd + + + Flow_01pbz6s + + + Flow_1urp3d2 + + + Flow_1urp3d2 + Flow_1oy6e8u + Flow_1rxws1j + + + Flow_1oy6e8u + + + Flow_1rxws1j + + + + + Flow_1rie16h + + + + + + + + + + + + + + + Flow_0nuuhk7 + + + Flow_0nuuhk7 + Flow_197gie6 + Flow_0ruufha + + + Flow_197gie6 + + + + Flow_0ruufha + Flow_1duwugb + + + + Flow_19m4xhk + + + Flow_19m4xhk + Flow_0b4g73l + Flow_1duwugb + + + Flow_0b4g73l + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/workflow.png b/doc/workflow.png new file mode 100644 index 0000000..4946693 Binary files /dev/null and b/doc/workflow.png differ diff --git a/executor-base/pom.xml b/executor-base/pom.xml index 2acba18..80c9739 100644 --- a/executor-base/pom.xml +++ b/executor-base/pom.xml @@ -60,6 +60,12 @@ json 20210307 + + + ch.unisg + common + 0.0.1-SNAPSHOT + diff --git a/executor-base/src/main/java/ch/unisg/executorBase/Executor1Application.java b/executor-base/src/main/java/ch/unisg/executorBase/Executor1Application.java deleted file mode 100644 index 9bd3fa5..0000000 --- a/executor-base/src/main/java/ch/unisg/executorBase/Executor1Application.java +++ /dev/null @@ -1,13 +0,0 @@ -package ch.unisg.executorBase; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Executor1Application { - - public static void main(String[] args) { - SpringApplication.run(Executor1Application.class, args); - } - -} 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 deleted file mode 100644 index 5119ac5..0000000 --- a/executor-base/src/main/java/ch/unisg/executorBase/common/SelfValidating.java +++ /dev/null @@ -1,30 +0,0 @@ -package ch.unisg.executorBase.common; - -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; -import java.util.Set; - -public class SelfValidating { - - private Validator validator; - - public SelfValidating() { - ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); - validator = factory.getValidator(); - } - - /** - * Evaluates all Bean Validations on the attributes of this - * instance. - */ - protected void validateSelf() { - @SuppressWarnings("unchecked") - Set> 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 182f2ba..8fda5ac 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 @@ -1,4 +1,4 @@ -package ch.unisg.executorBase.executor.adapter.in.web; +package ch.unisg.executorbase.executor.adapter.in.web; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -7,9 +7,9 @@ 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 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 { @@ -19,7 +19,11 @@ public class TaskAvailableController { this.taskAvailableUseCase = taskAvailableUseCase; } - @GetMapping(path = "/newtask/{taskType}") + /** + * Controller for notification about new events. + * @return 200 OK + **/ + @GetMapping(path = "/newtask/{taskType}", consumes = { "application/json" }) public ResponseEntity retrieveTaskFromTaskList(@PathVariable("taskType") String taskType) { if (ExecutorType.contains(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 971e583..a5ae910 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 @@ -1,4 +1,4 @@ -package ch.unisg.executorBase.executor.adapter.out.web; +package ch.unisg.executorbase.executor.adapter.out.web; import java.io.IOException; import java.net.URI; @@ -9,16 +9,22 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Value; -import ch.unisg.executorBase.executor.application.port.out.ExecutionFinishedEventPort; -import ch.unisg.executorBase.executor.domain.ExecutionFinishedEvent; +import ch.unisg.executorbase.executor.application.port.out.ExecutionFinishedEventPort; +import ch.unisg.executorbase.executor.domain.ExecutionFinishedEvent; public class ExecutionFinishedEventAdapter implements ExecutionFinishedEventPort { - String server = "http://127.0.0.1:8082"; + @Value("${roster.url}") + String server; Logger logger = Logger.getLogger(ExecutionFinishedEventAdapter.class.getName()); + /** + * Publishes the execution finished event + * @return void + **/ @Override public void publishExecutionFinishedEvent(ExecutionFinishedEvent event) { @@ -37,13 +43,14 @@ public class ExecutionFinishedEventAdapter implements ExecutionFinishedEventPort try { client.send(request, HttpResponse.BodyHandlers.ofString()); - } catch (IOException | InterruptedException e) { + } catch (InterruptedException e) { logger.log(Level.SEVERE, e.getLocalizedMessage(), e); - // Restore interrupted state... Thread.currentThread().interrupt(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); } - System.out.println("Finish execution event sent with result:" + event.getResult()); + logger.log(Level.INFO, "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 411073b..3ed4e37 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,4 +1,4 @@ -package ch.unisg.executorBase.executor.adapter.out.web; +package ch.unisg.executorbase.executor.adapter.out.web; import java.io.IOException; import java.net.URI; @@ -8,12 +8,14 @@ import java.net.http.HttpResponse; import java.util.logging.Level; import java.util.logging.Logger; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; -import ch.unisg.executorBase.executor.application.port.out.GetAssignmentPort; -import ch.unisg.executorBase.executor.domain.ExecutorType; -import ch.unisg.executorBase.executor.domain.Task; +import ch.unisg.common.valueobject.ExecutorURI; +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; @@ -21,17 +23,22 @@ import org.json.JSONObject; @Primary public class GetAssignmentAdapter implements GetAssignmentPort { - String server = "http://127.0.0.1:8082"; + @Value("${roster.url}") + String server; Logger logger = Logger.getLogger(GetAssignmentAdapter.class.getName()); + /** + * Requests a new task assignment + * @return the assigned task + * @see Task + **/ @Override - public Task getAssignment(ExecutorType executorType, String ip, int port) { + public Task getAssignment(ExecutorType executorType, ExecutorURI executorURI) { String body = new JSONObject() .put("executorType", executorType) - .put("ip", ip) - .put("port", port) + .put("executorURI", executorURI.getValue()) .toString(); HttpClient client = HttpClient.newHttpClient(); @@ -42,17 +49,20 @@ public class GetAssignmentAdapter implements GetAssignmentPort { .build(); try { + logger.info("Sending getAssignment Request"); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + logger.log(Level.INFO, "getAssignment request result:\n {}", response.body()); if (response.body().equals("")) { return null; } JSONObject responseBody = new JSONObject(response.body()); return new Task(responseBody.getString("taskID"), responseBody.getString("input")); - } catch (IOException | InterruptedException e) { + } catch (InterruptedException e) { logger.log(Level.SEVERE, e.getLocalizedMessage(), e); - // Restore interrupted state... Thread.currentThread().interrupt(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); } 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 720b015..2dba64f 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 @@ -1,4 +1,4 @@ -package ch.unisg.executorBase.executor.adapter.out.web; +package ch.unisg.executorbase.executor.adapter.out.web; import java.io.IOException; import java.net.URI; @@ -9,28 +9,34 @@ import java.util.logging.Level; import java.util.logging.Logger; 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.stereotype.Component; -import ch.unisg.executorBase.executor.application.port.out.NotifyExecutorPoolPort; -import ch.unisg.executorBase.executor.domain.ExecutorType; +import ch.unisg.common.valueobject.ExecutorURI; +import ch.unisg.executorbase.executor.application.port.out.NotifyExecutorPoolPort; +import ch.unisg.executorbase.executor.domain.ExecutorType; @Component @Primary public class NotifyExecutorPoolAdapter implements NotifyExecutorPoolPort { - String server = "http://127.0.0.1:8083"; + @Value("${executor-pool.url}") + String server; Logger logger = Logger.getLogger(NotifyExecutorPoolAdapter.class.getName()); + /** + * Notifies the executor-pool about the startup of this executor + * @return if the notification was successful + **/ @Override - public boolean notifyExecutorPool(String ip, int port, ExecutorType executorType) { + public boolean notifyExecutorPool(ExecutorURI executorURI, ExecutorType executorType) { String body = new JSONObject() .put("executorTaskType", executorType) - .put("executorIp", ip) - .put("executorPort", Integer.toString(port)) + .put("executorURI", executorURI.getValue()) .toString(); HttpClient client = HttpClient.newHttpClient(); @@ -45,10 +51,11 @@ public class NotifyExecutorPoolAdapter implements NotifyExecutorPoolPort { if (response.statusCode() == HttpStatus.CREATED.value()) { return true; } - } catch (IOException | InterruptedException e) { + } catch (InterruptedException e) { logger.log(Level.SEVERE, e.getLocalizedMessage(), e); - // Restore interrupted state... Thread.currentThread().interrupt(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); } return false; 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 cfa32bb..57bee60 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 @@ -1,10 +1,9 @@ -package ch.unisg.executorBase.executor.application.port.in; - -import ch.unisg.executorBase.common.SelfValidating; -import ch.unisg.executorBase.executor.domain.ExecutorType; +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.Value; @Value diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/in/TaskAvailableUseCase.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/in/TaskAvailableUseCase.java index cc5215f..5e000da 100644 --- a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/in/TaskAvailableUseCase.java +++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/in/TaskAvailableUseCase.java @@ -1,4 +1,4 @@ -package ch.unisg.executorBase.executor.application.port.in; +package ch.unisg.executorbase.executor.application.port.in; public interface TaskAvailableUseCase { void newTaskAvailable(TaskAvailableCommand command); diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/ExecutionFinishedEventPort.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/ExecutionFinishedEventPort.java index 1bf668e..ef65922 100644 --- a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/ExecutionFinishedEventPort.java +++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/ExecutionFinishedEventPort.java @@ -1,6 +1,6 @@ -package ch.unisg.executorBase.executor.application.port.out; +package ch.unisg.executorbase.executor.application.port.out; -import ch.unisg.executorBase.executor.domain.ExecutionFinishedEvent; +import ch.unisg.executorbase.executor.domain.ExecutionFinishedEvent; public interface ExecutionFinishedEventPort { void publishExecutionFinishedEvent(ExecutionFinishedEvent event); 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 79d3a0a..95dc15d 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 @@ -1,8 +1,9 @@ -package ch.unisg.executorBase.executor.application.port.out; +package ch.unisg.executorbase.executor.application.port.out; -import ch.unisg.executorBase.executor.domain.ExecutorType; -import ch.unisg.executorBase.executor.domain.Task; +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, String ip, int port); + Task getAssignment(ExecutorType executorType, ExecutorURI executorURI); } diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/NotifyExecutorPoolPort.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/NotifyExecutorPoolPort.java index 6d41ab4..1d4d3d3 100644 --- a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/NotifyExecutorPoolPort.java +++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/port/out/NotifyExecutorPoolPort.java @@ -1,7 +1,8 @@ -package ch.unisg.executorBase.executor.application.port.out; +package ch.unisg.executorbase.executor.application.port.out; -import ch.unisg.executorBase.executor.domain.ExecutorType; +import ch.unisg.common.valueobject.ExecutorURI; +import ch.unisg.executorbase.executor.domain.ExecutorType; public interface NotifyExecutorPoolPort { - boolean notifyExecutorPool(String ip, int port, ExecutorType executorType); + boolean notifyExecutorPool(ExecutorURI executorURI, ExecutorType executorType); } diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/service/NotifyExecutorPoolService.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/service/NotifyExecutorPoolService.java index a5ccb64..aee3142 100644 --- a/executor-base/src/main/java/ch/unisg/executorBase/executor/application/service/NotifyExecutorPoolService.java +++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/application/service/NotifyExecutorPoolService.java @@ -1,7 +1,8 @@ -package ch.unisg.executorBase.executor.application.service; +package ch.unisg.executorbase.executor.application.service; -import ch.unisg.executorBase.executor.application.port.out.NotifyExecutorPoolPort; -import ch.unisg.executorBase.executor.domain.ExecutorType; +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 @@ -9,7 +10,7 @@ public class NotifyExecutorPoolService { private final NotifyExecutorPoolPort notifyExecutorPoolPort; - public boolean notifyExecutorPool(String ip, int port, ExecutorType executorType) { - return notifyExecutorPoolPort.notifyExecutorPool(ip, port, executorType); + public boolean notifyExecutorPool(ExecutorURI executorURI, ExecutorType executorType) { + return notifyExecutorPoolPort.notifyExecutorPool(executorURI, executorType); } } 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 index a4f5e6e..050a807 100644 --- 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 @@ -1,9 +1,9 @@ -package ch.unisg.executorBase.executor.application.service; +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 ch.unisg.executorbase.executor.application.port.in.TaskAvailableCommand; +import ch.unisg.executorbase.executor.application.port.in.TaskAvailableUseCase; import lombok.RequiredArgsConstructor; import javax.transaction.Transactional; @@ -15,6 +15,6 @@ public class TaskAvailableService implements TaskAvailableUseCase { @Override public void newTaskAvailable(TaskAvailableCommand command) { - // Placeholder so spring can create a bean + // Placeholder so spring can create a bean, implementation of this function is inside the executors } } diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutionFinishedEvent.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutionFinishedEvent.java index 31fd0e6..fea6102 100644 --- a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutionFinishedEvent.java +++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutionFinishedEvent.java @@ -1,12 +1,12 @@ -package ch.unisg.executorBase.executor.domain; +package ch.unisg.executorbase.executor.domain; import lombok.Getter; public class ExecutionFinishedEvent { - + @Getter private String taskID; - + @Getter private String result; 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 83ab862..122ea4b 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 @@ -1,45 +1,47 @@ -package ch.unisg.executorBase.executor.domain; +package ch.unisg.executorbase.executor.domain; -import ch.unisg.executorBase.executor.application.port.out.ExecutionFinishedEventPort; -import ch.unisg.executorBase.executor.application.port.out.GetAssignmentPort; -import ch.unisg.executorBase.executor.application.port.out.NotifyExecutorPoolPort; +import java.util.logging.Logger; -import ch.unisg.executorBase.executor.adapter.out.web.ExecutionFinishedEventAdapter; -import ch.unisg.executorBase.executor.adapter.out.web.GetAssignmentAdapter; -import ch.unisg.executorBase.executor.adapter.out.web.NotifyExecutorPoolAdapter; -import ch.unisg.executorBase.executor.application.service.NotifyExecutorPoolService; +import 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 String ip; + private ExecutorURI executorURI; @Getter private ExecutorType executorType; - @Getter - private int port; - @Getter private ExecutorStatus status; // TODO Violation of the Dependency Inversion Principle?, but we havn't really got a better solutions to send a http request / access a service from a domain model + // TODO I guess we can implement the execution as a service but there still is the problem with the startup request. // TODO I guess we can somehow autowire this but I don't know why it's not working :D private final NotifyExecutorPoolPort notifyExecutorPoolPort = new NotifyExecutorPoolAdapter(); private final NotifyExecutorPoolService notifyExecutorPoolService = new NotifyExecutorPoolService(notifyExecutorPoolPort); private final GetAssignmentPort getAssignmentPort = new GetAssignmentAdapter(); private final ExecutionFinishedEventPort executionFinishedEventPort = new ExecutionFinishedEventAdapter(); - public ExecutorBase(ExecutorType executorType) { - System.out.println("Starting Executor"); - // TODO set this automaticly - this.ip = "localhost"; - this.port = 8084; - this.executorType = executorType; + Logger logger = Logger.getLogger(ExecutorBase.class.getName()); + protected ExecutorBase(ExecutorType executorType) { + logger.info("Starting Executor"); this.status = ExecutorStatus.STARTING_UP; - if(!notifyExecutorPoolService.notifyExecutorPool(this.ip, this.port, this.executorType)) { + this.executorType = executorType; + // TODO set this automaticly + this.executorURI = new ExecutorURI("localhost:8084"); + + // Notify executor-pool about existence. If executor-pools response is successfull start with getting an assignment, else shut down executor. + if(!notifyExecutorPoolService.notifyExecutorPool(this.executorURI, this.executorType)) { System.exit(0); } else { this.status = ExecutorStatus.IDLING; @@ -47,9 +49,12 @@ public abstract class ExecutorBase { } } + /** + * Requests a new task from the task queue + * @return void + **/ public void getAssignment() { - Task newTask = getAssignmentPort.getAssignment(this.getExecutorType(), this.getIp(), - this.getPort()); + Task newTask = getAssignmentPort.getAssignment(this.getExecutorType(), this.getExecutorURI()); if (newTask != null) { this.executeTask(newTask); } else { @@ -57,19 +62,28 @@ public abstract class ExecutorBase { } } + /** + * Start the execution of a task + * @return void + **/ private void executeTask(Task task) { - System.out.println("Starting execution"); + logger.info("Starting execution"); this.status = ExecutorStatus.EXECUTING; task.setResult(execution(task.getInput())); + // TODO implement logic if execution was not successful executionFinishedEventPort.publishExecutionFinishedEvent( new ExecutionFinishedEvent(task.getTaskID(), task.getResult(), "SUCCESS")); - System.out.println("Finish execution"); + logger.info("Finish execution"); getAssignment(); } + /** + * Implementation of the actual execution method of an executor + * @return the execution result + **/ protected abstract String execution(String... input); - + } diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorStatus.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorStatus.java index 8bd5bc3..1fcf7de 100644 --- a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorStatus.java +++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorStatus.java @@ -1,7 +1,7 @@ -package ch.unisg.executorBase.executor.domain; +package ch.unisg.executorbase.executor.domain; public enum ExecutorStatus { - STARTING_UP, - EXECUTING, - IDLING, + STARTING_UP, // Executor is starting + EXECUTING, // Executor is currently executing a task + IDLING, // Executor has no tasks left and is waiting for new instructions } diff --git a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorType.java b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorType.java index 0b2b305..ca9533a 100644 --- a/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorType.java +++ b/executor-base/src/main/java/ch/unisg/executorBase/executor/domain/ExecutorType.java @@ -1,8 +1,12 @@ -package ch.unisg.executorBase.executor.domain; +package ch.unisg.executorbase.executor.domain; public enum ExecutorType { ADDITION, ROBOT; + /** + * Checks if the give executor type exists. + * @return Wheter the given executor type exists + **/ public static boolean contains(String test) { for (ExecutorType x : ExecutorType.values()) { 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 f455dcd..7dc5783 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,4 +1,4 @@ -package ch.unisg.executorBase.executor.domain; +package ch.unisg.executorbase.executor.domain; import lombok.Getter; import lombok.Setter; diff --git a/executor-base/src/main/resources/application.properties b/executor-base/src/main/resources/application.properties index 4d360de..3eee96a 100644 --- a/executor-base/src/main/resources/application.properties +++ b/executor-base/src/main/resources/application.properties @@ -1 +1,6 @@ server.port=8081 +roster.url=http://127.0.0.1:8082 +executor-pool.url=http://127.0.0.1:8083 +executor1.url=http://127.0.0.1:8084 +executor2.url=http://127.0.0.1:8085 +task-list.url=http://127.0.0.1:8081 diff --git a/executor-base/src/test/java/ch/unisg/executorBase/Executor1ApplicationTests.java b/executor-base/src/test/java/ch/unisg/executorBase/Executor1ApplicationTests.java deleted file mode 100644 index 6fec034..0000000 --- a/executor-base/src/test/java/ch/unisg/executorBase/Executor1ApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package ch.unisg.executorBase; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class executorBaseApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/executorcomputation/src/main/java/ch/unisg/executor2/executor/adapter/in/web/TaskAvailableController.java b/executorcomputation/src/main/java/ch/unisg/executor2/executor/adapter/in/web/TaskAvailableController.java index 223c88c..a421924 100644 --- a/executorcomputation/src/main/java/ch/unisg/executor2/executor/adapter/in/web/TaskAvailableController.java +++ b/executorcomputation/src/main/java/ch/unisg/executor2/executor/adapter/in/web/TaskAvailableController.java @@ -9,9 +9,9 @@ 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 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 { diff --git a/executorcomputation/src/main/java/ch/unisg/executor2/executor/application/service/TaskAvailableService.java b/executorcomputation/src/main/java/ch/unisg/executor2/executor/application/service/TaskAvailableService.java index 23d9056..6a94577 100644 --- a/executorcomputation/src/main/java/ch/unisg/executor2/executor/application/service/TaskAvailableService.java +++ b/executorcomputation/src/main/java/ch/unisg/executor2/executor/application/service/TaskAvailableService.java @@ -3,9 +3,9 @@ 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 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; diff --git a/executorcomputation/src/main/java/ch/unisg/executor2/executor/domain/Executor.java b/executorcomputation/src/main/java/ch/unisg/executor2/executor/domain/Executor.java index bc8040a..eb09699 100644 --- a/executorcomputation/src/main/java/ch/unisg/executor2/executor/domain/Executor.java +++ b/executorcomputation/src/main/java/ch/unisg/executor2/executor/domain/Executor.java @@ -1,8 +1,9 @@ package ch.unisg.executorcomputation.executor.domain; import java.util.concurrent.TimeUnit; -import ch.unisg.executorBase.executor.domain.ExecutorBase; -import ch.unisg.executorBase.executor.domain.ExecutorType; + +import ch.unisg.executorbase.executor.domain.ExecutorBase; +import ch.unisg.executorbase.executor.domain.ExecutorType; public class Executor extends ExecutorBase { diff --git a/executorrobot/src/main/java/ch/unisg/executor1/executor/adapter/in/web/TaskAvailableController.java b/executorrobot/src/main/java/ch/unisg/executor1/executor/adapter/in/web/TaskAvailableController.java index c5348df..7f256df 100644 --- a/executorrobot/src/main/java/ch/unisg/executor1/executor/adapter/in/web/TaskAvailableController.java +++ b/executorrobot/src/main/java/ch/unisg/executor1/executor/adapter/in/web/TaskAvailableController.java @@ -9,9 +9,9 @@ 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 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 { diff --git a/executorrobot/src/main/java/ch/unisg/executor1/executor/application/port/out/UserToRobotPort.java b/executorrobot/src/main/java/ch/unisg/executor1/executor/application/port/out/UserToRobotPort.java index b5ab55b..3da8ded 100644 --- a/executorrobot/src/main/java/ch/unisg/executor1/executor/application/port/out/UserToRobotPort.java +++ b/executorrobot/src/main/java/ch/unisg/executor1/executor/application/port/out/UserToRobotPort.java @@ -1,6 +1,6 @@ package ch.unisg.executorrobot.executor.application.port.out; -import ch.unisg.executorBase.executor.domain.ExecutorType; +import ch.unisg.executorbase.executor.domain.ExecutorType; public interface UserToRobotPort { String userToRobot(); diff --git a/executorrobot/src/main/java/ch/unisg/executor1/executor/application/service/TaskAvailableService.java b/executorrobot/src/main/java/ch/unisg/executor1/executor/application/service/TaskAvailableService.java index ce1705a..5d26502 100644 --- a/executorrobot/src/main/java/ch/unisg/executor1/executor/application/service/TaskAvailableService.java +++ b/executorrobot/src/main/java/ch/unisg/executor1/executor/application/service/TaskAvailableService.java @@ -3,9 +3,9 @@ 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 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; @@ -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/executorrobot/src/main/java/ch/unisg/executor1/executor/domain/Executor.java b/executorrobot/src/main/java/ch/unisg/executor1/executor/domain/Executor.java index e23dca5..44ddcb4 100644 --- a/executorrobot/src/main/java/ch/unisg/executor1/executor/domain/Executor.java +++ b/executorrobot/src/main/java/ch/unisg/executor1/executor/domain/Executor.java @@ -10,8 +10,8 @@ import ch.unisg.executorrobot.executor.adapter.out.UserToRobotAdapter; import ch.unisg.executorrobot.executor.application.port.out.DeleteUserFromRobotPort; import ch.unisg.executorrobot.executor.application.port.out.InstructionToRobotPort; import ch.unisg.executorrobot.executor.application.port.out.UserToRobotPort; -import ch.unisg.executorBase.executor.domain.ExecutorBase; -import ch.unisg.executorBase.executor.domain.ExecutorType; +import ch.unisg.executorbase.executor.domain.ExecutorBase; +import ch.unisg.executorbase.executor.domain.ExecutorType; public class Executor extends ExecutorBase { diff --git a/assignment/.gitignore b/roster/.gitignore similarity index 100% rename from assignment/.gitignore rename to roster/.gitignore diff --git a/roster/.mvn/wrapper/MavenWrapperDownloader.java b/roster/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..e76d1f3 --- /dev/null +++ b/roster/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/roster/.mvn/wrapper/maven-wrapper.jar b/roster/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..2cc7d4a Binary files /dev/null and b/roster/.mvn/wrapper/maven-wrapper.jar differ diff --git a/roster/.mvn/wrapper/maven-wrapper.properties b/roster/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..abd303b --- /dev/null +++ b/roster/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/assignment/Dockerfile b/roster/Dockerfile similarity index 100% rename from assignment/Dockerfile rename to roster/Dockerfile diff --git a/roster/mvnw b/roster/mvnw new file mode 100755 index 0000000..a16b543 --- /dev/null +++ b/roster/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/roster/mvnw.cmd b/roster/mvnw.cmd new file mode 100644 index 0000000..c8d4337 --- /dev/null +++ b/roster/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/assignment/pom.xml b/roster/pom.xml similarity index 89% rename from assignment/pom.xml rename to roster/pom.xml index 99996b8..f51bff7 100644 --- a/assignment/pom.xml +++ b/roster/pom.xml @@ -56,12 +56,24 @@ 1.2 + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + 1.2.5 + + org.json json 20210307 + + ch.unisg + common + 0.0.1-SNAPSHOT + + diff --git a/assignment/src/main/java/ch/unisg/assignment/AssignmentApplication.java b/roster/src/main/java/ch/unisg/roster/RosterApplication.java similarity index 60% rename from assignment/src/main/java/ch/unisg/assignment/AssignmentApplication.java rename to roster/src/main/java/ch/unisg/roster/RosterApplication.java index 30d7782..dd57a5d 100644 --- a/assignment/src/main/java/ch/unisg/assignment/AssignmentApplication.java +++ b/roster/src/main/java/ch/unisg/roster/RosterApplication.java @@ -1,13 +1,13 @@ -package ch.unisg.assignment; +package ch.unisg.roster; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class AssignmentApplication { +public class RosterApplication { public static void main(String[] args) { - SpringApplication.run(AssignmentApplication.class, args); + SpringApplication.run(RosterApplication.class, args); } } diff --git a/roster/src/main/java/ch/unisg/roster/roster/adapter/common/clients/TapasMqttClient.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/common/clients/TapasMqttClient.java new file mode 100644 index 0000000..8b5411b --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/common/clients/TapasMqttClient.java @@ -0,0 +1,94 @@ +package ch.unisg.roster.roster.adapter.common.clients; + +import ch.unisg.roster.roster.adapter.in.messaging.mqtt.AuctionEventsMqttDispatcher; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.paho.client.mqttv3.*; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +/** + * MQTT client for your TAPAS application. This class is defined as a singleton, but it does not have + * to be this way. This class is only provided as an example to help you bootstrap your project. + * You are welcomed to change this class as you see fit. + */ +public class TapasMqttClient { + private static final Logger LOGGER = LogManager.getLogger(TapasMqttClient.class); + + private static TapasMqttClient tapasClient = null; + + private MqttClient mqttClient; + private final String mqttClientId; + private final String brokerAddress; + + private final MessageReceivedCallback messageReceivedCallback; + + private final AuctionEventsMqttDispatcher dispatcher; + + private TapasMqttClient(String brokerAddress, AuctionEventsMqttDispatcher dispatcher) { + this.mqttClientId = UUID.randomUUID().toString(); + this.brokerAddress = brokerAddress; + + this.messageReceivedCallback = new MessageReceivedCallback(); + + this.dispatcher = dispatcher; + } + + public static synchronized TapasMqttClient getInstance(String brokerAddress, + AuctionEventsMqttDispatcher dispatcher) { + + if (tapasClient == null) { + tapasClient = new TapasMqttClient(brokerAddress, dispatcher); + } + + return tapasClient; + } + + public void startReceivingMessages() throws MqttException { + mqttClient = new org.eclipse.paho.client.mqttv3.MqttClient(brokerAddress, mqttClientId, new MemoryPersistence()); + mqttClient.connect(); + mqttClient.setCallback(messageReceivedCallback); + + subscribeToAllTopics(); + } + + public void stopReceivingMessages() throws MqttException { + mqttClient.disconnect(); + } + + private void subscribeToAllTopics() throws MqttException { + for (String topic : dispatcher.getAllTopics()) { + subscribeToTopic(topic); + } + } + + private void subscribeToTopic(String topic) throws MqttException { + mqttClient.subscribe(topic); + } + + private void publishMessage(String topic, String payload) throws MqttException { + MqttMessage message = new MqttMessage(payload.getBytes(StandardCharsets.UTF_8)); + mqttClient.publish(topic, message); + } + + private class MessageReceivedCallback implements MqttCallback { + + @Override + public void connectionLost(Throwable cause) { } + + @Override + public void messageArrived(String topic, MqttMessage message) { + LOGGER.info("Received new MQTT message for topic " + topic + ": " + + new String(message.getPayload())); + + if (topic != null && !topic.isEmpty()) { + dispatcher.dispatchEvent(topic, message); + } + } + + @Override + public void deliveryComplete(IMqttDeliveryToken token) { } + } +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/AuctionEventMqttListener.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/AuctionEventMqttListener.java new file mode 100644 index 0000000..6eb109f --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/AuctionEventMqttListener.java @@ -0,0 +1,11 @@ +package ch.unisg.roster.roster.adapter.in.messaging.mqtt; + +import org.eclipse.paho.client.mqttv3.MqttMessage; + +/** + * Abstract MQTT listener for auction-related events + */ +public abstract class AuctionEventMqttListener { + + public abstract boolean handleEvent(MqttMessage message); +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/AuctionEventsMqttDispatcher.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/AuctionEventsMqttDispatcher.java new file mode 100644 index 0000000..d19c803 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/AuctionEventsMqttDispatcher.java @@ -0,0 +1,52 @@ +package ch.unisg.roster.roster.adapter.in.messaging.mqtt; + +import org.eclipse.paho.client.mqttv3.*; + +import java.util.Hashtable; +import java.util.Map; +import java.util.Set; + +/** + * Dispatches MQTT messages for known topics to associated event listeners. Used in conjunction with + * {@link ch.unisg.tapas.auctionhouse.adapter.common.clients.TapasMqttClient}. + * + * This is where you would define MQTT topics and map them to event listeners (see + * {@link AuctionEventsMqttDispatcher#initRouter()}). + * + * This class is only provided as an example to help you bootstrap the project. You are welcomed to + * change this class as you see fit. + */ +public class AuctionEventsMqttDispatcher { + private final Map router; + + public AuctionEventsMqttDispatcher() { + this.router = new Hashtable<>(); + initRouter(); + } + + // TODO: Register here your topics and event listener adapters + private void initRouter() { + router.put("ch/unisg/tapas-group-tutors/executors/added", new ExecutorAddedEventListenerMqttAdapter()); + router.put("ch/unisg/tapas-group-tutors/executors/removed", new ExecutorRemovedEventListenerMqttAdapter()); + } + + /** + * Returns all topics registered with this dispatcher. + * + * @return the set of registered topics + */ + public Set getAllTopics() { + return router.keySet(); + } + + /** + * Dispatches an event received via MQTT for a given topic. + * + * @param topic the topic for which the MQTT message was received + * @param message the received MQTT message + */ + public void dispatchEvent(String topic, MqttMessage message) { + AuctionEventMqttListener listener = router.get(topic); + listener.handleEvent(message); + } +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/ExecutorAddedEventListenerMqttAdapter.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/ExecutorAddedEventListenerMqttAdapter.java new file mode 100644 index 0000000..dd9257e --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/ExecutorAddedEventListenerMqttAdapter.java @@ -0,0 +1,44 @@ +package ch.unisg.roster.roster.adapter.in.messaging.mqtt; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +import ch.unisg.common.valueobject.ExecutorURI; +import ch.unisg.roster.roster.application.handler.ExecutorAddedHandler; +import ch.unisg.roster.roster.application.port.in.ExecutorAddedEvent; +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; + +public class ExecutorAddedEventListenerMqttAdapter extends AuctionEventMqttListener { + private static final Logger LOGGER = LogManager.getLogger(ExecutorAddedEventListenerMqttAdapter.class); + + @Override + public boolean handleEvent(MqttMessage message) { + String payload = new String(message.getPayload()); + + try { + // Note: this messge representation is provided only as an example. You should use a + // representation that makes sense in the context of your application. + JsonNode data = new ObjectMapper().readTree(payload); + + String taskType = data.get("taskType").asText(); + String executorId = data.get("executorURI").asText(); + + ExecutorAddedEvent executorAddedEvent = new ExecutorAddedEvent( + new ExecutorURI(executorId), + new ExecutorType(taskType) + ); + + ExecutorAddedHandler newExecutorHandler = new ExecutorAddedHandler(); + newExecutorHandler.handleNewExecutorEvent(executorAddedEvent); + } catch (JsonProcessingException | NullPointerException e) { + LOGGER.error(e.getMessage(), e); + return false; + } + + return true; + } +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/ExecutorRemovedEventListenerMqttAdapter.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/ExecutorRemovedEventListenerMqttAdapter.java new file mode 100644 index 0000000..d7b5067 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/messaging/mqtt/ExecutorRemovedEventListenerMqttAdapter.java @@ -0,0 +1,41 @@ +package ch.unisg.roster.roster.adapter.in.messaging.mqtt; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.paho.client.mqttv3.MqttMessage; + +import ch.unisg.common.valueobject.ExecutorURI; +import ch.unisg.roster.roster.application.handler.ExecutorRemovedHandler; +import ch.unisg.roster.roster.application.port.in.ExecutorRemovedEvent; + +public class ExecutorRemovedEventListenerMqttAdapter extends AuctionEventMqttListener { + private static final Logger LOGGER = LogManager.getLogger(ExecutorRemovedEventListenerMqttAdapter.class); + + @Override + public boolean handleEvent(MqttMessage message) { + String payload = new String(message.getPayload()); + + try { + // Note: this messge representation is provided only as an example. You should use a + // representation that makes sense in the context of your application. + JsonNode data = new ObjectMapper().readTree(payload); + + String executorId = data.get("executorURI").asText(); + + ExecutorRemovedEvent executorRemovedEvent = new ExecutorRemovedEvent( + new ExecutorURI(executorId)); + + ExecutorRemovedHandler executorRemovedHandler = new ExecutorRemovedHandler(); + executorRemovedHandler.handleExecutorRemovedEvent(executorRemovedEvent); + + } catch (JsonProcessingException | NullPointerException e) { + LOGGER.error(e.getMessage(), e); + return false; + } + + return true; + } +} diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/ApplyForTaskController.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/ApplyForTaskController.java similarity index 62% rename from assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/ApplyForTaskController.java rename to roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/ApplyForTaskController.java index 1d0111d..28170f0 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/ApplyForTaskController.java +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/ApplyForTaskController.java @@ -1,13 +1,13 @@ -package ch.unisg.assignment.assignment.adapter.in.web; +package ch.unisg.roster.roster.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; +import ch.unisg.roster.roster.application.port.in.ApplyForTaskCommand; +import ch.unisg.roster.roster.application.port.in.ApplyForTaskUseCase; +import ch.unisg.roster.roster.domain.ExecutorInfo; +import ch.unisg.roster.roster.domain.Task; @RestController public class ApplyForTaskController { @@ -17,13 +17,16 @@ public class ApplyForTaskController { this.applyForTaskUseCase = applyForTaskUseCase; } + /** + * Checks if task is available for the requesting executor. + * @return a task or null if no task found + **/ @PostMapping(path = "/task/apply", consumes = {"application/json"}) public Task applyForTask(@RequestBody ExecutorInfo executorInfo) { ApplyForTaskCommand command = new ApplyForTaskCommand(executorInfo.getExecutorType(), - executorInfo.getIp(), executorInfo.getPort()); + executorInfo.getExecutorURI()); return applyForTaskUseCase.applyForTask(command); - } } diff --git a/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/DeleteTaskController.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/DeleteTaskController.java new file mode 100644 index 0000000..eef8b71 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/DeleteTaskController.java @@ -0,0 +1,35 @@ +package ch.unisg.roster.roster.adapter.in.web; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import ch.unisg.roster.roster.application.port.in.DeleteTaskCommand; +import ch.unisg.roster.roster.application.port.in.DeleteTaskUseCase; +import ch.unisg.roster.roster.domain.Task; + +@RestController +public class DeleteTaskController { + private final DeleteTaskUseCase deleteTaskUseCase; + + public DeleteTaskController(DeleteTaskUseCase deleteTaskUseCase) { + this.deleteTaskUseCase = deleteTaskUseCase; + } + + /** + * Controller to delete a task + * @return 200 OK, 409 Conflict + **/ + @DeleteMapping(path = "/task", consumes = {"application/task+json"}) + public ResponseEntity applyForTask(@RequestBody Task task) { + + DeleteTaskCommand command = new DeleteTaskCommand(task.getTaskID(), task.getTaskType()); + + if (deleteTaskUseCase.deleteTask(command)) { + return new ResponseEntity<>(HttpStatus.OK); + } + return new ResponseEntity<>(HttpStatus.CONFLICT); + } +} diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/NewTaskController.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/NewTaskController.java similarity index 68% rename from assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/NewTaskController.java rename to roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/NewTaskController.java index 18bad8f..af01346 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/NewTaskController.java +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/NewTaskController.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.adapter.in.web; +package ch.unisg.roster.roster.adapter.in.web; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -6,9 +6,9 @@ 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; +import ch.unisg.roster.roster.application.port.in.NewTaskCommand; +import ch.unisg.roster.roster.application.port.in.NewTaskUseCase; +import ch.unisg.roster.roster.domain.Task; @RestController public class NewTaskController { @@ -18,7 +18,11 @@ public class NewTaskController { this.newTaskUseCase = newTaskUseCase; } - @PostMapping(path = "/task", consumes = {"application/json"}) + /** + * Controller which handles the new task event from the tasklist + * @return 201 Create or 409 Conflict + **/ + @PostMapping(path = "/task", consumes = {"application/task+json"}) public ResponseEntity newTaskController(@RequestBody Task task) { NewTaskCommand command = new NewTaskCommand(task.getTaskID(), task.getTaskType()); diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/TaskCompletedController.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/TaskCompletedController.java similarity index 73% rename from assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/TaskCompletedController.java rename to roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/TaskCompletedController.java index cde4c0a..f81db32 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/in/web/TaskCompletedController.java +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/TaskCompletedController.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.adapter.in.web; +package ch.unisg.roster.roster.adapter.in.web; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -6,9 +6,9 @@ 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; +import ch.unisg.roster.roster.application.port.in.TaskCompletedCommand; +import ch.unisg.roster.roster.application.port.in.TaskCompletedUseCase; +import ch.unisg.roster.roster.domain.Task; @RestController public class TaskCompletedController { @@ -19,6 +19,10 @@ public class TaskCompletedController { this.taskCompletedUseCase = taskCompletedUseCase; } + /** + * Controller which handles the task completed event from executors + * @return 200 OK + **/ @PostMapping(path = "/task/completed", consumes = {"application/json"}) public ResponseEntity addNewTaskTaskToTaskList(@RequestBody Task task) { diff --git a/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/WebControllerExceptionHandler.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/WebControllerExceptionHandler.java new file mode 100644 index 0000000..f0a4974 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/in/web/WebControllerExceptionHandler.java @@ -0,0 +1,25 @@ +package ch.unisg.roster.roster.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.common.exception.ErrorResponse; +import ch.unisg.common.exception.InvalidExecutorURIException; + +@ControllerAdvice +public class WebControllerExceptionHandler { + + /** + * Handles error of type InvalidExecutorURIException + * @return 404 Bad Request + **/ + @ExceptionHandler(InvalidExecutorURIException.class) + public ResponseEntity handleException(InvalidExecutorURIException 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/GetAllExecutorInExecutorPoolByTypeAdapter.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/GetAllExecutorInExecutorPoolByTypeAdapter.java similarity index 65% rename from assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/GetAllExecutorInExecutorPoolByTypeAdapter.java rename to roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/GetAllExecutorInExecutorPoolByTypeAdapter.java index 4163a53..df444ca 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/GetAllExecutorInExecutorPoolByTypeAdapter.java +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/GetAllExecutorInExecutorPoolByTypeAdapter.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.adapter.out.web; +package ch.unisg.roster.roster.adapter.out.web; import java.io.IOException; import java.net.URI; @@ -9,21 +9,28 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.json.JSONArray; -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.stereotype.Component; -import ch.unisg.assignment.assignment.application.port.out.GetAllExecutorInExecutorPoolByTypePort; -import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType; +import ch.unisg.roster.roster.application.port.out.GetAllExecutorInExecutorPoolByTypePort; +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; @Component @Primary public class GetAllExecutorInExecutorPoolByTypeAdapter implements GetAllExecutorInExecutorPoolByTypePort { + @Value("${executor-pool.url}") + private String server; + + /** + * Requests all executor of the give type from the executor-pool and cheks if there is one + * avaialable of this type. + * @return Whether an executor exist or not + **/ @Override public boolean doesExecutorTypeExist(ExecutorType type) { - String server = "http://127.0.0.1:8083"; Logger logger = Logger.getLogger(PublishNewTaskEventAdapter.class.getName()); @@ -37,17 +44,18 @@ public class GetAllExecutorInExecutorPoolByTypeAdapter implements GetAllExecutor try { - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == HttpStatus.OK.value()) { - JSONArray jsonArray = new JSONArray(response.body().toString()); + JSONArray jsonArray = new JSONArray(response.body()); if (jsonArray.length() > 0) { return true; } } - } catch (IOException | InterruptedException e) { + } catch (InterruptedException e) { logger.log(Level.SEVERE, e.getLocalizedMessage(), e); - // Restore interrupted state... Thread.currentThread().interrupt(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); } return false; } diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishNewTaskEventAdapter.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/PublishNewTaskEventAdapter.java similarity index 63% rename from assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishNewTaskEventAdapter.java rename to roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/PublishNewTaskEventAdapter.java index 5007c1c..6a6b7f7 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishNewTaskEventAdapter.java +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/PublishNewTaskEventAdapter.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.adapter.out.web; +package ch.unisg.roster.roster.adapter.out.web; import java.io.IOException; import java.net.URI; @@ -8,21 +8,29 @@ import java.net.http.HttpResponse; import java.util.logging.Level; import java.util.logging.Logger; +import org.springframework.beans.factory.annotation.Value; 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; +import ch.unisg.roster.roster.application.port.out.NewTaskEventPort; +import ch.unisg.roster.roster.domain.event.NewTaskEvent; @Component @Primary public class PublishNewTaskEventAdapter implements NewTaskEventPort { - String server = "http://127.0.0.1:8084"; - String server2 = "http://127.0.0.1:8085"; + @Value("${executor1.url}") + private String server; + + @Value("${executor2.url}") + private String server2; Logger logger = Logger.getLogger(PublishNewTaskEventAdapter.class.getName()); + /** + * Informs executors about the availability of a new task. + * @return void + **/ @Override public void publishNewTaskEvent(NewTaskEvent event) { @@ -35,10 +43,11 @@ public class PublishNewTaskEventAdapter implements NewTaskEventPort { try { client.send(request, HttpResponse.BodyHandlers.ofString()); - } catch (IOException | InterruptedException e) { + } catch (InterruptedException e) { logger.log(Level.SEVERE, e.getLocalizedMessage(), e); - // Restore interrupted state... Thread.currentThread().interrupt(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); } HttpClient client2 = HttpClient.newHttpClient(); @@ -49,11 +58,12 @@ public class PublishNewTaskEventAdapter implements NewTaskEventPort { try { - client.send(request, HttpResponse.BodyHandlers.ofString()); - } catch (IOException | InterruptedException e) { + client2.send(request2, HttpResponse.BodyHandlers.ofString()); + } catch (InterruptedException e) { logger.log(Level.SEVERE, e.getLocalizedMessage(), e); - // Restore interrupted state... Thread.currentThread().interrupt(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); } } diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskAssignedEventAdapter.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/PublishTaskAssignedEventAdapter.java similarity index 70% rename from assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskAssignedEventAdapter.java rename to roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/PublishTaskAssignedEventAdapter.java index 56cb803..c71e306 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskAssignedEventAdapter.java +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/PublishTaskAssignedEventAdapter.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.adapter.out.web; +package ch.unisg.roster.roster.adapter.out.web; import java.io.IOException; import java.net.URI; @@ -9,20 +9,26 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Value; 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; +import ch.unisg.roster.roster.application.port.out.TaskAssignedEventPort; +import ch.unisg.roster.roster.domain.event.TaskAssignedEvent; @Component @Primary public class PublishTaskAssignedEventAdapter implements TaskAssignedEventPort { - String server = "http://127.0.0.1:8081"; + @Value("${task-list.url}") + private String server; Logger logger = Logger.getLogger(PublishTaskAssignedEventAdapter.class.getName()); + /** + * Informs the task service about the assignment of the task. + * @return void + **/ @Override public void publishTaskAssignedEvent(TaskAssignedEvent event) { @@ -40,10 +46,11 @@ public class PublishTaskAssignedEventAdapter implements TaskAssignedEventPort { try { client.send(request, HttpResponse.BodyHandlers.ofString()); - } catch (IOException | InterruptedException e) { + } catch (InterruptedException e) { logger.log(Level.SEVERE, e.getLocalizedMessage(), e); - // Restore interrupted state... Thread.currentThread().interrupt(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); } } diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskCompletedEventAdapter.java b/roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/PublishTaskCompletedEventAdapter.java similarity index 71% rename from assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskCompletedEventAdapter.java rename to roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/PublishTaskCompletedEventAdapter.java index f9f2833..7038291 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/adapter/out/web/PublishTaskCompletedEventAdapter.java +++ b/roster/src/main/java/ch/unisg/roster/roster/adapter/out/web/PublishTaskCompletedEventAdapter.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.adapter.out.web; +package ch.unisg.roster.roster.adapter.out.web; import java.io.IOException; import java.net.URI; @@ -9,20 +9,26 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Value; 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; +import ch.unisg.roster.roster.application.port.out.TaskCompletedEventPort; +import ch.unisg.roster.roster.domain.event.TaskCompletedEvent; @Component @Primary public class PublishTaskCompletedEventAdapter implements TaskCompletedEventPort { - String server = "http://127.0.0.1:8081"; + @Value("${task-list.url}") + private String server; Logger logger = Logger.getLogger(PublishTaskCompletedEventAdapter.class.getName()); + /** + * Informs the task service about the completion of the task. + * @return void + **/ @Override public void publishTaskCompleted(TaskCompletedEvent event) { @@ -42,10 +48,11 @@ public class PublishTaskCompletedEventAdapter implements TaskCompletedEventPort try { client.send(request, HttpResponse.BodyHandlers.ofString()); - } catch (IOException | InterruptedException e) { + } catch (InterruptedException e) { logger.log(Level.SEVERE, e.getLocalizedMessage(), e); - // Restore interrupted state... Thread.currentThread().interrupt(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); } } diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/handler/ExecutorAddedHandler.java b/roster/src/main/java/ch/unisg/roster/roster/application/handler/ExecutorAddedHandler.java new file mode 100644 index 0000000..9545c07 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/handler/ExecutorAddedHandler.java @@ -0,0 +1,16 @@ +package ch.unisg.roster.roster.application.handler; + +import ch.unisg.roster.roster.application.port.in.ExecutorAddedEvent; +import ch.unisg.roster.roster.application.port.in.ExecutorAddedEventHandler; +import ch.unisg.roster.roster.domain.ExecutorRegistry; +import org.springframework.stereotype.Component; + +@Component +public class ExecutorAddedHandler implements ExecutorAddedEventHandler { + + @Override + public boolean handleNewExecutorEvent(ExecutorAddedEvent executorAddedEvent) { + return ExecutorRegistry.getInstance().addExecutor(executorAddedEvent.getExecutorType(), + executorAddedEvent.getExecutorURI()); + } +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/handler/ExecutorRemovedHandler.java b/roster/src/main/java/ch/unisg/roster/roster/application/handler/ExecutorRemovedHandler.java new file mode 100644 index 0000000..c6e3f68 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/handler/ExecutorRemovedHandler.java @@ -0,0 +1,19 @@ +package ch.unisg.roster.roster.application.handler; + +import ch.unisg.roster.roster.application.port.in.ExecutorRemovedEvent; +import ch.unisg.roster.roster.application.port.in.ExecutorRemovedEventHandler; +import ch.unisg.roster.roster.domain.ExecutorRegistry; +import org.springframework.stereotype.Component; + +/** + * Handler for executor removed events. It removes the executor from this roster's executor + * registry. + */ +@Component +public class ExecutorRemovedHandler implements ExecutorRemovedEventHandler { + + @Override + public boolean handleExecutorRemovedEvent(ExecutorRemovedEvent executorRemovedEvent) { + return ExecutorRegistry.getInstance().removeExecutor(executorRemovedEvent.getExecutorURI()); + } +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ApplyForTaskCommand.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ApplyForTaskCommand.java new file mode 100644 index 0000000..f03ef5f --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ApplyForTaskCommand.java @@ -0,0 +1,26 @@ +package ch.unisg.roster.roster.application.port.in; + +import javax.validation.constraints.NotNull; + +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; +import ch.unisg.common.validation.SelfValidating; +import ch.unisg.common.valueobject.ExecutorURI; +import lombok.EqualsAndHashCode; +import lombok.Value; + +@Value +@EqualsAndHashCode(callSuper=false) +public class ApplyForTaskCommand extends SelfValidating{ + + @NotNull + private final ExecutorType taskType; + + @NotNull + private final ExecutorURI executorURI; + + public ApplyForTaskCommand(ExecutorType taskType, ExecutorURI executorURI) { + this.taskType = taskType; + this.executorURI = executorURI; + this.validateSelf(); + } +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ApplyForTaskUseCase.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ApplyForTaskUseCase.java new file mode 100644 index 0000000..61b7bd4 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ApplyForTaskUseCase.java @@ -0,0 +1,7 @@ +package ch.unisg.roster.roster.application.port.in; + +import ch.unisg.roster.roster.domain.Task; + +public interface ApplyForTaskUseCase { + Task applyForTask(ApplyForTaskCommand applyForTaskCommand); +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/in/DeleteTaskCommand.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/DeleteTaskCommand.java new file mode 100644 index 0000000..9f59dc3 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/DeleteTaskCommand.java @@ -0,0 +1,24 @@ +package ch.unisg.roster.roster.application.port.in; + +import javax.validation.constraints.NotNull; + +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; +import ch.unisg.common.validation.SelfValidating; +import lombok.EqualsAndHashCode; +import lombok.Value; + +@Value +@EqualsAndHashCode(callSuper=false) +public class DeleteTaskCommand extends SelfValidating { + @NotNull + private final String taskId; + + @NotNull + private final ExecutorType taskType; + + public DeleteTaskCommand(String taskId, ExecutorType taskType) { + this.taskId = taskId; + this.taskType = taskType; + this.validateSelf(); + } +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/in/DeleteTaskUseCase.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/DeleteTaskUseCase.java new file mode 100644 index 0000000..2acfc63 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/DeleteTaskUseCase.java @@ -0,0 +1,5 @@ +package ch.unisg.roster.roster.application.port.in; + +public interface DeleteTaskUseCase { + boolean deleteTask(DeleteTaskCommand deleteTaskCommand); +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorAddedEvent.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorAddedEvent.java new file mode 100644 index 0000000..0e10b8e --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorAddedEvent.java @@ -0,0 +1,33 @@ +package ch.unisg.roster.roster.application.port.in; + +import lombok.Value; + +import javax.validation.constraints.NotNull; + +import ch.unisg.common.validation.SelfValidating; +import ch.unisg.common.valueobject.ExecutorURI; +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; + +/** + * Event that notifies the auction house that an executor has been added to this TAPAS application. + */ +@Value +public class ExecutorAddedEvent extends SelfValidating { + @NotNull + private final ExecutorURI executorURI; + + @NotNull + private final ExecutorType executorType; + + /** + * Constructs an executor added event. + * + * @param executorURI the identifier of the executor that was added to this TAPAS application + */ + public ExecutorAddedEvent(ExecutorURI executorURI, ExecutorType executorType) { + this.executorURI = executorURI; + this.executorType = executorType; + + this.validateSelf(); + } +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorAddedEventHandler.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorAddedEventHandler.java new file mode 100644 index 0000000..c7a9076 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorAddedEventHandler.java @@ -0,0 +1,6 @@ +package ch.unisg.roster.roster.application.port.in; + +public interface ExecutorAddedEventHandler { + + boolean handleNewExecutorEvent(ExecutorAddedEvent executorAddedEvent); +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorRemovedEvent.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorRemovedEvent.java new file mode 100644 index 0000000..8753683 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorRemovedEvent.java @@ -0,0 +1,27 @@ +package ch.unisg.roster.roster.application.port.in; + +import lombok.Value; + +import javax.validation.constraints.NotNull; + +import ch.unisg.common.validation.SelfValidating; +import ch.unisg.common.valueobject.ExecutorURI; + +/** + * Event that notifies the auction house that an executor has been removed from this TAPAS application. + */ +@Value +public class ExecutorRemovedEvent extends SelfValidating { + @NotNull + private final ExecutorURI executorURI; + + /** + * Constructs an executor removed event. + * + * @param executorURI the identifier of the executor that was removed from this TAPAS application + */ + public ExecutorRemovedEvent(ExecutorURI executorURI) { + this.executorURI = executorURI; + this.validateSelf(); + } +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorRemovedEventHandler.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorRemovedEventHandler.java new file mode 100644 index 0000000..79ee6a7 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/ExecutorRemovedEventHandler.java @@ -0,0 +1,6 @@ +package ch.unisg.roster.roster.application.port.in; + +public interface ExecutorRemovedEventHandler { + + boolean handleExecutorRemovedEvent(ExecutorRemovedEvent executorRemovedEvent); +} diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskCommand.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/NewTaskCommand.java similarity index 72% rename from assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskCommand.java rename to roster/src/main/java/ch/unisg/roster/roster/application/port/in/NewTaskCommand.java index ab6838e..92a7403 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskCommand.java +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/NewTaskCommand.java @@ -1,9 +1,9 @@ -package ch.unisg.assignment.assignment.application.port.in; +package ch.unisg.roster.roster.application.port.in; import javax.validation.constraints.NotNull; -import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType; -import ch.unisg.assignment.common.SelfValidating; +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; +import ch.unisg.common.validation.SelfValidating; import lombok.EqualsAndHashCode; import lombok.Value; diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskUseCase.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/NewTaskUseCase.java similarity index 62% rename from assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskUseCase.java rename to roster/src/main/java/ch/unisg/roster/roster/application/port/in/NewTaskUseCase.java index 21f084e..f1bd733 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/NewTaskUseCase.java +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/NewTaskUseCase.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.application.port.in; +package ch.unisg.roster.roster.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/roster/src/main/java/ch/unisg/roster/roster/application/port/in/TaskCompletedCommand.java similarity index 84% rename from assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedCommand.java rename to roster/src/main/java/ch/unisg/roster/roster/application/port/in/TaskCompletedCommand.java index b0af2b4..b7438c0 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedCommand.java +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/TaskCompletedCommand.java @@ -1,8 +1,8 @@ -package ch.unisg.assignment.assignment.application.port.in; +package ch.unisg.roster.roster.application.port.in; import javax.validation.constraints.NotNull; -import ch.unisg.assignment.common.SelfValidating; +import ch.unisg.common.validation.SelfValidating; import lombok.EqualsAndHashCode; import lombok.Value; diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedUseCase.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/TaskCompletedUseCase.java similarity index 64% rename from assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedUseCase.java rename to roster/src/main/java/ch/unisg/roster/roster/application/port/in/TaskCompletedUseCase.java index 1902952..51b305a 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/port/in/TaskCompletedUseCase.java +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/in/TaskCompletedUseCase.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.application.port.in; +package ch.unisg.roster.roster.application.port.in; public interface TaskCompletedUseCase { void taskCompleted(TaskCompletedCommand taskCompletedCommand); diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/out/GetAllExecutorInExecutorPoolByTypePort.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/out/GetAllExecutorInExecutorPoolByTypePort.java new file mode 100644 index 0000000..f32a3f5 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/out/GetAllExecutorInExecutorPoolByTypePort.java @@ -0,0 +1,13 @@ +package ch.unisg.roster.roster.application.port.out; + +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; + +public interface GetAllExecutorInExecutorPoolByTypePort { + /** + * Checks if a executor with the given type exist in our executor pool + * @return boolean + **/ + boolean doesExecutorTypeExist(ExecutorType type); +} + + diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/out/NewTaskEventPort.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/out/NewTaskEventPort.java new file mode 100644 index 0000000..75fda6d --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/out/NewTaskEventPort.java @@ -0,0 +1,11 @@ +package ch.unisg.roster.roster.application.port.out; + +import ch.unisg.roster.roster.domain.event.NewTaskEvent; + +public interface NewTaskEventPort { + /** + * Publishes the new task event. + * @return void + **/ + void publishNewTaskEvent(NewTaskEvent event); +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/out/TaskAssignedEventPort.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/out/TaskAssignedEventPort.java new file mode 100644 index 0000000..2bcb2ae --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/out/TaskAssignedEventPort.java @@ -0,0 +1,11 @@ +package ch.unisg.roster.roster.application.port.out; + +import ch.unisg.roster.roster.domain.event.TaskAssignedEvent; + +public interface TaskAssignedEventPort { + /** + * Publishes the task assigned event. + * @return void + **/ + void publishTaskAssignedEvent(TaskAssignedEvent taskAssignedEvent); +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/port/out/TaskCompletedEventPort.java b/roster/src/main/java/ch/unisg/roster/roster/application/port/out/TaskCompletedEventPort.java new file mode 100644 index 0000000..a8c11ef --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/port/out/TaskCompletedEventPort.java @@ -0,0 +1,11 @@ +package ch.unisg.roster.roster.application.port.out; + +import ch.unisg.roster.roster.domain.event.TaskCompletedEvent; + +public interface TaskCompletedEventPort { + /** + * Publishes the task completed event. + * @return void + **/ + void publishTaskCompleted(TaskCompletedEvent event); +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/service/ApplyForTaskService.java b/roster/src/main/java/ch/unisg/roster/roster/application/service/ApplyForTaskService.java new file mode 100644 index 0000000..26b75aa --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/service/ApplyForTaskService.java @@ -0,0 +1,39 @@ +package ch.unisg.roster.roster.application.service; + +import javax.transaction.Transactional; + +import org.springframework.stereotype.Component; + +import ch.unisg.roster.roster.application.port.in.ApplyForTaskCommand; +import ch.unisg.roster.roster.application.port.in.ApplyForTaskUseCase; +import ch.unisg.roster.roster.application.port.out.TaskAssignedEventPort; +import ch.unisg.roster.roster.domain.Roster; +import ch.unisg.roster.roster.domain.Task; +import ch.unisg.roster.roster.domain.event.TaskAssignedEvent; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Component +@Transactional +public class ApplyForTaskService implements ApplyForTaskUseCase { + + private final TaskAssignedEventPort taskAssignedEventPort; + + /** + * Checks if a task is available and assignes it to the executor. If task got assigned a task + * assigned event gets published. + * @return assigned task or null if no task is found + **/ + @Override + public Task applyForTask(ApplyForTaskCommand command) { + Task task = Roster.getInstance().assignTaskToExecutor(command.getTaskType(), + command.getExecutorURI()); + + if (task != null) { + taskAssignedEventPort.publishTaskAssignedEvent(new TaskAssignedEvent(task.getTaskID())); + } + + return task; + } + +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/service/DeleteTaskService.java b/roster/src/main/java/ch/unisg/roster/roster/application/service/DeleteTaskService.java new file mode 100644 index 0000000..a6b4841 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/service/DeleteTaskService.java @@ -0,0 +1,27 @@ +package ch.unisg.roster.roster.application.service; + +import javax.transaction.Transactional; + +import org.springframework.stereotype.Component; + +import ch.unisg.roster.roster.application.port.in.DeleteTaskCommand; +import ch.unisg.roster.roster.application.port.in.DeleteTaskUseCase; +import ch.unisg.roster.roster.domain.Roster; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Component +@Transactional +public class DeleteTaskService implements DeleteTaskUseCase { + + /** + * Check if task can get deleted + * @return if task can get deleted + **/ + @Override + public boolean deleteTask(DeleteTaskCommand command) { + Roster roster = Roster.getInstance(); + return roster.deleteTask(command.getTaskId(), command.getTaskType()); + } + +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/application/service/NewTaskService.java b/roster/src/main/java/ch/unisg/roster/roster/application/service/NewTaskService.java new file mode 100644 index 0000000..588ed04 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/application/service/NewTaskService.java @@ -0,0 +1,46 @@ +package ch.unisg.roster.roster.application.service; + +import javax.transaction.Transactional; + +import org.springframework.stereotype.Component; + +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.out.NewTaskEventPort; +import ch.unisg.roster.roster.domain.ExecutorRegistry; +import ch.unisg.roster.roster.domain.Roster; +import ch.unisg.roster.roster.domain.Task; +import ch.unisg.roster.roster.domain.event.NewTaskEvent; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Component +@Transactional +public class NewTaskService implements NewTaskUseCase { + + private final NewTaskEventPort newTaskEventPort; + + /** + * Checks if we can execute the give task, if yes the task gets added to the task queue and return true. + * If the task can not be executed by an internal or auction house executor, the method return false. + * @return boolean + **/ + @Override + public boolean addNewTaskToQueue(NewTaskCommand command) { + + ExecutorRegistry executorRegistry = ExecutorRegistry.getInstance(); + if (!executorRegistry.containsTaskType(command.getTaskType())) { + return false; + } + + Task task = new Task(command.getTaskID(), command.getTaskType()); + + Roster.getInstance().addTaskToQueue(task); + + 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/roster/src/main/java/ch/unisg/roster/roster/application/service/TaskCompletedService.java similarity index 56% rename from assignment/src/main/java/ch/unisg/assignment/assignment/application/service/TaskCompletedService.java rename to roster/src/main/java/ch/unisg/roster/roster/application/service/TaskCompletedService.java index c8273ff..69b65d1 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/application/service/TaskCompletedService.java +++ b/roster/src/main/java/ch/unisg/roster/roster/application/service/TaskCompletedService.java @@ -1,14 +1,14 @@ -package ch.unisg.assignment.assignment.application.service; +package ch.unisg.roster.roster.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 ch.unisg.roster.roster.application.port.in.TaskCompletedCommand; +import ch.unisg.roster.roster.application.port.in.TaskCompletedUseCase; +import ch.unisg.roster.roster.application.port.out.TaskCompletedEventPort; +import ch.unisg.roster.roster.domain.Roster; +import ch.unisg.roster.roster.domain.event.TaskCompletedEvent; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @@ -18,6 +18,10 @@ public class TaskCompletedService implements TaskCompletedUseCase { private final TaskCompletedEventPort taskCompletedEventPort; + /** + * Completes the task in the roster and publishes a task completed event. + * @return void + **/ @Override public void taskCompleted(TaskCompletedCommand command) { diff --git a/roster/src/main/java/ch/unisg/roster/roster/domain/ExecutorInfo.java b/roster/src/main/java/ch/unisg/roster/roster/domain/ExecutorInfo.java new file mode 100644 index 0000000..eb32ec0 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/domain/ExecutorInfo.java @@ -0,0 +1,16 @@ +package ch.unisg.roster.roster.domain; + +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; +import ch.unisg.common.valueobject.ExecutorURI; +import lombok.Getter; +import lombok.Setter; + +public class ExecutorInfo { + @Getter + @Setter + private ExecutorURI executorURI; + + @Getter + @Setter + private ExecutorType executorType; +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/domain/ExecutorRegistry.java b/roster/src/main/java/ch/unisg/roster/roster/domain/ExecutorRegistry.java new file mode 100644 index 0000000..4ddba0f --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/domain/ExecutorRegistry.java @@ -0,0 +1,92 @@ +package ch.unisg.roster.roster.domain; + +import java.util.*; + +import ch.unisg.common.valueobject.ExecutorURI; +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; + +/** + * Registry that keeps a track of executors internal to the TAPAS application and the types of tasks + * they can achieve. One executor may correspond to multiple task types. + * This class is a singleton. + */ +public class ExecutorRegistry { + private static ExecutorRegistry registry; + + private final Map> executors; + + private ExecutorRegistry() { + this.executors = new Hashtable<>(); + } + + public static synchronized ExecutorRegistry getInstance() { + if (registry == null) { + registry = new ExecutorRegistry(); + } + + return registry; + } + + /** + * Adds an executor to the registry for a given task type. + * + * @param taskType the type of the task + * @param executorIdentifier the identifier of the executor (can be any string) + * @return true unless a runtime exception occurs + */ + public boolean addExecutor(ExecutorType executorType, ExecutorURI executorURI) { + Set taskTypeExecs = executors.getOrDefault(executorType, + Collections.synchronizedSet(new HashSet<>())); + + taskTypeExecs.add(executorURI); + executors.put(executorType, taskTypeExecs); + + return true; + } + + /** + * Removes an executor from the registry. The executor is disassociated from all known task types. + * + * @param executorURI the identifier of the executor + * @return true unless a runtime exception occurs + */ + public boolean removeExecutor(ExecutorURI executorURI) { + Iterator iterator = executors.keySet().iterator(); + + while (iterator.hasNext()) { + ExecutorType executorType = iterator.next(); + Set set = executors.get(executorType); + + set.remove(executorURI); + + if (set.isEmpty()) { + iterator.remove(); + } + } + + return true; + } + + /** + * Checks if the registry contains an executor for a given task type. Used during task creation + * to decide if a task can be executed. + * + * @param taskType the task type being auctioned + * @return + */ + public boolean containsTaskType(ExecutorType taskType) { + return executors.containsKey(taskType); + } + + /** + * Adds a list of executors to current executor list. Should only be used on startup to + * add all available executors from the executor pool to the registry. + * + * @param executors the initial executors + * @return + */ + public void init(Map> executors) { + this.executors.putAll(executors); + } + +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/domain/Roster.java b/roster/src/main/java/ch/unisg/roster/roster/domain/Roster.java new file mode 100644 index 0000000..cc9a0a6 --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/domain/Roster.java @@ -0,0 +1,86 @@ +package ch.unisg.roster.roster.domain; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; +import ch.unisg.common.valueobject.ExecutorURI; + +public class Roster { + + private static final Roster roster = new Roster(); + + // Queues which hold all the tasks which need to be assigned | Will be replaced by message queue later + private HashMap> queues = new HashMap<>(); + + // Roster witch holds information about which executor is assigned to a task + private HashMap rosterMap = new HashMap<>(); + + Logger logger = Logger.getLogger(Roster.class.getName()); + + public static Roster getInstance() { + return roster; + } + + private Roster() {} + + /** + * Adds a task to the task queue. + * @return void + * @see Task + **/ + 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))); + } + logger.log(Level.INFO, "Added task with id {0} to queue", task.getTaskID()); + } + + /** + * Checks if a task of this type is in a queue and if so assignes it to the executor. + * @return assigned task or null if no task is found + * @see Task + **/ + public Task assignTaskToExecutor(ExecutorType taskType, ExecutorURI executorURI) { + // TODO I don't think we need this if + 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(), executorURI)); + + return task; + } + + /** + * Removed a task from the roster after if got completed + * @return void + * @see Task + * @see Roster + **/ + public void taskCompleted(String taskID) { + rosterMap.remove(taskID); + logger.log(Level.INFO, "Task {0} completed", taskID); + } + + /** + * Deletes a task if it is still in the queue. + * @return Whether the task got deleted or not + **/ + public boolean deleteTask(String taskID, ExecutorType taskType) { + logger.log(Level.INFO, "Try to delete task with id {0}", taskID); + return queues.get(taskType.getValue()).removeIf(task -> task.getTaskID().equalsIgnoreCase(taskID)); + } + +} diff --git a/roster/src/main/java/ch/unisg/roster/roster/domain/RosterItem.java b/roster/src/main/java/ch/unisg/roster/roster/domain/RosterItem.java new file mode 100644 index 0000000..cc39c6c --- /dev/null +++ b/roster/src/main/java/ch/unisg/roster/roster/domain/RosterItem.java @@ -0,0 +1,23 @@ +package ch.unisg.roster.roster.domain; + +import ch.unisg.common.valueobject.ExecutorURI; +import lombok.Getter; + +public class RosterItem { + + @Getter + private String taskID; + + @Getter + private String taskType; + + @Getter + private ExecutorURI executorURI; + + public RosterItem(String taskID, String taskType, ExecutorURI executorURI) { + this.taskID = taskID; + this.taskType = taskType; + this.executorURI = executorURI; + } + +} diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/Task.java b/roster/src/main/java/ch/unisg/roster/roster/domain/Task.java similarity index 82% rename from assignment/src/main/java/ch/unisg/assignment/assignment/domain/Task.java rename to roster/src/main/java/ch/unisg/roster/roster/domain/Task.java index 7daa738..40ef9fa 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/Task.java +++ b/roster/src/main/java/ch/unisg/roster/roster/domain/Task.java @@ -1,6 +1,6 @@ -package ch.unisg.assignment.assignment.domain; +package ch.unisg.roster.roster.domain; -import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType; +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; import lombok.Getter; import lombok.Setter; diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/NewTaskEvent.java b/roster/src/main/java/ch/unisg/roster/roster/domain/event/NewTaskEvent.java similarity index 56% rename from assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/NewTaskEvent.java rename to roster/src/main/java/ch/unisg/roster/roster/domain/event/NewTaskEvent.java index 34e7f0b..1457f1d 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/NewTaskEvent.java +++ b/roster/src/main/java/ch/unisg/roster/roster/domain/event/NewTaskEvent.java @@ -1,6 +1,6 @@ -package ch.unisg.assignment.assignment.domain.event; +package ch.unisg.roster.roster.domain.event; -import ch.unisg.assignment.assignment.domain.valueobject.ExecutorType; +import ch.unisg.roster.roster.domain.valueobject.ExecutorType; public class NewTaskEvent { public final ExecutorType taskType; diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskAssignedEvent.java b/roster/src/main/java/ch/unisg/roster/roster/domain/event/TaskAssignedEvent.java similarity index 74% rename from assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskAssignedEvent.java rename to roster/src/main/java/ch/unisg/roster/roster/domain/event/TaskAssignedEvent.java index d0178d4..9c57270 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskAssignedEvent.java +++ b/roster/src/main/java/ch/unisg/roster/roster/domain/event/TaskAssignedEvent.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.domain.event; +package ch.unisg.roster.roster.domain.event; public class TaskAssignedEvent { public final String taskID; diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskCompletedEvent.java b/roster/src/main/java/ch/unisg/roster/roster/domain/event/TaskCompletedEvent.java similarity index 85% rename from assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskCompletedEvent.java rename to roster/src/main/java/ch/unisg/roster/roster/domain/event/TaskCompletedEvent.java index 432a8f0..926f601 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/event/TaskCompletedEvent.java +++ b/roster/src/main/java/ch/unisg/roster/roster/domain/event/TaskCompletedEvent.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.domain.event; +package ch.unisg.roster.roster.domain.event; public class TaskCompletedEvent { public final String taskID; diff --git a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/ExecutorType.java b/roster/src/main/java/ch/unisg/roster/roster/domain/valueobject/ExecutorType.java similarity index 74% rename from assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/ExecutorType.java rename to roster/src/main/java/ch/unisg/roster/roster/domain/valueobject/ExecutorType.java index bc5f467..72368e3 100644 --- a/assignment/src/main/java/ch/unisg/assignment/assignment/domain/valueobject/ExecutorType.java +++ b/roster/src/main/java/ch/unisg/roster/roster/domain/valueobject/ExecutorType.java @@ -1,4 +1,4 @@ -package ch.unisg.assignment.assignment.domain.valueobject; +package ch.unisg.roster.roster.domain.valueobject; import lombok.Value; diff --git a/roster/src/main/resources/application.properties b/roster/src/main/resources/application.properties new file mode 100644 index 0000000..dc443ab --- /dev/null +++ b/roster/src/main/resources/application.properties @@ -0,0 +1,5 @@ +server.port=8082 +executor-pool.url=http://127.0.0.1:8083 +executor1.url=http://127.0.0.1:8084 +executor2.url=http://127.0.0.1:8085 +task-list.url=http://127.0.0.1:8081 diff --git a/assignment/src/test/java/ch/unisg/assignment/AssignmentApplicationTests.java b/roster/src/test/java/ch/unisg/roster/RosterApplicationTests.java similarity index 70% rename from assignment/src/test/java/ch/unisg/assignment/AssignmentApplicationTests.java rename to roster/src/test/java/ch/unisg/roster/RosterApplicationTests.java index 9da24b5..5ee712b 100644 --- a/assignment/src/test/java/ch/unisg/assignment/AssignmentApplicationTests.java +++ b/roster/src/test/java/ch/unisg/roster/RosterApplicationTests.java @@ -1,10 +1,10 @@ -package ch.unisg.assignment; +package ch.unisg.roster; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest -class AssignmentApplicationTests { +class RosterApplicationTests { @Test void contextLoads() {