diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/domain/Name.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/domain/Name.java index 6cbfb2b541a40f8069710598d0e571b2f1bf5f1a..623eca4eda67b26d6b40e8a53e4e64c07c80441f 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/domain/Name.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/domain/Name.java @@ -7,6 +7,7 @@ import de.unikoblenz.fgbks.base.value.AbstractStringValueObject; */ public class Name extends AbstractStringValueObject { + public static final Name NO_NAME = new Name("[no name]"); /** Create a new copy of the given name object. */ public Name(Name initialValue) { this(initialValue.getValue()); diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/AbstractVDmnElement.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/AbstractVDmnElement.java index 25cdced13235b4cc8f11faeb82d6997de3eddd68..7ea73aa2368f6ac030938d276fe1e9be133056b8 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/AbstractVDmnElement.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/AbstractVDmnElement.java @@ -2,6 +2,7 @@ package de.unikoblenz.fgbks.core.dmn.domain.vdmn.impl; import de.unikoblenz.fgbks.core.dmn.domain.ids.AbstractId; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnElement; +import java.util.Objects; /** * Implementation of {@link VDmnElement} @@ -14,4 +15,21 @@ public abstract class AbstractVDmnElement implements VDmnElement { public AbstractId getId() { return id; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AbstractVDmnElement that = (AbstractVDmnElement) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/utils/VDmnFunctions.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/utils/VDmnFunctions.java index 4c504b213a3cc6240488e210727c28f2abd4eb66..c83c7058e411c6c4d3e103807bc175981e12535f 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/utils/VDmnFunctions.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/utils/VDmnFunctions.java @@ -1,7 +1,9 @@ package de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils; +import de.unikoblenz.fgbks.base.domain.Name; import de.unikoblenz.fgbks.core.dmn.domain.ids.RuleId; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnColumn; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecision; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecisionTable; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDefinition; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnInputColumn; @@ -11,6 +13,7 @@ import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnRule; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnValue; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VTypeRef; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.lang3.Validate; @@ -20,6 +23,7 @@ import org.apache.commons.lang3.Validate; */ public class VDmnFunctions { + private VDmnFunctions() {} /** * Generate a list of {@link VDmnColumn}, which are in the {@link VDmnDefinition} and has the * defined type ({@link VTypeRef}). @@ -213,4 +217,66 @@ public class VDmnFunctions { } return clusters; } + + /** + * Get the name of a column as string. If a label is present, the string of the label is returned. + * If the label is not present, the name is returned. If the name is not present, "[no name]" is + * returned. + * + * @param column the {@link VDmnColumn} + * @return a string, representing the "name" of the column + */ + public static String getColumnStringName(VDmnColumn column) { + Validate.notNull(column); + return column.getLabel().isPresent() + ? column.getLabel().get().toString() + : column.getName().orElse(Name.NO_NAME).toString(); + } + + /** + * Get a string with all row numbers of the given list of {@link VDmnRule}. The rows are sorted. + * + * @param rules the collection of {@link VDmnRule} + * @return the string of (sorted) rows + */ + public static String getRulesRowsStrings(Collection<VDmnRule> rules) { + return Validate.notNull(rules).stream() + .map(r -> r.getRowNumber().toString()) + .sorted() + .collect(Collectors.joining(", ")); + } + + /** + * Get the String for a decision (for message text) + * + * @param decision the {@link VDmnDecision} + * @return a string "Decision %s: ' + */ + public static String templateDecision(VDmnDecision decision) { + return String.format("Decision \"%s\": ", decision.getName().orElse(Name.NO_NAME)); + } + + /** + * Get the String for a decision and a column (for message text) + * + * @param column the {@link VDmnColumn} + * @return a string "Decision %s, Column %s: ' + */ + public static String templateDecisionColumn(VDmnColumn column) { + return String.format( + "Decision \"%s\", Column \"%s\": ", + column.getDmnDecision().getName().orElse(Name.NO_NAME), getColumnStringName(column)); + } + + /** + * Get the String for a decision and a rule (for message text) + * + * @param rule the {@link VDmnRule} + * @return a string "Decision %s, Rule %s: ' + */ + public static String templateDecisionRule(VDmnRule rule) { + return String.format( + "Decision \"%s\", Rule \"%s\": ", + rule.getDmnDecision().getName().orElse(Name.NO_NAME), rule.getRowNumber()); + } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/result/VerificationResultEntryElement.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/result/VerificationResultEntryElement.java index cc2584f7dc011a6fcd2c6852a21e1b53be0686cd..c4bc41389848c39e5ac7c2d5b44baaf390f7bc7b 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/result/VerificationResultEntryElement.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/result/VerificationResultEntryElement.java @@ -7,6 +7,7 @@ import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecision; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecisionTable; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnInputData; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnNode; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnRule; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnValue; import java.util.HashMap; import java.util.Map; @@ -113,6 +114,22 @@ public class VerificationResultEntryElement extends AbstractResultObject { .withIdentifier(vDmnNode.getId()); } + /** + * Create a new {@link VerificationResultEntryElement} with the initial identifier from a {@link + * VDmnRule}. Call {@link VerificationResultEntryElement#withIdentifier(AbstractId)} to add + * further identifier. + * + * @param rule the {@link VDmnRule} + * @return the new {@link VerificationResultEntryElement} + */ + public static VerificationResultEntryElement create(VDmnRule rule) { + return new VerificationResultEntryElement() + .withIdentifier(rule.getDmnDefinition().getDefinitionId()) + .withIdentifier(rule.getDmnDecision().getDecisionId()) + .withIdentifier(rule.getDmnDecisionTable().getDecisionTableId()) + .withIdentifier(rule.getId()); + } + /** * Get all required ids ({@link AbstractId}) of the {@link VerificationResultEntryElement}. * diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/DateVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/DateVerifier.java index 1f63eb34f5094e2ba8bf4cbd346bd3f7d435bc2c..b87b250422018651b8126cdd4f49f129dc5e1bb5 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/DateVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/DateVerifier.java @@ -2,6 +2,7 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; import static de.unikoblenz.fgbks.base.utils.boundary.impl.DateBoundary.dateGroupName; import static de.unikoblenz.fgbks.base.utils.boundary.impl.DateBoundary.datePattern; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecisionRule; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_INPUT_ENTRIES; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_OUTPUT_ENTRIES; @@ -62,7 +63,8 @@ public class DateVerifier extends AbstractVerifier { vreFactory.addElement(VerificationResultEntryElement.create(dateValue)); vreFactory.addToEntry( VerificationClassification.FATAL_ERROR, - "Date value '%s' does not match 'date and time(\"yyyy-mm-ddTHH:MM:SS\").'", + templateDecisionRule(dateValue.getDmnRule()) + + "Date value '%s' does not match 'date and time(\"yyyy-mm-ddTHH:MM:SS\").'", dateStringValue); } else { // 2. check correct date @@ -74,7 +76,10 @@ public class DateVerifier extends AbstractVerifier { vreFactory.addVerificationFix( dateValue.isInputValue() ? SHOW_INPUT_ENTRIES : SHOW_OUTPUT_ENTRIES); vreFactory.addToEntry( - VerificationClassification.FATAL_ERROR, "Date value '%s' is no valid date.", dateTime); + VerificationClassification.FATAL_ERROR, + templateDecisionRule(dateValue.getDmnRule()) + + "Date value '%s' has no valid date format.", + dateTime); } } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/EmptyOutputVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/EmptyOutputVerifier.java index 5686a34fab8bc2a195f3dc09fbb7a4b4261efd7e..f81106aaf1795979f2bb0cd83ef7c63873b61379 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/EmptyOutputVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/EmptyOutputVerifier.java @@ -1,5 +1,6 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecisionRule; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_OUTPUT_ENTRIES; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnOutputColumn; @@ -32,7 +33,9 @@ public class EmptyOutputVerifier extends AbstractVerifier { if (outputValue.getText().getValue().isEmpty()) { vreFactory.addElement(VerificationResultEntryElement.create(outputValue)); vreFactory.addVerificationFix(SHOW_OUTPUT_ENTRIES); - vreFactory.addToEntry(VerificationClassification.WARNING, "Output value is empty.'"); + vreFactory.addToEntry( + VerificationClassification.WARNING, + templateDecisionRule(outputValue.getDmnRule()) + "Output value is empty.'"); } } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/EquivalentVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/EquivalentVerifier.java index e12a97e53c322eff4254c7c80e5cab61152a7d13..5e58ad5e1b9b3a2efe459bdfbbb912347459b8bf 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/EquivalentVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/EquivalentVerifier.java @@ -1,5 +1,6 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecisionColumn; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_INPUT_ENTRIES; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_OUTPUT_ENTRIES; @@ -74,9 +75,12 @@ public class EquivalentVerifier extends AbstractVerifier { v1.isInputValue() ? SHOW_INPUT_ENTRIES : SHOW_OUTPUT_ENTRIES); vreFactory.addToEntry( VerificationClassification.WARNING, - "String values %s and %s might be equivalent.", + templateDecisionColumn(v1.getDmnColumn()) + + "String values \"%s\" (Row %s) and \"%s\" (Row %s) might be equivalent.", stringVals.get(i), - stringValsInner.get(u)); + v1.getDmnRule().getRowNumber().toString(), + stringValsInner.get(u), + v2.getDmnRule().getRowNumber().toString()); } } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/IdenticalVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/IdenticalVerifier.java index f7b0eb9f928e197c0a4d471bafab75066157b1ab..1f4a0a6ec70bb022bf5de50dd26c483ed1fa4e8e 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/IdenticalVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/IdenticalVerifier.java @@ -1,6 +1,8 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; import static de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType.IS_EQUAL; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.getRulesRowsStrings; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecision; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_RULES; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecision; @@ -44,10 +46,13 @@ public class IdenticalVerifier extends AbstractVerifier { currentRules.forEach( rule -> vreFactory.addElement( - VerificationResultEntryElement.create(dmnDecisionTable) - .withIdentifier(rule.getRuleId()))); + VerificationResultEntryElement.create(rule))); vreFactory.addVerificationFix(SHOW_RULES); - vreFactory.addToEntry(VerificationClassification.WARNING, "identical"); + vreFactory.addToEntry( + VerificationClassification.WARNING, + templateDecision(dmnDecisionTable.getDmnDecision()) + + "Rules %s have identical input.", + getRulesRowsStrings(currentRules)); } else { List<VDmnInputValue> curInVals = new ArrayList<>(); List<VDmnInputValue> sortInVals = diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/InputValueSyntaxVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/InputValueSyntaxVerifier.java index 86f11f89cc0a0d67b4d93f25b7dbeb125743af63..547b1fda38040f68784c97d232dc8f88734e0444 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/InputValueSyntaxVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/InputValueSyntaxVerifier.java @@ -1,5 +1,6 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecisionRule; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_INPUT_ENTRIES; import de.unikoblenz.fgbks.base.utils.boundary.impl.InvalidBoundary; @@ -33,7 +34,9 @@ public class InputValueSyntaxVerifier extends AbstractVerifier { .addVerificationFix(SHOW_INPUT_ENTRIES) .addToEntry( VerificationClassification.FATAL_ERROR, - "Input value is not valid: " + inputValue.getText()); + templateDecisionRule(inputValue.getDmnRule()) + + "Input value is not valid: " + + inputValue.getText()); System.out.println(inputValue.getText() + " IS INVALID SYNTAX"); } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputColumnVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputColumnVerifier.java index 803c72554456ecb4a33bd6c0632d2c4f82a831bd..9d99c39a54be0608103bc382a2ddb246f7ef3162 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputColumnVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputColumnVerifier.java @@ -22,8 +22,6 @@ import java.util.stream.Collectors; @DmnVerifier(verifierType = MissingInputColumnVerification.class) public class MissingInputColumnVerifier extends AbstractVerifier { - private Name defaultName = new Name("[no name]"); - @Override protected void doVerification() { // 1. check for input data nodes @@ -70,9 +68,12 @@ public class MissingInputColumnVerifier extends AbstractVerifier { .build()) .addToEntry( VerificationClassification.WARNING, - "Node \"%s\" has no corresponding input column in decision \"%s\"", - inputDataNode.getName().orElse(defaultName), - decision.getName().orElse(defaultName)); + inputDataNode.isInputData() + ? "Input data" + : "Decision" + + " node \"%s\" has no corresponding input column in decision \"%s\"", + inputDataNode.getName().orElse(Name.NO_NAME), + decision.getName().orElse(Name.NO_NAME)); } } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputDataVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputDataVerifier.java index d498c3e3f456ab9f4ab7f91761520cbda29fe6c5..4e0da173b9b3325918a612cb03dfd857b4c5de62 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputDataVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputDataVerifier.java @@ -1,5 +1,7 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.getColumnStringName; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecision; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_INPUT_COLUMNS; import de.unikoblenz.fgbks.base.domain.Name; @@ -54,18 +56,13 @@ public class MissingInputDataVerifier extends AbstractVerifier { } } // no input data found yet -> add column to results - String label = ""; - if (inputColumn.getLabel().isPresent()) { - label = inputColumn.getLabel().get().getValue(); - } else if (inputColumn.getName().isPresent()) { - label = inputColumn.getName().get().getValue(); - } else { - label = "no name"; - } vreFactory .addElement(VerificationResultEntryElement.create(inputColumn)) .addVerificationFix(SHOW_INPUT_COLUMNS) .addToEntry( - VerificationClassification.WARNING, "Input column \"%s\" has no input data.", label); + VerificationClassification.WARNING, + templateDecision(inputColumn.getDmnDecision()) + + "Input column \"%s\" has no input data node.", + getColumnStringName(inputColumn)); } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingRuleVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingRuleVerifier.java index ae0c4346e2810025579eec6aa47aa7f1dff95633..3dbce41afc6d92fa22f8b8c2ab0b9f1b7ce5040a 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingRuleVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingRuleVerifier.java @@ -1,5 +1,7 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecision; + import de.unikoblenz.fgbks.base.utils.boundary.Boundary; import de.unikoblenz.fgbks.base.utils.boundary.bicreater.BoundaryBiCreaterType; import de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType; @@ -45,14 +47,14 @@ public class MissingRuleVerifier extends AbstractVerifier { checkForMissingRules(inputs, dmnDecisionTable.getRules()); // add errors for missing intervals for (VDmnRule missingRule : missingRules) { - StringBuilder sb = new StringBuilder("In table "); - sb.append(dmnDecisionTable.getDecisionTableId()); // TODO: add real name - sb.append(", the following rule is not defined: ("); + StringBuilder sb = new StringBuilder(); + sb.append(templateDecision(dmnDecisionTable.getDmnDecision())); + sb.append("The following rule is not defined: {"); sb.append( missingRule.getDmnInputValues().stream() .map(v -> v.getBoundary().getParsedText()) .collect(Collectors.joining("), ("))); - sb.append(")"); + sb.append("}"); vreFactory.addElement(VerificationResultEntryElement.create(dmnDecisionTable)); vreFactory.addToEntry(VerificationClassification.WARNING, sb.toString()); diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/OverlappingVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/OverlappingVerifier.java index 8ba2baa8ad8b01411e3f4ad843bed7bd4d300b83..4c308bd808a7b61a166b7bcd98a3762a6f03071f 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/OverlappingVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/OverlappingVerifier.java @@ -3,6 +3,7 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; import static de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType.IS_NOT_IN_CONTACT; import static de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType.IS_OVERLAPPING; import static de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType.SUBSUMES; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.getRulesRowsStrings; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_RULES; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecision; @@ -45,7 +46,7 @@ public class OverlappingVerifier extends AbstractVerifier { private void checkOverlapping( List<VDmnInputColumn> inColumns, int i, - List<VDmnRule> currentRuleIds, + List<VDmnRule> currentRules, boolean hasOverlap, List<VDmnRule> subsumptionRules) { // no more columns to check @@ -53,19 +54,20 @@ public class OverlappingVerifier extends AbstractVerifier { // do nothing, if there was no real overlap found prev.. if (hasOverlap) { // add to rules to result - currentRuleIds.forEach( - rule -> - vreFactory.addElement( - VerificationResultEntryElement.create(inColumns.get(0).getDmnDecisionTable()) - .withIdentifier(rule.getRuleId()))); + currentRules.forEach( + rule -> vreFactory.addElement(VerificationResultEntryElement.create(rule))); vreFactory.addVerificationFix(SHOW_RULES); - vreFactory.addToEntry(VerificationClassification.WARNING, "overlapping"); + vreFactory.addToEntry( + VerificationClassification.WARNING, + VDmnFunctions.templateDecision(inColumns.get(0).getDmnDecision()) + + "The rules %s are overlapping.", + getRulesRowsStrings(currentRules)); } } else { // check current column List<VDmnInputValue> currentBounds = new ArrayList<>(); List<VDmnInputValue> sortedBounds = - VDmnFunctions.getColumnValuesInRules(inColumns.get(i), currentRuleIds); + VDmnFunctions.getColumnValuesInRules(inColumns.get(i), currentRules); sortedBounds.sort(Comparator.comparing(VDmnInputValue::getBoundary)); int z = 0; boolean foundPOverlap = false; diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PartialReductionVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PartialReductionVerifier.java index 38aca480857e44095531b9f35087c071b6c960ea..567a033ceb4ecf9c75f75517c5e8303cd0236ebe 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PartialReductionVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PartialReductionVerifier.java @@ -2,6 +2,8 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; import static de.unikoblenz.fgbks.base.utils.boundary.bicreater.BoundaryBiCreaterType.COMBINE; import static de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType.IS_EQUAL; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.getRulesRowsStrings; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecision; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_RULES; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecision; @@ -40,12 +42,12 @@ public class PartialReductionVerifier extends AbstractVerifier { if (i == inColumns.size()) { if (hasCombination) { clusterRules.forEach( - rule -> - vreFactory.addElement( - VerificationResultEntryElement.create(inColumns.get(0).getDmnDecisionTable()) - .withIdentifier(rule.getRuleId()))); + rule -> vreFactory.addElement(VerificationResultEntryElement.create(rule))); vreFactory.addVerificationFix(SHOW_RULES); - vreFactory.addToEntry(VerificationClassification.INFO, "PartialReduction"); + vreFactory.addToEntry( + VerificationClassification.INFO, + templateDecision(inColumns.get(0).getDmnDecision()) + "Rules %s can be combined.", + getRulesRowsStrings(clusterRules)); } } else { List<VDmnInputValue> rules = diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PredefinedExistingValueVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PredefinedExistingValueVerifier.java index aef754da4061b7c77d9b3b3b8cba51c7c5476ed2..a810a9e68c804c4387ab33629266a86c54578e74 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PredefinedExistingValueVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PredefinedExistingValueVerifier.java @@ -1,5 +1,6 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecisionColumn; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_INPUT_ENTRIES; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_OUTPUT_ENTRIES; @@ -80,7 +81,8 @@ public class PredefinedExistingValueVerifier extends AbstractVerifier { stringValue.isInputValue() ? SHOW_INPUT_ENTRIES : SHOW_OUTPUT_ENTRIES); vreFactory.addToEntry( VerificationClassification.WARNING, - "String value \"%s\" was not found in the list of predefined values.", + templateDecisionColumn(stringValue.getDmnColumn()) + + "String value \"%s\" was not found in the list of predefined values.", missingStringValue); } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PredefinedMissingValueVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PredefinedMissingValueVerifier.java index 4dc9443b15073f6e7dc0b6f80e54c47266b773ee..b9f0f452cc319e2b4d03c5cfab546c81248ea153 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PredefinedMissingValueVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/PredefinedMissingValueVerifier.java @@ -58,8 +58,8 @@ public class PredefinedMissingValueVerifier extends AbstractVerifier { } // get all missing strings Set<String> missingStrings = new HashSet<>(); - for (String s : stringValuesInColumn) { - if (!predefinedValues.contains(s)) { + for (String s : predefinedValues) { + if (!stringValuesInColumn.contains(s)) { missingStrings.add(s); } } @@ -86,8 +86,9 @@ public class PredefinedMissingValueVerifier extends AbstractVerifier { vreFactory.addVerificationFix( stringColumn.isInputColumn() ? SHOW_INPUT_COLUMNS : SHOW_OUTPUT_COLUMNS); StringBuilder sb = new StringBuilder(); + sb.append(VDmnFunctions.templateDecisionColumn(stringColumn)); sb.append(missingStringValues.size() > 1 ? "These string values are" : "This string value is"); - sb.append(" not present in the predefined values of the column: "); + sb.append(" not used: "); sb.append( missingStringValues.stream().map(v -> '"' + v + '"').collect(Collectors.joining(","))); vreFactory.addToEntry(VerificationClassification.WARNING, sb.toString()); diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/SubsumptionVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/SubsumptionVerifier.java index 7c42d67af52464fd9bb4a10e7a0f8ed77b2fd566..fe62a425a134a5910eaaefd605dbbbfe2d677d4a 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/SubsumptionVerifier.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/SubsumptionVerifier.java @@ -2,6 +2,8 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; import static de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType.IS_EQUAL; import static de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType.SUBSUMES; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.getRulesRowsStrings; +import static de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions.templateDecision; import static de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix.SHOW_RULES; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecision; @@ -43,25 +45,29 @@ public class SubsumptionVerifier extends AbstractVerifier { private void checkSubsumptions( List<VDmnInputColumn> inColumns, int i, - List<VDmnRule> currentRuleIds, + List<VDmnRule> currentRules, boolean hasSubsumption, List<VDmnRule> currentRootSubsumptionElements) { if (i == inColumns.size()) { - if (hasSubsumption && currentRuleIds.size() > currentRootSubsumptionElements.size()) { + if (hasSubsumption && currentRules.size() > currentRootSubsumptionElements.size()) { // add to rules to result - // TODO - currentRuleIds.forEach( + boolean differentConclusions = VDmnFunctions.differentConclusions(currentRules); + currentRules.forEach( rule -> vreFactory.addElement( VerificationResultEntryElement.create(inColumns.get(0).getDmnDecisionTable()) .withIdentifier(rule.getRuleId()))); vreFactory.addVerificationFix(SHOW_RULES); - vreFactory.addToEntry(VerificationClassification.WARNING, "subsumption"); + vreFactory.addToEntry( + VerificationClassification.WARNING, + templateDecision(inColumns.get(0).getDmnDecision()) + + getMessageText( + currentRules, currentRootSubsumptionElements, differentConclusions)); } } else { // get all input values from the current column, and filter with the prev. iteration List<VDmnInputValue> selectedBounds = - VDmnFunctions.getColumnValuesInRules(inColumns.get(i), currentRuleIds); + VDmnFunctions.getColumnValuesInRules(inColumns.get(i), currentRules); List<List<VDmnInputValue>> clusters = new ArrayList<>(); // clusters of subsumptions List<Boolean> subsumptions = @@ -69,7 +75,7 @@ public class SubsumptionVerifier extends AbstractVerifier { List<List<VDmnInputValue>> subsumptionValue = new ArrayList<>(); // save the subsumption value of the current cluster // if previously a rule was found, which has a subsumption, than it must be also the element, - // which subsume the other elements. + // which subsumes the other elements. // First, build clusters, which contain a subsumption set if (!currentRootSubsumptionElements.isEmpty()) { // get the value from the subsumption rule @@ -85,7 +91,7 @@ public class SubsumptionVerifier extends AbstractVerifier { c1.add(cb2); } else if (nValue.getBoundary().checkWith(IS_EQUAL, cb2.getBoundary())) { c1.add(cb2); - if (currentRootSubsumptionElements.contains(cb2)) { + if (currentRootSubsumptionElements.contains(cb2.getDmnRule())) { subsumptionVals.add(cb2); } } @@ -166,4 +172,47 @@ public class SubsumptionVerifier extends AbstractVerifier { } } } + + private String getMessageText( + List<VDmnRule> currentRules, + List<VDmnRule> currentRootSubsumptionElements, + boolean differentConclusions) { + StringBuilder sb = new StringBuilder(); + sb.append(templateDecision(currentRules.get(0).getDmnDecision())); + sb.append("Rule"); + if (currentRootSubsumptionElements.size() > 1) { + sb.append("s"); + } + sb.append(" "); + sb.append(getRulesRowsStrings(currentRootSubsumptionElements)); + if (currentRootSubsumptionElements.size() > 1) { + sb.append("subsume"); // Plural + } else { + sb.append(" subsumes"); + } + // subsumed rules: + List<VDmnRule> subsumedRules = + currentRules.stream() + .filter( + r -> + !currentRootSubsumptionElements.stream() + .map(VDmnRule::getRuleId) + .collect(Collectors.toList()) + .contains(r.getRuleId())) + .collect(Collectors.toList()); + + sb.append(" rule"); + if (subsumedRules.size() > 1) { + sb.append("s"); + } + sb.append(" "); + sb.append(getRulesRowsStrings(subsumedRules)); + sb.append("."); + if (differentConclusions) { + sb.append(" The outputs have different conclusions!"); + } else { + sb.append(" The output is the same."); + } + return sb.toString(); + } }