Skip to content

Commit

Permalink
Simplify and adapt DB model to new ReportNode API (#87)
Browse files Browse the repository at this point in the history
* Simplify and adapt DB model to new ReportNode API

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>

* fix unit tests

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>

* Fix checkStyle

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>

* fix sonar issues

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>

* add message based filter

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>

* Fix incremental modifications reports

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>

* Requested changes

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>

* Refacto

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>

* Requested change

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>

---------

Signed-off-by: Ayoub LABIDI <ayoub.labidi@protonmail.com>
  • Loading branch information
ayolab authored Aug 22, 2024
1 parent 6117707 commit f9f10b3
Show file tree
Hide file tree
Showing 32 changed files with 905 additions and 1,665 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.gridsuite.report.server;

import org.gridsuite.report.server.entities.ReportNodeEntity;

import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
* @author Joris Mancini <joris.mancini_externe at rte-france.com>
*/
public record OptimizedReportNodeEntities(Map<Integer, List<UUID>> treeIds, Map<UUID, ReportNodeEntity> reportNodeEntityById) {

public int treeDepth() {
return treeIds.keySet().size();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public ResponseEntity<List<Report>> getReport(@PathVariable("id") UUID id,
@Parameter(description = "Filter on severity levels. Will only return elements with those severities.") @RequestParam(name = "severityLevels", required = false) Set<String> severityLevels,
@Parameter(description = "Empty report with default name") @RequestParam(name = "defaultName", required = false, defaultValue = "defaultName") String defaultName) {
try {
List<Report> reports = service.getReport(id, severityLevels, reportNameFilter, reportNameMatchingType);
List<Report> reports = service.getReport(id, severityLevels, reportNameFilter, reportNameMatchingType).getSubReports();
return reports.isEmpty() ?
ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(List.of(service.getEmptyReport(id, defaultName))) :
ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(reports);
Expand All @@ -66,7 +66,7 @@ public ResponseEntity<Report> getSubReport(@PathVariable("id") UUID id,
try {
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(service.getSubReport(id, severityLevels));
.body(service.getReport(id, severityLevels, null, null));
} catch (EntityNotFoundException ignored) {
return ResponseEntity.notFound().build();
}
Expand Down Expand Up @@ -97,7 +97,7 @@ public ResponseEntity<Void> deleteReport(@PathVariable("id") UUID reportUuid,
@Operation(summary = "delete treereports from a list of parent reports based on a key")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The reports have been deleted")})
public ResponseEntity<Void> deleteTreeReports(@Parameter(description = "parent reports to parse and their associated tree report key to identify which to delete") @RequestBody Map<UUID, String> identifiers) {
service.deleteTreeReports(identifiers);
service.deleteReports(identifiers);
return ResponseEntity.ok().build();
}
}
112 changes: 112 additions & 0 deletions src/main/java/org/gridsuite/report/server/ReportNodeMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.gridsuite.report.server;

import jakarta.persistence.EntityNotFoundException;
import org.apache.commons.lang3.StringUtils;
import org.gridsuite.report.server.dto.Report;
import org.gridsuite.report.server.entities.ReportNodeEntity;

import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Predicate;

/**
* @author Joris Mancini <joris.mancini_externe at rte-france.com>
*/
public final class ReportNodeMapper {

private ReportNodeMapper() {
// Should not be instantiated
}

public static Report map(OptimizedReportNodeEntities optimizedReportNodeEntities, @Nullable Set<String> severityLevels, @Nullable String reportNameFilter, @Nullable ReportService.ReportNameMatchingType reportNameMatchingType) {
UUID rootId = getRootId(optimizedReportNodeEntities);

Map<UUID, Report> reportsMap = new HashMap<>();
mapRootNode(optimizedReportNodeEntities.reportNodeEntityById().get(rootId), reportsMap);
mapLevels(optimizedReportNodeEntities, reportsMap, severityLevels, reportNameFilter, reportNameMatchingType);

return reportsMap.get(rootId);
}

private static UUID getRootId(OptimizedReportNodeEntities optimizedReportNodeEntities) {
List<UUID> rootIds = optimizedReportNodeEntities.treeIds().get(0);
if (rootIds == null || rootIds.size() != 1) {
throw new EntityNotFoundException();
}
return rootIds.get(0);
}

private static void mapRootNode(ReportNodeEntity rootReportNodeEntity, Map<UUID, Report> reportsMap) {
Report rootReport = createReportFromNode(rootReportNodeEntity);
reportsMap.put(rootReportNodeEntity.getId(), rootReport);
}

private static Report createReportFromNode(ReportNodeEntity reportNodeEntity) {
Report report = new Report();
report.setMessage(Optional.ofNullable(reportNodeEntity.getMessage()).orElse(reportNodeEntity.getId().toString()));
mapValues(reportNodeEntity, report);
return report;
}

private static void mapLevels(OptimizedReportNodeEntities optimizedReportNodeEntities, Map<UUID, Report> reportsMap, @Nullable Set<String> severityLevels, @Nullable String reportNameFilter, @Nullable ReportService.ReportNameMatchingType reportNameMatchingType) {
if (optimizedReportNodeEntities.treeDepth() > 1) {
mapLevel(optimizedReportNodeEntities, reportsMap, 1, reportMessageKeyMatches(reportNameFilter, reportNameMatchingType).and(hasOneOfSeverityLevels(severityLevels)));
}
for (int i = 2; i < optimizedReportNodeEntities.treeDepth(); i++) {
mapLevel(optimizedReportNodeEntities, reportsMap, i, hasOneOfSeverityLevels(severityLevels));
}
}

private static void mapLevel(OptimizedReportNodeEntities optimizedReportNodeEntities, Map<UUID, Report> reportsMap, int level, Predicate<ReportNodeEntity> filter) {
List<UUID> nodeIdsToMap = optimizedReportNodeEntities.treeIds().get(level).stream()
.map(optimizedReportNodeEntities.reportNodeEntityById()::get)
.sorted(Comparator.comparing(ReportNodeEntity::getNanos))
.filter(filter)
.map(ReportNodeEntity::getId)
.toList();
nodeIdsToMap.forEach(id -> mapReportNodeEntity(id, optimizedReportNodeEntities.reportNodeEntityById(), reportsMap));
}

private static void mapReportNodeEntity(UUID id, Map<UUID, ReportNodeEntity> reportEntities, Map<UUID, Report> reports) {
ReportNodeEntity reportNodeEntity = reportEntities.get(id);
Optional.ofNullable(reports.get(reportNodeEntity.getParent().getId())).ifPresent(parentReport -> {
Report report = parentReport.addEmptyReport();
report.setMessage(extractMessage(reportNodeEntity));
mapValues(reportNodeEntity, report);
reports.put(id, report);
});
}

private static String extractMessage(ReportNodeEntity reportNodeEntity) {
return reportNodeEntity.getMessage().contains("@") ? reportNodeEntity.getMessage().split("@")[0] : reportNodeEntity.getMessage();
}

private static void mapValues(ReportNodeEntity reportNodeEntity, Report report) {
report.setSeverities(reportNodeEntity.getSeverities().stream().map(Severity::valueOf).toList());
if (!reportNodeEntity.getChildren().isEmpty() || reportNodeEntity.getSeverities().isEmpty()) {
report.setId(reportNodeEntity.getId());
}
}

private static Predicate<ReportNodeEntity> hasOneOfSeverityLevels(Set<String> severityLevels) {
return reportNodeEntity -> severityLevels == null ||
hasNoReportSeverity(reportNodeEntity) || reportNodeEntity.getSeverities().stream().anyMatch(severityLevels::contains);
}

private static Predicate<ReportNodeEntity> reportMessageKeyMatches(@Nullable String reportNameFilter, @Nullable ReportService.ReportNameMatchingType reportNameMatchingType) {
return reportNodeEntity -> StringUtils.isBlank(reportNameFilter)
|| reportNodeEntity.getMessage().startsWith("Root") // FIXME remove this hack when "Root" report will follow the same rules than computations and modifications
|| reportNameMatchingType == ReportService.ReportNameMatchingType.EXACT_MATCHING && reportNodeEntity.getMessage().equals(reportNameFilter)
|| reportNameMatchingType == ReportService.ReportNameMatchingType.ENDS_WITH && reportNodeEntity.getMessage().endsWith(reportNameFilter);
}

private static boolean hasNoReportSeverity(ReportNodeEntity reportNodeEntity) {
return reportNodeEntity.getSeverities().isEmpty();
}
}
Loading

0 comments on commit f9f10b3

Please sign in to comment.