Skip to content
Snippets Groups Projects
Commit d2114bdd authored by Jonas Blatt's avatar Jonas Blatt :ant:
Browse files

Add implementation for overlapping verifier

parent 8950f036
Branches
Tags
No related merge requests found
package de.unikoblenz.fgbks.core.dmn.domain.vdmn;
import de.unikoblenz.fgbks.core.dmn.domain.ids.DecisionTableId;
import de.unikoblenz.fgbks.core.dmn.domain.ids.RuleId;
import java.util.List;
import java.util.stream.Collectors;
import org.camunda.bpm.model.dmn.HitPolicy;
public interface VDmnDecisionTable extends VDmnElement {
......@@ -19,4 +21,10 @@ public interface VDmnDecisionTable extends VDmnElement {
List<VDmnInputColumn> getInputColumns();
List<VDmnRule> getRules();
default List<RuleId> getRulesIds() {
return getRules().stream()
.map(VDmnRule::getRuleId)
.collect(Collectors.toList()); // TODO optimize (e.g. cache)
}
}
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 de.unikoblenz.fgbks.core.dmn.domain.ids.RuleId;
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.VDmnValue;
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;
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.config.DefaultConfiguration;
import de.unikoblenz.fgbks.core.dmn.verification.verifier.types.OverlappingVerification;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@DmnVerifier(
verifierType = OverlappingVerification.class,
......@@ -11,5 +29,130 @@ import de.unikoblenz.fgbks.core.dmn.verification.verifier.types.OverlappingVerif
public class OverlappingVerifier extends AbstractVerifier {
@Override
protected void doVerification() {}
protected void doVerification() {
for (VDmnDecision decision : dmnObjectContainer.getVDmnDefinition().getDmnDecisions()) {
checkOverlapping(decision.getDmnDecisionTable());
}
}
private void checkOverlapping(VDmnDecisionTable dmnDecisionTable) {
checkOverlapping(
new ArrayList<VDmnInputColumn>(dmnDecisionTable.getInputColumns()),
0,
dmnDecisionTable.getRulesIds(),
false,
Collections.emptyList());
}
private void checkOverlapping(
ArrayList<VDmnInputColumn> inColumns,
int i,
List<RuleId> currentRuleIds,
boolean hasOverlap,
List<RuleId> subsumptionRules) {
// no more columns to check
if (i == inColumns.size()) {
// do nothing, if there was no real overlap found prev..
if (hasOverlap) {
// add to rules to result
// TODO
currentRuleIds.forEach(
ruleId ->
vref.addElement(
VerificationResultEntryElement.create(inColumns.get(0).getDmnDecisionTable())
.withIdentifier(ruleId)));
vref.addToEntry(VerificationClassification.WARNING, "overlapping");
}
} else {
// check current column
List<VDmnInputValue> currentBounds = new ArrayList<>();
List<VDmnInputValue> sortedBounds =
VDmnFunctions.getColumnValuesInRules(inColumns.get(i), currentRuleIds);
sortedBounds.sort(Comparator.comparing(VDmnInputValue::getBoundary));
int z = 0;
boolean foundPOverlap = false;
for (VDmnInputValue currentBound : sortedBounds) {
z++;
boolean foundOverlap = hasOverlap;
// copy of current bounds
List<VDmnInputValue> currentBoundsCpy = new ArrayList<>(currentBounds);
// add current bound to overlapping bounds
currentBounds.add(currentBound);
// check, if current bound is overlapping an other bound in the current list of overlapping
// rules
boolean foundNotInContact = false;
for (int x = 0; x < currentBounds.size(); x++) {
VDmnInputValue bound = currentBounds.get(x);
if (currentBound.getBoundary().checkWith(IS_NOT_IN_CONTACT, bound.getBoundary())) {
currentBounds.remove(x--);
foundNotInContact = true;
} else {
foundOverlap =
foundOverlap
|| currentBound.getBoundary().checkWith(IS_OVERLAPPING, bound.getBoundary());
}
}
if (foundNotInContact && currentBoundsCpy.size() > 1) {
List<RuleId> newSubsumtionRules = searchSubsubmtionElement(currentBoundsCpy);
checkOverlapping(
inColumns,
i + 1,
currentBoundsCpy.stream().map(VDmnValue::getRuleId).collect(Collectors.toList()),
hasOverlap
|| foundPOverlap
|| (newSubsumtionRules.size() > 0
&& subsumptionRules.size() > 0
&& containsNoDuplicateRows(newSubsumtionRules, subsumptionRules)),
newSubsumtionRules);
foundPOverlap = false;
}
if (z == sortedBounds.size() && currentBounds.size() > 1) {
List<RuleId> newSubsumtionRules = searchSubsubmtionElement(currentBounds);
// check if
checkOverlapping(
inColumns,
i + 1,
currentBounds.stream().map(VDmnValue::getRuleId).collect(Collectors.toList()),
hasOverlap
|| foundOverlap
|| (newSubsumtionRules.size() > 0
&& subsumptionRules.size() > 0
&& containsNoDuplicateRows(newSubsumtionRules, subsumptionRules)),
newSubsumtionRules);
}
foundPOverlap |= foundOverlap;
}
}
}
private boolean containsNoDuplicateRows(List<RuleId> ri1, List<RuleId> ri2) {
for (RuleId r1 : ri1) {
for (RuleId r2 : ri2) {
if (r1.equals(r2)) {
return false;
}
}
}
return true;
}
private List<RuleId> searchSubsubmtionElement(List<VDmnInputValue> inValues) {
List<RuleId> subsubmtionRules = new ArrayList<>();
outer:
for (VDmnInputValue value : inValues) {
boolean containsSubsumption = false;
for (VDmnInputValue innerValue : inValues) {
if (value.getBoundary().checkWith(SUBSUMES, innerValue.getBoundary())) {
containsSubsumption = true;
} else if (value.getBoundary().checkWith(IS_NOT_IN_CONTACT, innerValue.getBoundary())
|| value.getBoundary().checkWith(IS_OVERLAPPING, innerValue.getBoundary())) {
continue outer;
}
}
if (containsSubsumption) {
subsubmtionRules.add(value.getRuleId());
}
}
return subsubmtionRules;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment