mt.edu.um.cs.rv.eventmanager.observers.ExternalEventObserver Maven / Gradle / Ivy
package mt.edu.um.cs.rv.eventmanager.observers;
import mt.edu.um.cs.rv.eventmanager.engine.EventMessageSender;
import mt.edu.um.cs.rv.events.Event;
import mt.edu.um.cs.rv.events.builders.EventBuilder;
import mt.edu.um.cs.rv.events.builders.EventBuilderRegistry;
import mt.edu.um.cs.rv.events.triggers.Trigger;
import mt.edu.um.cs.rv.events.triggers.TriggerData;
import mt.edu.um.cs.rv.monitors.results.MonitorResult;
import mt.edu.um.cs.rv.monitors.results.MonitorResultList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.MessagingException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
/**
* An interface that defines how an event observer can generate an event based on an external observation/trigger.
*
* Created by edwardmallia on 19/01/2017.
*/
public abstract class ExternalEventObserver implements Trigger {
private static Logger LOGGER = LoggerFactory.getLogger(ExternalEventObserver.class);
@Autowired
EventBuilderRegistry eventBuilderRegistry;
@Autowired
EventMessageSender eventMessageSender;
public final CompletableFuture onMessage(M message) {
LOGGER.debug("Generating Trigger from Message");
TD triggerData = generateTriggerData(message);
LOGGER.debug("Computing whether event should be a/synchronous");
Boolean shouldEventBeSynchronous = shouldEventBeSynchronous(triggerData);
LOGGER.debug("Event should be {}", shouldEventBeSynchronous ? "synchronous" : "asynchronous");
LOGGER.debug("Building event ...");
List eventBuilders = eventBuilderRegistry.getBuilders(triggerData.getClass(), this.getClass());
List>> monitorResultFutures = new ArrayList();
for (EventBuilder eventBuilder: eventBuilders) {
Event event = eventBuilder.build(triggerData, shouldEventBeSynchronous);
LOGGER.debug("Built new event {}", event);
//TODO should this be the default ?
Future> monitorResultFuture = null;
LOGGER.debug("Checking whether event should be fired ...");
if (eventBuilder.shouldFireEvent(event)) {
LOGGER.debug("Event should be fired. Firing event ...");
monitorResultFuture = fireEvent(event);
} else {
LOGGER.debug("Event should not be fired.");
monitorResultFuture = CompletableFuture.completedFuture(MonitorResult.ok());
}
monitorResultFutures.add(monitorResultFuture);
}
LOGGER.debug("Building chained CompletableFuture that will get the monitor result and generate the response.");
return buildCompletableFuture(message, triggerData, monitorResultFutures);
}
private CompletableFuture buildCompletableFuture(final M m, final TD triggerData, final List>> monitorResultFutures) {
return CompletableFuture.supplyAsync(() -> {
try {
if (monitorResultFutures == null || monitorResultFutures.isEmpty()){
return MonitorResult.ok();
}
else if (monitorResultFutures.size() == 1) {
return monitorResultFutures.get(0).get();
}
else {
MonitorResultList monitorResultList = new MonitorResultList();
for (Future> monitorResultFuture : monitorResultFutures) {
MonitorResult> monitorResult = monitorResultFuture.get();
monitorResultList.addMonitorResult(monitorResult);
}
return monitorResultList;
}
} catch (MessagingException me){
String msg = "Unexpected MessageException occurred";
LOGGER.error("{}. Creating and returning a FAILURE MonitorResult.", msg, me);
return MonitorResult.failure(null, me);
}
catch (Throwable throwable){
String msg = "Unexpected Throwable occurred";
LOGGER.error("{}. Creating and returning a FAILURE MonitorResult.", msg, throwable);
return MonitorResult.failure(null, throwable);
}
}).thenApply(monitorResult -> generateResponse(m, triggerData, monitorResult));
}
private Future> fireEvent(Event event) {
return eventMessageSender.send(event);
}
public abstract TD generateTriggerData(M m);
public abstract R generateResponse(M m, TD triggerData, MonitorResult monitorResult);
//default implementation
public Boolean shouldEventBeSynchronous(TD triggerData) {
return false;
}
}