diff --git a/drools-core/src/main/java/org/drools/core/RuleBaseConfiguration.java b/drools-core/src/main/java/org/drools/core/RuleBaseConfiguration.java index e137bdb7b37..3d54c56cde4 100755 --- a/drools-core/src/main/java/org/drools/core/RuleBaseConfiguration.java +++ b/drools-core/src/main/java/org/drools/core/RuleBaseConfiguration.java @@ -110,6 +110,7 @@ * drools.declarativeAgendaEnabled = <true|false> * drools.permgenThreshold = <1...n> * drools.jittingThreshold = <1...n> + * drools.alphaNodeOrdering = <count|custom|none> (custom is experimental) * */ public class RuleBaseConfiguration diff --git a/drools-core/src/main/java/org/drools/core/addon/AlphaNodeOrderingStrategy.java b/drools-core/src/main/java/org/drools/core/addon/AlphaNodeOrderingStrategy.java index d749bcf8437..840f384e014 100644 --- a/drools-core/src/main/java/org/drools/core/addon/AlphaNodeOrderingStrategy.java +++ b/drools-core/src/main/java/org/drools/core/addon/AlphaNodeOrderingStrategy.java @@ -22,6 +22,7 @@ import org.drools.core.definitions.InternalKnowledgePackage; import org.drools.core.spi.AlphaNodeFieldConstraint; import org.drools.core.spi.ObjectType; +import org.drools.core.util.ClassUtils; import org.kie.api.conf.AlphaNodeOrderingOption; /** @@ -39,10 +40,17 @@ public interface AlphaNodeOrderingStrategy { static AlphaNodeOrderingStrategy createAlphaNodeOrderingStrategy(AlphaNodeOrderingOption option) { if (AlphaNodeOrderingOption.COUNT.equals(option)) { return new CountBasedOrderingStrategy(); + } else if (AlphaNodeOrderingOption.CUSTOM.equals(option)) { + String customStrategyClassName = System.getProperty(AlphaNodeOrderingOption.CUSTOM_CLASS_PROPERTY_NAME); + if (customStrategyClassName == null || customStrategyClassName.trim().isEmpty()) { + throw new RuntimeException("Configure system property " + AlphaNodeOrderingOption.CUSTOM_CLASS_PROPERTY_NAME + " with custom strategy implementation FQCN when you use AlphaNodeOrderingOption.CUSTOM"); + } else { + return (AlphaNodeOrderingStrategy) ClassUtils.instantiateObject(customStrategyClassName); + } } else if (AlphaNodeOrderingOption.NONE.equals(option)) { return new NoopOrderingStrategy(); } else { throw new IllegalArgumentException("No implementation found for AlphaNodeOrderingOption [" + option + "]"); } } -} \ No newline at end of file +} diff --git a/drools-model/drools-model-compiler/src/test/java/org/drools/modelcompiler/AlphaNodeOrderingTest.java b/drools-model/drools-model-compiler/src/test/java/org/drools/modelcompiler/AlphaNodeOrderingTest.java index db493db4694..b9f1fbf1720 100644 --- a/drools-model/drools-model-compiler/src/test/java/org/drools/modelcompiler/AlphaNodeOrderingTest.java +++ b/drools-model/drools-model-compiler/src/test/java/org/drools/modelcompiler/AlphaNodeOrderingTest.java @@ -18,12 +18,18 @@ import java.math.BigDecimal; import java.util.Arrays; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import org.drools.core.addon.AlphaNodeOrderingStrategy; +import org.drools.core.definitions.InternalKnowledgePackage; import org.drools.core.reteoo.AlphaNode; import org.drools.core.rule.constraint.MvelConstraint; +import org.drools.core.spi.AlphaNodeFieldConstraint; +import org.drools.core.spi.ObjectType; import org.drools.modelcompiler.domain.Address; import org.drools.modelcompiler.domain.FactASuper; import org.drools.modelcompiler.domain.FactBSub; @@ -432,4 +438,70 @@ public void testExists() { assertEquals(2, ksession.fireAllRules()); } + + @Test + public void testCustomAlphaNodeOrdering() { + + System.setProperty(AlphaNodeOrderingOption.CUSTOM_CLASS_PROPERTY_NAME, "org.drools.modelcompiler.AlphaNodeOrderingTest$MyCustomStrategy"); + + try { + String str = + "import " + Person.class.getCanonicalName() + "\n" + + "rule R1 when\n" + + " $p : Person(age != 0, age != 1, age != 2, age != 3)\n" + + "then\n" + + "end\n" + + "rule R2 when\n" + + " $p : Person(age != 1, age != 2, age != 3)\n" + + "then\n" + + "end\n" + + "rule R3 when\n" + + " $p : Person(age != 2, age != 3)\n" + + "then\n" + + "end\n" + + "rule R4 when\n" + + " $p : Person(age != 3)\n" + + "then\n" + + "end\n"; + + KieModuleModel model = KieServices.get().newKieModuleModel(); + model.newKieBaseModel("kb") + .setDefault(true) + .setAlphaNodeOrdering(AlphaNodeOrderingOption.CUSTOM) + .newKieSessionModel("ks") + .setDefault(true); + + KieSession ksession = getKieSession(model, str); + + List alphaNodes = ReteDumper.collectNodes(ksession) + .stream() + .filter(AlphaNode.class::isInstance) + .map(node -> (AlphaNode) node) + .collect(Collectors.toList()); + assertEquals(10, alphaNodes.size()); + + ksession.insert(new Person("Mario", 1)); + assertEquals(2, ksession.fireAllRules()); + + assertTrue(MyCustomStrategy.counter > 0); + } finally { + System.clearProperty(AlphaNodeOrderingOption.CUSTOM_CLASS_PROPERTY_NAME); + } + } + + public static class MyCustomStrategy implements AlphaNodeOrderingStrategy { + + public static int counter = 0; + + @Override + public void analyzeAlphaConstraints(Map pkgs, Collection newPkgs) { + counter++; + } + + @Override + public void reorderAlphaConstraints(List alphaConstraints, ObjectType objectType) { + counter++; + } + + } }