|
@@ -4,11 +4,11 @@ import cz.senslog.watchdog.config.EmailMessageBrokerConfig;
|
|
|
import cz.senslog.watchdog.core.connection.EmailServerConnection;
|
|
import cz.senslog.watchdog.core.connection.EmailServerConnection;
|
|
|
import cz.senslog.watchdog.domain.*;
|
|
import cz.senslog.watchdog.domain.*;
|
|
|
import cz.senslog.watchdog.messagebroker.MessageBrokerHandler;
|
|
import cz.senslog.watchdog.messagebroker.MessageBrokerHandler;
|
|
|
|
|
+import cz.senslog.watchdog.messagebroker.MessageException;
|
|
|
import cz.senslog.watchdog.messagebroker.MessageStatus;
|
|
import cz.senslog.watchdog.messagebroker.MessageStatus;
|
|
|
import cz.senslog.watchdog.messagebroker.MultiMessageBroker;
|
|
import cz.senslog.watchdog.messagebroker.MultiMessageBroker;
|
|
|
-import cz.senslog.watchdog.messagebroker.writer.HtmlTableWriter;
|
|
|
|
|
-import cz.senslog.watchdog.messagebroker.writer.TableWriter;
|
|
|
|
|
-import cz.senslog.watchdog.util.Tuple;
|
|
|
|
|
|
|
+import cz.senslog.watchdog.messagebroker.template.HtmlTemplate;
|
|
|
|
|
+import cz.senslog.watchdog.messagebroker.template.HtmlTemplateManager;
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.LogManager;
|
|
|
import org.apache.logging.log4j.Logger;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
|
|
|
@@ -17,14 +17,9 @@ import java.time.LocalDateTime;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
|
|
|
|
|
import static cz.senslog.watchdog.config.MessageBrokerType.EMAIL;
|
|
import static cz.senslog.watchdog.config.MessageBrokerType.EMAIL;
|
|
|
-import static cz.senslog.watchdog.domain.StatusReport.*;
|
|
|
|
|
-import static java.time.format.DateTimeFormatter.ofPattern;
|
|
|
|
|
|
|
|
|
|
public class EmailMessageBroker extends MultiMessageBroker {
|
|
public class EmailMessageBroker extends MultiMessageBroker {
|
|
|
|
|
|
|
|
- private static final String BREAK_LINE = "<br />";
|
|
|
|
|
- private static final String HORIZONTAL_SEPARATOR = "<hr>";
|
|
|
|
|
-
|
|
|
|
|
private static final String SUBSTITUTABLE_VARIABLE_PREFIX = "$";
|
|
private static final String SUBSTITUTABLE_VARIABLE_PREFIX = "$";
|
|
|
|
|
|
|
|
private static final Logger logger = LogManager.getLogger(EmailMessageBroker.class);
|
|
private static final Logger logger = LogManager.getLogger(EmailMessageBroker.class);
|
|
@@ -36,222 +31,50 @@ public class EmailMessageBroker extends MultiMessageBroker {
|
|
|
this.serverConnection = serverConnection;
|
|
this.serverConnection = serverConnection;
|
|
|
this.messageConfig = messageConfig;
|
|
this.messageConfig = messageConfig;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- private static int[] createStatusProgressForUnit(int[] statuses) {
|
|
|
|
|
- int[] statusToColor = new int[statuses.length];
|
|
|
|
|
-
|
|
|
|
|
- int max = 0;
|
|
|
|
|
- for (int status : statuses) {
|
|
|
|
|
- max += status;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int maxPercent = 100;
|
|
|
|
|
- for (int i = 0; i < statuses.length; i++) {
|
|
|
|
|
- int percent = (int) ((double) statuses[i] / (double) max * 100.0);
|
|
|
|
|
- statusToColor[i] = percent;
|
|
|
|
|
- maxPercent -= percent;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (maxPercent != 0) {
|
|
|
|
|
- for (int i = statusToColor.length - 1; i >= 0; i--) {
|
|
|
|
|
- if (statusToColor[i] != 0) {
|
|
|
|
|
- statusToColor[i] += maxPercent;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- return statusToColor;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private Tuple<String, Map<String, String>> createMessage(Report report) {
|
|
|
|
|
- StringBuilder content = new StringBuilder();
|
|
|
|
|
- final String rowStyle = "border: 1px solid #dddddd; text-align: left; padding: 8px;";
|
|
|
|
|
-
|
|
|
|
|
- boolean isMessages = !report.getMessages().isEmpty();
|
|
|
|
|
- boolean isRecords = !report.getReports().isEmpty();
|
|
|
|
|
-
|
|
|
|
|
- Map<String, String> operationProperties = report.getOperationProperties();
|
|
|
|
|
- Map<String, String> substitutableVariables = new HashMap<>(operationProperties.size());
|
|
|
|
|
- if (!operationProperties.isEmpty()) {
|
|
|
|
|
- for (Map.Entry<String, String> property : operationProperties.entrySet()) {
|
|
|
|
|
- if (property.getKey().startsWith(SUBSTITUTABLE_VARIABLE_PREFIX)) {
|
|
|
|
|
- substitutableVariables.put(property.getKey(), property.getValue());
|
|
|
|
|
- operationProperties.remove(property.getKey());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!operationProperties.isEmpty()) {
|
|
|
|
|
- TableWriter tableSourceWriter = HtmlTableWriter.createWithHeader("width: 100%;", "background-color: #dddddd")
|
|
|
|
|
- .cell("Operation Type").cell("Operation Value").end();
|
|
|
|
|
-
|
|
|
|
|
- for (Map.Entry<String, String> operationEntry : operationProperties.entrySet()) {
|
|
|
|
|
- tableSourceWriter.row(rowStyle)
|
|
|
|
|
- .cell(operationEntry.getKey(), rowStyle)
|
|
|
|
|
- .cell(operationEntry.getValue(), rowStyle)
|
|
|
|
|
- .end();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- content.append(tableSourceWriter.table()).append(BREAK_LINE);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (isMessages || !isRecords) {
|
|
|
|
|
- TableWriter tableMsgWriter = HtmlTableWriter.createWithHeader("width: 100%;", "background-color: #dddddd")
|
|
|
|
|
- .cell("Messages").end();
|
|
|
|
|
-
|
|
|
|
|
- for (String message : report.getMessages()) {
|
|
|
|
|
- tableMsgWriter.row(rowStyle).cell(message, rowStyle).end();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!isRecords) {
|
|
|
|
|
- tableMsgWriter.row(rowStyle).cell("All received observations are valid.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- content.append(tableMsgWriter.table()).append(BREAK_LINE);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (isRecords) {
|
|
|
|
|
-
|
|
|
|
|
- boolean renderReportTable = false;
|
|
|
|
|
- Map<Unit, List<ObservationInfo>> unitsToReport = new HashMap<>();
|
|
|
|
|
- Map<Unit, Tuple<Unit, int[]>> unitToStatus = new HashMap<>();
|
|
|
|
|
- for (SimpleReport simpleReport : report.getReports()) {
|
|
|
|
|
- StatusReport status = simpleReport.getStatus();
|
|
|
|
|
- boolean isOk = status.equals(OK);
|
|
|
|
|
- if (simpleReport.getRecord() instanceof ObservationInfo) {
|
|
|
|
|
- ObservationInfo observation = (ObservationInfo) simpleReport.getRecord();
|
|
|
|
|
- Unit unit = observation.getSource().getUnit();
|
|
|
|
|
-
|
|
|
|
|
- int[] statusReportCounters = unitToStatus.computeIfAbsent(unit,
|
|
|
|
|
- u -> Tuple.of(u, new int[StatusReport.values().length]))
|
|
|
|
|
- .getItem2();
|
|
|
|
|
-
|
|
|
|
|
- statusReportCounters[status.ordinal()] += 1;
|
|
|
|
|
-
|
|
|
|
|
- List<ObservationInfo> observations = unitsToReport.computeIfAbsent(unit, u -> new ArrayList<>());
|
|
|
|
|
-
|
|
|
|
|
- if (!isOk) {
|
|
|
|
|
- observations.add(observation);
|
|
|
|
|
- renderReportTable = true;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- TableWriter tableUnitStatusWriter = HtmlTableWriter.createWithHeader("width: 100%;", "background-color: #dddddd")
|
|
|
|
|
- .cell("unitName").cell("unitId").end();
|
|
|
|
|
-
|
|
|
|
|
- List<Tuple<Unit, int[]>> statuses = new ArrayList<>(unitToStatus.values());
|
|
|
|
|
- statuses.sort(Comparator.comparing(e -> e.getItem2()[OK.ordinal()] != 0));
|
|
|
|
|
- for (Tuple<Unit, int[]> unitEntry : statuses) {
|
|
|
|
|
- Unit unit = unitEntry.getItem1();
|
|
|
|
|
- // TODO change color according to the statu
|
|
|
|
|
- int[] statusProgress = createStatusProgressForUnit(unitEntry.getItem2());
|
|
|
|
|
- int percentOK = statusProgress[OK.ordinal()];
|
|
|
|
|
- int percentFAIL = statusProgress[FAIL.ordinal()] + statusProgress[OK.ordinal()];
|
|
|
|
|
- int percentNODATA = statusProgress[NO_DATA.ordinal()] + percentFAIL;
|
|
|
|
|
- String color = String.format("linear-gradient(135deg, #CCFFCC %d%%, #FFCCCC 0 %d%%, white 0 %d%%)",
|
|
|
|
|
- percentOK, percentFAIL, percentNODATA);
|
|
|
|
|
-
|
|
|
|
|
- tableUnitStatusWriter.row(rowStyle + "background: " + color)
|
|
|
|
|
- .cell(unit.getName(), rowStyle)
|
|
|
|
|
- .cell(String.valueOf(unit.getId()), rowStyle)
|
|
|
|
|
- .end();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- content.append(tableUnitStatusWriter.table());
|
|
|
|
|
-
|
|
|
|
|
- if (renderReportTable) {
|
|
|
|
|
-
|
|
|
|
|
- content.append(HORIZONTAL_SEPARATOR).append(HORIZONTAL_SEPARATOR).append(BREAK_LINE);
|
|
|
|
|
-
|
|
|
|
|
- TableWriter tableReportWriter = HtmlTableWriter.createWithHeader("width: 100%;", "background-color: #dddddd")
|
|
|
|
|
- .cell("unitName (unitId)").cell("sensorName (sensorId)").cell("timestamp").end();
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- for (Map.Entry<Unit, List<ObservationInfo>> unitEntry : unitsToReport.entrySet()) {
|
|
|
|
|
- for (ObservationInfo observation : unitEntry.getValue()) {
|
|
|
|
|
- Source source = observation.getSource();
|
|
|
|
|
- Unit unit = source.getUnit();
|
|
|
|
|
- Sensor sensor = source.getSensor();
|
|
|
|
|
-
|
|
|
|
|
- String unitCell = String.format("%s (%s)", unit.getName(), unit.getId());
|
|
|
|
|
- String sensorCell = String.format("%s (%s)", sensor.getName(), sensor.getId());
|
|
|
|
|
-
|
|
|
|
|
- tableReportWriter.row(rowStyle + "background-color: #FFCCCC")
|
|
|
|
|
- .cell(unitCell, rowStyle)
|
|
|
|
|
- .cell(sensorCell, rowStyle)
|
|
|
|
|
- .cell(observation.getTimestamp().toString(), rowStyle)
|
|
|
|
|
- .end();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- tableReportWriter.emptyRow().emptyRow().emptyRow();
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /*
|
|
|
|
|
- report.getReports().sort(Comparator.comparing(SimpleReport::getStatus).reversed());
|
|
|
|
|
- for (SimpleReport simpleReport : report.getReports()) {
|
|
|
|
|
- boolean isOk = simpleReport.getStatus().equals(OK);
|
|
|
|
|
- // ALLOW ONLY NOT OK REPORTS -> // TODO create a template system
|
|
|
|
|
- if (!isOk && simpleReport.getRecord() instanceof ObservationInfo) {
|
|
|
|
|
- ObservationInfo observation = (ObservationInfo) simpleReport.getRecord();
|
|
|
|
|
- Source source = observation.getSource();
|
|
|
|
|
-
|
|
|
|
|
- String unitCell = String.format("%s (%s)", source.getUnit().getName(), source.getUnit().getId());
|
|
|
|
|
- String sensorCell = String.format("%s (%s)", source.getSensor().getName(), source.getSensor().getId());
|
|
|
|
|
-
|
|
|
|
|
- tableReportWriter.row(rowStyle + "background-color: " + (isOk ? "#CCFFCC" : "#FFCCCC"))
|
|
|
|
|
- .cell(unitCell, rowStyle)
|
|
|
|
|
- .cell(sensorCell, rowStyle)
|
|
|
|
|
- .cell(observation.getTimestamp().toString(), rowStyle)
|
|
|
|
|
- // .cell(reportedTime, rowStyle)
|
|
|
|
|
- // .cell(simpleReport.getStatus().name(), rowStyle)
|
|
|
|
|
- .end();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- */
|
|
|
|
|
-
|
|
|
|
|
- content.append(tableReportWriter.table()).append(BREAK_LINE);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return Tuple.of(content.toString(), substitutableVariables);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void send(Report[] reports, MessageBrokerHandler status) {
|
|
public void send(Report[] reports, MessageBrokerHandler status) {
|
|
|
- if (reports == null || reports.length <= 0) {
|
|
|
|
|
|
|
+ if (reports == null || reports.length == 0) {
|
|
|
logger.info("Nothing to send. The receive report is null.");
|
|
logger.info("Nothing to send. The receive report is null.");
|
|
|
status.handle(new MessageStatus(null, "No report to send.", EMAIL.name())); return;
|
|
status.handle(new MessageStatus(null, "No report to send.", EMAIL.name())); return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- StringBuilder reportMessage = new StringBuilder();
|
|
|
|
|
- Map<String, String> substitutableVariables = new HashMap<>();
|
|
|
|
|
- for (Report report : reports) {
|
|
|
|
|
- Tuple<String, Map<String, String>> message = createMessage(report);
|
|
|
|
|
- for (Map.Entry<String, String> varEntry : message.getItem2().entrySet()) {
|
|
|
|
|
- if (substitutableVariables.containsKey(varEntry.getKey())) {
|
|
|
|
|
- String oldValue = substitutableVariables.get(varEntry.getKey());
|
|
|
|
|
- substitutableVariables.put(varEntry.getKey(), oldValue + " & " + varEntry.getValue());
|
|
|
|
|
- } else {
|
|
|
|
|
- substitutableVariables.put(varEntry.getKey(), varEntry.getValue());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- reportMessage.append(message.getItem1())
|
|
|
|
|
- .append(HORIZONTAL_SEPARATOR).append(HORIZONTAL_SEPARATOR)
|
|
|
|
|
- .append(BREAK_LINE);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ HtmlTemplate template = HtmlTemplateManager.getTemplate(messageConfig.getTemplateType());
|
|
|
|
|
+ Report report = mergeReports(reports);
|
|
|
|
|
+ String reportMessage = template.createMessage(report);
|
|
|
logger.info("Sending a message via email.");
|
|
logger.info("Sending a message via email.");
|
|
|
- serverConnection.send(reportMessage.toString(), substitutableVariables, messageConfig);
|
|
|
|
|
|
|
+ serverConnection.send(reportMessage, report.getOperationProperties(), messageConfig);
|
|
|
logger.info("The message was send successfully.");
|
|
logger.info("The message was send successfully.");
|
|
|
status.handle(MessageStatus.success(LocalDateTime.now(), EMAIL.name()));
|
|
status.handle(MessageStatus.success(LocalDateTime.now(), EMAIL.name()));
|
|
|
- } catch (MessagingException e) {
|
|
|
|
|
|
|
+ } catch (MessagingException | MessageException e) {
|
|
|
logger.catching(e);
|
|
logger.catching(e);
|
|
|
status.handle(MessageStatus.error(LocalDateTime.now(), e.getMessage(), EMAIL.name()));
|
|
status.handle(MessageStatus.error(LocalDateTime.now(), e.getMessage(), EMAIL.name()));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ private static Report mergeReports(Report... reports) {
|
|
|
|
|
+ if (reports == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (reports.length == 1) {
|
|
|
|
|
+ return reports[0];
|
|
|
|
|
+ }
|
|
|
|
|
+ Report newReport = new Report(reports[0].getCreated(), new ArrayList<>(), new ArrayList<>(), new HashMap<>());
|
|
|
|
|
+ for (Report report : reports) {
|
|
|
|
|
+ newReport.getReports().addAll(report.getReports());
|
|
|
|
|
+ newReport.getMessages().addAll(report.getMessages());
|
|
|
|
|
+ Map<String, String> opVar = newReport.getOperationProperties();
|
|
|
|
|
+ for (Map.Entry<String, String> entry : report.getOperationProperties().entrySet()) {
|
|
|
|
|
+ if (entry.getKey().startsWith(SUBSTITUTABLE_VARIABLE_PREFIX)) {
|
|
|
|
|
+ if (opVar.containsKey(entry.getKey())) {
|
|
|
|
|
+ String oldValue = opVar.get(entry.getKey());
|
|
|
|
|
+ opVar.put(entry.getKey(), oldValue + " & " + entry.getValue());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ opVar.put(entry.getKey(), entry.getValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return newReport;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|