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 bbee2a33c0fe9981101a4dd759162ab45933b76f..62a39f3722dd1b65a16a2e462cbe048dfe820672 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,22 +2,18 @@ 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.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.base.domain.Name; -import de.unikoblenz.fgbks.core.dmn.domain.common.RowNumber; -import de.unikoblenz.fgbks.core.dmn.domain.ids.InputEntryId; -import de.unikoblenz.fgbks.core.dmn.domain.ids.RuleId; +import de.unikoblenz.fgbks.base.utils.boundary.Boundary; 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.VDmnInputColumn; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnInputValue; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnRule; -import de.unikoblenz.fgbks.core.dmn.domain.vdmn.impl.VDmnInputValueImpl; -import de.unikoblenz.fgbks.core.dmn.domain.vdmn.impl.VDmnRuleChangeableImpl; -import de.unikoblenz.fgbks.core.dmn.domain.vdmn.impl.VDmnRuleImpl; import de.unikoblenz.fgbks.core.dmn.domain.vdmn.utils.VDmnFunctions; import de.unikoblenz.fgbks.core.dmn.verification.result.VerificationResultEntry.VerificationClassification; import de.unikoblenz.fgbks.core.dmn.verification.result.VerificationResultEntryElement; @@ -45,11 +41,15 @@ public class PartialReductionVerifier extends AbstractVerifier { List<List<VDmnRule>> identicalOutputCluster = VDmnFunctions.getRuleClustersWithIdenticalOutput(dmnDecisionTable); List<VDmnInputColumn> inColumns = dmnDecisionTable.getInputColumns(); - identicalOutputCluster.forEach(c -> findPartialReduction(inColumns, 0, c, false)); + identicalOutputCluster.forEach(c -> findPartialReduction(inColumns, 0, c, false, null)); } private void findPartialReduction( - List<VDmnInputColumn> inColumns, int i, List<VDmnRule> clusterRules, boolean hasCombination) { + List<VDmnInputColumn> inColumns, + int i, + List<VDmnRule> clusterRules, + boolean hasCombination, + VDmnRule subsumptionRule) { if (i == inColumns.size()) { if (hasCombination) { createCombinedRule(inColumns, clusterRules); @@ -60,7 +60,6 @@ public class PartialReductionVerifier extends AbstractVerifier { VerificationClassification.INFO, templateDecision(inColumns.get(0).getDmnDecision()) + "Rules %s can be combined.", getRulesRowsStrings(clusterRules)); - } } else { List<VDmnInputValue> rules = @@ -68,33 +67,61 @@ public class PartialReductionVerifier extends AbstractVerifier { List<List<VDmnRule>> nClusters = new ArrayList<>(); List<Boolean> combinationCluster = new ArrayList<>(); for (int i1 = 0; i1 < rules.size(); i1++) { - VDmnInputValue currentRule = rules.get(i1); - // 1. Find combinations - if (!hasCombination) { - for (int i2 = i1 + 1; i2 < rules.size(); i2++) { - VDmnInputValue currentRuleInner = rules.get(i2); - if (currentRule != currentRuleInner) { - if (currentRule + VDmnInputValue currentRuleValue = rules.get(i1); + for (int i2 = i1 + 1; i2 < rules.size(); i2++) { + VDmnInputValue currentRuleValueInner = rules.get(i2); + if (currentRuleValue != currentRuleValueInner) { + boolean found = false; + // 1. Is subsumption? + if (currentRuleValue + .getBoundary() + .checkWith(SUBSUMES, currentRuleValueInner.getBoundary())) { + if (subsumptionRule == null || subsumptionRule == currentRuleValue.getDmnRule()) { + subsumptionRule = currentRuleValue.getDmnRule(); + found = true; + List<VDmnRule> cluster = new ArrayList<>(); + cluster.add(currentRuleValue.getDmnRule()); + cluster.add(currentRuleValueInner.getDmnRule()); + nClusters.add(cluster); + combinationCluster.add(true); + } + } + if (currentRuleValueInner + .getBoundary() + .checkWith(SUBSUMES, currentRuleValue.getBoundary())) { + if (subsumptionRule == null + || subsumptionRule == currentRuleValueInner.getDmnRule()) { + subsumptionRule = currentRuleValueInner.getDmnRule(); + found = true; + List<VDmnRule> cluster = new ArrayList<>(); + cluster.add(currentRuleValue.getDmnRule()); + cluster.add(currentRuleValueInner.getDmnRule()); + nClusters.add(cluster); + combinationCluster.add(true); + } + } + // 2. Find other combinations (only of no real combination + if (!found && !hasCombination) { + if (currentRuleValue .getBoundary() - .createBi(COMBINE, currentRuleInner.getBoundary()) + .createBi(COMBINE, currentRuleValueInner.getBoundary()) .isPresent()) { + found = true; List<VDmnRule> cluster = new ArrayList<>(); - cluster.add(currentRule.getDmnRule()); - cluster.add(currentRuleInner.getDmnRule()); + cluster.add(currentRuleValue.getDmnRule()); + cluster.add(currentRuleValueInner.getDmnRule()); nClusters.add(cluster); combinationCluster.add(true); } } - } - } - // 2. Find equal values - for (int i2 = i1 + 1; i2 < rules.size(); i2++) { - VDmnInputValue currentRuleInner = rules.get(i2); - if (currentRule != currentRuleInner) { - if (currentRule.getBoundary().checkWith(IS_EQUAL, currentRuleInner.getBoundary())) { + // 2. Find equal + if (!found + && currentRuleValue + .getBoundary() + .checkWith(IS_EQUAL, currentRuleValueInner.getBoundary())) { List<VDmnRule> cluster = new ArrayList<>(); - cluster.add(currentRule.getDmnRule()); - cluster.add(currentRuleInner.getDmnRule()); + cluster.add(currentRuleValue.getDmnRule()); + cluster.add(currentRuleValueInner.getDmnRule()); nClusters.add(cluster); combinationCluster.add(false); } @@ -105,7 +132,11 @@ public class PartialReductionVerifier extends AbstractVerifier { for (int x = 0; x < combinationCluster.size(); x++) { if (nClusters.get(x).size() > 1) { findPartialReduction( - inColumns, i + 1, nClusters.get(x), combinationCluster.get(x) || hasCombination); + inColumns, + i + 1, + nClusters.get(x), + combinationCluster.get(x) || hasCombination, + subsumptionRule); } } } @@ -113,41 +144,39 @@ public class PartialReductionVerifier extends AbstractVerifier { private void createCombinedRule(List<VDmnInputColumn> inColumns, List<VDmnRule> clusterRules) { // Combined Rule: - VDmnRuleChangeableImpl r = - new VDmnRuleChangeableImpl( - VDmnRuleImpl.getBuilder() - .withRuleId(new RuleId("TODO")) - .addInputValue(clusterRules.get(1).getDmnInputValues().get(0)) - .withDmnDecisionTable(inColumns.get(0).getDmnDecisionTable()) - .withRowNumber(new RowNumber(999L)) - .build()); - for (int x = 0; x < inColumns.size(); x++) { - r.setInputValue( - x, - VDmnInputValueImpl.getBuilder() - .withInputEntryId(new InputEntryId("TODO")) - .withText("") - .withBoundary( - clusterRules - .get(0) - .getDmnInputValues() - .get(x) - .getBoundary() - .createBi( - COMBINE, clusterRules.get(1).getDmnInputValues().get(x).getBoundary()) - .get()) - .withDmnInputColumn(inColumns.get(x)) - .withDmnRule(r) - .build()); + List<Boundary> boundaries = new ArrayList<>(); + for (int i = 0; i < inColumns.size(); i++) { + boundaries.add( + clusterRules + .get(0) + .getDmnInputValues() + .get(i) + .getBoundary() + .createBi(COMBINE, clusterRules.get(1).getDmnInputValues().get(i).getBoundary()) + .get()); + } + Action.Builder fixActionBuilder = + Action.getBuilder().withActionScope(ActionScope.RULE).withActionType(ActionType.CREATE); + for (int i = 0; i < inColumns.size(); i++) { + fixActionBuilder.addValue( + inColumns.get(i).getInputId().getValue(), boundaries.get(i).getParsedText()); } - vreFactory.addVerificationFix(VerificationFix.getBuilder() - .withFixName(new Name("Combine")) - .addAction(Action.getBuilder() - .withActionScope(ActionScope.RULE) - .withActionType(ActionType.CREATE) - .addValue("value", r.toString()) // TODO - .build()) - .build() - ); + Action.Builder fixActionBuilder2 = + Action.getBuilder().withActionScope(ActionScope.RULE).withActionType(ActionType.DELETE); + fixActionBuilder2.addValue( + "decisionId", clusterRules.get(0).getDmnDecision().getDecisionId().getValue()); + fixActionBuilder2.addValue("ruleId", clusterRules.get(0).getRuleId().getValue()); + Action.Builder fixActionBuilder3 = + Action.getBuilder().withActionScope(ActionScope.RULE).withActionType(ActionType.DELETE); + fixActionBuilder3.addValue( + "decisionId", clusterRules.get(1).getDmnDecision().getDecisionId().getValue()); + fixActionBuilder3.addValue("ruleId", clusterRules.get(1).getRuleId().getValue()); + vreFactory.addVerificationFix( + VerificationFix.getBuilder() + .withFixName(new Name("Combine")) + .addAction(fixActionBuilder.build()) + .addAction(fixActionBuilder2.build()) + .addAction(fixActionBuilder3.build()) + .build()); } } 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 687582295addd43a72f6d187a5f2225698baf5b9..6adf2109a9035944cecb6ea14cacaf91bf7170eb 100644 --- a/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnVerifierActions.js +++ b/dmnverifierfrontend/src/main/resources/META-INF/resources/js/dmnVerifierActions.js @@ -1,3 +1,10 @@ +/** + * @returns {Modeling} + */ +function getCurrentModeler() { + return dmnModeler.getActiveViewer().get("modeling"); +} + /** * * @param {VerificationEntry} verificationEntry @@ -20,7 +27,8 @@ function performVerificationFix(verificationEntry, fix, id) { performVerificationFixCREATE(verificationEntry, fix.actions[i]); break; case 'DELETE': - // break; + performVerificationFixDELETE(verificationEntry, fix.actions[i]); + break; default: alert("Action not defined: " + fix); } @@ -160,6 +168,29 @@ function performVerificationFixCREATE(verificationEntry, fixAction) { } } +/** + * + * @param {VerificationEntry} verificationEntry + * @param {Action} fixAction + */ +function performVerificationFixDELETE(verificationEntry, fixAction) { + switch (fixAction.actionScope) { + case 'RULE': + deleteRule(verificationEntry, fixAction); + break; + case 'INPUT_ENTRY': + case 'OUTPUT_ENTRY': + case 'INPUT_DATA': + case 'INPUT_COLUMN': + case 'OUTPUT_COLUMN': + case 'DECISION_TABLE': + case 'DECISION': + default: + alert("ACTION undefined: " + fix.actions[i].actionType + ' -> ' + + fix.actions[i].actionScope); + } +} + /** * * @param {VerificationEntry} verificationEntry @@ -168,14 +199,38 @@ function performVerificationFixCREATE(verificationEntry, fixAction) { function createRule(verificationEntry, fixAction) { $('#tab-dec-' + verificationEntry.elements[0].identifier['decisionId']).click(); - $('.tjs-table tfoot .add-rule-add').click(); - let $lastRow = $('.tjs-table tbody tr:last'); + const modeler = getCurrentModeler(); + const rule = modeler.addRow({type: "dmn:DecisionRule"}); + const {cells} = rule; + for (const [key, value] of Object.entries(fixAction.actionValues)) { + modeler.editCell(getCellByColId(key, cells), value); + } +} + +/** + * + * @param {VerificationEntry} verificationEntry + * @param {Action} fixAction + */ +function deleteRule(verificationEntry, fixAction) { + $('#tab-dec-' + + verificationEntry.elements[0].identifier['decisionId']).click(); + const modeler = getCurrentModeler(); for (const [key, value] of Object.entries(fixAction.actionValues)) { - let $cell = $lastRow.find('[data-col-id=' + key + ']').find( - '.content-editable'); - $cell.empty(); - $cell.append(`${value}`); - $cell.append(`<br>`); - $cell.trigger('input') + if (key === 'ruleId') { + modeler.removeRow(modeler._sheet._elementRegistry.get(value)); + } + } +} + +// get a rule: +// dmnModeler.getActiveViewer().get('modeling')._sheet._elementRegistry.get('DecisionRule_049xiav') + +function getCellByColId(colId, cells) { + for (let i = 0; i < cells.length; i++) { + if (cells[i].col.id === colId) { + return cells[i]; + } } + return undefined; }