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 index 32544d24d5cf05deaa61edd7b5bd8848030fb9f4..c879d4d30ec512bfe2c5b5400b940360a996456a 100644 --- 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 @@ -1,5 +1,21 @@ 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; @@ -9,6 +25,62 @@ public class MissingInputValueVerifier extends AbstractVerifier { @Override protected void doVerification() { - // TODO + 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/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); } }); }