diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputValueVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputValueVerifier.java new file mode 100644 index 0000000000000000000000000000000000000000..c879d4d30ec512bfe2c5b5400b940360a996456a --- /dev/null +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputValueVerifier.java @@ -0,0 +1,86 @@ +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.DEFAULT_SHOW_NAME; + +import de.unikoblenz.fgbks.base.utils.boundary.Boundary; +import de.unikoblenz.fgbks.base.utils.boundary.checker.BoundaryCheckType; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnDecision; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnInputColumn; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnInputValue; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnOutputColumn; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnOutputValue; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VTypeRef; +import de.unikoblenz.fgbks.core.dmn.verification.result.VerificationResultEntry.VerificationClassification; +import de.unikoblenz.fgbks.core.dmn.verification.result.VerificationResultEntryElement; +import de.unikoblenz.fgbks.core.dmn.verification.result.actions.Action; +import de.unikoblenz.fgbks.core.dmn.verification.result.actions.VerificationFix; +import de.unikoblenz.fgbks.core.dmn.verification.verifier.AbstractVerifier; +import de.unikoblenz.fgbks.core.dmn.verification.verifier.DmnVerifier; +import de.unikoblenz.fgbks.core.dmn.verification.verifier.types.MissingInputValueVerification; + +@DmnVerifier(verifierType = MissingInputValueVerification.class) +public class MissingInputValueVerifier extends AbstractVerifier { + + @Override + protected void doVerification() { + for (VDmnDecision decision : dmnObjectContainer.getVDmnDefinition().getDmnDecisions()) { + for (VDmnDecision nextDecision : decision.getInformationProvidingDecisions()) { + checkMissingInputValues(decision, nextDecision); + } + } + } + + private void checkMissingInputValues(VDmnDecision decision, VDmnDecision nextDecision) { + // find the matching output -> input column + for (VDmnOutputColumn outputColumn : decision.getDmnDecisionTable().getOutputColumns()) { + for (VDmnInputColumn inputColumn : nextDecision.getDmnDecisionTable().getInputColumns()) { + if (outputColumn.getName().isPresent() + && inputColumn.getName().isPresent() + && outputColumn.getName().get().equals(inputColumn.getName().get()) + && outputColumn.getTypeRef().equals(inputColumn.getTypeRef())) { + checkMissingInputValues(outputColumn, inputColumn); + } + } + } + } + + private void checkMissingInputValues(VDmnOutputColumn outputColumn, VDmnInputColumn inputColumn) { + // check for each value on outputColumn, if it is used in the inputColumn + outer: + for (VDmnOutputValue outputValue : outputColumn.getDmnOutputValues()) { + if (!outputValue.getText().getValue().isEmpty()) { + // create pseudo boundary for output value + String outputText = outputValue.getText().getValue(); + if (outputColumn.getTypeRef() == VTypeRef.DOUBLE + || outputColumn.getTypeRef() == VTypeRef.INTEGER + || outputColumn.getTypeRef() == VTypeRef.LONG) { + outputText = "= " + outputText; + } + Boundary b = outputColumn.getTypeRef().getBoundaryFromText(outputText); + for (VDmnInputValue inputValue : inputColumn.getInputValues()) { + if (b.checkWith(BoundaryCheckType.IS_IN_CONTACT, inputValue.getBoundary())) { + continue outer; + } + } + // no matching input value found for current output Value + vreFactory + .addElement(VerificationResultEntryElement.create(inputColumn)) + .addElement(VerificationResultEntryElement.create(outputValue)) + .addVerificationFix( + VerificationFix.getBuilder() + .withFixName(DEFAULT_SHOW_NAME) + .addAction(Action.ACTION_SHOW_OUTPUT_ENTRIES) + .addAction(Action.ACTION_SHOW_INPUT_COLUMNS) + .build()) + .addToEntry( + VerificationClassification.WARNING, + templateDecision(inputColumn.getDmnDecision()) + + "Input column \"%s\" never handles the value '%s'.", + getColumnStringName(inputColumn), + outputValue.getText().getValue()); + } + } + } +} diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingOutputValueVerifier.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingOutputValueVerifier.java new file mode 100644 index 0000000000000000000000000000000000000000..6d894cebd84696491eaea15438417f86e283cb47 --- /dev/null +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingOutputValueVerifier.java @@ -0,0 +1,14 @@ +package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; + +import de.unikoblenz.fgbks.core.dmn.verification.verifier.AbstractVerifier; +import de.unikoblenz.fgbks.core.dmn.verification.verifier.DmnVerifier; +import de.unikoblenz.fgbks.core.dmn.verification.verifier.types.MissingOutputValueVerification; + +@DmnVerifier(verifierType = MissingOutputValueVerification.class) +public class MissingOutputValueVerifier extends AbstractVerifier { + + @Override + protected void doVerification() { + // TODO + } +} diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/types/MissingInputValueVerification.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/types/MissingInputValueVerification.java new file mode 100644 index 0000000000000000000000000000000000000000..5d9a4f2f24a47179237a097d5d510e75bea46e39 --- /dev/null +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/types/MissingInputValueVerification.java @@ -0,0 +1,31 @@ +package de.unikoblenz.fgbks.core.dmn.verification.verifier.types; + +import de.unikoblenz.fgbks.base.domain.Description; +import de.unikoblenz.fgbks.base.domain.Name; +import de.unikoblenz.fgbks.core.dmn.verification.verifier.classification.ClassificationType; +import de.unikoblenz.fgbks.core.dmn.verification.verifier.classification.ModelingLevelVerification; +import javax.validation.constraints.NotNull; + +@Type +public class MissingInputValueVerification extends AbstractVerificationType { + + private static final MissingInputValueVerification instance = new MissingInputValueVerification(); + + private MissingInputValueVerification() { + super( + new Name("MissingInputValueVerification"), + new Name("Missing Input Value"), + new Description( + "Detecting output values of output columns in decision tables" + + " which are not used in the connected decision table as input values.")); + } + + public static MissingInputValueVerification getInstance() { + return instance; + } + + @Override + public @NotNull ClassificationType getClassification() { + return ModelingLevelVerification.getInstance(); + } +} diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/types/MissingOutputValueVerification.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/types/MissingOutputValueVerification.java new file mode 100644 index 0000000000000000000000000000000000000000..2025887459589c88387b16e7ac4fcafe6ce6c9b7 --- /dev/null +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/types/MissingOutputValueVerification.java @@ -0,0 +1,31 @@ +package de.unikoblenz.fgbks.core.dmn.verification.verifier.types; + +import de.unikoblenz.fgbks.base.domain.Description; +import de.unikoblenz.fgbks.base.domain.Name; +import de.unikoblenz.fgbks.core.dmn.verification.verifier.classification.ClassificationType; +import de.unikoblenz.fgbks.core.dmn.verification.verifier.classification.ModelingLevelVerification; +import javax.validation.constraints.NotNull; + +@Type +public class MissingOutputValueVerification extends AbstractVerificationType { + + private static final MissingOutputValueVerification instance = new MissingOutputValueVerification(); + + private MissingOutputValueVerification() { + super( + new Name("MissingOutputValueVerification"), + new Name("Missing Output Value"), + new Description( + "Detecting input values of input columns in decision tables " + + "which are not defined in the connected decision table as output values.")); + } + + public static MissingOutputValueVerification getInstance() { + return instance; + } + + @Override + public @NotNull ClassificationType getClassification() { + return ModelingLevelVerification.getInstance(); + } +} diff --git a/dmnverifierapi/verifier.md b/dmnverifierapi/verifier.md index f59d9942297570a3875d5ac33183c0d875007cc6..3f7421d57a0ef37a7e8619ab72a83084f281bb44 100644 --- a/dmnverifierapi/verifier.md +++ b/dmnverifierapi/verifier.md @@ -91,6 +91,30 @@ Detecting predefined string values of a column, which itself are not used in the TODO ``` +### Missing Input Value Verification +- Type: [MissingInputValueVerification](src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/types/MissingInputValueVerification.java) +- Verifier: [MissingInputValueVerifier](src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingInputValueVerifier.java) + +#### Description +Detecting output values of output columns in decision tables which are not used in the connected decision table as input values. + +#### Algorithm +``` +TODO +``` + +### Missing Output Value Verification +- Type: [MissingOutputValueVerification](src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/types/MissingOutputValueVerification.java) +- Verifier: [MissingOutputValueVerifier](src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/MissingOutputValueVerifier.java) + +#### Description +Detecting input values of input columns in decision tables which are not defined in the connected decision table as output values. + +#### Algorithm +``` +TODO +``` + ### Empty Output Verification - Type: [EmptyOutputVerification](/src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/types/EmptyOutputVerification.java) - Verifier: [EmptyOutputVerifier](src/main/java/de/unikoblenz/fgbks/core/dmn/verification/verifier/impl/EmptyOutputVerifier.java) diff --git a/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnVerifierActions.js b/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnVerifierActions.js index 757065377b627a10ce23ff5480a1cd1755ce28e6..a0ad8640a987f09bf01ee50549762131d01a0589 100644 --- a/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnVerifierActions.js +++ b/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnVerifierActions.js @@ -124,7 +124,7 @@ function fixSHOW_OUTPUT_COLUMN(verificationEntry, fixAction) { * @param {Action} fixAction */ function fixSHOW_DECISION_TABLE(verificationEntry, fixAction) { - highlightDecision(verificationEntry.elements); + highlightDecisions(verificationEntry.elements); } /** @@ -133,5 +133,5 @@ function fixSHOW_DECISION_TABLE(verificationEntry, fixAction) { * @param {Action} fixAction */ function fixSHOW_DECISION(verificationEntry, fixAction) { - highlightDecision(verificationEntry.elements); + highlightDecisions(verificationEntry.elements); } diff --git a/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnViewer.js b/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnViewer.js index b40ca4a69168be6b46cd19a141344da36a7bb5a0..7ab3c8d3c88f21c70f95ca86e438cfe53d87d950 100644 --- a/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnViewer.js +++ b/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnViewer.js @@ -131,6 +131,12 @@ function cleanHighlightFunction() { renderHighlightFunction = []; } +function highlightMultipleDecisions(elements) { + elements.forEach(function (el) { + highlightSingleDecision(el.identifier['decisionId']); + }); +} + function highlightSingleDecision(decisionId) { // node let $decisionNode = $( @@ -140,6 +146,12 @@ function highlightSingleDecision(decisionId) { $('#tab-dec-' + decisionId).addClass('highlight'); } +function cleanMultipleDecisions(elements) { + elements.forEach(function (el) { + cleanSingleDecision(el.identifier['decisionId']); + }); +} + function cleanSingleDecision(decisionId) { // node let $decisionNode = $( @@ -156,14 +168,14 @@ function cleanSingleDecision(decisionId) { function highlightRules(elements) { renderHighlightFunction.push({ highlight: function () { - highlightSingleDecision(elements[0].identifier['decisionId']); + highlightMultipleDecisions(elements); elements.forEach(function (el) { $('[data-row-id=' + el.identifier['ruleId'] + ']').addClass( 'highlight'); }); }, clean: function () { - cleanSingleDecision(elements[0].identifier['decisionId']); + cleanMultipleDecisions(elements); elements.forEach(function (el) { $('[data-row-id=' + el.identifier['ruleId'] + ']').removeClass( 'highlight'); @@ -180,14 +192,14 @@ function highlightRules(elements) { function highlightColumns(elements, identifier) { renderHighlightFunction.push({ highlight: function () { - highlightSingleDecision(elements[0].identifier['decisionId']); + highlightMultipleDecisions(elements); elements.forEach(function (el) { $('[data-col-id=' + el.identifier[identifier] + ']').addClass( 'highlight'); }); }, clean: function () { - cleanSingleDecision(elements[0].identifier['decisionId']); + cleanMultipleDecisions(elements); elements.forEach(function (el) { $('[data-col-id=' + el.identifier[identifier] + ']').removeClass( 'highlight'); @@ -204,14 +216,14 @@ function highlightColumns(elements, identifier) { function highlightDataEntries(elements, identifier) { renderHighlightFunction.push({ highlight: function () { - highlightSingleDecision(elements[0].identifier['decisionId']); + highlightMultipleDecisions(elements); elements.forEach(function (el) { $('[data-element-id=' + el.identifier[identifier] + ']').addClass( 'highlight'); }); }, clean: function () { - cleanSingleDecision(elements[0].identifier['decisionId']); + cleanMultipleDecisions(elements); elements.forEach(function (el) { $('[data-element-id=' + el.identifier[identifier] + ']').removeClass( 'highlight'); @@ -245,18 +257,14 @@ function highlightInputData(elements) { * * @param {Array<VerificationEntryElement>}elements */ -function highlightDecision(elements) { +function highlightDecisions(elements) { console.log(elements); renderHighlightFunction.push({ highlight: function () { - elements.forEach(function (el) { - highlightSingleDecision(el.identifier['decisionId']); - }); + highlightMultipleDecisions(elements) }, clean: function () { - elements.forEach(function (el) { - cleanSingleDecision(el.identifier['decisionId']); - }); + cleanMultipleDecisions(elements); } }); }