From 8d8d83bc2526c5eb66c7c0772ed66d9f84152e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kilian=20Sch=C3=BCttler?= Date: Thu, 2 Nov 2023 11:13:26 +0100 Subject: [PATCH] rule validation hotfix: --- .../model/drools/RuleFileBluePrint.java | 8 ++++ .../drools/DroolsSyntaxValidationService.java | 39 +++++++++++++++---- .../DroolsSyntaxValidationServiceTest.java | 19 ++++++++- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/model/drools/RuleFileBluePrint.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/model/drools/RuleFileBluePrint.java index 8dc3f863..8bbfbc43 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/model/drools/RuleFileBluePrint.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/model/drools/RuleFileBluePrint.java @@ -1,10 +1,12 @@ package com.iqser.red.service.redaction.v1.server.model.drools; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -39,6 +41,12 @@ public final class RuleFileBluePrint { } + public Set getImportSplitByKeyword() { + + return Arrays.stream(imports.replaceAll("\n", "").split("import")).map(String::trim).collect(Collectors.toSet()); + } + + public List findRulesByIdentifier(RuleIdentifier ruleIdentifier) { if (Objects.isNull(ruleIdentifier.unit())) { diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/service/drools/DroolsSyntaxValidationService.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/service/drools/DroolsSyntaxValidationService.java index 2242a91b..d0a7f734 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/service/drools/DroolsSyntaxValidationService.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/service/drools/DroolsSyntaxValidationService.java @@ -1,12 +1,15 @@ package com.iqser.red.service.redaction.v1.server.service.drools; import java.util.List; +import java.util.Locale; +import java.util.Set; import java.util.stream.Collectors; import org.kie.api.builder.KieBuilder; import org.kie.api.builder.Message; import org.springframework.stereotype.Service; +import com.google.common.collect.Sets; import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType; import com.iqser.red.service.redaction.v1.model.DroolsSyntaxErrorMessage; import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation; @@ -46,7 +49,7 @@ public class DroolsSyntaxValidationService { case COMPONENT -> RuleFileParser.buildBluePrintFromRulesString(RuleManagementResources.getBaseComponentRuleFileString()); }; - if (!ruleFileBluePrint.getImports().equals(baseRuleFileBluePrint.getImports())) { + if (!importsAreValid(baseRuleFileBluePrint, ruleFileBluePrint)) { customSyntaxValidation.getDroolsSyntaxErrorMessages() .add(DroolsSyntaxErrorMessage.builder() .line(ruleFileBluePrint.getImportLine()) @@ -56,8 +59,10 @@ public class DroolsSyntaxValidationService { } if (!ruleFileBluePrint.getGlobals().equals(baseRuleFileBluePrint.getGlobals())) { customSyntaxValidation.getDroolsSyntaxErrorMessages() - .add(DroolsSyntaxErrorMessage.builder().line(ruleFileBluePrint.getGlobalsLine()) - .column(0).message(String.format("Changing the globals is not allowed! Must be: %n%s", baseRuleFileBluePrint.getGlobals())) + .add(DroolsSyntaxErrorMessage.builder() + .line(ruleFileBluePrint.getGlobalsLine()) + .column(0) + .message(String.format("Changing the globals is not allowed! Must be: %n%s", baseRuleFileBluePrint.getGlobals())) .build()); } baseRuleFileBluePrint.getQueries().forEach(basicQuery -> { @@ -72,9 +77,8 @@ public class DroolsSyntaxValidationService { }); baseRuleFileBluePrint.streamAllRules().forEach(basicRule -> { if (!validateRuleIsPresent(basicRule, ruleFileBluePrint)) { - customSyntaxValidation.getDroolsSyntaxErrorMessages() - .add(DroolsSyntaxErrorMessage.builder() - .line(basicRule.getLine()) + int line = ruleFileBluePrint.findRulesByIdentifier(basicRule.getIdentifier()).stream().findFirst().map(BasicRule::getLine).orElse(basicRule.getLine()); + customSyntaxValidation.getDroolsSyntaxErrorMessages().add(DroolsSyntaxErrorMessage.builder().line(line) .column(0) .message(String.format("Changing or removing the rule %s is not allowed! Must be: %n%s", basicRule.getName(), basicRule.getCode())) .build()); @@ -84,9 +88,26 @@ public class DroolsSyntaxValidationService { } + private boolean importsAreValid(RuleFileBluePrint baseRuleFileBluePrint, RuleFileBluePrint ruleFileBluePrint) { + + // imports may shrink, but not add anything new! + Set baseImports = baseRuleFileBluePrint.getImportSplitByKeyword(); + Set imports = ruleFileBluePrint.getImportSplitByKeyword(); + return Sets.difference(imports, baseImports).isEmpty(); + } + + private static boolean validateRuleIsPresent(BasicRule basicRule, RuleFileBluePrint ruleFileBluePrint) { - return ruleFileBluePrint.findRulesByIdentifier(basicRule.getIdentifier()).stream().anyMatch(otherRule -> otherRule.getCode().equals(basicRule.getCode())); + return ruleFileBluePrint.findRulesByIdentifier(basicRule.getIdentifier()).stream().anyMatch(otherRule -> rulesMatch(basicRule, otherRule)); + } + + + private static boolean rulesMatch(BasicRule basicRule, BasicRule otherRule) { + + // Name only needs to match with to lower case, everything else must match exactly + return otherRule.getName().toLowerCase(Locale.ENGLISH).equals(basicRule.getName().toLowerCase(Locale.ROOT)) && // + otherRule.getCode().replace(otherRule.getName(), "").equals(basicRule.getCode().replace(basicRule.getName(), "")); } @@ -101,7 +122,9 @@ public class DroolsSyntaxValidationService { var versionId = System.currentTimeMillis(); var testRules = "test-rules"; KieBuilder kieBuilder = kieContainerCreationService.registerNewKieContainerVersion(testRules, - versionId, rules.getRulesString(), RuleFileType.valueOf(rules.getRuleFileType())); + versionId, + rules.getRulesString(), + RuleFileType.valueOf(rules.getRuleFileType())); return buildDroolsCompilerSyntaxValidation(kieBuilder); } diff --git a/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/drools/files/management/services/DroolsSyntaxValidationServiceTest.java b/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/drools/files/management/services/DroolsSyntaxValidationServiceTest.java index 3f5c1055..95cdf199 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/drools/files/management/services/DroolsSyntaxValidationServiceTest.java +++ b/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/drools/files/management/services/DroolsSyntaxValidationServiceTest.java @@ -58,6 +58,22 @@ class DroolsSyntaxValidationServiceTest { } + @Test + @SneakyThrows + void testRulesWithRemovedImportsAndChangedName() { + + DroolsSyntaxValidationService droolsSyntaxValidationService = new DroolsSyntaxValidationService(new KieContainerCreationService(rulesClient)); + var rulesFile = new ClassPathResource("drools/rules.drl"); + + String rulesString = new String(rulesFile.getInputStream().readAllBytes()); + rulesString = rulesString.replaceAll("import com.iqser.red.service.redaction.v1.server.model.document.nodes.TableCell;", ""); + rulesString = rulesString.replaceAll("rule \"LDS.0.0: Run local dictionary search\"", "rule \"LDS.0.0: run local dictionary search\""); + DroolsSyntaxValidation droolsSyntaxValidation = droolsSyntaxValidationService.testRules(new RuleValidationModel(RuleFileType.ENTITY.name(), rulesString)); + droolsSyntaxValidation.getDroolsSyntaxErrorMessages().forEach(System.out::println); + assertTrue(droolsSyntaxValidation.isCompiled()); + } + + @Test @SneakyThrows void testAllRules() { @@ -156,7 +172,8 @@ class DroolsSyntaxValidationServiceTest { var rulesFile = new ClassPathResource("drools/rules.drl"); String rulesString = new String(rulesFile.getInputStream().readAllBytes()); - String corruptedRules = rulesString.replaceAll("import com.iqser.red.service.redaction.v1.server.model.document.nodes.ImageType;", ""); + String corruptedRules = rulesString.replaceAll("import com.iqser.red.service.redaction.v1.server.model.document.nodes.ImageType;", + "import com.iqser.red.service.redaction.v1.server.model.document.nodes.ImageType;\nimport com.iqser.red.service.redaction.v1.server.model.document.nodes.SomethingElse;"); DroolsSyntaxValidation droolsSyntaxValidation = droolsSyntaxValidationService.testRules(new RuleValidationModel(RuleFileType.ENTITY.name(), corruptedRules)); assertFalse(droolsSyntaxValidation.isCompiled());