diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/AbstractBoundary.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/AbstractBoundary.java index 8883fe32c3164f7cc75918febb61907ccbc0d3f9..868e621d9e0b06db428e56fd57f59c1fe42d9759 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/AbstractBoundary.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/AbstractBoundary.java @@ -66,12 +66,12 @@ public abstract class AbstractBoundary<T extends Comparable<? super T>> implemen } @Override - public Optional<Boundary> createBi(BoundaryBiCreaterType combineType, Boundary other) { + public Optional<Boundary> createBi(BoundaryBiCreaterType biCreaterType, Boundary other) { if (other instanceof InvalidBoundary) { return Optional.empty(); } - BoundaryBiCreater biCreater = getBiCreaterFunction(combineType); - if (biCreater == null || !isValidOperation(combineType, other)) { + BoundaryBiCreater biCreater = getBiCreaterFunction(biCreaterType); + if (biCreater == null || !isValidOperation(biCreaterType, other)) { throw new BoundaryOperationNotSupportedException(); // TODO: add error text } return biCreater.create(this, other); // TODO, remove RAW type @@ -119,8 +119,6 @@ public abstract class AbstractBoundary<T extends Comparable<? super T>> implemen protected abstract HashMap<BoundaryCreaterType, BoundaryCreater> getCreater(); - protected abstract String getParsedText(); - @Override public String toString() { return "{" + getText() + "},{" + getParsedText() + "}"; diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/AbstractGrowingBoundary.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/AbstractGrowingBoundary.java index 092e7a8895a9cfc4c970c8fc4cfbf3e297305451..5c4498cd3ff32ffc387fb055dd0771e015921696 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/AbstractGrowingBoundary.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/AbstractGrowingBoundary.java @@ -193,7 +193,7 @@ public abstract class AbstractGrowingBoundary<T extends Comparable<? super T>> T lowerBound, T upperBound, BoundType lowerBoundType, BoundType upperBoundType); @Override - protected String getParsedText() { - return ""; + public String getParsedText() { + return lowerBoundType + " " + lowerBound + " " + upperBound + " " + upperBoundType; } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/Boundary.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/Boundary.java index 7772b3d8b9c457eeb9a45fc23dfae144a093149c..29f997b69ee74d8a8cd531fbb194468be99f56be 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/Boundary.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/Boundary.java @@ -12,6 +12,8 @@ public interface Boundary extends Comparable<Boundary> { String getText(); + String getParsedText(); + boolean checkWith(BoundaryCheckType checkType, Boundary other); Optional<Boundary> create(BoundaryCreaterType createType); diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterAppend.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterAppend.java index 0ff5fd3b501cd5fd2dcfe3132d96400d02647492..848b72e07bd3b28bc20ff332514615e18a490667 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterAppend.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterAppend.java @@ -64,9 +64,10 @@ public class BiCreaterAppend extends AbstractBoundaryBiCreater<AbstractGrowingBo AbstractGrowingBoundary b1, AbstractGrowingBoundary b2) { int b1L = (int) b1.getLowerBound(); int b1U = (int) b1.getUpperBound(); - int b2L = (int) b1.getLowerBound(); - int b2U = (int) b1.getUpperBound(); + int b2L = (int) b2.getLowerBound(); + int b2U = (int) b2.getUpperBound(); if (b1U + 1 == b2L + && b1.getMaxValue().compareTo(b1U) != 0 && b1.getUpperBoundType() == INCLUSIVE && b2.getLowerBoundType() == INCLUSIVE) { return Optional.of( @@ -76,6 +77,7 @@ public class BiCreaterAppend extends AbstractBoundaryBiCreater<AbstractGrowingBo b1.getLowerBoundType(), b2.getUpperBoundType())); } else if (b2U + 1 == b1L + && b2.getMaxValue().compareTo(b2U) != 0 && b2.getUpperBoundType() == INCLUSIVE && b1.getLowerBoundType() == INCLUSIVE) { return Optional.of( @@ -92,8 +94,8 @@ public class BiCreaterAppend extends AbstractBoundaryBiCreater<AbstractGrowingBo AbstractGrowingBoundary b1, AbstractGrowingBoundary b2) { long b1L = (long) b1.getLowerBound(); long b1U = (long) b1.getUpperBound(); - long b2L = (long) b1.getLowerBound(); - long b2U = (long) b1.getUpperBound(); + long b2L = (long) b2.getLowerBound(); + long b2U = (long) b2.getUpperBound(); if (b1U + 1 == b2L && b1.getUpperBoundType() == INCLUSIVE && b2.getLowerBoundType() == INCLUSIVE) { diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterLowerBounds.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterLowerBounds.java index 2723cf33707b556f417c9265729283550e670aa5..2a385096e0747be737aba0d310e3a50384a023eb 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterLowerBounds.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterLowerBounds.java @@ -43,13 +43,16 @@ public class BiCreaterLowerBounds extends AbstractBoundaryBiCreater<AbstractGrow return Optional.empty(); } } + if (b2.getLowerBound().equals(b2.getMinValue())) { + return Optional.empty(); + } try { return Optional.of( b1.getCopy( b1.getLowerBound(), b2.getLowerBound(), - b1.getLowerBoundType().getOp(), - b2.getLowerBoundType())); + b1.getLowerBoundType(), + b2.getLowerBoundType().getOp())); } catch (Exception e) { return Optional.empty(); } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterUpperBounds.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterUpperBounds.java index a9a3ff2ae37a5ea925be5f4748c79bca62680220..eec40d2a27ef23632f14ee15fd7df309b8cc003b 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterUpperBounds.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/bicreater/BiCreaterUpperBounds.java @@ -43,6 +43,9 @@ public class BiCreaterUpperBounds extends AbstractBoundaryBiCreater<AbstractGrow return Optional.empty(); } } + if (b2.getUpperBound().equals(b2.getMaxValue())) { + return Optional.empty(); + } try { return Optional.of( b1.getCopy( diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/checker/CheckEqual.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/checker/CheckEqual.java index 1da5446244f82b28ac850ca21f831037bfafa18f..fe5c2ac2c70953c5c15143ba931e7bae4524123f 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/checker/CheckEqual.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/checker/CheckEqual.java @@ -28,9 +28,6 @@ public class CheckEqual extends AbstractBoundaryCheck<AbstractGrowingBoundary> { if (b1 == b2) { return true; } - if (b1.getText().equals(b2.getText())) { - return true; - } return ((b1.getLowerBound().equals(b2.getLowerBound()) && b1.getLowerBoundType().equals(b2.getLowerBoundType()) && b1.getUpperBound().equals(b2.getUpperBound()) diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/impl/InvalidBoundary.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/impl/InvalidBoundary.java index 2523efd075d9fd122c34e545218f2423f8443768..7a9cfafbf0756959bc9bed6cb2b9c732aa17a21c 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/impl/InvalidBoundary.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/impl/InvalidBoundary.java @@ -27,6 +27,11 @@ public class InvalidBoundary implements Boundary { return "null"; } + @Override + public String getParsedText() { + return ""; + } + @Override public boolean checkWith(BoundaryCheckType checkType, Boundary other) { return false; diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/impl/StringBoundary.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/impl/StringBoundary.java index 3f4540aaedd21dd618248b3346adaf2c677ec384..c0484570d89eab357a9a88bcd5b37e60b10c8433 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/impl/StringBoundary.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/base/utils/boundary/impl/StringBoundary.java @@ -42,7 +42,7 @@ public class StringBoundary extends AbstractBoundary<String> { private static HashMap<BoundaryCheckType, BoundaryCheck> checkerMap = new HashMap<>(); private static HashMap<BoundaryCreaterType, BoundaryCreater> createrMap = new HashMap<>(); - private static HashMap<BoundaryBiCreaterType, BoundaryBiCreater> combinerMap = new HashMap<>(); + private static HashMap<BoundaryBiCreaterType, BoundaryBiCreater> biCreaterMap = new HashMap<>(); static { checkerMap.put(IS_EQUAL, CheckStringEqual.getInstance()); @@ -53,12 +53,12 @@ public class StringBoundary extends AbstractBoundary<String> { checkerMap.put(SUBSUMES, CheckStringSubsumes.getInstance()); createrMap.put(UPPER, CreaterUpper.getInstance()); createrMap.put(LOWER, CreaterLower.getInstance()); - combinerMap.put(INTERSECTION, EmptyBiCreater.getInstance()); - combinerMap.put(LOWER_BOUNDS, EmptyBiCreater.getInstance()); - combinerMap.put(UPPER_BOUNDS, EmptyBiCreater.getInstance()); - combinerMap.put(BETWEEN, EmptyBiCreater.getInstance()); - combinerMap.put(APPEND, EmptyBiCreater.getInstance()); - combinerMap.put(COMBINE, EmptyBiCreater.getInstance()); + biCreaterMap.put(INTERSECTION, EmptyBiCreater.getInstance()); + biCreaterMap.put(LOWER_BOUNDS, EmptyBiCreater.getInstance()); + biCreaterMap.put(UPPER_BOUNDS, EmptyBiCreater.getInstance()); + biCreaterMap.put(BETWEEN, EmptyBiCreater.getInstance()); + biCreaterMap.put(APPEND, EmptyBiCreater.getInstance()); + biCreaterMap.put(COMBINE, EmptyBiCreater.getInstance()); } private boolean matchNoneOfValues; @@ -137,7 +137,7 @@ public class StringBoundary extends AbstractBoundary<String> { @Override protected HashMap<BoundaryBiCreaterType, BoundaryBiCreater> getBiCreater() { - return combinerMap; + return biCreaterMap; } @Override @@ -146,7 +146,7 @@ public class StringBoundary extends AbstractBoundary<String> { } @Override - protected String getParsedText() { + public String getParsedText() { return (matchNoneOfValues ? "not" : "") + Arrays.toString(values); } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnDecisionTableImpl.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnDecisionTableImpl.java index 2d8e47d5800dd85af0c0501b19e86505f2af298c..370ae7998172b6e2ebe881d9a4d5a2184a6470b5 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnDecisionTableImpl.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnDecisionTableImpl.java @@ -101,7 +101,7 @@ public class VDmnDecisionTableImpl extends AbstractVDmnElement implements VDmnDe public Builder addRuleFromBuilder(VDmnRuleImpl.Builder dmnRuleBuilder) { addRule(Validate.notNull(dmnRuleBuilder.getUnbuildValue())); - dmnRuleBuilder.withDmnDecision(value); + dmnRuleBuilder.withDmnDecisionTable(value); return this; } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnInputValueChangeableImpl.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnInputValueChangeableImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..6108f4b405b49cb97ed9ec82774be11735d12645 --- /dev/null +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnInputValueChangeableImpl.java @@ -0,0 +1,23 @@ +package de.unikoblenz.fgbks.core.dmn.domain.vdmn.impl; + +import de.unikoblenz.fgbks.base.utils.boundary.Boundary; +import org.apache.commons.lang3.Validate; + +public class VDmnInputValueChangeableImpl extends VDmnInputValueImpl { + + public VDmnInputValueChangeableImpl(VDmnInputValueImpl inputValue) { + super(); + Validate.notNull(inputValue); + super.boundary = inputValue.boundary; + super.description = inputValue.description; + super.dmnColumn = inputValue.dmnColumn; + super.dmnRule = inputValue.dmnRule; + super.id = inputValue.id; + super.text = inputValue.text; + } + + public VDmnInputValueChangeableImpl withNewBoundary(Boundary boundary) { + super.boundary = Validate.notNull(boundary); + return this; + } +} diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnInputValueImpl.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnInputValueImpl.java index 0d923df9320001daac30a3ca02a806ac0bd181e6..30130748fa81435b00f2637935604ec71192b855 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnInputValueImpl.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnInputValueImpl.java @@ -9,9 +9,9 @@ import org.apache.commons.lang3.Validate; public class VDmnInputValueImpl extends VDmnValueImpl implements VDmnInputValue { - private Boundary boundary; + protected Boundary boundary; - private VDmnInputValueImpl() {} + protected VDmnInputValueImpl() {} public static Builder getBuilder() { return new VDmnInputValueImpl().new Builder(); @@ -29,6 +29,11 @@ public class VDmnInputValueImpl extends VDmnValueImpl implements VDmnInputValue return this; } + public Builder withDmnRuleFromBuilder(VDmnRuleImpl.Builder dmnRuleBuilder) { + value.dmnRule = dmnRuleBuilder.getUnbuildValue(); + return this; + } + public Builder withText(String text) { value.text = text; return this; @@ -49,6 +54,11 @@ public class VDmnInputValueImpl extends VDmnValueImpl implements VDmnInputValue return this; } + public Builder withBoundary(Boundary boundary) { + value.boundary = boundary; + return this; + } + @Override protected void validate() { super.validate(); @@ -60,9 +70,11 @@ public class VDmnInputValueImpl extends VDmnValueImpl implements VDmnInputValue @Override public VDmnInputValueImpl build() { - // create boundary - value.boundary = - value.dmnColumn.getTypeRef().getBoundaryFromText(value.getText()).orElse(null); + // create boundary, if not created before + if (value.boundary == null) { + value.boundary = + value.dmnColumn.getTypeRef().getBoundaryFromText(value.getText()).orElse(null); + } return super.build(); } } diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnRuleChangeableImpl.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnRuleChangeableImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..3179702c3bac283e763d1eff12bed1c737d47ad6 --- /dev/null +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnRuleChangeableImpl.java @@ -0,0 +1,26 @@ +package de.unikoblenz.fgbks.core.dmn.domain.vdmn.impl; + +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnInputValue; +import de.unikoblenz.fgbks.core.dmn.domain.vdmn.VDmnOutputValue; +import org.apache.commons.lang3.Validate; + +public class VDmnRuleChangeableImpl extends VDmnRuleImpl { + + public VDmnRuleChangeableImpl(VDmnRuleImpl rule) { + super(); + Validate.notNull(rule); + super.dmnDecisionTable = rule.dmnDecisionTable; + super.inputValues = rule.inputValues; + super.outputValues = rule.outputValues; + super.rowNumber = rule.rowNumber; + super.id = rule.id; + } + + public void setInputValue(int i, VDmnInputValue inputValue) { + inputValues.set(i, inputValue); + } + + public void setOutputValue(int i, VDmnOutputValue outputValue) { + outputValues.set(i, outputValue); + } +} diff --git a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnRuleImpl.java b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnRuleImpl.java index 114111e839451c7262ea80b76952d06668545303..013750e53158450b5f5868b0217fa1d0143fa512 100644 --- a/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnRuleImpl.java +++ b/dmnverifierapi/src/main/java/de/unikoblenz/fgbks/core/dmn/domain/vdmn/impl/VDmnRuleImpl.java @@ -13,14 +13,14 @@ import org.apache.commons.lang3.Validate; public class VDmnRuleImpl extends AbstractVDmnElement implements VDmnRule { - private RowNumber rowNumber; - private VDmnDecisionTable dmnDecisionTable; - private List<VDmnInputValue> inputValues; - private List<VDmnOutputValue> outputValues; - - private VDmnRuleImpl() { - inputValues = new ArrayList<>(); - outputValues = new ArrayList<>(); + protected RowNumber rowNumber; + protected VDmnDecisionTable dmnDecisionTable; + protected List<VDmnInputValue> inputValues; + protected List<VDmnOutputValue> outputValues; + + protected VDmnRuleImpl() { + inputValues = new ArrayList<>(10); + outputValues = new ArrayList<>(3); } @Override @@ -59,7 +59,7 @@ public class VDmnRuleImpl extends AbstractVDmnElement implements VDmnRule { return this; } - public Builder withDmnDecision(VDmnDecisionTable vDmnDecisionTable) { + public Builder withDmnDecisionTable(VDmnDecisionTable vDmnDecisionTable) { value.dmnDecisionTable = vDmnDecisionTable; return this; } 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 39dbdf5a2638684a6f78caecea23aa2834bfc20d..e2cfb1077eaa0c31a66062dd9f406c05f72478b9 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,15 +1,265 @@ package de.unikoblenz.fgbks.core.dmn.verification.verifier.impl; +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; +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.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.VDmnInputValueChangeableImpl; +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.impl.VDmnRuleImpl.Builder; +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.MissingRuleVerification; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; @DmnVerifier( verifierType = MissingRuleVerification.class, verifierConfig = DefaultConfiguration.class) public class MissingRuleVerifier extends AbstractVerifier { + public static final long INITIAL_ROW_NUMER = 9999L; + @Override - protected void doVerification() {} + protected void doVerification() { + for (VDmnDecision decision : dmnObjectContainer.getVDmnDefinition().getDmnDecisions()) { + findMissingRules(decision.getDmnDecisionTable()); + } + } + + private void findMissingRules(VDmnDecisionTable dmnDecisionTable) { + List<VDmnInputColumn> inputs = dmnDecisionTable.getInputColumns(); + List<VDmnRuleChangeableImpl> missingRules = + 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: ("); + sb.append( + missingRule.getDmnInputValues().stream() + .map(v -> v.getBoundary().getParsedText()) + .collect(Collectors.joining("), ("))); + sb.append(")"); + + vreFactory.addElement(VerificationResultEntryElement.create(dmnDecisionTable)); + vreFactory.addToEntry(VerificationClassification.WARNING, sb.toString()); + } + } + + private List<VDmnRuleChangeableImpl> checkForMissingRules( + List<VDmnInputColumn> inputs, List<VDmnRule> rules) { + // check, if missingIntervals are empty + List<VDmnRuleChangeableImpl> missingRules = new LinkedList<>(); + missingRules.add(constructPseudoMissingRule(inputs)); + // Check new Missing Rules for each rule + for (VDmnRule rule : rules) { + checkForMissingRules(inputs, rule, missingRules); + } + mergeRules(missingRules); + return missingRules; + } + + private VDmnRuleChangeableImpl constructPseudoMissingRule(List<VDmnInputColumn> inputs) { + Builder b = + VDmnRuleImpl.getBuilder() + .withRuleId(new RuleId("TODO")) // TODO + .withDmnDecisionTable(inputs.get(0).getDmnDecisionTable()) + .withRowNumber(new RowNumber(INITIAL_ROW_NUMER)); + + for (VDmnInputColumn col : inputs) { + b.addInputValue( + VDmnInputValueImpl.getBuilder() + .withInputEntryId(new InputEntryId("TODO")) // TODO + .withText("") + .withDmnInputColumn(col) + .withDmnRuleFromBuilder(b) + .build()); + } + return new VDmnRuleChangeableImpl(b.build()); + } + + private void checkForMissingRules( + List<VDmnInputColumn> inputs, + VDmnRule currentRule, + List<VDmnRuleChangeableImpl> missingRules) { + // search the missing rules, which are in contact with the current rule + List<VDmnRuleChangeableImpl> inContactRules = new LinkedList<>(); + for (VDmnRuleChangeableImpl missingRule : missingRules) { + if (isInContact(missingRule, currentRule)) { + inContactRules.add(missingRule); + } + } + // remove found rules from current missingRules + missingRules.removeAll(inContactRules); + // Build new missing rules from in contact rules + List<VDmnRuleChangeableImpl> newMissingRules = new LinkedList<>(); + for (VDmnRuleChangeableImpl inContactRule : inContactRules) { + newMissingRules.addAll(constructNewMissingRules(inputs, inContactRule, currentRule)); + } + // mergeRules(newMissingRules); + missingRules.addAll(newMissingRules); + mergeRules(missingRules); + } + + private List<VDmnRuleChangeableImpl> constructNewMissingRules( + List<VDmnInputColumn> inputs, VDmnRuleChangeableImpl missingRule, VDmnRule currentRule) { + List<VDmnRuleChangeableImpl> newMissingRules = new LinkedList<>(); + List<VDmnInputValue> missingInValues = new ArrayList<>(missingRule.getDmnInputValues()); + List<VDmnInputValue> currentRuleValues = new ArrayList<>(currentRule.getDmnInputValues()); + for (int i = 0; i < missingInValues.size(); i++) { + // change bound for i-1 + if (i != 0) { + VDmnInputValue missingRuleValue = missingInValues.get(i - 1); + Boundary missingRuleBoundary = missingRuleValue.getBoundary(); + Boundary valueBoundary = currentRuleValues.get(i - 1).getBoundary(); + Optional<Boundary> b = + valueBoundary.createBi(BoundaryBiCreaterType.INTERSECTION, missingRuleBoundary); + if (b.isPresent()) { + missingRule.setInputValue( + i - 1, + VDmnInputValueImpl.getBuilder() + .withInputEntryId(new InputEntryId("TODO")) // TODO + .withText("") + .withDmnInputColumn((VDmnInputColumn) missingRuleValue.getDmnColumn()) + .withDmnRule(missingRule) + .withBoundary(b.get()) + .build()); + } + } + // calc next missing intervals: left + right + VDmnInputValue currentValue = currentRuleValues.get(i); + // left + addMissingRules( + i, + inputs, + missingInValues + .get(i) + .getBoundary() + .createBi(BoundaryBiCreaterType.LOWER_BOUNDS, currentValue.getBoundary()), + missingRule, + newMissingRules); + + // right + addMissingRules( + i, + inputs, + missingInValues + .get(i) + .getBoundary() + .createBi(BoundaryBiCreaterType.UPPER_BOUNDS, currentValue.getBoundary()), + missingRule, + newMissingRules); + } + return newMissingRules; + } + + private void addMissingRules( + int i, + List<VDmnInputColumn> inputs, + Optional<Boundary> bi, + VDmnRuleChangeableImpl missingRule, + List<VDmnRuleChangeableImpl> newMissingRules) { + if (bi.isPresent()) { + List<VDmnInputValue> missingRuleValues = missingRule.getDmnInputValues(); + + Builder b = + VDmnRuleImpl.getBuilder() + .withRuleId(new RuleId("TODO")) // TODO + .withDmnDecisionTable(inputs.get(0).getDmnDecisionTable()) + .withRowNumber(new RowNumber(INITIAL_ROW_NUMER)); + for (VDmnInputValue inputValue : missingRuleValues) { + b.addInputValue(inputValue); + } + + VDmnRuleChangeableImpl copy = new VDmnRuleChangeableImpl(b.build()); + + for (int x = 0; x < missingRuleValues.size(); x++) { + copy.setInputValue( + x, + VDmnInputValueImpl.getBuilder() + .withInputEntryId(new InputEntryId("TODO")) // TODO + .withText("") + .withDmnRule(copy) + .withBoundary(x == i ? bi.get() : missingRuleValues.get(x).getBoundary()) + .withDmnInputColumn(inputs.get(x)) + .build()); + } + newMissingRules.add(copy); + } + } + + private boolean isInContact(VDmnRule missingRule, VDmnRule currentRule) { + List<VDmnInputValue> inValsMissingRule = missingRule.getDmnInputValues(); + List<VDmnInputValue> inValsCurrentRule = currentRule.getDmnInputValues(); + for (int i = 0; i < inValsMissingRule.size(); i++) { + if (inValsMissingRule + .get(i) + .getBoundary() + .checkWith(BoundaryCheckType.IS_NOT_IN_CONTACT, inValsCurrentRule.get(i).getBoundary())) { + return false; + } + } + return true; + } + + private void mergeRules(List<VDmnRuleChangeableImpl> missingRules) { + boolean found = true; + while (found) { + List<VDmnRule> removeRules = new ArrayList<>(100); + found = false; + for (int i = 0; i < missingRules.size(); i++) { + List<VDmnInputValue> inputValuesI = missingRules.get(i).getDmnInputValues(); + for (int u = i + 1; u < missingRules.size(); u++) { + List<VDmnInputValue> inputValuesU = missingRules.get(u).getDmnInputValues(); + int foundCombination = -1; + Optional<Boundary> newOBoundary; + Boundary newBoundary = null; + + for (int x = 0; x < inputValuesI.size(); x++) { + VDmnInputValue v1 = inputValuesI.get(x); + VDmnInputValue v2 = inputValuesU.get(x); + newOBoundary = + v1.getBoundary().createBi(BoundaryBiCreaterType.COMBINE, v2.getBoundary()); + if (v1.getBoundary().checkWith(BoundaryCheckType.IS_EQUAL, v2.getBoundary())) { + // nothing + } else if (newOBoundary.isPresent() && foundCombination == -1) { + newBoundary = newOBoundary.get(); + foundCombination = x; + } else { + foundCombination = -1; + break; + } + } + if (foundCombination >= 0) { + found = true; + missingRules + .get(i) + .setInputValue( + foundCombination, + new VDmnInputValueChangeableImpl( + (VDmnInputValueImpl) inputValuesI.get(foundCombination)) + .withNewBoundary(newBoundary)); + removeRules.add(missingRules.get(u)); + } + } + } + missingRules.removeAll(removeRules); + } + } }