rename assignment to roster & added executor registry to roster
This commit is contained in:
13
roster/src/main/java/ch/unisg/roster/RosterApplication.java
Normal file
13
roster/src/main/java/ch/unisg/roster/RosterApplication.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package ch.unisg.roster;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class RosterApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RosterApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@@ -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) { }
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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<String, AuctionEventMqttListener> 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<String> 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);
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
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.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 {
|
||||
private final ApplyForTaskUseCase applyForTaskUseCase;
|
||||
|
||||
public ApplyForTaskController(ApplyForTaskUseCase applyForTaskUseCase) {
|
||||
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.getExecutorURI());
|
||||
|
||||
return applyForTaskUseCase.applyForTask(command);
|
||||
}
|
||||
}
|
@@ -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<Void> 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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package ch.unisg.roster.roster.adapter.in.web;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.unisg.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 {
|
||||
private final NewTaskUseCase newTaskUseCase;
|
||||
|
||||
public NewTaskController(NewTaskUseCase newTaskUseCase) {
|
||||
this.newTaskUseCase = newTaskUseCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<Void> newTaskController(@RequestBody Task task) {
|
||||
|
||||
NewTaskCommand command = new NewTaskCommand(task.getTaskID(), task.getTaskType());
|
||||
|
||||
boolean success = newTaskUseCase.addNewTaskToQueue(command);
|
||||
|
||||
if (success) {
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
return new ResponseEntity<>(HttpStatus.CONFLICT);
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package ch.unisg.roster.roster.adapter.in.web;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.unisg.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 {
|
||||
|
||||
private final TaskCompletedUseCase taskCompletedUseCase;
|
||||
|
||||
public TaskCompletedController(TaskCompletedUseCase taskCompletedUseCase) {
|
||||
this.taskCompletedUseCase = taskCompletedUseCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller which handles the task completed event from executors
|
||||
* @return 200 OK
|
||||
**/
|
||||
@PostMapping(path = "/task/completed", consumes = {"application/json"})
|
||||
public ResponseEntity<Void> addNewTaskTaskToTaskList(@RequestBody Task task) {
|
||||
|
||||
TaskCompletedCommand command = new TaskCompletedCommand(task.getTaskID(),
|
||||
task.getStatus(), task.getResult());
|
||||
|
||||
taskCompletedUseCase.taskCompleted(command);
|
||||
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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<ErrorResponse> handleException(InvalidExecutorURIException e){
|
||||
|
||||
ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST, e.getLocalizedMessage());
|
||||
return new ResponseEntity<>(error, error.getHttpStatus());
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
package ch.unisg.roster.roster.adapter.out.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
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) {
|
||||
|
||||
Logger logger = Logger.getLogger(PublishNewTaskEventAdapter.class.getName());
|
||||
|
||||
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(server + "/executor-pool/GetAllExecutorInExecutorPoolByType/" + type.getValue()))
|
||||
.header("Content-Type", "application/json")
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
|
||||
try {
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
if (response.statusCode() == HttpStatus.OK.value()) {
|
||||
JSONArray jsonArray = new JSONArray(response.body());
|
||||
if (jsonArray.length() > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
package ch.unisg.roster.roster.adapter.out.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.unisg.roster.roster.application.port.out.NewTaskEventPort;
|
||||
import ch.unisg.roster.roster.domain.event.NewTaskEvent;
|
||||
|
||||
@Component
|
||||
@Primary
|
||||
public class PublishNewTaskEventAdapter implements NewTaskEventPort {
|
||||
|
||||
@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) {
|
||||
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(server + "/newtask/" + event.taskType.getValue()))
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
|
||||
try {
|
||||
client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
}
|
||||
|
||||
HttpClient client2 = HttpClient.newHttpClient();
|
||||
HttpRequest request2 = HttpRequest.newBuilder()
|
||||
.uri(URI.create(server2 + "/newtask/" + event.taskType.getValue()))
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
|
||||
try {
|
||||
client2.send(request2, HttpResponse.BodyHandlers.ofString());
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package ch.unisg.roster.roster.adapter.out.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.unisg.roster.roster.application.port.out.TaskAssignedEventPort;
|
||||
import ch.unisg.roster.roster.domain.event.TaskAssignedEvent;
|
||||
|
||||
@Component
|
||||
@Primary
|
||||
public class PublishTaskAssignedEventAdapter implements TaskAssignedEventPort {
|
||||
|
||||
@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) {
|
||||
|
||||
String body = new JSONObject()
|
||||
.put("taskId", event.taskID)
|
||||
.toString();
|
||||
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(server + "/tasks/assignTask"))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(body))
|
||||
.build();
|
||||
|
||||
|
||||
try {
|
||||
client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package ch.unisg.roster.roster.adapter.out.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.unisg.roster.roster.application.port.out.TaskCompletedEventPort;
|
||||
import ch.unisg.roster.roster.domain.event.TaskCompletedEvent;
|
||||
|
||||
@Component
|
||||
@Primary
|
||||
public class PublishTaskCompletedEventAdapter implements TaskCompletedEventPort {
|
||||
|
||||
@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) {
|
||||
|
||||
String body = new JSONObject()
|
||||
.put("taskId", event.taskID)
|
||||
.put("status", event.status)
|
||||
.put("taskResult", event.result)
|
||||
.toString();
|
||||
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(server + "/tasks/completeTask"))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(body))
|
||||
.build();
|
||||
|
||||
|
||||
try {
|
||||
client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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());
|
||||
}
|
||||
}
|
@@ -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());
|
||||
}
|
||||
}
|
@@ -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<ApplyForTaskCommand>{
|
||||
|
||||
@NotNull
|
||||
private final ExecutorType taskType;
|
||||
|
||||
@NotNull
|
||||
private final ExecutorURI executorURI;
|
||||
|
||||
public ApplyForTaskCommand(ExecutorType taskType, ExecutorURI executorURI) {
|
||||
this.taskType = taskType;
|
||||
this.executorURI = executorURI;
|
||||
this.validateSelf();
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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<ApplyForTaskCommand> {
|
||||
@NotNull
|
||||
private final String taskId;
|
||||
|
||||
@NotNull
|
||||
private final ExecutorType taskType;
|
||||
|
||||
public DeleteTaskCommand(String taskId, ExecutorType taskType) {
|
||||
this.taskId = taskId;
|
||||
this.taskType = taskType;
|
||||
this.validateSelf();
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package ch.unisg.roster.roster.application.port.in;
|
||||
|
||||
public interface DeleteTaskUseCase {
|
||||
boolean deleteTask(DeleteTaskCommand deleteTaskCommand);
|
||||
}
|
@@ -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<ExecutorAddedEvent> {
|
||||
@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();
|
||||
}
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
package ch.unisg.roster.roster.application.port.in;
|
||||
|
||||
public interface ExecutorAddedEventHandler {
|
||||
|
||||
boolean handleNewExecutorEvent(ExecutorAddedEvent executorAddedEvent);
|
||||
}
|
@@ -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<ExecutorRemovedEvent> {
|
||||
@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();
|
||||
}
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
package ch.unisg.roster.roster.application.port.in;
|
||||
|
||||
public interface ExecutorRemovedEventHandler {
|
||||
|
||||
boolean handleExecutorRemovedEvent(ExecutorRemovedEvent executorRemovedEvent);
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
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 NewTaskCommand extends SelfValidating<NewTaskCommand> {
|
||||
|
||||
@NotNull
|
||||
private final String taskID;
|
||||
|
||||
@NotNull
|
||||
private final ExecutorType taskType;
|
||||
|
||||
public NewTaskCommand(String taskID, ExecutorType taskType) {
|
||||
this.taskID = taskID;
|
||||
this.taskType = taskType;
|
||||
this.validateSelf();
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package ch.unisg.roster.roster.application.port.in;
|
||||
|
||||
public interface NewTaskUseCase {
|
||||
boolean addNewTaskToQueue(NewTaskCommand newTaskCommand);
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package ch.unisg.roster.roster.application.port.in;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import ch.unisg.common.validation.SelfValidating;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper=false)
|
||||
public class TaskCompletedCommand extends SelfValidating<TaskCompletedCommand>{
|
||||
|
||||
@NotNull
|
||||
private final String taskID;
|
||||
|
||||
@NotNull
|
||||
private final String taskStatus;
|
||||
|
||||
@NotNull
|
||||
private final String taskResult;
|
||||
|
||||
public TaskCompletedCommand(String taskID, String taskStatus, String taskResult) {
|
||||
this.taskID = taskID;
|
||||
this.taskStatus = taskStatus;
|
||||
this.taskResult = taskResult;
|
||||
this.validateSelf();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package ch.unisg.roster.roster.application.port.in;
|
||||
|
||||
public interface TaskCompletedUseCase {
|
||||
void taskCompleted(TaskCompletedCommand taskCompletedCommand);
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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());
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package ch.unisg.roster.roster.application.service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
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
|
||||
@Component
|
||||
@Transactional
|
||||
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) {
|
||||
|
||||
Roster.getInstance().taskCompleted(command.getTaskID());
|
||||
|
||||
taskCompletedEventPort.publishTaskCompleted(new TaskCompletedEvent(command.getTaskID(),
|
||||
command.getTaskStatus(), command.getTaskResult()));
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -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<ExecutorType, Set<ExecutorURI>> 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<ExecutorURI> 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<ExecutorType> iterator = executors.keySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ExecutorType executorType = iterator.next();
|
||||
Set<ExecutorURI> 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<ExecutorType, Set<ExecutorURI>> executors) {
|
||||
this.executors.putAll(executors);
|
||||
}
|
||||
|
||||
}
|
@@ -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<String, ArrayList<Task>> queues = new HashMap<>();
|
||||
|
||||
// Roster witch holds information about which executor is assigned to a task
|
||||
private HashMap<String, RosterItem> 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));
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
35
roster/src/main/java/ch/unisg/roster/roster/domain/Task.java
Normal file
35
roster/src/main/java/ch/unisg/roster/roster/domain/Task.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package ch.unisg.roster.roster.domain;
|
||||
|
||||
import ch.unisg.roster.roster.domain.valueobject.ExecutorType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class Task {
|
||||
|
||||
@Getter
|
||||
private String taskID;
|
||||
|
||||
@Getter
|
||||
private ExecutorType taskType;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String result;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String status;
|
||||
|
||||
public Task(String taskID, String taskType) {
|
||||
this.taskID = taskID;
|
||||
this.taskType = new ExecutorType(taskType);
|
||||
}
|
||||
|
||||
public Task(String taskID, ExecutorType taskType) {
|
||||
this.taskID = taskID;
|
||||
this.taskType = taskType;
|
||||
}
|
||||
|
||||
public Task() {}
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package ch.unisg.roster.roster.domain.event;
|
||||
|
||||
import ch.unisg.roster.roster.domain.valueobject.ExecutorType;
|
||||
|
||||
public class NewTaskEvent {
|
||||
public final ExecutorType taskType;
|
||||
|
||||
public NewTaskEvent(ExecutorType taskType) {
|
||||
this.taskType = taskType;
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
package ch.unisg.roster.roster.domain.event;
|
||||
|
||||
public class TaskAssignedEvent {
|
||||
public final String taskID;
|
||||
|
||||
public TaskAssignedEvent(String taskID) {
|
||||
this.taskID = taskID;
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package ch.unisg.roster.roster.domain.event;
|
||||
|
||||
public class TaskCompletedEvent {
|
||||
public final String taskID;
|
||||
|
||||
public final String status;
|
||||
|
||||
public final String result;
|
||||
|
||||
public TaskCompletedEvent(String taskID, String status, String result) {
|
||||
this.taskID = taskID;
|
||||
this.status = status;
|
||||
this.result = result;
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package ch.unisg.roster.roster.domain.valueobject;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class ExecutorType {
|
||||
private String value;
|
||||
|
||||
public ExecutorType(String type) {
|
||||
this.value = type.toUpperCase();
|
||||
}
|
||||
}
|
5
roster/src/main/resources/application.properties
Normal file
5
roster/src/main/resources/application.properties
Normal file
@@ -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
|
Reference in New Issue
Block a user