From c30dcef4c3d87f3995a622c330abd915a6c70267 Mon Sep 17 00:00:00 2001 From: latlon team <info@lat-lon.de> Date: Tue, 1 Oct 2024 10:18:40 +0000 Subject: [PATCH] Code drop - XPLANBOX-3349 - set routing keys for import events, updated ManagerPublicEventsIT (6f9eca9e7) - XPLANBOX-3349 - implement ValidationProcessListener to send rabbitmq events (dce8f1419) - fixed typo in log (4c9d6bf64) - XPLANBOX-3349 - added ValidationProcessListener, send validation status to listener (5e9dd18b1) - XPLANBOX-3349 - added EventTypes, added valid and error (c89226e05) Co-authored-by: Lyn Elisa Goltz <goltz@lat-lon.de> Dropped from commit: ae6d7358ac20c2b171e2e410a4710f5c213470ab --- .../commons/handler/AbstractAsyncWrapper.java | 2 +- .../core/validator/events/EventSender.java | 2 +- .../validator/events/RabbitEventSender.java | 18 ++-- .../events/v1/XPlanPublicV1Event.java | 77 ++++++++++++++--- .../events/v1/XPlanPublicV1EventTest.java | 16 ++-- .../xplan/validator/XPlanGmlValidation.java | 17 +++- .../xplan/validator/XPlanValidator.java | 85 +++++++++++++------ .../InactiveValidationProcessListener.java | 48 +++++++++++ .../listener/ValidationProcessListener.java | 25 ++++++ .../validator/XPlanGmlValidationTest.java | 6 +- .../xplan/validator/XPlanValidatorTest.java | 18 +++- .../geometric/GeometricValidatorImplTest.java | 6 +- ...rameterizedGeometricValidatorImplTest.java | 6 +- .../planinfo/PlanInfoParserTest.java | 9 +- .../api/manager/executor/PlanImporter.java | 9 +- .../api/manager/handler/PlanHandler.java | 4 +- .../manager/messagingrabbitmq/Receiver.java | 4 +- .../xplanbox/api/manager/v2/PlanApi2.java | 2 +- .../manager/executor/PlanImporterTest.java | 8 +- .../de/latlon/xplanbox/tests/TestConfig.java | 2 +- .../rabbit/manager/ManagerPublicEventsIT.java | 68 +++++++++++---- .../validator/ValidationPublicEventsIT.java | 68 ++++++++++----- .../api/validator/v2/ValidateApi2.java | 2 +- .../validator/executor/PlanValidator.java | 85 ++++++++++--------- .../executor/config/ApplicationContext.java | 7 +- .../executor/handler/ValidationHandler.java | 10 +-- .../EventValidationProcessListener.java | 82 ++++++++++++++++++ .../executor/messagingrabbitmq/Receiver.java | 12 +-- .../validator/executor/PlanValidatorTest.java | 32 +++++-- .../handler/ValidationHandlerTest.java | 2 +- 30 files changed, 544 insertions(+), 188 deletions(-) create mode 100644 xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/listener/InactiveValidationProcessListener.java create mode 100644 xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/listener/ValidationProcessListener.java create mode 100644 xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/listener/EventValidationProcessListener.java diff --git a/xplan-core/xplan-core-api/src/main/java/de/latlon/xplanbox/api/commons/handler/AbstractAsyncWrapper.java b/xplan-core/xplan-core-api/src/main/java/de/latlon/xplanbox/api/commons/handler/AbstractAsyncWrapper.java index ff0b4eb82..75c8a1f14 100644 --- a/xplan-core/xplan-core-api/src/main/java/de/latlon/xplanbox/api/commons/handler/AbstractAsyncWrapper.java +++ b/xplan-core/xplan-core-api/src/main/java/de/latlon/xplanbox/api/commons/handler/AbstractAsyncWrapper.java @@ -28,7 +28,7 @@ public abstract class AbstractAsyncWrapper { } public boolean sendEvent(ValidationRequestedEvent event) throws AsyncTimeout { - eventSender.sendEvent(event); + eventSender.sendPrivateEvent(event); String uuid = event.getUuid(); LOG.info("Event sent. Waiting for processing of {}", uuid); diff --git a/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/EventSender.java b/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/EventSender.java index f9bee85f9..56d448f6b 100644 --- a/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/EventSender.java +++ b/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/EventSender.java @@ -26,7 +26,7 @@ package de.latlon.core.validator.events; */ public interface EventSender { - void sendEvent(XPlanPrivateEvent e); + void sendPrivateEvent(XPlanPrivateEvent e); void sendPublicEvent(XPlanPublicEvent event, String routingKeySuffix); diff --git a/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/RabbitEventSender.java b/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/RabbitEventSender.java index d5ba61e74..83fef8447 100644 --- a/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/RabbitEventSender.java +++ b/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/RabbitEventSender.java @@ -65,7 +65,7 @@ class RabbitEventSender implements EventSender { } @Override - public void sendEvent(XPlanPrivateEvent event) { + public void sendPrivateEvent(XPlanPrivateEvent event) { if (event instanceof XPlanPrivateTaskEvent) { sendPrivateTaskEvent((XPlanPrivateTaskEvent) event); } @@ -73,6 +73,14 @@ class RabbitEventSender implements EventSender { sendPrivateTopicEvent((XPlanPrivateTopicEvent) event); } + @Override + public void sendPublicEvent(XPlanPublicEvent event, String routingKeySuffix) { + String routingKey = publicTopicRoutingPrefix + routingKeySuffix; + + LOG.info("Sending public event with key >{}<: {}", routingKey, event); + rabbitTemplate.convertAndSend(publicTopicExchangeName, routingKey, event); + } + private void sendPrivateTaskEvent(XPlanPrivateTaskEvent event) { String workQueueName = taskClass2QueueName.get(event.getClass()); if (workQueueName == null) { @@ -91,12 +99,4 @@ class RabbitEventSender implements EventSender { rabbitTemplate.convertAndSend(privateTopicExchangeName, routingKey, event); } - @Override - public void sendPublicEvent(XPlanPublicEvent event, String routingKeySuffix) { - String routingKey = publicTopicRoutingPrefix + routingKeySuffix; - - LOG.info("Sending public event with key >{}<: {}", routingKey, event); - rabbitTemplate.convertAndSend(publicTopicExchangeName, routingKey, event); - } - } diff --git a/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/v1/XPlanPublicV1Event.java b/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/v1/XPlanPublicV1Event.java index c295c1af3..d4e6cb97b 100644 --- a/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/v1/XPlanPublicV1Event.java +++ b/xplan-core/xplan-core-validator-events/src/main/java/de/latlon/core/validator/events/v1/XPlanPublicV1Event.java @@ -14,26 +14,75 @@ public class XPlanPublicV1Event implements XPlanPublicEvent { public enum EventType { - VALIDATION_STARTED, VALIDATION_FINISHED, IMPORT_STARTED, IMPORT_FINISHED + VALIDATION_STARTED("validation"), + + SYNTACTIC_VALIDATION_STARTED("validation.syntaktisch"), + + SYNTACTIC_VALIDATION_FINISHED("validation.syntaktisch"), + + GEOMETRIC_VALIDATION_STARTED("validation.geometrisch"), + + GEOMETRIC_VALIDATION_FINISHED("validation.geometrisch"), + + SEMANTIC_VALIDATION_STARTED("validation.semantisch"), + + SEMANTIC_VALIDATION_FINISHED("validation.semantisch"), + + PROFILE_VALIDATION_STARTED("validation.profile."), + + PROFILE_VALIDATION_FINISHED("validation.profile."), + + VALIDATION_FINISHED("validation"), + + VALIDATION_FAILED("validation"), + + IMPORT_STARTED("import"), + + IMPORT_FINISHED("import"), + + IMPORT_FAILED("import"); + + private final String routingKeySuffix; + + EventType(String routingKeySuffix) { + this.routingKeySuffix = routingKeySuffix; + } + + public String routingKeySuffix() { + return routingKeySuffix; + } } - private String apiVersion = "1.0"; + private final String apiVersion = "1.0"; private EventType eventType; private String uuid; - private String message; + private Boolean valid; + + private String error; public XPlanPublicV1Event() { } - public XPlanPublicV1Event(EventType eventType, String uuid, String message) { + public XPlanPublicV1Event(EventType eventType, String uuid) { + this.eventType = eventType; + this.uuid = uuid; + } + + public XPlanPublicV1Event(EventType eventType, String uuid, Boolean valid) { this.eventType = eventType; this.uuid = uuid; - this.message = message; + this.valid = valid; + } + + public XPlanPublicV1Event(EventType eventType, String uuid, String error) { + this.eventType = eventType; + this.uuid = uuid; + this.error = error; } public String getApiVersion() { @@ -44,17 +93,21 @@ public class XPlanPublicV1Event implements XPlanPublicEvent { return eventType; } - public String getMessage() { - return message; - } - public String getUuid() { return uuid; } + public Boolean getValid() { + return valid; + } + + public String getError() { + return error; + } + @Override public int hashCode() { - return Objects.hash(apiVersion, eventType, message, uuid); + return Objects.hash(apiVersion, eventType, uuid); } @Override @@ -67,12 +120,12 @@ public class XPlanPublicV1Event implements XPlanPublicEvent { return false; XPlanPublicV1Event other = (XPlanPublicV1Event) obj; return Objects.equals(apiVersion, other.apiVersion) && eventType == other.eventType - && Objects.equals(message, other.message) && Objects.equals(uuid, other.uuid); + && Objects.equals(uuid, other.uuid); } @Override public String toString() { - return "XPlanboxPublicV1Event(" + eventType + ", " + uuid + ", " + message + ")"; + return "XPlanboxPublicV1Event(" + eventType + ", " + uuid + ")"; } } diff --git a/xplan-core/xplan-core-validator-events/src/test/java/de/latlon/core/validator/events/v1/XPlanPublicV1EventTest.java b/xplan-core/xplan-core-validator-events/src/test/java/de/latlon/core/validator/events/v1/XPlanPublicV1EventTest.java index 1d698f880..f8d07c401 100644 --- a/xplan-core/xplan-core-validator-events/src/test/java/de/latlon/core/validator/events/v1/XPlanPublicV1EventTest.java +++ b/xplan-core/xplan-core-validator-events/src/test/java/de/latlon/core/validator/events/v1/XPlanPublicV1EventTest.java @@ -14,48 +14,48 @@ class XPlanPublicV1EventTest { @Test void jsonSerializeValidationStarted() throws Exception { - XPlanPublicV1Event event = new XPlanPublicV1Event(EventType.VALIDATION_STARTED, "uuid1", "start validation"); + XPlanPublicV1Event event = new XPlanPublicV1Event(EventType.VALIDATION_STARTED, "uuid1"); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(event); - String expected = "{\"apiVersion\":\"1.0\",\"eventType\":\"VALIDATION_STARTED\",\"uuid\":\"uuid1\",\"message\":\"start validation\"}"; + String expected = "{\"apiVersion\":\"1.0\",\"eventType\":\"VALIDATION_STARTED\",\"uuid\":\"uuid1\",\"valid\":null,\"error\":null}"; assertThat(json).isEqualTo(expected); } @Test void jsonSerializeValidationFinished() throws Exception { - XPlanPublicV1Event event = new XPlanPublicV1Event(EventType.VALIDATION_FINISHED, "uuid1", "end validation"); + XPlanPublicV1Event event = new XPlanPublicV1Event(EventType.VALIDATION_FINISHED, "uuid1", true); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(event); - String expected = "{\"apiVersion\":\"1.0\",\"eventType\":\"VALIDATION_FINISHED\",\"uuid\":\"uuid1\",\"message\":\"end validation\"}"; + String expected = "{\"apiVersion\":\"1.0\",\"eventType\":\"VALIDATION_FINISHED\",\"uuid\":\"uuid1\",\"valid\":true,\"error\":null}"; assertThat(json).isEqualTo(expected); } @Test void jsonSerializeImportStart() throws Exception { - XPlanPublicV1Event event = new XPlanPublicV1Event(EventType.IMPORT_STARTED, "uuid1", "start import"); + XPlanPublicV1Event event = new XPlanPublicV1Event(EventType.IMPORT_STARTED, "uuid1"); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(event); - String expected = "{\"apiVersion\":\"1.0\",\"eventType\":\"IMPORT_STARTED\",\"uuid\":\"uuid1\",\"message\":\"start import\"}"; + String expected = "{\"apiVersion\":\"1.0\",\"eventType\":\"IMPORT_STARTED\",\"uuid\":\"uuid1\",\"valid\":null,\"error\":null}"; assertThat(json).isEqualTo(expected); } @Test void jsonSerializeImportFinished() throws Exception { - XPlanPublicV1Event event = new XPlanPublicV1Event(EventType.IMPORT_FINISHED, "uuid1", "end import"); + XPlanPublicV1Event event = new XPlanPublicV1Event(EventType.IMPORT_FINISHED, "uuid1"); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(event); - String expected = "{\"apiVersion\":\"1.0\",\"eventType\":\"IMPORT_FINISHED\",\"uuid\":\"uuid1\",\"message\":\"end import\"}"; + String expected = "{\"apiVersion\":\"1.0\",\"eventType\":\"IMPORT_FINISHED\",\"uuid\":\"uuid1\",\"valid\":null,\"error\":null}"; assertThat(json).isEqualTo(expected); } diff --git a/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/XPlanGmlValidation.java b/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/XPlanGmlValidation.java index 3df90d774..7ac66b805 100644 --- a/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/XPlanGmlValidation.java +++ b/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/XPlanGmlValidation.java @@ -12,6 +12,7 @@ import de.latlon.xplan.commons.feature.XPlanGmlParser; import de.latlon.xplan.commons.feature.XPlanGmlParserBuilder; import de.latlon.xplan.validator.geometric.GeometricValidator; import de.latlon.xplan.validator.geometric.report.GeometricValidatorResult; +import de.latlon.xplan.validator.listener.ValidationProcessListener; import de.latlon.xplan.validator.planinfo.PlanInfoParser; import de.latlon.xplan.validator.planinfo.PlanInfoReport; import de.latlon.xplan.validator.report.ValidatorReport; @@ -45,23 +46,27 @@ public class XPlanGmlValidation { private PlanInfoReport planInfoReport; + private final ValidationProcessListener validationProcessListener; + public XPlanGmlValidation(GeometricValidator geometricValidator, PlanInfoParser planInfoParser, - XPlanArchive archive, ValidationSettings validationSettings) { + XPlanArchive archive, ValidationSettings validationSettings, + ValidationProcessListener validationProcessListener) { this.geometricValidator = geometricValidator; this.planInfoParser = planInfoParser; this.archive = archive; this.validationSettings = validationSettings; + this.validationProcessListener = validationProcessListener; this.gmlParserBuilder = XPlanGmlParserBuilder.newBuilder(); } - public void executeGmlValidation(ValidatorReport report) throws ValidatorException { + public void executeGmlValidation(String uuid, ValidatorReport report) throws ValidatorException { boolean skipGeometric = !validationSettings.getValidationTypes().contains(GEOMETRIC); // prepare prepareGmlValidation(skipGeometric); // build buildGmlValidation(skipGeometric); // validate - parseGmlValidation(report, skipGeometric); + parseGmlValidation(uuid, report, skipGeometric); } public XPlanGmlParserBuilder getGmlParserBuilder() { @@ -115,7 +120,8 @@ public class XPlanGmlValidation { geometricValidator.afterParserBuild(this); } - private void parseGmlValidation(ValidatorReport report, boolean skipGeometric) throws ValidatorException { + private void parseGmlValidation(String uuid, ValidatorReport report, boolean skipGeometric) + throws ValidatorException { parse(); this.planInfoReport = planInfoParser.parsePlanInfo(this); report.setPlanInfoReport(planInfoReport); @@ -126,10 +132,13 @@ public class XPlanGmlValidation { .geometricValidatorResult(new GeometricValidatorResult(SKIPPED))); } else { + validationProcessListener.validationPartStarted(uuid, GEOMETRIC); Map<String, GeometricValidatorResult> validatorResult = geometricValidator.validateGeometry(this); report.getPlanInfoReport() .getPlanInfos() .forEach((planGmlId, planInfo) -> planInfo.geometricValidatorResult(validatorResult.get(planGmlId))); + validationProcessListener.validationPartFinished(uuid, GEOMETRIC, + validatorResult.values().stream().allMatch(GeometricValidatorResult::isValid)); } } diff --git a/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/XPlanValidator.java b/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/XPlanValidator.java index 5f00fb609..fc300df11 100644 --- a/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/XPlanValidator.java +++ b/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/XPlanValidator.java @@ -24,6 +24,7 @@ import static de.latlon.xplan.validator.report.SkipCode.SKIPPED; import static de.latlon.xplan.validator.report.SkipCode.SYNTAX_ERRORS; import static de.latlon.xplan.validator.report.SkipCode.UNSUPPORTED; import static de.latlon.xplan.validator.web.shared.ValidationType.SEMANTIC; +import static de.latlon.xplan.validator.web.shared.ValidationType.SYNTACTIC; import java.io.File; import java.io.IOException; @@ -33,6 +34,7 @@ import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.UUID; import java.util.stream.Collectors; import de.latlon.xplan.commons.archive.SemanticValidableXPlanArchive; @@ -40,6 +42,8 @@ import de.latlon.xplan.commons.archive.XPlanArchive; import de.latlon.xplan.commons.archive.XPlanArchiveCreator; import de.latlon.xplan.commons.feature.XPlanFeatureCollection; import de.latlon.xplan.validator.geometric.GeometricValidator; +import de.latlon.xplan.validator.listener.InactiveValidationProcessListener; +import de.latlon.xplan.validator.listener.ValidationProcessListener; import de.latlon.xplan.validator.planinfo.PlanInfo; import de.latlon.xplan.validator.planinfo.PlanInfoParser; import de.latlon.xplan.validator.planinfo.PlanInfoReport; @@ -85,15 +89,26 @@ public class XPlanValidator { private final XPlanArchiveCreator archiveCreator = new XPlanArchiveCreator(); + private final ValidationProcessListener validationProcessListener; + public XPlanValidator(GeometricValidator geometricValidator, SyntacticValidator syntacticValidator, SemanticValidator semanticValidator, List<SemanticProfileValidator> semanticProfileValidators, ReportArchiveGenerator reportArchiveGenerator, PlanInfoParser planInfoParser) { + this(geometricValidator, syntacticValidator, semanticValidator, semanticProfileValidators, + reportArchiveGenerator, planInfoParser, new InactiveValidationProcessListener()); + } + + public XPlanValidator(GeometricValidator geometricValidator, SyntacticValidator syntacticValidator, + SemanticValidator semanticValidator, List<SemanticProfileValidator> semanticProfileValidators, + ReportArchiveGenerator reportArchiveGenerator, PlanInfoParser planInfoParser, + ValidationProcessListener validationProcessListener) { this.geometricValidator = geometricValidator; this.syntacticValidator = syntacticValidator; this.semanticValidator = semanticValidator; this.semanticProfileValidators = semanticProfileValidators; this.reportArchiveGenerator = reportArchiveGenerator; this.planInfoParser = planInfoParser; + this.validationProcessListener = validationProcessListener; } /** @@ -109,7 +124,7 @@ public class XPlanValidator { public ValidatorReport validate(ValidationSettings validationSettings, File planArchive, String archiveName) throws ValidatorException, IOException, ReportGenerationException { XPlanArchive archive = archiveCreator.createXPlanArchive(planArchive); - ValidatorReport report = validate(validationSettings, archive, archiveName); + ValidatorReport report = validate(UUID.randomUUID().toString(), validationSettings, archive, archiveName); writeReport(report); LOG.info("Archiv mit Validierungsergebnissen wird erstellt."); Path validationReportDirectory = createZipArchive(validationSettings, report); @@ -129,7 +144,7 @@ public class XPlanValidator { public ValidatorReport validateNotWriteReport(ValidationSettings validationSettings, File planArchive, String archiveName) throws ValidatorException, IOException { XPlanArchive archive = archiveCreator.createXPlanArchive(planArchive); - return validateNotWriteReport(validationSettings, archive, archiveName); + return validateNotWriteReport(null, validationSettings, archive, archiveName); } /** @@ -139,9 +154,9 @@ public class XPlanValidator { * @return <link>ValidatorReport</link> * @throws ValidatorException */ - public ValidatorReport validateNotWriteReport(ValidationSettings validationSettings, XPlanArchive planArchive, - String archiveName) throws ValidatorException { - ValidatorReport validationReport = validate(validationSettings, planArchive, archiveName); + public ValidatorReport validateNotWriteReport(String uuid, ValidationSettings validationSettings, + XPlanArchive planArchive, String archiveName) throws ValidatorException { + ValidatorReport validationReport = validate(uuid, validationSettings, planArchive, archiveName); validationReport.setHasMultipleXPlanElements(planArchive.hasMultipleXPlanElements()); return validationReport; } @@ -162,30 +177,40 @@ public class XPlanValidator { } } - private ValidatorReport validate(ValidationSettings validationSettings, XPlanArchive archive, String archiveName) - throws ValidatorException { - List<SemanticValidationOptions> semanticValidationOptions = extractSemanticValidationOptions( - validationSettings); + private ValidatorReport validate(String uuid, ValidationSettings validationSettings, XPlanArchive archive, + String archiveName) throws ValidatorException { + try { + validationProcessListener.validationStarted(uuid); + List<SemanticValidationOptions> semanticValidationOptions = extractSemanticValidationOptions( + validationSettings); + + ValidatorReport report = new ValidatorReport(); + report.setValidationName(validationSettings.getValidationName()); + report.setArchiveName(archiveName); + report.setDate(new Date()); + + List<ValidationType> validationType = getValidationType(validationSettings); + validationProcessListener.validationPartStarted(uuid, SYNTACTIC); + SyntacticValidatorResult syntacticValidatorResult = validateSyntactic(archive, report); + validationProcessListener.validationPartFinished(uuid, SYNTACTIC, syntacticValidatorResult.isValid()); + if (!syntacticValidatorResult.isValid()) { + report.setPlanInfoReport(new PlanInfoReport().skipCode(SYNTAX_ERRORS)); + return report; + } - ValidatorReport report = new ValidatorReport(); - report.setValidationName(validationSettings.getValidationName()); - report.setArchiveName(archiveName); - report.setDate(new Date()); + XPlanGmlValidation xPlanGmlValidation = new XPlanGmlValidation(geometricValidator, planInfoParser, archive, + validationSettings, validationProcessListener); + xPlanGmlValidation.executeGmlValidation(uuid, report); - List<ValidationType> validationType = getValidationType(validationSettings); - SyntacticValidatorResult syntacticValidatorResult = validateSyntactic(archive, report); - if (!syntacticValidatorResult.isValid()) { - report.setPlanInfoReport(new PlanInfoReport().skipCode(SYNTAX_ERRORS)); + valideSemanticAndProfiles(uuid, validationSettings, archive, xPlanGmlValidation, semanticValidationOptions, + validationType, report); + validationProcessListener.validationFinished(uuid, report.isValid()); return report; } - - XPlanGmlValidation xPlanGmlValidation = new XPlanGmlValidation(geometricValidator, planInfoParser, archive, - validationSettings); - xPlanGmlValidation.executeGmlValidation(report); - - valideSemanticAndProfiles(validationSettings, archive, xPlanGmlValidation, semanticValidationOptions, - validationType, report); - return report; + catch (ValidatorException e) { + validationProcessListener.validationFailed(uuid, e.getMessage()); + throw e; + } } private SyntacticValidatorResult validateSyntactic(XPlanArchive archive, ValidatorReport report) { @@ -195,7 +220,7 @@ public class XPlanValidator { } - private void valideSemanticAndProfiles(ValidationSettings validationSettings, XPlanArchive archive, + private void valideSemanticAndProfiles(String uuid, ValidationSettings validationSettings, XPlanArchive archive, XPlanGmlValidation gmlValidation, List<SemanticValidationOptions> semanticValidationOptions, List<ValidationType> validationTypes, ValidatorReport report) throws ValidatorException { boolean multiplePlansReferencesWithMultiplePlans = archive.hasMultipleXPlanElements() @@ -216,24 +241,28 @@ public class XPlanValidator { else if (!validationTypes.contains(SEMANTIC)) planInfo.semanticValidatorResult(new SemanticValidatorResult(SKIPPED)); else { + validationProcessListener.validationPartStarted(uuid, SEMANTIC); SemanticValidatorResult semanticallyResult = validateSemanticallyAndWriteResult(semanticValidator, instanceAsArchive, semanticValidationOptions); planInfo.semanticValidatorResult(semanticallyResult); + validationProcessListener.validationPartFinished(uuid, SEMANTIC, semanticallyResult.isValid()); } - validateSemanticProfiles(instanceAsArchive, profiles, planInfo); + validateSemanticProfiles(uuid, instanceAsArchive, profiles, planInfo); } } - private void validateSemanticProfiles(SemanticValidableXPlanArchive archive, List<String> profiles, + private void validateSemanticProfiles(String uuid, SemanticValidableXPlanArchive archive, List<String> profiles, PlanInfo planInfo) throws ValidatorException { for (String profileId : profiles) { Optional<SemanticProfileValidator> profileValidator = semanticProfileValidators.stream() .filter(semanticProfileValidator -> semanticProfileValidator.getId().equals(profileId)) .findFirst(); if (profileValidator.isPresent()) { + validationProcessListener.validationProfileStarted(uuid, profileId); SemanticValidatorResult semanticValidatorResult = validateSemanticallyAndWriteResult( profileValidator.get(), archive, Collections.emptyList()); planInfo.addSemanticProfileValidatorResults(semanticValidatorResult); + validationProcessListener.validationProfileFinished(uuid, profileId, semanticValidatorResult.isValid()); } else { throw new ValidatorException("Profile with id " + profileId + " does not exist"); diff --git a/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/listener/InactiveValidationProcessListener.java b/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/listener/InactiveValidationProcessListener.java new file mode 100644 index 000000000..66d9351ba --- /dev/null +++ b/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/listener/InactiveValidationProcessListener.java @@ -0,0 +1,48 @@ +package de.latlon.xplan.validator.listener; + +import de.latlon.xplan.validator.web.shared.ValidationType; + +/** + * Implements {@link ValidationProcessListener with empty methods + * + * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> + * @since 8.0 + */ +public class InactiveValidationProcessListener implements ValidationProcessListener { + + @Override + public void validationStarted(String uuid) { + + } + + @Override + public void validationPartStarted(String uuid, ValidationType validationType) { + + } + + @Override + public void validationPartFinished(String uuid, ValidationType validationType, Boolean isValid) { + + } + + @Override + public void validationProfileStarted(String uuid, String profileId) { + + } + + @Override + public void validationProfileFinished(String uuid, String profileId, Boolean isValid) { + + } + + @Override + public void validationFinished(String uuid, Boolean valid) { + + } + + @Override + public void validationFailed(String uuid, String error) { + + } + +} diff --git a/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/listener/ValidationProcessListener.java b/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/listener/ValidationProcessListener.java new file mode 100644 index 000000000..524be4a4b --- /dev/null +++ b/xplan-core/xplan-core-validator/src/main/java/de/latlon/xplan/validator/listener/ValidationProcessListener.java @@ -0,0 +1,25 @@ +package de.latlon.xplan.validator.listener; + +import de.latlon.xplan.validator.web.shared.ValidationType; + +/** + * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> + * @since 8.0 + */ +public interface ValidationProcessListener { + + void validationStarted(String uuid); + + void validationPartStarted(String uuid, ValidationType validationType); + + void validationPartFinished(String uuid, ValidationType validationType, Boolean isValid); + + void validationProfileStarted(String uuid, String profileId); + + void validationProfileFinished(String uuid, String profileId, Boolean isValid); + + void validationFinished(String uuid, Boolean isValid); + + void validationFailed(String uuid, String error); + +} diff --git a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/XPlanGmlValidationTest.java b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/XPlanGmlValidationTest.java index a36efd802..2a9ad3939 100644 --- a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/XPlanGmlValidationTest.java +++ b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/XPlanGmlValidationTest.java @@ -18,6 +18,7 @@ import de.latlon.xplan.validator.geometric.GeometricValidatorImpl; import de.latlon.xplan.validator.geometric.report.GeometricValidatorResult; import de.latlon.xplan.validator.geometric.result.GeometricValidationFinding; import de.latlon.xplan.validator.geometric.result.GeometricValidationRule; +import de.latlon.xplan.validator.listener.InactiveValidationProcessListener; import de.latlon.xplan.validator.planinfo.PlanInfoParser; import de.latlon.xplan.validator.report.ValidatorReport; import de.latlon.xplan.validator.web.shared.ValidationSettings; @@ -36,9 +37,10 @@ public class XPlanGmlValidationTest { ValidationSettings validationSettings = new ValidationSettings("test", List.of(SYNTACTIC, SEMANTIC, GEOMETRIC), SKIP_OPTIONS); XPlanGmlValidation xPlanGmlValidation = new XPlanGmlValidation(new GeometricValidatorImpl(), - new PlanInfoParser(Optional.empty()), archive, validationSettings); + new PlanInfoParser(Optional.empty()), archive, validationSettings, + new InactiveValidationProcessListener()); ValidatorReport report = new ValidatorReport(); - xPlanGmlValidation.executeGmlValidation(report); + xPlanGmlValidation.executeGmlValidation("uuid", report); GeometricValidatorResult geometricReport = report.getPlanInfoReport() .getPlanInfos() diff --git a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/XPlanValidatorTest.java b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/XPlanValidatorTest.java index e16c554f4..c01d59124 100644 --- a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/XPlanValidatorTest.java +++ b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/XPlanValidatorTest.java @@ -28,6 +28,9 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -55,6 +58,7 @@ import de.latlon.xplan.commons.feature.XPlanGmlParserBuilder; import de.latlon.xplan.validator.geometric.GeometricValidator; import de.latlon.xplan.validator.geometric.GeometricValidatorImpl; import de.latlon.xplan.validator.geometric.report.GeometricValidatorResult; +import de.latlon.xplan.validator.listener.ValidationProcessListener; import de.latlon.xplan.validator.planinfo.PlanInfo; import de.latlon.xplan.validator.planinfo.PlanInfoParser; import de.latlon.xplan.validator.report.ReportArchiveGenerator; @@ -99,6 +103,8 @@ public class XPlanValidatorTest { private XPlanGmlParser xPlanGmlParser; + private ValidationProcessListener validationProcessListener; + private static File planToValidate; @Before @@ -109,6 +115,7 @@ public class XPlanValidatorTest { synVal = mockSyntacticValidator(); synValInvalid = mockSyntacticValidatorWithError(); xPlanGmlParser = mockXPlanGmlParser(); + validationProcessListener = mock(ValidationProcessListener.class); } @BeforeClass @@ -176,6 +183,15 @@ public class XPlanValidatorTest { verify(geoVal, times(1)).validateGeometry(gmlValidation()); verify(semVal, times(1)).validateSemantic(semanticValidableXPlanArchive(), list()); verifyNoInteractions(xPlanGmlParser); + + verify(validationProcessListener, times(1)).validationStarted(anyString()); + verify(validationProcessListener, times(1)).validationPartStarted(anyString(), eq(SYNTACTIC)); + verify(validationProcessListener, times(1)).validationPartFinished(anyString(), eq(SYNTACTIC), anyBoolean()); + verify(validationProcessListener, times(1)).validationPartStarted(anyString(), eq(SEMANTIC)); + verify(validationProcessListener, times(1)).validationPartFinished(anyString(), eq(SEMANTIC), anyBoolean()); + verify(validationProcessListener, times(1)).validationPartStarted(anyString(), eq(GEOMETRIC)); + verify(validationProcessListener, times(1)).validationPartFinished(anyString(), eq(GEOMETRIC), anyBoolean()); + verify(validationProcessListener, times(1)).validationFinished(anyString(), anyBoolean()); } @Test @@ -389,7 +405,7 @@ public class XPlanValidatorTest { SyntacticValidator synVal, List<SemanticProfileValidator> profileValidators, ValidationSettings settings) throws IOException, ValidatorException, ReportGenerationException { XPlanValidator validator = new XPlanValidator(geomVal, synVal, semVal, profileValidators, - mock(ReportArchiveGenerator.class), new PlanInfoParser(Optional.empty())); + mock(ReportArchiveGenerator.class), new PlanInfoParser(Optional.empty()), validationProcessListener); return validator.validate(settings, planToValidate, "archiveName"); } diff --git a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/geometric/GeometricValidatorImplTest.java b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/geometric/GeometricValidatorImplTest.java index 31a860251..4a42d1ed5 100644 --- a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/geometric/GeometricValidatorImplTest.java +++ b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/geometric/GeometricValidatorImplTest.java @@ -45,6 +45,7 @@ import de.latlon.xplan.validator.XPlanGmlValidation; import de.latlon.xplan.validator.geometric.report.GeometricValidatorResult; import de.latlon.xplan.validator.geometric.result.GeometricValidationFinding; import de.latlon.xplan.validator.geometric.result.GeometricValidationRule; +import de.latlon.xplan.validator.listener.InactiveValidationProcessListener; import de.latlon.xplan.validator.planinfo.PlanInfoParser; import de.latlon.xplan.validator.report.ValidatorReport; import de.latlon.xplan.validator.report.ValidatorResult; @@ -243,9 +244,10 @@ public class GeometricValidatorImplTest { voOptions); GeometricValidatorImpl geometricValidator = new GeometricValidatorImpl(); XPlanGmlValidation xPlanGmlValidation = new XPlanGmlValidation(geometricValidator, - new PlanInfoParser(Optional.empty()), archive, validationSettings); + new PlanInfoParser(Optional.empty()), archive, validationSettings, + new InactiveValidationProcessListener()); ValidatorReport report = new ValidatorReport(); - xPlanGmlValidation.executeGmlValidation(report); + xPlanGmlValidation.executeGmlValidation("uuid", report); return report.getPlanInfoReport() .getPlanInfos() .values() diff --git a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/geometric/ParameterizedGeometricValidatorImplTest.java b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/geometric/ParameterizedGeometricValidatorImplTest.java index 9b2e78695..d52857d6d 100644 --- a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/geometric/ParameterizedGeometricValidatorImplTest.java +++ b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/geometric/ParameterizedGeometricValidatorImplTest.java @@ -37,6 +37,7 @@ import de.latlon.xplan.commons.archive.XPlanArchiveCreator; import de.latlon.xplan.validator.ValidatorException; import de.latlon.xplan.validator.XPlanGmlValidation; import de.latlon.xplan.validator.geometric.report.GeometricValidatorResult; +import de.latlon.xplan.validator.listener.InactiveValidationProcessListener; import de.latlon.xplan.validator.planinfo.PlanInfoParser; import de.latlon.xplan.validator.report.ValidatorReport; import de.latlon.xplan.validator.report.ValidatorResult; @@ -101,9 +102,10 @@ public class ParameterizedGeometricValidatorImplTest { SKIP_OPTIONS); XPlanGmlValidation xPlanGmlValidation = new XPlanGmlValidation(geometricValidator, - new PlanInfoParser(Optional.empty()), archive, validationSettings); + new PlanInfoParser(Optional.empty()), archive, validationSettings, + new InactiveValidationProcessListener()); ValidatorReport report = new ValidatorReport(); - xPlanGmlValidation.executeGmlValidation(report); + xPlanGmlValidation.executeGmlValidation("uuid", report); return report.getPlanInfoReport() .getPlanInfos() .values() diff --git a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/planinfo/PlanInfoParserTest.java b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/planinfo/PlanInfoParserTest.java index 924582b52..916eefad9 100644 --- a/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/planinfo/PlanInfoParserTest.java +++ b/xplan-core/xplan-core-validator/src/test/java/de/latlon/xplan/validator/planinfo/PlanInfoParserTest.java @@ -19,6 +19,7 @@ import de.latlon.xplan.manager.web.shared.RasterEvaluationResult; import de.latlon.xplan.validator.ValidatorException; import de.latlon.xplan.validator.XPlanGmlValidation; import de.latlon.xplan.validator.geometric.GeometricValidatorImpl; +import de.latlon.xplan.validator.listener.InactiveValidationProcessListener; import de.latlon.xplan.validator.report.ValidatorReport; import de.latlon.xplan.validator.web.shared.ValidationSettings; import de.latlon.xplanbox.core.raster.evaluation.XPlanRasterEvaluation; @@ -38,8 +39,8 @@ public class PlanInfoParserTest { XPlanArchive archive = new XPlanArchiveCreator().createXPlanArchiveFromZip("test", planToTest); XPlanGmlValidation xPlanGmlValidation = new XPlanGmlValidation(new GeometricValidatorImpl(), planInfoParser, - archive, new ValidationSettings()); - xPlanGmlValidation.executeGmlValidation(new ValidatorReport()); + archive, new ValidationSettings(), new InactiveValidationProcessListener()); + xPlanGmlValidation.executeGmlValidation("uuid", new ValidatorReport()); PlanInfoReport planInfoReport = planInfoParser.parsePlanInfo(xPlanGmlValidation); assertEquals(1, planInfoReport.getPlanInfos().size()); @@ -67,8 +68,8 @@ public class PlanInfoParserTest { XPlanArchive archive = new XPlanArchiveCreator().createXPlanArchiveFromGml("test", planToTest); XPlanGmlValidation xPlanGmlValidation = new XPlanGmlValidation(new GeometricValidatorImpl(), planInfoParser, - archive, new ValidationSettings()); - xPlanGmlValidation.executeGmlValidation(new ValidatorReport()); + archive, new ValidationSettings(), new InactiveValidationProcessListener()); + xPlanGmlValidation.executeGmlValidation("uuid", new ValidatorReport()); PlanInfoReport planInfoReport = planInfoParser.parsePlanInfo(xPlanGmlValidation); assertEquals(planInfoReport.getPlanInfos().size(), 3); diff --git a/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/executor/PlanImporter.java b/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/executor/PlanImporter.java index 3ec8bd9bd..9c0beb2cc 100644 --- a/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/executor/PlanImporter.java +++ b/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/executor/PlanImporter.java @@ -20,6 +20,7 @@ */ package de.latlon.xplanbox.api.manager.executor; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.IMPORT_FINISHED; import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.IMPORT_STARTED; import static de.latlon.xplanbox.validator.storage.StatusType.IMPORT_FAILED; import static de.latlon.xplanbox.validator.storage.exception.ErrorType.INTERNAL_ERROR; @@ -88,8 +89,8 @@ public class PlanImporter { private void doImportPlan(ImportRequestedEvent event) throws Exception { validationExecutionStorage.changeStatus(event.getUuid(), StatusType.IMPORT_STARTED); - eventSender.sendPublicEvent(new XPlanPublicV1Event(IMPORT_STARTED, event.getUuid(), "import started"), - "routing.suffix.for.import-started.to.be.determined"); + eventSender.sendPublicEvent(new XPlanPublicV1Event(IMPORT_STARTED, event.getUuid()), + IMPORT_STARTED.routingKeySuffix()); Path tmpPath = Files.createTempFile(event.getUuid(), ".rcv"); if (Files.exists(tmpPath)) Files.delete(tmpPath); @@ -119,8 +120,8 @@ public class PlanImporter { } finally { Files.delete(tmpPath); - eventSender.sendPublicEvent(new XPlanPublicV1Event(XPlanPublicV1Event.EventType.IMPORT_FINISHED, - event.getUuid(), "import finished"), "routing.suffix.for.import-finished.to.be.determined"); + eventSender.sendPublicEvent(new XPlanPublicV1Event(IMPORT_FINISHED, event.getUuid()), + IMPORT_FINISHED.routingKeySuffix()); } } diff --git a/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/handler/PlanHandler.java b/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/handler/PlanHandler.java index 2f58e2d8d..d98e96136 100644 --- a/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/handler/PlanHandler.java +++ b/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/handler/PlanHandler.java @@ -137,7 +137,7 @@ public class PlanHandler { } public List<Bereich> findBereiche(String planId) { - LOG.info("Finding Bereiche of plan with dd '{}'", planId); + LOG.info("Finding Bereiche of plan with id '{}'", planId); return xPlanDao.retrieveBereicheOfPlanWithId(planId) .stream() .map(bereich -> new Bereich().name(bereich.getName()).nummer(bereich.getNummer())) @@ -145,7 +145,7 @@ public class PlanHandler { } public List<Gemeinde> findGemeinden(String planId) { - LOG.info("Finding Bereiche of plan with dd '{}'", planId); + LOG.info("Finding Gemeinden of plan with id '{}'", planId); return xPlanDao.retrieveGemeindeOfPlanWithId(planId) .stream() .map(gemeinde -> new Gemeinde().ags(gemeinde.getAgs()) diff --git a/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/messagingrabbitmq/Receiver.java b/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/messagingrabbitmq/Receiver.java index 5a739c385..9ca6e7e98 100644 --- a/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/messagingrabbitmq/Receiver.java +++ b/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/messagingrabbitmq/Receiver.java @@ -59,13 +59,13 @@ public class Receiver { planImporter.importPlan(event); ImportFinishedEvent finishedEvent = new ImportFinishedEvent(event.getUuid(), IMPORT_SUCCEEDED); - eventSender.sendEvent(finishedEvent); + eventSender.sendPrivateEvent(finishedEvent); } catch (Exception e) { LOG.error("Failed to process event. Discarding it", e); ImportFinishedEvent finishedEvent = new ImportFinishedEvent(event.getUuid(), IMPORT_FAILED); - eventSender.sendEvent(finishedEvent); + eventSender.sendPrivateEvent(finishedEvent); } } diff --git a/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/v2/PlanApi2.java b/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/v2/PlanApi2.java index 5a6ce31ec..617b1c5e6 100644 --- a/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/v2/PlanApi2.java +++ b/xplan-manager/xplan-manager-api/src/main/java/de/latlon/xplanbox/api/manager/v2/PlanApi2.java @@ -267,7 +267,7 @@ public class PlanApi2 { overwriteByRequest(skipLaufrichtung, validationConfig.isSkipLaufrichtung()), profiles, WITH_SKIP_RASTER_EVALUATION); - eventSender.sendEvent(new ImportValidationRequestedEvent(uuid, validationSettings, xFilename, internalId, + eventSender.sendPrivateEvent(new ImportValidationRequestedEvent(uuid, validationSettings, xFilename, internalId, planStatus, ValidationRequestedEvent.MediaType.JSON, originFile, false)); URI linkToStatus = createLinkToStatus(uuid); diff --git a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/executor/PlanImporterTest.java b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/executor/PlanImporterTest.java index ffcb792fc..a5e184edc 100644 --- a/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/executor/PlanImporterTest.java +++ b/xplan-manager/xplan-manager-api/src/test/java/de/latlon/xplanbox/api/manager/executor/PlanImporterTest.java @@ -100,12 +100,12 @@ public class PlanImporterTest { verify(validationExecutionStorage).cleanupAfterValidation(uuid); - XPlanPublicV1Event expectedStartEvent = new XPlanPublicV1Event(IMPORT_STARTED, uuid, "import started"); - XPlanPublicV1Event expectedFinishedEvent = new XPlanPublicV1Event(IMPORT_FINISHED, uuid, "import finished"); + XPlanPublicV1Event expectedStartEvent = new XPlanPublicV1Event(IMPORT_STARTED, uuid); + XPlanPublicV1Event expectedFinishedEvent = new XPlanPublicV1Event(IMPORT_FINISHED, uuid, true); verify(eventSender, times(2)).sendPublicEvent(publicEventCaptor.capture(), stringCaptor.capture()); assertThat(publicEventCaptor.getAllValues()).containsExactly(expectedStartEvent, expectedFinishedEvent); - assertThat(stringCaptor.getAllValues()).containsExactly("routing.suffix.for.import-started.to.be.determined", - "routing.suffix.for.import-finished.to.be.determined"); + assertThat(stringCaptor.getAllValues()).containsExactly(IMPORT_STARTED.routingKeySuffix(), + IMPORT_FINISHED.routingKeySuffix()); } } diff --git a/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/TestConfig.java b/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/TestConfig.java index 28f1f110a..bd3cad8ce 100644 --- a/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/TestConfig.java +++ b/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/TestConfig.java @@ -53,7 +53,7 @@ public record TestConfig(String dokumenteApiBaseUrl, String managerApiBaseUrl, S int rabbitPort = Integer.parseInt(getEnv("XPLAN_RABBIT_PORT", "5672"), 10); String rabbitUsername = getEnv("XPLAN_RABBIT_USER", "guest"); String rabbitPassword = getEnv("XPLAN_RABBIT_PASSWORD", "guest"); - String publicTopicName = getEnv("XPLAN_RABBIT_PUBLIC_TOPIC", "xplanbox-public"); + String publicTopicName = getEnv("XPLAN_RABBIT_PUBLIC_TOPIC", "latlon.public"); String publicTopicRoutingPrefix = getEnv("XPLAN_RABBIT_PUBLIC_TOPIC_ROUTING_PREFIX", ""); RabbitConfig rabbitConfig = new RabbitConfig(rabbitHost, rabbitPort, rabbitUsername, rabbitPassword, diff --git a/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/rabbit/manager/ManagerPublicEventsIT.java b/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/rabbit/manager/ManagerPublicEventsIT.java index abf842256..9b404be43 100644 --- a/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/rabbit/manager/ManagerPublicEventsIT.java +++ b/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/rabbit/manager/ManagerPublicEventsIT.java @@ -5,14 +5,13 @@ import static org.assertj.core.api.Assertions.assertThat; import java.nio.file.Path; import java.nio.file.Paths; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; - import de.latlon.xplanbox.tests.FeignUtils; import de.latlon.xplanbox.tests.TestConfig; import de.latlon.xplanbox.tests.rabbit.AbstractRabbitITExecution; import feign.Feign; import feign.jackson.JacksonDecoder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz</a> @@ -25,12 +24,12 @@ class ManagerPublicEventsIT extends AbstractRabbitITExecution { @Test void importAndVerifyPublicEvents() throws Exception { - ManagerApiV2 v2Api = Feign.builder() // + ManagerApiV2 v2Api = Feign.builder() .client(FeignUtils.unsecuredClient()) - // .logger(new Logger.ErrorLogger()) // - // .logLevel(Level.FULL) // - .encoder(new SimpleBodyFileEncoder()) // - .decoder(new JacksonDecoder()) // + // .logger(new Logger.ErrorLogger()) + // .logLevel(Level.FULL) + .encoder(new SimpleBodyFileEncoder()) + .decoder(new JacksonDecoder()) .target(ManagerApiV2.class, testConfig.managerApiBaseUrl()); startRabbitPublicEventsReception(testConfig.rabbitConfig()); @@ -46,34 +45,67 @@ class ManagerPublicEventsIT extends AbstractRabbitITExecution { assertThat(statusResponse.status()).isIn("VALIDATION_REQUESTED", "VALIDATION_FINISHED", "IMPORT_REQUESTED", "IMPORT_FINISHED"); - // awaiting 4 events for this uuid + // awaiting 10 events for this uuid ReceivedPublicEvent expectedEventValidationStarted = new ReceivedPublicEvent( - testConfig.rabbitConfig().publicTopicRoutingPrefix() + "routing.suffix.for.started.to.be.determined", + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation", "{\"apiVersion\":\"1.0\",\"eventType\":\"VALIDATION_STARTED\",\"uuid\":\"" + r.uuid() - + "\",\"message\":\"validation started\"}"); + + "\",\"valid\":null,\"error\":null}"); + + ReceivedPublicEvent expectedEventSynValidationStarted = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.syntaktisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"SYNTACTIC_VALIDATION_STARTED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":null,\"error\":null}"); + ReceivedPublicEvent expectedEventSynValidationFinished = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.syntaktisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"SYNTACTIC_VALIDATION_FINISHED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":true,\"error\":null}"); + + ReceivedPublicEvent expectedEventGeomValidationStarted = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.geometrisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"GEOMETRIC_VALIDATION_STARTED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":null,\"error\":null}"); + ReceivedPublicEvent expectedEventGeomValidationFinished = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.geometrisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"GEOMETRIC_VALIDATION_FINISHED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":true,\"error\":null}"); + + ReceivedPublicEvent expectedEventSemValidationStarted = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.semantisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"SEMANTIC_VALIDATION_STARTED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":null,\"error\":null}"); + ReceivedPublicEvent expectedEventSemValidationFinished = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.semantisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"SEMANTIC_VALIDATION_FINISHED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":true,\"error\":null}"); + ReceivedPublicEvent expectedEventValidationFinished = new ReceivedPublicEvent( - testConfig.rabbitConfig().publicTopicRoutingPrefix() + "routing.suffix.for.finished.to.be.determined", + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation", "{\"apiVersion\":\"1.0\",\"eventType\":\"VALIDATION_FINISHED\",\"uuid\":\"" + r.uuid() - + "\",\"message\":\"validation finished\"}"); + + "\",\"valid\":true,\"error\":null}"); + ReceivedPublicEvent expectedEventImportStarted = new ReceivedPublicEvent( testConfig.rabbitConfig().publicTopicRoutingPrefix() + "routing.suffix.for.import-started.to.be.determined", "{\"apiVersion\":\"1.0\",\"eventType\":\"IMPORT_STARTED\",\"uuid\":\"" + r.uuid() - + "\",\"message\":\"import started\"}"); + + "\",\"valid\":true,\"error\":null}"); + ReceivedPublicEvent expectedEventImportFinished = new ReceivedPublicEvent( testConfig.rabbitConfig().publicTopicRoutingPrefix() + "routing.suffix.for.import-finished.to.be.determined", "{\"apiVersion\":\"1.0\",\"eventType\":\"IMPORT_FINISHED\",\"uuid\":\"" + r.uuid() - + "\",\"message\":\"import finished\"}"); + + "\",\"valid\":true,\"error\":null}"); - waitingIfNeeded(20, + waitingIfNeeded(30, () -> assertThat(receivedEventsFor(r.uuid())).containsExactly(expectedEventValidationStarted, + expectedEventSynValidationStarted, expectedEventSynValidationFinished, + expectedEventGeomValidationStarted, expectedEventGeomValidationFinished, + expectedEventSemValidationStarted, expectedEventSemValidationFinished, expectedEventValidationFinished, expectedEventImportStarted, expectedEventImportFinished)); // verify status statusResponse = v2Api.status(r.uuid()); - assertThat(statusResponse.status()).isEqualTo("IMPORT_FINISHED"); // now surely - // finished + // now surely finished + assertThat(statusResponse.status()).isEqualTo("IMPORT_FINISHED"); } } diff --git a/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/rabbit/validator/ValidationPublicEventsIT.java b/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/rabbit/validator/ValidationPublicEventsIT.java index 79decc1a0..e9fa44eb0 100644 --- a/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/rabbit/validator/ValidationPublicEventsIT.java +++ b/xplan-tests/xplan-tests-integration/src/test/java/de/latlon/xplanbox/tests/rabbit/validator/ValidationPublicEventsIT.java @@ -5,9 +5,6 @@ import static org.assertj.core.api.Assertions.assertThat; import java.nio.file.Path; import java.nio.file.Paths; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; - import de.latlon.xplanbox.tests.FeignUtils; import de.latlon.xplanbox.tests.TestConfig; import de.latlon.xplanbox.tests.rabbit.AbstractRabbitITExecution; @@ -16,6 +13,8 @@ import de.latlon.xplanbox.tests.validatorapi.ValidatorApi.StatusResponse; import de.latlon.xplanbox.tests.validatorapi.ValidatorApi.ValidateResponse; import feign.Feign; import feign.jackson.JacksonDecoder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; /** * @author <a href="mailto:guillemot@lat-lon.de">Marc Guillemot</a> @@ -24,16 +23,14 @@ import feign.jackson.JacksonDecoder; @DisabledIfEnvironmentVariable(named = "SKIP_RABBIT_TESTS", matches = "(1|true)") class ValidationPublicEventsIT extends AbstractRabbitITExecution { - private TestConfig testConfig = TestConfig.getTestConfig(); + private final TestConfig testConfig = TestConfig.getTestConfig(); @Test void validateAndVerifyPublicEvents() throws Exception { - ValidatorApi validatorApi = Feign.builder() // + ValidatorApi validatorApi = Feign.builder() .client(FeignUtils.unsecuredClient()) - // .logger(new Logger.ErrorLogger()) // - // .logLevel(Level.FULL) // - .encoder(new SimpleBodyFileEncoder()) // - .decoder(new JacksonDecoder()) // + .encoder(new SimpleBodyFileEncoder()) + .decoder(new JacksonDecoder()) .target(ValidatorApi.class, testConfig.validatorApiBaseUrl()); startRabbitPublicEventsReception(testConfig.rabbitConfig()); @@ -46,25 +43,56 @@ class ValidationPublicEventsIT extends AbstractRabbitITExecution { // verify status (probably not yet finished but who knows...) StatusResponse statusResponse = validatorApi.v2Status(r.uuid()); - assertThat(statusResponse.status()).isIn("VALIDATION_REQUESTED", "VALIDATION_FINISHED"); // .... + assertThat(statusResponse.status()).isIn("VALIDATION_REQUESTED", "VALIDATION_FINISHED"); - // awaiting 2 events for this uuid + // awaiting 8 events for this uuid ReceivedPublicEvent expectedEventValidationStarted = new ReceivedPublicEvent( - testConfig.rabbitConfig().publicTopicRoutingPrefix() + "routing.suffix.for.started.to.be.determined", + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation", "{\"apiVersion\":\"1.0\",\"eventType\":\"VALIDATION_STARTED\",\"uuid\":\"" + r.uuid() - + "\",\"message\":\"validation started\"}"); + + "\",\"valid\":null,\"error\":null}"); + + ReceivedPublicEvent expectedEventSynValidationStarted = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.syntaktisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"SYNTACTIC_VALIDATION_STARTED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":null,\"error\":null}"); + ReceivedPublicEvent expectedEventSynValidationFinished = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.syntaktisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"SYNTACTIC_VALIDATION_FINISHED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":true,\"error\":null}"); + + ReceivedPublicEvent expectedEventGeomValidationStarted = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.geometrisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"GEOMETRIC_VALIDATION_STARTED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":null,\"error\":null}"); + ReceivedPublicEvent expectedEventGeomValidationFinished = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.geometrisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"GEOMETRIC_VALIDATION_FINISHED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":true,\"error\":null}"); + + ReceivedPublicEvent expectedEventSemValidationStarted = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.semantisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"SEMANTIC_VALIDATION_STARTED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":null,\"error\":null}"); + ReceivedPublicEvent expectedEventSemValidationFinished = new ReceivedPublicEvent( + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation.semantisch", + "{\"apiVersion\":\"1.0\",\"eventType\":\"SEMANTIC_VALIDATION_FINISHED\",\"uuid\":\"" + r.uuid() + + "\",\"valid\":true,\"error\":null}"); + ReceivedPublicEvent expectedEventValidationFinished = new ReceivedPublicEvent( - testConfig.rabbitConfig().publicTopicRoutingPrefix() + "routing.suffix.for.finished.to.be.determined", + testConfig.rabbitConfig().publicTopicRoutingPrefix() + "xplanbox.validation", "{\"apiVersion\":\"1.0\",\"eventType\":\"VALIDATION_FINISHED\",\"uuid\":\"" + r.uuid() - + "\",\"message\":\"validation finished\"}"); - waitingIfNeeded(10, () -> assertThat(receivedEventsFor(r.uuid())) - .containsExactly(expectedEventValidationStarted, expectedEventValidationFinished)); + + "\",\"valid\":true,\"error\":null}"); + waitingIfNeeded(20, + () -> assertThat(receivedEventsFor(r.uuid())).containsExactly(expectedEventValidationStarted, + expectedEventSynValidationStarted, expectedEventSynValidationFinished, + expectedEventGeomValidationStarted, expectedEventGeomValidationFinished, + expectedEventSemValidationStarted, expectedEventSemValidationFinished, + expectedEventValidationFinished)); // verify status statusResponse = validatorApi.v2Status(r.uuid()); - assertThat(statusResponse.status()).isEqualTo("VALIDATION_FINISHED"); // now - // surely - // finished + // now surely finished + assertThat(statusResponse.status()).isEqualTo("VALIDATION_FINISHED"); } } diff --git a/xplan-validator/xplan-validator-api/src/main/java/de/latlon/xplanbox/api/validator/v2/ValidateApi2.java b/xplan-validator/xplan-validator-api/src/main/java/de/latlon/xplanbox/api/validator/v2/ValidateApi2.java index 83961d901..98079b05e 100644 --- a/xplan-validator/xplan-validator-api/src/main/java/de/latlon/xplanbox/api/validator/v2/ValidateApi2.java +++ b/xplan-validator/xplan-validator-api/src/main/java/de/latlon/xplanbox/api/validator/v2/ValidateApi2.java @@ -179,7 +179,7 @@ public class ValidateApi2 { skipFlaechenschluss, skipGeltungsbereich, skipLaufrichtung, profiles, validatorApiConfiguration.isSkipRasterEvaluation()); - validationRequestNotifier.sendEvent(new ValidationRequestedEvent(uuid, settings, xFilename, + validationRequestNotifier.sendPrivateEvent(new ValidationRequestedEvent(uuid, settings, xFilename, ValidationRequestedEvent.MediaType.JSON, originFile)); URI linkToStatus = createLinkToStatus(uuid); diff --git a/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/PlanValidator.java b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/PlanValidator.java index d0f0e8b32..d6a735d79 100644 --- a/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/PlanValidator.java +++ b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/PlanValidator.java @@ -1,5 +1,7 @@ package de.latlon.xplanbox.validator.executor; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.VALIDATION_FINISHED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.VALIDATION_STARTED; import static de.latlon.xplan.validator.report.geojson.GeoJsonBuilder.createGeoJsonFailures; import static de.latlon.xplanbox.validator.storage.StatusType.VALIDATION_FAILED; import static de.latlon.xplanbox.validator.storage.exception.ErrorType.INTERNAL_ERROR; @@ -17,7 +19,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import de.latlon.core.validator.events.EventSender; import de.latlon.core.validator.events.ValidationRequestedEvent; import de.latlon.core.validator.events.v1.XPlanPublicV1Event; -import de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType; import de.latlon.xplan.commons.archive.XPlanArchive; import de.latlon.xplan.validator.ValidatorException; import de.latlon.xplan.validator.report.ReportGenerationException; @@ -25,9 +26,9 @@ import de.latlon.xplan.validator.report.ValidatorReport; import de.latlon.xplan.validator.report.geojson.model.FeatureCollection; import de.latlon.xplanbox.api.commons.ObjectMapperContextResolver; import de.latlon.xplanbox.api.commons.ValidationReportBuilder; +import de.latlon.xplanbox.api.commons.exception.InvalidXPlanGmlOrArchive; import de.latlon.xplanbox.api.commons.exception.XPlanApiException; import de.latlon.xplanbox.api.commons.v2.model.ValidationReport; -import de.latlon.xplanbox.core.raster.evaluation.XPlanRasterEvaluator; import de.latlon.xplanbox.validator.executor.handler.ValidationHandler; import de.latlon.xplanbox.validator.storage.StatusType; import de.latlon.xplanbox.validator.storage.StoredValidationReport; @@ -52,13 +53,10 @@ public class PlanValidator { private final EventSender eventSender; - private XPlanRasterEvaluator xPlanRasterEvaluator; - public PlanValidator(ValidationExecutionStorage validationExecutionStorage, ValidationHandler validationHandler, - XPlanRasterEvaluator xPlanRasterEvaluator, EventSender eventSender) { + EventSender eventSender) { this.validationExecutionStorage = validationExecutionStorage; this.validationHandler = validationHandler; - this.xPlanRasterEvaluator = xPlanRasterEvaluator; this.eventSender = eventSender; } @@ -72,49 +70,25 @@ public class PlanValidator { private ValidationReport validate(ValidationRequestedEvent event, boolean cleanUp) throws Exception { validationExecutionStorage.changeStatus(event.getUuid(), StatusType.VALIDATION_STARTED); - eventSender.sendPublicEvent( - new XPlanPublicV1Event(EventType.VALIDATION_STARTED, event.getUuid(), "validation started"), - "routing.suffix.for.started.to.be.determined"); - - try { - return doValidate(event, cleanUp); - } - finally { - eventSender.sendPublicEvent( - new XPlanPublicV1Event(EventType.VALIDATION_FINISHED, event.getUuid(), "validation finished"), - "routing.suffix.for.finished.to.be.determined"); - } + eventSender.sendPublicEvent(new XPlanPublicV1Event(VALIDATION_STARTED, event.getUuid()), + VALIDATION_STARTED.routingKeySuffix()); + return doValidate(event, cleanUp); } private ValidationReport doValidate(ValidationRequestedEvent event, boolean cleanUp) throws Exception { Map<ReportType, Path> reports = new HashMap<>(); + Path tmpPath = null; try { - Path tmpPath = Files.createTempFile(event.getUuid(), ".rcv"); - if (Files.exists(tmpPath)) - Files.delete(tmpPath); + tmpPath = createTmpPath(event); validationExecutionStorage.writePlanToValidate(event.getUuid(), tmpPath); - final XPlanArchive archive; - if (event.getOriginFile() == ValidationRequestedEvent.OriginFile.GML) { - archive = validationHandler.createArchiveFromGml(tmpPath.toFile(), - event.getSettings().getValidationName()); - } - else { - archive = validationHandler.createArchiveFromZip(tmpPath.toFile(), - event.getSettings().getValidationName()); - } + XPlanArchive archive = readAsArchive(event, tmpPath); LOG.info("Validating {}", tmpPath); - ValidatorReport validatorReport = validationHandler.validate(archive, event.getxFileName(), + ValidatorReport validatorReport = validationHandler.validate(event.getUuid(), archive, event.getxFileName(), event.getSettings()); - // TODO: delete tmpPath - ValidationReport validationReport = createValidationReport(event, archive, validatorReport); - - reports.put(ReportType.JSON, createJsonReportFile(validationReport)); - reports.put(ReportType.GEOJSON, createGeoJsonReportFile(validatorReport)); - reports.put(ReportType.PDF, createPdfReportFile(validatorReport)); - reports.put(ReportType.ZIP, createZipReportFile(validatorReport)); + ValidationReport validationReport = createAndAddReports(event, archive, validatorReport, reports); StoredValidationReport storedValidationReport = validationExecutionStorage .saveValidationResult(event.getUuid(), reports); @@ -123,6 +97,9 @@ public class PlanValidator { storedValidationReport); if (cleanUp && validatorReport.isValid()) validationExecutionStorage.cleanupAfterValidation(event.getUuid()); + eventSender.sendPublicEvent( + new XPlanPublicV1Event(VALIDATION_FINISHED, event.getUuid(), validatorReport.isValid()), + VALIDATION_FINISHED.routingKeySuffix()); return validationReport; } catch (XPlanApiException e) { @@ -146,7 +123,39 @@ public class PlanValidator { for (Path path : reports.values()) { Files.deleteIfExists(path); } + if (tmpPath != null) + Files.deleteIfExists(tmpPath); + } + } + + private ValidationReport createAndAddReports(ValidationRequestedEvent event, XPlanArchive archive, + ValidatorReport validatorReport, Map<ReportType, Path> reports) + throws IOException, ReportGenerationException { + ValidationReport validationReport = createValidationReport(event, archive, validatorReport); + + reports.put(ReportType.JSON, createJsonReportFile(validationReport)); + reports.put(ReportType.GEOJSON, createGeoJsonReportFile(validatorReport)); + reports.put(ReportType.PDF, createPdfReportFile(validatorReport)); + reports.put(ReportType.ZIP, createZipReportFile(validatorReport)); + return validationReport; + } + + private static Path createTmpPath(ValidationRequestedEvent event) throws IOException { + Path tmpPath = Files.createTempFile(event.getUuid(), ".rcv"); + if (Files.exists(tmpPath)) + Files.delete(tmpPath); + return tmpPath; + } + + private XPlanArchive readAsArchive(ValidationRequestedEvent event, Path tmpPath) throws InvalidXPlanGmlOrArchive { + final XPlanArchive archive; + if (event.getOriginFile() == ValidationRequestedEvent.OriginFile.GML) { + archive = validationHandler.createArchiveFromGml(tmpPath.toFile(), event.getSettings().getValidationName()); + } + else { + archive = validationHandler.createArchiveFromZip(tmpPath.toFile(), event.getSettings().getValidationName()); } + return archive; } private ValidationReport createValidationReport(ValidationRequestedEvent event, final XPlanArchive archive, diff --git a/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/config/ApplicationContext.java b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/config/ApplicationContext.java index 334d07873..01416b14c 100644 --- a/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/config/ApplicationContext.java +++ b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/config/ApplicationContext.java @@ -37,6 +37,7 @@ import de.latlon.xplan.validator.configuration.ValidatorConfiguration; import de.latlon.xplan.validator.configuration.ValidatorConfigurationParser; import de.latlon.xplan.validator.geometric.GeometricValidator; import de.latlon.xplan.validator.geometric.GeometricValidatorImpl; +import de.latlon.xplan.validator.listener.ValidationProcessListener; import de.latlon.xplan.validator.planinfo.PlanInfoParser; import de.latlon.xplan.validator.report.ReportArchiveGenerator; import de.latlon.xplan.validator.report.ReportWriter; @@ -130,9 +131,11 @@ public class ApplicationContext { @Bean public XPlanValidator xplanValidator(GeometricValidator geometricValidator, SyntacticValidator syntacticValidator, SemanticValidator semanticValidator, SemanticProfiles semanticProfiles, - ReportArchiveGenerator reportArchiveGenerator, PlanInfoParser planInfoParser) { + ReportArchiveGenerator reportArchiveGenerator, PlanInfoParser planInfoParser, + ValidationProcessListener validationProcessListener) { return new XPlanValidator(geometricValidator, syntacticValidator, semanticValidator, - semanticProfiles.getProfileValidators(), reportArchiveGenerator, planInfoParser); + semanticProfiles.getProfileValidators(), reportArchiveGenerator, planInfoParser, + validationProcessListener); } @Bean diff --git a/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandler.java b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandler.java index 50f6df0ef..daee7d6e6 100644 --- a/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandler.java +++ b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandler.java @@ -8,12 +8,12 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% @@ -83,10 +83,10 @@ public class ValidationHandler { private XPlanArchiveCreator archiveCreator = new XPlanArchiveCreator(); - public ValidatorReport validate(XPlanArchive archive, String xFileName, ValidationSettings validationSettings) - throws ValidatorException { + public ValidatorReport validate(String uuid, XPlanArchive archive, String xFileName, + ValidationSettings validationSettings) throws ValidatorException { LOG.debug("Validate plan with validationName {}", validationSettings.getValidationName()); - return xPlanValidator.validateNotWriteReport(validationSettings, archive, xFileName); + return xPlanValidator.validateNotWriteReport(uuid, validationSettings, archive, xFileName); } public Path zipReports(ValidatorReport validatorReport) throws IOException { diff --git a/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/listener/EventValidationProcessListener.java b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/listener/EventValidationProcessListener.java new file mode 100644 index 000000000..17f583e96 --- /dev/null +++ b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/listener/EventValidationProcessListener.java @@ -0,0 +1,82 @@ +package de.latlon.xplanbox.validator.executor.listener; + +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.GEOMETRIC_VALIDATION_FINISHED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.GEOMETRIC_VALIDATION_STARTED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.PROFILE_VALIDATION_FINISHED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.PROFILE_VALIDATION_STARTED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.SEMANTIC_VALIDATION_FINISHED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.SEMANTIC_VALIDATION_STARTED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.SYNTACTIC_VALIDATION_FINISHED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.SYNTACTIC_VALIDATION_STARTED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.VALIDATION_FAILED; +import static de.latlon.core.validator.events.v1.XPlanPublicV1Event.EventType.VALIDATION_STARTED; + +import de.latlon.core.validator.events.EventSender; +import de.latlon.core.validator.events.v1.XPlanPublicV1Event; +import de.latlon.xplan.validator.listener.ValidationProcessListener; +import de.latlon.xplan.validator.web.shared.ValidationType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> + */ +@Component +public class EventValidationProcessListener implements ValidationProcessListener { + + @Autowired + private EventSender eventSender; + + @Override + public void validationStarted(String uuid) { + // handled in PlanValidator.validate + } + + @Override + public void validationPartStarted(String uuid, ValidationType validationType) { + XPlanPublicV1Event.EventType eventType = SYNTACTIC_VALIDATION_STARTED; + switch (validationType) { + case GEOMETRIC -> eventType = GEOMETRIC_VALIDATION_STARTED; + case SEMANTIC -> eventType = SEMANTIC_VALIDATION_STARTED; + } + XPlanPublicV1Event event = new XPlanPublicV1Event(eventType, uuid); + eventSender.sendPublicEvent(event, eventType.routingKeySuffix()); + } + + @Override + public void validationPartFinished(String uuid, ValidationType validationType, Boolean isValid) { + XPlanPublicV1Event.EventType eventType = SYNTACTIC_VALIDATION_FINISHED; + switch (validationType) { + case GEOMETRIC -> eventType = GEOMETRIC_VALIDATION_FINISHED; + case SEMANTIC -> eventType = SEMANTIC_VALIDATION_FINISHED; + } + XPlanPublicV1Event event = new XPlanPublicV1Event(eventType, uuid, isValid); + eventSender.sendPublicEvent(event, eventType.routingKeySuffix()); + } + + @Override + public void validationProfileStarted(String uuid, String profileId) { + XPlanPublicV1Event event = new XPlanPublicV1Event(PROFILE_VALIDATION_STARTED, uuid); + eventSender.sendPublicEvent(event, PROFILE_VALIDATION_STARTED.routingKeySuffix() + profileId); + + } + + @Override + public void validationProfileFinished(String uuid, String profileId, Boolean isValid) { + XPlanPublicV1Event event = new XPlanPublicV1Event(PROFILE_VALIDATION_FINISHED, uuid, isValid); + eventSender.sendPublicEvent(event, PROFILE_VALIDATION_FINISHED.routingKeySuffix() + profileId); + } + + @Override + public void validationFinished(String uuid, Boolean isValid) { + // handled in PlanValidator.validate + } + + @Override + public void validationFailed(String uuid, String error) { + XPlanPublicV1Event event = new XPlanPublicV1Event(VALIDATION_FAILED, uuid, error); + eventSender.sendPublicEvent(event, VALIDATION_STARTED.routingKeySuffix()); + + } + +} diff --git a/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/messagingrabbitmq/Receiver.java b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/messagingrabbitmq/Receiver.java index 47e24f008..d5d14aa13 100644 --- a/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/messagingrabbitmq/Receiver.java +++ b/xplan-validator/xplan-validator-executor/src/main/java/de/latlon/xplanbox/validator/executor/messagingrabbitmq/Receiver.java @@ -79,13 +79,13 @@ public class Receiver { validator.validateAndCleanUp(event); ValidationFinishedEvent finishedEvent = new ValidationFinishedEvent(event.getUuid(), SUCCEEDED); - eventSender.sendEvent(finishedEvent); + eventSender.sendPrivateEvent(finishedEvent); } catch (Exception e) { LOG.error("Failed to process event. Discarding it", e); ValidationFinishedEvent finishedEvent = new ValidationFinishedEvent(event.getUuid(), FAILED); - eventSender.sendEvent(finishedEvent); + eventSender.sendPrivateEvent(finishedEvent); } } @@ -94,20 +94,20 @@ public class Receiver { ValidationReport validationReport = validator.validate(event); ValidationFinishedEvent finishedEvent = new ValidationFinishedEvent(event.getUuid(), SUCCEEDED); - eventSender.sendEvent(finishedEvent); + eventSender.sendPrivateEvent(finishedEvent); ImportRequestedEvent importRequestedEvent = new ImportRequestedEvent(event.getUuid(), event.getSettings().getValidationName(), event.getInternalId(), event.getPlanStatus(), event.getOriginFile(), ValidationReportUtils.isValid(validationReport) ? VALID : INVALID, rasterEvaluationStatus(validationReport), event.isSupportsGetPlanByIdAsZip()); - eventSender.sendEvent(importRequestedEvent); + eventSender.sendPrivateEvent(importRequestedEvent); } catch (Exception e) { LOG.error("Failed to process event. Discarding it", e); ValidationFinishedEvent finishedEvent = new ValidationFinishedEvent(event.getUuid(), FAILED); - eventSender.sendEvent(finishedEvent); + eventSender.sendPrivateEvent(finishedEvent); ImportFinishedEvent finishedImportEvent = new ImportFinishedEvent(event.getUuid(), VALIDATION_FAILED); - eventSender.sendEvent(finishedImportEvent); + eventSender.sendPrivateEvent(finishedImportEvent); } } diff --git a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/PlanValidatorTest.java b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/PlanValidatorTest.java index 02fbac962..e9a1cb301 100644 --- a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/PlanValidatorTest.java +++ b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/PlanValidatorTest.java @@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.nio.charset.StandardCharsets; @@ -58,7 +59,6 @@ import org.json.JSONObject; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Captor; -import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; @@ -143,14 +143,28 @@ class PlanValidatorTest { verifyExpectedReport(uuid, ReportType.JSON, "report1.expected.json"); - XPlanPublicV1Event expectedStartEvent = new XPlanPublicV1Event(EventType.VALIDATION_STARTED, uuid, - "validation started"); - XPlanPublicV1Event expectedFinishedEvent = new XPlanPublicV1Event(EventType.VALIDATION_FINISHED, uuid, - "validation finished"); - Mockito.verify(eventSender, times(2)).sendPublicEvent(publicEventCaptor.capture(), stringCaptor.capture()); - assertThat(publicEventCaptor.getAllValues()).containsExactly(expectedStartEvent, expectedFinishedEvent); - assertThat(stringCaptor.getAllValues()).containsExactly("routing.suffix.for.started.to.be.determined", - "routing.suffix.for.finished.to.be.determined"); + XPlanPublicV1Event expectedStartEvent = new XPlanPublicV1Event(EventType.VALIDATION_STARTED, uuid); + XPlanPublicV1Event expectedSynStartedEvent = new XPlanPublicV1Event(EventType.SYNTACTIC_VALIDATION_STARTED, + uuid); + XPlanPublicV1Event expectedSynFinishedEvent = new XPlanPublicV1Event(EventType.SYNTACTIC_VALIDATION_FINISHED, + uuid, true); + XPlanPublicV1Event expectedSemStartedEvent = new XPlanPublicV1Event(EventType.SEMANTIC_VALIDATION_STARTED, + uuid); + XPlanPublicV1Event expectedSemFinishedEvent = new XPlanPublicV1Event(EventType.SEMANTIC_VALIDATION_FINISHED, + uuid, true); + XPlanPublicV1Event expectedGeomStartedEvent = new XPlanPublicV1Event(EventType.GEOMETRIC_VALIDATION_STARTED, + uuid); + XPlanPublicV1Event expectedGeomFinishedEvent = new XPlanPublicV1Event(EventType.GEOMETRIC_VALIDATION_FINISHED, + uuid, false); + XPlanPublicV1Event expectedFinishedEvent = new XPlanPublicV1Event(EventType.VALIDATION_FINISHED, uuid, false); + verify(eventSender, times(8)).sendPublicEvent(publicEventCaptor.capture(), stringCaptor.capture()); + + assertThat(publicEventCaptor.getAllValues()).containsExactly(expectedStartEvent, expectedSynStartedEvent, + expectedSynFinishedEvent, expectedGeomStartedEvent, expectedGeomFinishedEvent, expectedSemStartedEvent, + expectedSemFinishedEvent, expectedFinishedEvent); + assertThat(stringCaptor.getAllValues()).containsExactly("validation", "validation.syntaktisch", + "validation.syntaktisch", "validation.geometrisch", "validation.geometrisch", "validation.semantisch", + "validation.semantisch", "validation"); } @Test diff --git a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandlerTest.java b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandlerTest.java index 2c930dd98..cb96eaff9 100644 --- a/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandlerTest.java +++ b/xplan-validator/xplan-validator-executor/src/test/java/de/latlon/xplanbox/validator/executor/handler/ValidationHandlerTest.java @@ -111,7 +111,7 @@ public class ValidationHandlerTest { final ValidationSettings settings = Mockito.mock(ValidationSettings.class); XPlanArchive archive = validationHandler.createArchiveFromZip(file, "bplan_valid_41"); - ValidatorReport report = validationHandler.validate(archive, "bplan_valid_41", settings); + ValidatorReport report = validationHandler.validate("uuid", archive, "bplan_valid_41", settings); assertTrue(report.isValid()); assertTrue(report.getPlanInfoReport().getPlanInfos().values().stream().findFirst().get().isValid()); } -- GitLab