getkSessionConfs() {
return kSessionConfs;
}
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/CoercedExpression.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/CoercedExpression.java
index 4bbd12d9630..e26c1332734 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/CoercedExpression.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/CoercedExpression.java
@@ -52,6 +52,8 @@
import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toJavaParserType;
import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toStringLiteral;
import static org.drools.util.ClassUtils.toNonPrimitiveType;
+import static org.drools.util.CoercionUtil.areComparisonCompatible;
+import static org.drools.util.CoercionUtil.areEqualityCompatible;
public class CoercedExpression {
@@ -151,9 +153,22 @@ public CoercedExpressionResult coerce() {
coercedLeft = left;
}
+ checkCoercion(coercedLeft, coercedRight, leftClass, rightClass);
return new CoercedExpressionResult(coercedLeft, coercedRight, rightAsStaticField);
}
+ private void checkCoercion(TypedExpression coercedLeft, TypedExpression coercedRight, Class> leftClass, Class> rightClass) {
+ if (equalityExpr) {
+ if (!areEqualityCompatible(coercedLeft.getRawClass(), coercedRight.getRawClass())) {
+ throw new CoercedExpressionException(new InvalidExpressionErrorResult("Equality operation requires compatible types. Found " + leftClass + " and " + rightClass));
+ }
+ } else {
+ if (!areComparisonCompatible(coercedLeft.getRawClass(), coercedRight.getRawClass())) {
+ throw new CoercedExpressionException(new InvalidExpressionErrorResult("Comparison operation requires compatible types. Found " + leftClass + " and " + rightClass));
+ }
+ }
+ }
+
private boolean isBoolean(Class> leftClass) {
return Boolean.class.isAssignableFrom(leftClass) || boolean.class.isAssignableFrom(leftClass);
}
@@ -163,12 +178,14 @@ private boolean shouldCoerceBToMap() {
}
private boolean canCoerce() {
- final Class> leftClass = left.getRawClass();
+ return canCoerce(left.getRawClass(), right.getRawClass());
+ }
+
+ private static boolean canCoerce(Class> leftClass, Class> rightClass) {
if (!leftClass.isPrimitive() || !canCoerceLiteralNumberExpr(leftClass)) {
return true;
}
- final Class> rightClass = right.getRawClass();
return rightClass.isPrimitive()
|| Number.class.isAssignableFrom(rightClass)
|| Boolean.class == rightClass
diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/project/ProjectRuntimeGenerator.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/project/ProjectRuntimeGenerator.java
index 053a3161c39..5bb12d525e8 100644
--- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/project/ProjectRuntimeGenerator.java
+++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/project/ProjectRuntimeGenerator.java
@@ -90,31 +90,33 @@ private void writeInitKieBasesMethod(ClassOrInterfaceDeclaration clazz) {
}
private void writeGetDefaultKieBaseMethod(ClassOrInterfaceDeclaration clazz) {
- MethodDeclaration getDefaultKieBaseMethod = clazz.findAll(MethodDeclaration.class).stream()
- .filter(m -> m.getNameAsString().equals("getKieBase"))
- .filter(m -> m.getParameters().isEmpty())
- .findFirst()
- .orElseThrow(() -> new InvalidTemplateException(generator, "Cannot find getKieBase method"));
-
if (modelMethod.getDefaultKieBaseName() != null) {
- getDefaultKieBaseMethod.findFirst(StringLiteralExpr.class)
+ findDefaultKieMethod(clazz, "getKieBase").findFirst(StringLiteralExpr.class)
.orElseThrow(() -> new InvalidTemplateException(generator, "Cannot find string inside getKieBase method"))
.setString(modelMethod.getDefaultKieBaseName());
}
}
private void writeNewDefaultKieSessionMethod(ClassOrInterfaceDeclaration clazz) {
- MethodDeclaration newDefaultKieSessionMethod = clazz.findAll(MethodDeclaration.class).stream()
- .filter(m -> m.getNameAsString().equals("newKieSession"))
- .filter(m -> m.getParameters().isEmpty())
- .findFirst()
- .orElseThrow(() -> new InvalidTemplateException(generator, "Cannot find newKieSession method"));
-
if (modelMethod.getDefaultKieSessionName() != null) {
- newDefaultKieSessionMethod.findFirst(StringLiteralExpr.class)
+ findDefaultKieMethod(clazz, "newKieSession").findFirst(StringLiteralExpr.class)
.orElseThrow(() -> new InvalidTemplateException(generator, "Cannot find string inside newKieSession method"))
.setString(modelMethod.getDefaultKieSessionName());
}
+
+ if (modelMethod.getDefaultKieStatelessSessionName() != null) {
+ findDefaultKieMethod(clazz, "newStatelessKieSession").findFirst(StringLiteralExpr.class)
+ .orElseThrow(() -> new InvalidTemplateException(generator, "Cannot find string inside newStatelessKieSession method"))
+ .setString(modelMethod.getDefaultKieStatelessSessionName());
+ }
+ }
+
+ private MethodDeclaration findDefaultKieMethod(ClassOrInterfaceDeclaration clazz, String methodName) {
+ return clazz.findAll(MethodDeclaration.class).stream()
+ .filter(m -> m.getNameAsString().equals(methodName))
+ .filter(m -> m.getParameters().isEmpty())
+ .findFirst()
+ .orElseThrow(() -> new InvalidTemplateException(generator, "Cannot find " + methodName + " method"));
}
private void writeGetKieBaseForSessionMethod(ClassOrInterfaceDeclaration clazz) {
diff --git a/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeJavaTemplate.java b/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeJavaTemplate.java
index 90edc28323a..f6363b63c40 100644
--- a/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeJavaTemplate.java
+++ b/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeJavaTemplate.java
@@ -25,6 +25,7 @@
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieRuntimeBuilder;
+import org.kie.api.runtime.StatelessKieSession;
import org.drools.modelcompiler.KieBaseBuilder;
public class ProjectRuntime implements KieRuntimeBuilder {
@@ -62,8 +63,21 @@ public KieSession newKieSession(String sessionName) {
if (kbase == null) {
throw new RuntimeException("Unknown KieSession with name '" + sessionName + "'");
}
- KieSession ksession = kbase.newKieSession(getConfForSession(sessionName), null);
- return ksession;
+ return kbase.newKieSession(getConfForSession(sessionName), null);
+ }
+
+ @Override
+ public StatelessKieSession newStatelessKieSession() {
+ return newStatelessKieSession("$defaultStatelessKieSession$");
+ }
+
+ @Override
+ public StatelessKieSession newStatelessKieSession(String sessionName) {
+ KieBase kbase = getKieBaseForSession(sessionName);
+ if (kbase == null) {
+ throw new RuntimeException("Unknown StatelessKieSession with name '" + sessionName + "'");
+ }
+ return kbase.newStatelessKieSession(getConfForSession(sessionName));
}
private KieBase getKieBaseForSession(String sessionName) {
diff --git a/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeQuarkusTemplate.java b/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeQuarkusTemplate.java
index ee69deb295e..5f4da3847b9 100644
--- a/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeQuarkusTemplate.java
+++ b/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeQuarkusTemplate.java
@@ -25,6 +25,7 @@
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieRuntimeBuilder;
+import org.kie.api.runtime.StatelessKieSession;
import org.drools.modelcompiler.KieBaseBuilder;
@jakarta.enterprise.context.ApplicationScoped
@@ -63,8 +64,21 @@ public KieSession newKieSession(String sessionName) {
if (kbase == null) {
throw new RuntimeException("Unknown KieSession with name '" + sessionName + "'");
}
- KieSession ksession = kbase.newKieSession(getConfForSession(sessionName), null);
- return ksession;
+ return kbase.newKieSession(getConfForSession(sessionName), null);
+ }
+
+ @Override
+ public StatelessKieSession newStatelessKieSession() {
+ return newStatelessKieSession("$defaultStatelessKieSession$");
+ }
+
+ @Override
+ public StatelessKieSession newStatelessKieSession(String sessionName) {
+ KieBase kbase = getKieBaseForSession(sessionName);
+ if (kbase == null) {
+ throw new RuntimeException("Unknown StatelessKieSession with name '" + sessionName + "'");
+ }
+ return kbase.newStatelessKieSession(getConfForSession(sessionName));
}
private KieBase getKieBaseForSession(String sessionName) {
diff --git a/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeSpringTemplate.java b/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeSpringTemplate.java
index 3bb8b500842..13ac7e0e26e 100644
--- a/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeSpringTemplate.java
+++ b/drools-model/drools-model-codegen/src/main/resources/class-templates/rules/ProjectRuntimeSpringTemplate.java
@@ -25,6 +25,7 @@
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieRuntimeBuilder;
+import org.kie.api.runtime.StatelessKieSession;
import org.drools.modelcompiler.KieBaseBuilder;
@org.springframework.stereotype.Component
@@ -63,8 +64,21 @@ public KieSession newKieSession(String sessionName) {
if (kbase == null) {
throw new RuntimeException("Unknown KieSession with name '" + sessionName + "'");
}
- KieSession ksession = kbase.newKieSession(getConfForSession(sessionName), null);
- return ksession;
+ return kbase.newKieSession(getConfForSession(sessionName), null);
+ }
+
+ @Override
+ public StatelessKieSession newStatelessKieSession() {
+ return newStatelessKieSession("$defaultStatelessKieSession$");
+ }
+
+ @Override
+ public StatelessKieSession newStatelessKieSession(String sessionName) {
+ KieBase kbase = getKieBaseForSession(sessionName);
+ if (kbase == null) {
+ throw new RuntimeException("Unknown StatelessKieSession with name '" + sessionName + "'");
+ }
+ return kbase.newStatelessKieSession(getConfForSession(sessionName));
}
private KieBase getKieBaseForSession(String sessionName) {
diff --git a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/CustomConstraintOperatorTest.java b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/CustomConstraintOperatorTest.java
new file mode 100644
index 00000000000..d1b5c6f7768
--- /dev/null
+++ b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/CustomConstraintOperatorTest.java
@@ -0,0 +1,254 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.drools.model.codegen.execmodel;
+
+import java.util.function.BiPredicate;
+
+import org.drools.base.common.NetworkNode;
+import org.drools.base.prototype.PrototypeObjectType;
+import org.drools.base.rule.IndexableConstraint;
+import org.drools.core.reteoo.AlphaNode;
+import org.drools.core.reteoo.BetaNode;
+import org.drools.core.reteoo.EntryPointNode;
+import org.drools.core.reteoo.ObjectTypeNode;
+import org.drools.kiesession.rulebase.InternalKnowledgeBase;
+import org.drools.model.ConstraintOperator;
+import org.drools.model.Index;
+import org.drools.model.Model;
+import org.drools.model.Rule;
+import org.drools.model.codegen.execmodel.domain.Result;
+import org.drools.model.impl.ModelImpl;
+import org.drools.model.prototype.PrototypeVariable;
+import org.drools.modelcompiler.KieBaseBuilder;
+import org.drools.modelcompiler.constraints.LambdaConstraint;
+import org.junit.Test;
+import org.kie.api.KieBase;
+import org.kie.api.prototype.PrototypeFact;
+import org.kie.api.prototype.PrototypeFactInstance;
+import org.kie.api.runtime.KieSession;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.drools.model.DSL.on;
+import static org.drools.model.PatternDSL.rule;
+import static org.drools.model.prototype.PrototypeDSL.protoPattern;
+import static org.drools.model.prototype.PrototypeDSL.variable;
+import static org.drools.model.prototype.PrototypeExpression.fixedValue;
+import static org.drools.model.prototype.PrototypeExpression.prototypeField;
+import static org.kie.api.prototype.PrototypeBuilder.prototype;
+
+public class CustomConstraintOperatorTest {
+
+ static class CustomConstraintOperator implements ConstraintOperator {
+
+ public int counter = 0;
+
+ @Override
+ public BiPredicate asPredicate() {
+ return (t, v) -> {
+ counter++;
+ return t.equals(v);
+ };
+ }
+
+ @Override
+ public boolean hasIndex() {
+ return true;
+ }
+
+ @Override
+ public Index.ConstraintType getIndexType() {
+ return Index.ConstraintType.EQUAL;
+ }
+
+ @Override
+ public String toString() {
+ return Index.ConstraintType.EQUAL.toString();
+ }
+ }
+
+ @Test
+ public void alphaIndexIneffective() {
+ CustomConstraintOperator customConstraintOperator = new CustomConstraintOperator();
+
+ PrototypeFact testPrototype = prototype("test").asFact();
+ PrototypeVariable testV = variable(testPrototype);
+
+ Rule rule1 = rule("alpha1")
+ .build(
+ protoPattern(testV)
+ .expr(prototypeField("fieldA"), customConstraintOperator, fixedValue(1)),
+ on(testV).execute((drools, x) ->
+ drools.insert(new Result("Found"))
+ )
+ );
+
+ Model model = new ModelImpl().addRule(rule1);
+ KieBase kieBase = KieBaseBuilder.createKieBaseFromModel(model);
+ KieSession ksession = kieBase.newKieSession();
+
+ PrototypeFactInstance testFact = testPrototype.newInstance();
+ testFact.put("fieldA", 1);
+
+ ksession.insert(testFact);
+ assertThat(ksession.fireAllRules()).isEqualTo(1);
+
+ // Index is created, but actual alpha index hashing works only with more than 3 nodes
+ Index index = getFirstAlphaNodeIndex((InternalKnowledgeBase) kieBase, testPrototype);
+ assertThat(index.getIndexType()).isEqualTo(Index.IndexType.ALPHA);
+ assertThat(index.getConstraintType()).isEqualTo(Index.ConstraintType.EQUAL);
+
+ // alpha index hashing is not effective, so the predicated is called
+ assertThat(customConstraintOperator.counter).isEqualTo(1);
+ }
+
+ @Test
+ public void alphaIndexEffective() {
+ CustomConstraintOperator customConstraintOperator = new CustomConstraintOperator();
+
+ PrototypeFact testPrototype = prototype("test").asFact();
+ PrototypeVariable testV = variable(testPrototype);
+
+ Rule rule1 = rule("alpha1")
+ .build(
+ protoPattern(testV)
+ .expr(prototypeField("fieldA"), customConstraintOperator, fixedValue(1)),
+ on(testV).execute((drools, x) ->
+ drools.insert(new Result("Found"))
+ )
+ );
+ Rule rule2 = rule("alpha2")
+ .build(
+ protoPattern(testV)
+ .expr(prototypeField("fieldA"), customConstraintOperator, fixedValue(2)),
+ on(testV).execute((drools, x) ->
+ drools.insert(new Result("Found"))
+ )
+ );
+ Rule rule3 = rule("alpha3")
+ .build(
+ protoPattern(testV)
+ .expr(prototypeField("fieldA"), customConstraintOperator, fixedValue(3)),
+ on(testV).execute((drools, x) ->
+ drools.insert(new Result("Found"))
+ )
+ );
+
+ Model model = new ModelImpl().addRule(rule1).addRule(rule2).addRule(rule3);
+ KieBase kieBase = KieBaseBuilder.createKieBaseFromModel(model);
+ KieSession ksession = kieBase.newKieSession();
+
+ PrototypeFactInstance testFact = testPrototype.newInstance();
+ testFact.put("fieldA", 1);
+
+ ksession.insert(testFact);
+ assertThat(ksession.fireAllRules()).isEqualTo(1);
+
+ Index index = getFirstAlphaNodeIndex((InternalKnowledgeBase) kieBase, testPrototype);
+ assertThat(index.getIndexType()).isEqualTo(Index.IndexType.ALPHA);
+ assertThat(index.getConstraintType()).isEqualTo(Index.ConstraintType.EQUAL);
+
+ // alpha index hashing is effective, so the predicated is not called
+ assertThat(customConstraintOperator.counter).isZero();
+ }
+
+ private static Index getFirstAlphaNodeIndex(InternalKnowledgeBase kieBase, PrototypeFact testPrototype) {
+ EntryPointNode epn = kieBase.getRete().getEntryPointNodes().values().iterator().next();
+ ObjectTypeNode otn = epn.getObjectTypeNodes().get(new PrototypeObjectType(testPrototype));
+ AlphaNode alphaNode = (AlphaNode) otn.getObjectSinkPropagator().getSinks()[0];
+ IndexableConstraint constraint = (IndexableConstraint) alphaNode.getConstraint();
+ return ((LambdaConstraint) constraint).getEvaluator().getIndex();
+ }
+
+ @Test
+ public void betaIndex() {
+ CustomConstraintOperator customConstraintOperator = new CustomConstraintOperator();
+
+ Result result = new Result();
+
+ PrototypeFact personFact = prototype("org.drools.Person").withField("name").withField("age").asFact();
+
+ PrototypeVariable markV = variable(personFact);
+ PrototypeVariable ageMateV = variable(personFact);
+
+ Rule rule = rule("beta")
+ .build(
+ protoPattern(markV)
+ .expr("name", Index.ConstraintType.EQUAL, "Mark"),
+ protoPattern(ageMateV)
+ .expr("name", Index.ConstraintType.NOT_EQUAL, "Mark")
+ .expr("age", customConstraintOperator, markV, "age"),
+ on(ageMateV, markV).execute((p1, p2) -> result.setValue(p1.get("name") + " is the same age as " + p2.get("name")))
+ );
+
+ Model model = new ModelImpl().addRule(rule);
+ KieBase kieBase = KieBaseBuilder.createKieBaseFromModel(model);
+
+ KieSession ksession = kieBase.newKieSession();
+
+ PrototypeFactInstance mark = personFact.newInstance();
+ mark.put("name", "Mark");
+ mark.put("age", 37);
+
+ PrototypeFactInstance john = personFact.newInstance();
+ john.put("name", "John");
+ john.put("age", 39);
+
+ PrototypeFactInstance paul = personFact.newInstance();
+ paul.put("name", "Paul");
+ paul.put("age", 37);
+
+ ksession.insert(mark);
+ ksession.insert(john);
+ ksession.insert(paul);
+
+ ksession.fireAllRules();
+ assertThat(result.getValue()).isEqualTo("Paul is the same age as Mark");
+
+ Index index = getFirstBetaNodeIndex((InternalKnowledgeBase) kieBase, personFact);
+ assertThat(index.getIndexType()).isEqualTo(Index.IndexType.BETA);
+ assertThat(index.getConstraintType()).isEqualTo(Index.ConstraintType.EQUAL);
+
+ // When beta index is used, the predicate in the custom operator is not actually called
+ assertThat(customConstraintOperator.counter).isZero();
+ }
+
+ private static Index getFirstBetaNodeIndex(InternalKnowledgeBase kieBase, PrototypeFact testPrototype) {
+ EntryPointNode epn = kieBase.getRete().getEntryPointNodes().values().iterator().next();
+ ObjectTypeNode otn = epn.getObjectTypeNodes().get(new PrototypeObjectType(testPrototype));
+ NetworkNode[] sinks = otn.getObjectSinkPropagator().getSinks();
+ BetaNode betaNode = findBetaNode(sinks);
+
+ IndexableConstraint constraint = (IndexableConstraint) betaNode.getConstraints()[0];
+ return ((LambdaConstraint) constraint).getEvaluator().getIndex();
+ }
+
+ private static BetaNode findBetaNode(NetworkNode[] sinks) {
+ for (NetworkNode sink : sinks) {
+ if (sink instanceof BetaNode) {
+ return (BetaNode) sink;
+ } else {
+ BetaNode betaNode = findBetaNode(sink.getSinks());
+ if (betaNode != null) {
+ return betaNode;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/drlxparse/CoercedExpressionTest.java b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/drlxparse/CoercedExpressionTest.java
index 1264a096981..83e1a2c3a6d 100644
--- a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/drlxparse/CoercedExpressionTest.java
+++ b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/drlxparse/CoercedExpressionTest.java
@@ -127,9 +127,9 @@ public void castToShort() {
@Test
public void castMaps() {
final TypedExpression left = expr(THIS_PLACEHOLDER + ".getAge()", Integer.class);
- final TypedExpression right = expr("$m.get(\"age\")", java.util.Map.class);
+ final TypedExpression right = expr("$m.get(\"age\")", Object.class);
final CoercedExpression.CoercedExpressionResult coerce = new CoercedExpression(left, right, false).coerce();
- assertThat(coerce.getCoercedRight()).isEqualTo(expr("(java.lang.Integer)$m.get(\"age\")", Map.class));
+ assertThat(coerce.getCoercedRight()).isEqualTo(expr("$m.get(\"age\")", Object.class));
}
@Test
diff --git a/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeDSL.java b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeDSL.java
index 1952375d118..265a4304297 100644
--- a/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeDSL.java
+++ b/drools-model/drools-model-prototype/src/main/java/org/drools/model/prototype/PrototypeDSL.java
@@ -127,16 +127,22 @@ public PrototypePatternDef expr(PrototypeExpression left, ConstraintOperator ope
reactOnFields.addAll(left.getImpactedFields());
reactOnFields.addAll(right.getImpactedFields());
+ // If operator is not Index.ConstraintType, it may contain Index.ConstraintType internally for indexing purposes
+ ConstraintOperator operatorAsIndexType = operator;
+ if (operator.hasIndex()) {
+ operatorAsIndexType = operator.getIndexType();
+ }
+
expr(createExprId(left, operator, right),
asPredicate1(leftExtractor, operator, right.asFunction(prototype)),
- createAlphaIndex(left, operator, right, prototype, leftExtractor),
+ createAlphaIndex(left, operatorAsIndexType, right, prototype, leftExtractor),
reactOn( reactOnFields.toArray(new String[reactOnFields.size()])) );
return this;
}
- private static AlphaIndex createAlphaIndex(PrototypeExpression left, ConstraintOperator operator, PrototypeExpression right, Prototype prototype, Function1 leftExtractor) {
- if (left.getIndexingKey().isPresent() && right instanceof PrototypeExpression.FixedValue && operator instanceof Index.ConstraintType constraintType) {
+ private static AlphaIndex createAlphaIndex(PrototypeExpression left, ConstraintOperator operatorAsIndexType, PrototypeExpression right, Prototype prototype, Function1 leftExtractor) {
+ if (left.getIndexingKey().isPresent() && right instanceof PrototypeExpression.FixedValue && operatorAsIndexType instanceof Index.ConstraintType constraintType) {
String fieldName = left.getIndexingKey().get();
Prototype.Field field = prototype.getField(fieldName);
Object value = ((PrototypeExpression.FixedValue) right).getValue();
@@ -167,9 +173,15 @@ public PrototypePatternDef expr(PrototypeExpression left, ConstraintOperator ope
reactOnFields.addAll(left.getImpactedFields());
reactOnFields.addAll(right.getImpactedFields());
+ // If operator is not Index.ConstraintType, it may contain Index.ConstraintType internally for indexing purposes
+ ConstraintOperator operatorAsIndexType = operator;
+ if (operator.hasIndex()) {
+ operatorAsIndexType = operator.getIndexType();
+ }
+
expr(createExprId(left, operator, right),
other, asPredicate2(left.asFunction(prototype), operator, right.asFunction(otherPrototype)),
- createBetaIndex(left, operator, right, prototype, otherPrototype),
+ createBetaIndex(left, operatorAsIndexType, right, prototype, otherPrototype),
reactOn( reactOnFields.toArray(new String[reactOnFields.size()])) );
return this;
@@ -181,8 +193,8 @@ private static String createExprId(PrototypeExpression left, ConstraintOperator
return "expr:" + leftId + ":" + operator + ":" + rightId;
}
- private BetaIndex createBetaIndex(PrototypeExpression left, ConstraintOperator operator, PrototypeExpression right, Prototype prototype, Prototype otherPrototype) {
- if (left.getIndexingKey().isPresent() && operator instanceof Index.ConstraintType constraintType && right.getIndexingKey().isPresent()) {
+ private BetaIndex createBetaIndex(PrototypeExpression left, ConstraintOperator operatorAsIndexType, PrototypeExpression right, Prototype prototype, Prototype otherPrototype) {
+ if (left.getIndexingKey().isPresent() && operatorAsIndexType instanceof Index.ConstraintType constraintType && right.getIndexingKey().isPresent()) {
String fieldName = left.getIndexingKey().get();
Prototype.Field field = prototype.getField(fieldName);
Function1 extractor = left.asFunction(prototype);
diff --git a/drools-mvel/src/main/java/org/drools/mvel/MVELConstraintBuilder.java b/drools-mvel/src/main/java/org/drools/mvel/MVELConstraintBuilder.java
index 38809896b71..2b9fb57ed10 100644
--- a/drools-mvel/src/main/java/org/drools/mvel/MVELConstraintBuilder.java
+++ b/drools-mvel/src/main/java/org/drools/mvel/MVELConstraintBuilder.java
@@ -97,6 +97,8 @@
import org.drools.mvel.expr.MVELObjectExpression;
import org.drools.mvel.expr.MvelEvaluator;
import org.drools.mvel.java.JavaForMvelDialectConfiguration;
+import org.drools.util.CoercionUtil;
+import org.drools.util.MethodUtils;
import org.kie.api.definition.rule.Rule;
import org.mvel2.ConversionHandler;
import org.mvel2.DataConversion;
@@ -426,8 +428,6 @@ private MVELCompilationUnit buildCompilationUnit( final RuleBuildContext context
}
}
- MVELDialect dialect = (MVELDialect) context.getDialect( "mvel" );
-
MVELCompilationUnit unit = null;
try {
@@ -439,16 +439,8 @@ private MVELCompilationUnit buildCompilationUnit( final RuleBuildContext context
((ClassObjectType) p.getObjectType()).getClassType() );
}
- unit = dialect.getMVELCompilationUnit( (String) predicateDescr.getContent(),
- analysis,
- previousDeclarations,
- localDeclarations,
- null,
- context,
- "drools",
- KnowledgeHelper.class,
- context.isInXpath(),
- MVELCompilationUnit.Scope.CONSTRAINT );
+ unit = MVELDialect.getMVELCompilationUnit( (String) predicateDescr.getContent(), analysis, previousDeclarations, localDeclarations,
+ null, context, "drools", KnowledgeHelper.class, context.isInXpath(), MVELCompilationUnit.Scope.CONSTRAINT );
} catch ( final Exception e ) {
copyErrorLocation(e, predicateDescr);
context.addError( new DescrBuildError( context.getParentDescr(),
@@ -486,48 +478,14 @@ private StringCoercionCompatibilityEvaluator() { }
@Override
public boolean areEqualityCompatible(Class> c1, Class> c2) {
- if (c1 == NullType.class || c2 == NullType.class) {
- return true;
- }
- if (c1 == String.class || c2 == String.class) {
- return true;
- }
- Class> boxed1 = convertFromPrimitiveType(c1);
- Class> boxed2 = convertFromPrimitiveType(c2);
- if (boxed1.isAssignableFrom(boxed2) || boxed2.isAssignableFrom(boxed1)) {
- return true;
- }
- if (Number.class.isAssignableFrom(boxed1) && Number.class.isAssignableFrom(boxed2)) {
- return true;
- }
- if (areEqualityCompatibleEnums(boxed1, boxed2)) {
- return true;
- }
- return !Modifier.isFinal(c1.getModifiers()) && !Modifier.isFinal(c2.getModifiers());
- }
-
- protected boolean areEqualityCompatibleEnums(final Class> boxed1,
- final Class> boxed2) {
- return boxed1.isEnum() && boxed2.isEnum() && boxed1.getName().equals(boxed2.getName())
- && equalEnumConstants(boxed1.getEnumConstants(), boxed2.getEnumConstants());
- }
-
- private boolean equalEnumConstants(final Object[] aa,
- final Object[] bb) {
- if (aa.length != bb.length) {
- return false;
- }
- for (int i = 0; i < aa.length; i++) {
- if (!Objects.equals(aa[i].getClass().getName(), bb[i].getClass().getName())) {
- return false;
- }
- }
- return true;
+ return CoercionUtil.areEqualityCompatible(c1 == NullType.class ? MethodUtils.NullType.class : c1,
+ c2 == NullType.class ? MethodUtils.NullType.class : c2);
}
@Override
public boolean areComparisonCompatible(Class> c1, Class> c2) {
- return areEqualityCompatible(c1, c2);
+ return CoercionUtil.areComparisonCompatible(c1 == NullType.class ? MethodUtils.NullType.class : c1,
+ c2 == NullType.class ? MethodUtils.NullType.class : c2);
}
}
@@ -558,16 +516,8 @@ public TimerExpression buildTimerExpression( String expression, RuleBuildContext
}
Arrays.sort(previousDeclarations, SortDeclarations.instance);
- MVELCompilationUnit unit = dialect.getMVELCompilationUnit( expression,
- analysis,
- previousDeclarations,
- null,
- null,
- context,
- "drools",
- KnowledgeHelper.class,
- false,
- MVELCompilationUnit.Scope.EXPRESSION );
+ MVELCompilationUnit unit = MVELDialect.getMVELCompilationUnit( expression, analysis, previousDeclarations, null, null,
+ context, "drools", KnowledgeHelper.class, false, MVELCompilationUnit.Scope.EXPRESSION );
MVELObjectExpression expr = new MVELObjectExpression( unit, dialect.getId() );
@@ -578,9 +528,7 @@ public TimerExpression buildTimerExpression( String expression, RuleBuildContext
return expr;
} catch ( final Exception e ) {
AsmUtil.copyErrorLocation(e, context.getRuleDescr());
- context.addError( new DescrBuildError( context.getParentDescr(),
- context.getRuleDescr(),
- null,
+ context.addError( new DescrBuildError( context.getParentDescr(), context.getRuleDescr(), null,
"Unable to build expression : " + e.getMessage() + "'" + expression + "'" ) );
return null;
} finally {
@@ -595,10 +543,8 @@ public AnalysisResult analyzeExpression(Class> thisClass, String expr) {
return analyzeExpression( expr, conf, new BoundIdentifiers( thisClass ) );
}
- private static MVELAnalysisResult analyzeExpression(String expr,
- ParserConfiguration conf,
- BoundIdentifiers availableIdentifiers) {
- if (expr.trim().length() == 0) {
+ private static MVELAnalysisResult analyzeExpression(String expr, ParserConfiguration conf, BoundIdentifiers availableIdentifiers) {
+ if (expr.trim().isEmpty()) {
MVELAnalysisResult result = analyze( (Set ) Collections.EMPTY_SET, availableIdentifiers );
result.setMvelVariables( new HashMap<>() );
result.setTypesafe( true );
diff --git a/drools-quarkus-extension/drools-quarkus-deployment/src/main/java/org/drools/quarkus/deployment/DroolsAssetsProcessor.java b/drools-quarkus-extension/drools-quarkus-deployment/src/main/java/org/drools/quarkus/deployment/DroolsAssetsProcessor.java
index 08c68ad06de..32022f63891 100644
--- a/drools-quarkus-extension/drools-quarkus-deployment/src/main/java/org/drools/quarkus/deployment/DroolsAssetsProcessor.java
+++ b/drools-quarkus-extension/drools-quarkus-deployment/src/main/java/org/drools/quarkus/deployment/DroolsAssetsProcessor.java
@@ -205,6 +205,9 @@ private Map readKieBaseModels() {
case "default":
kieSessionModel.setDefault( config.getValue(propertyName, Boolean.class) );
break;
+ case "stateless":
+ kieSessionModel.setType( config.getValue(propertyName, Boolean.class) ? KieSessionModel.KieSessionType.STATELESS : KieSessionModel.KieSessionType.STATEFUL );
+ break;
case "clockType":
kieSessionModel.setClockType( ClockTypeOption.get(config.getValue(propertyName, String.class) ) );
break;
diff --git a/drools-quarkus-extension/drools-quarkus-examples/drools-quarkus-examples-multiunit/src/test/java/org/drools/quarkus/ruleunit/examples/multiunit/RuntimeTest.java b/drools-quarkus-extension/drools-quarkus-examples/drools-quarkus-examples-multiunit/src/test/java/org/drools/quarkus/ruleunit/examples/multiunit/RuntimeTest.java
index 4122df9325f..322207cea27 100644
--- a/drools-quarkus-extension/drools-quarkus-examples/drools-quarkus-examples-multiunit/src/test/java/org/drools/quarkus/ruleunit/examples/multiunit/RuntimeTest.java
+++ b/drools-quarkus-extension/drools-quarkus-examples/drools-quarkus-examples-multiunit/src/test/java/org/drools/quarkus/ruleunit/examples/multiunit/RuntimeTest.java
@@ -29,7 +29,7 @@
import org.junit.jupiter.api.Test;
import org.kie.api.runtime.rule.FactHandle;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.assertj.core.api.Assertions.assertThat;
@QuarkusTest
public class RuntimeTest {
@@ -69,7 +69,7 @@ public void delete(DataHandle handle) {
instance.fire();
- assertEquals("Hi 1", output.get().getText());
+ assertThat(output.get().getText()).isEqualTo("Hi 1");
}
@Test
@@ -101,6 +101,6 @@ public void delete(DataHandle handle) {
instance.fire();
- assertEquals("Hi 2", output.get().getText());
+ assertThat(output.get().getText()).isEqualTo("Hi 2");
}
}
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test-hotreload/pom.xml b/drools-quarkus-extension/drools-quarkus-integration-test-hotreload/pom.xml
index e06d5791feb..7b406c931dc 100644
--- a/drools-quarkus-extension/drools-quarkus-integration-test-hotreload/pom.xml
+++ b/drools-quarkus-extension/drools-quarkus-integration-test-hotreload/pom.xml
@@ -54,6 +54,10 @@
io.quarkus
quarkus-resteasy-jackson
+
+ org.assertj
+ assertj-core
+
io.quarkus
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test-hotreload/src/test/java/org/drools/quarkus/test/hotreload/HotReloadIT.java b/drools-quarkus-extension/drools-quarkus-integration-test-hotreload/src/test/java/org/drools/quarkus/test/hotreload/HotReloadIT.java
index 5e5de51d846..1d5bb063a0a 100644
--- a/drools-quarkus-extension/drools-quarkus-integration-test-hotreload/src/test/java/org/drools/quarkus/test/hotreload/HotReloadIT.java
+++ b/drools-quarkus-extension/drools-quarkus-integration-test-hotreload/src/test/java/org/drools/quarkus/test/hotreload/HotReloadIT.java
@@ -28,8 +28,7 @@
import org.junit.jupiter.api.extension.RegisterExtension;
import static io.restassured.RestAssured.given;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
public class HotReloadIT {
@@ -50,7 +49,7 @@ public class HotReloadIT {
public void testServletChange() throws InterruptedException {
String personsPayload = "[{\"name\":\"Mario\",\"age\":45,\"adult\":false},{\"name\":\"Sofia\",\"age\":17,\"adult\":false}]";
- List names = given()
+ List names = given()
.baseUri("http://localhost:" + HTTP_TEST_PORT)
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
@@ -60,10 +59,9 @@ public void testServletChange() throws InterruptedException {
.then()
.statusCode(200)
.extract()
- .as(List.class);
+ .>as(List.class);
- assertEquals(1, names.size());
- assertEquals("Mario", names.get(0));
+ assertThat(names).hasSize(1).containsExactly("Mario");
test.modifyResourceFile(RESOURCE_FILE, s -> s.replaceAll("18", "16"));
@@ -75,10 +73,8 @@ public void testServletChange() throws InterruptedException {
.post("/find-adult")
.then()
.statusCode(200)
- .extract().as(List.class);
+ .extract().>as(List.class);
- assertEquals(2, names.size());
- assertTrue(names.contains("Mario"));
- assertTrue(names.contains("Sofia"));
+ assertThat(names).hasSize(2).containsExactlyInAnyOrder("Mario", "Sofia");
}
}
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test/pom.xml b/drools-quarkus-extension/drools-quarkus-integration-test/pom.xml
index 77e1fb06d06..1a4e3e16452 100644
--- a/drools-quarkus-extension/drools-quarkus-integration-test/pom.xml
+++ b/drools-quarkus-extension/drools-quarkus-integration-test/pom.xml
@@ -41,6 +41,10 @@
org.drools
drools-quarkus
+
+ org.drools
+ drools-commands
+
org.drools
drools-decisiontables
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/application.properties b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/application.properties
index b26fc31a187..e7193773be4 100644
--- a/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/application.properties
+++ b/drools-quarkus-extension/drools-quarkus-integration-test/src/main/resources/application.properties
@@ -21,12 +21,16 @@ drools.prototypes=allowed
drools.kbase.canDrinkKB.packages=org.drools.drl
drools.kbase.canDrinkKB.ksession.canDrinkKS.default=true
+drools.kbase.canDrinkKB.ksession.statelessCanDrinkKS.stateless=true
+drools.kbase.canDrinkKB.ksession.statelessCanDrinkKS.default=true
drools.kbase.canDrinkKBDTable.packages=org.drools.dtable
-drools.kbase.canDrinkKBDTable.ksession=canDrinkKSDTable
+drools.kbase.canDrinkKBDTable.ksession.canDrinkKSDTable.stateless=false
+drools.kbase.canDrinkKBDTable.ksession.statelessCanDrinkKSDTable.stateless=true
drools.kbase.canDrinkKBYaml.packages=org.drools.yaml
drools.kbase.canDrinkKBYaml.ksession=canDrinkKSYaml
+drools.kbase.canDrinkKBYaml.ksession.statelessCanDrinkKSYaml.stateless=true
drools.kbase.canDrinkKBPrototype.packages=org.drools.prototype
drools.kbase.canDrinkKBPrototype.prototypes=allowed
diff --git a/drools-quarkus-extension/drools-quarkus-integration-test/src/test/java/org/drools/quarkus/test/RuntimeTest.java b/drools-quarkus-extension/drools-quarkus-integration-test/src/test/java/org/drools/quarkus/test/RuntimeTest.java
index 96c380dd554..1ac971dafd9 100644
--- a/drools-quarkus-extension/drools-quarkus-integration-test/src/test/java/org/drools/quarkus/test/RuntimeTest.java
+++ b/drools-quarkus-extension/drools-quarkus-integration-test/src/test/java/org/drools/quarkus/test/RuntimeTest.java
@@ -24,14 +24,18 @@
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
+import org.kie.api.KieServices;
+import org.kie.api.command.KieCommands;
import org.kie.api.definition.KiePackage;
+import org.kie.api.internal.utils.KieService;
import org.kie.api.prototype.PrototypeFact;
import org.kie.api.prototype.PrototypeFactInstance;
import org.kie.api.runtime.KieRuntimeBuilder;
import org.kie.api.runtime.KieSession;
+import org.kie.api.runtime.RuntimeSession;
+import org.kie.api.runtime.StatelessKieSession;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.kie.api.prototype.PrototypeBuilder.prototype;
@QuarkusTest
@@ -43,31 +47,59 @@ public class RuntimeTest {
@Test
public void testDrlEvaluation() {
// canDrinkKS is the default session
- testSimpleDrl(runtimeBuilder.newKieSession(), "org.drools.drl");
+ testSimpleDrl(runtimeBuilder.newKieSession(), "org.drools.drl", true);
}
@Test
public void testDTableEvaluation() {
- testSimpleDrl(runtimeBuilder.newKieSession("canDrinkKSDTable"), "org.drools.dtable");
+ testSimpleDrl(runtimeBuilder.newKieSession("canDrinkKSDTable"), "org.drools.dtable", true);
}
@Test
public void testYamlEvaluation() {
- testSimpleDrl(runtimeBuilder.newKieSession("canDrinkKSYaml"), "org.drools.yaml");
+ testSimpleDrl(runtimeBuilder.newKieSession("canDrinkKSYaml"), "org.drools.yaml", true);
}
- private void testSimpleDrl(KieSession ksession, String assetPackage) {
- List pkgNames = ksession.getKieBase().getKiePackages().stream().map(KiePackage::getName).collect(Collectors.toList());
- assertEquals(2, pkgNames.size());
- assertTrue(pkgNames.contains("org.drools.quarkus.test"));
- assertTrue(pkgNames.contains(assetPackage));
+ @Test
+ public void testStatelessDrlEvaluation() {
+ // statelessCanDrinkKS is the default stateless session
+ testSimpleDrl(runtimeBuilder.newStatelessKieSession(), "org.drools.drl", false);
+ }
+
+ @Test
+ public void testStatelessDTableEvaluation() {
+ testSimpleDrl(runtimeBuilder.newStatelessKieSession("statelessCanDrinkKSDTable"), "org.drools.dtable", false);
+ }
+
+ @Test
+ public void testStatelessYamlEvaluation() {
+ testSimpleDrl(runtimeBuilder.newStatelessKieSession("statelessCanDrinkKSYaml"), "org.drools.yaml", false);
+ }
+
+ private void testSimpleDrl(RuntimeSession session, String assetPackage, boolean stateful) {
+ if (stateful) {
+ assertThat(session).isInstanceOf(KieSession.class);
+ } else {
+ assertThat(session).isInstanceOf(StatelessKieSession.class);
+ }
+
+ List pkgNames = session.getKieBase().getKiePackages().stream().map(KiePackage::getName).collect(Collectors.toList());
+
+ assertThat(pkgNames).hasSize(2).containsExactlyInAnyOrder("org.drools.quarkus.test", assetPackage);
+
+ KieCommands kieCommands = KieServices.get().getCommands();
Result result = new Result();
- ksession.insert(result);
- ksession.insert(new Person("Mark", 17));
- ksession.fireAllRules();
+ session.execute( kieCommands.newBatchExecution(
+ kieCommands.newInsert(result),
+ kieCommands.newInsert(new Person("Mark", 17)),
+ kieCommands.newFireAllRules() ) );
+
+ assertThat(result.toString()).isEqualTo("Mark can NOT drink");
- assertEquals("Mark can NOT drink", result.toString());
+ if (stateful) {
+ ((KieSession) session).dispose();
+ }
}
@Test
@@ -85,7 +117,6 @@ public void testPrototypeEvaluation() {
ksession.insert(result);
ksession.fireAllRules();
-
- assertEquals("Mark can NOT drink", result.get("value"));
+ assertThat(result.get("value")).isEqualTo("Mark can NOT drink");
}
}
diff --git a/drools-quarkus-extension/drools-quarkus-ruleunit-integration-test/src/test/java/org/drools/quarkus/ruleunit/test/RuntimeTest.java b/drools-quarkus-extension/drools-quarkus-ruleunit-integration-test/src/test/java/org/drools/quarkus/ruleunit/test/RuntimeTest.java
index 873e112e293..1ac86e8100d 100644
--- a/drools-quarkus-extension/drools-quarkus-ruleunit-integration-test/src/test/java/org/drools/quarkus/ruleunit/test/RuntimeTest.java
+++ b/drools-quarkus-extension/drools-quarkus-ruleunit-integration-test/src/test/java/org/drools/quarkus/ruleunit/test/RuntimeTest.java
@@ -25,7 +25,7 @@
import jakarta.inject.Inject;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.assertj.core.api.Assertions.assertThat;
@QuarkusTest
public class RuntimeTest {
@@ -42,7 +42,6 @@ public void testRuleUnit() {
instance.fire();
}
- assertEquals(1, unit.getResults().size());
- assertEquals("Hello Mario", unit.getResults().get(0));
+ assertThat(unit.getResults()).hasSize(1).containsExactly("Hello Mario");
}
}
diff --git a/drools-quarkus-extension/drools-quarkus-util-deployment/src/main/java/org/drools/quarkus/util/deployment/KmoduleKieBaseModelsBuiltItem.java b/drools-quarkus-extension/drools-quarkus-util-deployment/src/main/java/org/drools/quarkus/util/deployment/KmoduleKieBaseModelsBuiltItem.java
index d437bc3dc8a..797b46ab81d 100644
--- a/drools-quarkus-extension/drools-quarkus-util-deployment/src/main/java/org/drools/quarkus/util/deployment/KmoduleKieBaseModelsBuiltItem.java
+++ b/drools-quarkus-extension/drools-quarkus-util-deployment/src/main/java/org/drools/quarkus/util/deployment/KmoduleKieBaseModelsBuiltItem.java
@@ -19,8 +19,6 @@
package org.drools.quarkus.util.deployment;
import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
import org.kie.api.builder.model.KieBaseModel;
diff --git a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/TimerAndCalendarFireUntilHaltTest.java b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/TimerAndCalendarFireUntilHaltTest.java
index c36fac63bc9..5022ae79916 100644
--- a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/TimerAndCalendarFireUntilHaltTest.java
+++ b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/TimerAndCalendarFireUntilHaltTest.java
@@ -109,9 +109,12 @@ public void testTimerRuleFires() throws Exception {
startEngine();
activateRule();
- advanceTimerOneSecond();
-
await().until(ruleHasFired("TimerRule", 1));
+
+ advanceTimerOneSecond();
+ await().until(ruleHasFired("TimerRule", 2));
+
+ stopEngine();
}
@Test(timeout = 10000)
@@ -126,14 +129,17 @@ public void testTimerRuleHaltStopsFiring() throws Exception {
"end";
setupKSessionFor(drl);
startEngine();
+
activateRule();
- advanceTimerOneSecond();
await().until(ruleHasFired("TimerRule", 1));
+
+ advanceTimerOneSecond();
+ await().until(ruleHasFired("TimerRule", 2));
stopEngine();
advanceTimerOneSecond();
- await().during(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(2)).until(ruleHasFired("TimerRule", 1));
+ await().during(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(2)).until(ruleHasFired("TimerRule", 2));
}
@Test(timeout = 10000)
@@ -148,15 +154,20 @@ public void testTimerRuleRestartsAfterStop() throws Exception {
"end";
setupKSessionFor(drl);
startEngine();
+
activateRule();
- advanceTimerOneSecond();
await().until(ruleHasFired("TimerRule", 1));
+
+ advanceTimerOneSecond();
+ await().until(ruleHasFired("TimerRule", 2));
stopEngine();
startEngine();
advanceTimerOneSecond();
- await().during(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(2)).until(ruleHasFired("TimerRule", 2));
+ await().during(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(2)).until(ruleHasFired("TimerRule", 3));
+
+ stopEngine();
}
@Test(timeout = 10000)
@@ -171,18 +182,21 @@ public void testTimerRuleDoesRestartsIfNoLongerHolds() throws Exception {
"end";
setupKSessionFor(drl);
startEngine();
+
activateRule();
- advanceTimerOneSecond();
-
await().until(ruleHasFired("TimerRule", 1));
+
+ advanceTimerOneSecond();
+ await().until(ruleHasFired("TimerRule", 2));
stopEngine();
disactivateRule();
startEngine();
advanceTimerOneSecond();
+ await().during(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(2)).until(ruleHasFired("TimerRule", 2));
- await().during(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(2)).until(ruleHasFired("TimerRule", 1));
+ stopEngine();
}
diff --git a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/DateCoercionTest.java b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/DateCoercionTest.java
index 5d6a7157042..1dd24026b54 100644
--- a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/DateCoercionTest.java
+++ b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/DateCoercionTest.java
@@ -25,11 +25,14 @@
import org.drools.testcoverage.common.util.KieBaseTestConfiguration;
import org.drools.testcoverage.common.util.KieBaseUtil;
+import org.drools.testcoverage.common.util.KieUtil;
import org.drools.testcoverage.common.util.TestParametersUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.kie.api.KieBase;
+import org.kie.api.builder.KieBuilder;
+import org.kie.api.builder.Message;
import org.kie.api.runtime.KieSession;
import static org.assertj.core.api.Assertions.assertThat;
@@ -176,4 +179,37 @@ public void testDateCoercionWithNestedOr() {
assertThat(list.size()).isEqualTo(1);
assertThat(list.get(0)).isEqualTo("working");
}
+
+ @Test
+ public void testLocalDateTimeCoercion() {
+ // DROOLS-7631
+ String drl = "import java.util.Date\n" +
+ "import java.time.LocalDateTime\n" +
+ "global java.util.List list\n" +
+ "declare DateContainer\n" +
+ " date: Date\n" +
+ "end\n" +
+ "declare LocalDateTimeContainer\n" +
+ " date: LocalDateTime\n" +
+ "end\n" +
+ "\n" +
+ "rule Init when\n" +
+ "then\n" +
+ " insert(new DateContainer(new Date( 1439882189744L )));" +
+ " insert(new LocalDateTimeContainer( LocalDateTime.now() ));" +
+ "end\n" +
+ "\n" +
+ "rule \"Test rule\"\n" +
+ "when\n" +
+ " DateContainer( $date: date )\n" +
+ " LocalDateTimeContainer( date > $date )\n" +
+ "then\n" +
+ " list.add(\"working\");\n" +
+ "end\n";
+
+ KieBuilder kieBuilder = KieUtil.getKieBuilderFromDrls(kieBaseTestConfiguration, false, drl);
+ List errors = kieBuilder.getResults().getMessages(Message.Level.ERROR);
+ assertThat(errors).hasSize(1);
+ assertThat(errors.get(0).getText()).contains("Comparison operation requires compatible types");
+ }
}
diff --git a/drools-util/src/main/java/org/drools/util/CoercionUtil.java b/drools-util/src/main/java/org/drools/util/CoercionUtil.java
index f91b2bd2358..bb7d5ac0e73 100644
--- a/drools-util/src/main/java/org/drools/util/CoercionUtil.java
+++ b/drools-util/src/main/java/org/drools/util/CoercionUtil.java
@@ -19,10 +19,14 @@
package org.drools.util;
+import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.temporal.Temporal;
+import java.util.Objects;
-import org.drools.util.MathUtils;
+import static org.drools.util.ClassUtils.convertFromPrimitiveType;
public class CoercionUtil {
@@ -194,4 +198,49 @@ public static Number coerceToNumber(Number value, Class> toClass) {
}
return ret;
}
+
+ public static boolean areEqualityCompatible(Class> c1, Class> c2) {
+ if (c1 == MethodUtils.NullType.class || c2 == MethodUtils.NullType.class) {
+ return true;
+ }
+ if (c1 == String.class || c2 == String.class) {
+ return true;
+ }
+ if (Temporal.class.isAssignableFrom(c1) && Temporal.class.isAssignableFrom(c2)) {
+ return true;
+ }
+ Class> boxed1 = convertFromPrimitiveType(c1);
+ Class> boxed2 = convertFromPrimitiveType(c2);
+ if (boxed1.isAssignableFrom(boxed2) || boxed2.isAssignableFrom(boxed1)) {
+ return true;
+ }
+ if (Number.class.isAssignableFrom(boxed1) && Number.class.isAssignableFrom(boxed2)) {
+ return true;
+ }
+ if (areEqualityCompatibleEnums(boxed1, boxed2)) {
+ return true;
+ }
+ return !Modifier.isFinal(c1.getModifiers()) && !Modifier.isFinal(c2.getModifiers());
+ }
+
+ protected static boolean areEqualityCompatibleEnums(Class> boxed1, Class> boxed2) {
+ return boxed1.isEnum() && boxed2.isEnum() && boxed1.getName().equals(boxed2.getName())
+ && equalEnumConstants(boxed1.getEnumConstants(), boxed2.getEnumConstants());
+ }
+
+ private static boolean equalEnumConstants(Object[] aa, Object[] bb) {
+ if (aa.length != bb.length) {
+ return false;
+ }
+ for (int i = 0; i < aa.length; i++) {
+ if (!Objects.equals(aa[i].getClass().getName(), bb[i].getClass().getName())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean areComparisonCompatible(Class> c1, Class> c2) {
+ return areEqualityCompatible(c1, c2);
+ }
}
diff --git a/kie-api/src/main/java/org/kie/api/command/KieCommands.java b/kie-api/src/main/java/org/kie/api/command/KieCommands.java
index afb5d8d2bbd..9cb50473ad2 100644
--- a/kie-api/src/main/java/org/kie/api/command/KieCommands.java
+++ b/kie-api/src/main/java/org/kie/api/command/KieCommands.java
@@ -29,6 +29,8 @@
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.api.runtime.rule.FactHandle;
+import static java.util.Arrays.asList;
+
/**
* KieCommands is a factory for Commands that can be used by classes that implement CommandExecutor. Typically more than one Command
* will want to be executed, where is where the BatchExecution comes in, which takes a List of commands, think of it as CompositeCommand.
@@ -115,6 +117,10 @@ Command newQuery(String identifier,
String name,
Object[] arguments);
+ default BatchExecutionCommand newBatchExecution(Command... commands) {
+ return newBatchExecution( asList(commands) );
+ }
+
BatchExecutionCommand newBatchExecution(List< ? extends Command> commands);
BatchExecutionCommand newBatchExecution(List< ? extends Command> commands, String lookup);
diff --git a/kie-api/src/main/java/org/kie/api/event/usertask/Attachment.java b/kie-api/src/main/java/org/kie/api/event/usertask/Attachment.java
deleted file mode 100644
index ded0ce0df24..00000000000
--- a/kie-api/src/main/java/org/kie/api/event/usertask/Attachment.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.kie.api.event.usertask;
-
-import java.net.URI;
-import java.util.Date;
-
-public interface Attachment {
-
- String getAttachmentId();
-
- String getAttachmentName();
-
- URI getAttachmentURI();
-
- String getUpdatedBy();
-
- Date getUpdatedAt();
-
-}
diff --git a/kie-api/src/main/java/org/kie/api/event/usertask/Comment.java b/kie-api/src/main/java/org/kie/api/event/usertask/Comment.java
deleted file mode 100644
index 004d3e7d6ee..00000000000
--- a/kie-api/src/main/java/org/kie/api/event/usertask/Comment.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.kie.api.event.usertask;
-
-import java.util.Date;
-
-public interface Comment {
-
- String getCommentId();
-
- String getCommentContent();
-
- String getUpdatedBy();
-
- Date getUpdatedAt();
-
-}
diff --git a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskAssignmentEvent.java b/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskAssignmentEvent.java
deleted file mode 100644
index 01d460e0ddb..00000000000
--- a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskAssignmentEvent.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.kie.api.event.usertask;
-
-public interface UserTaskAssignmentEvent extends UserTaskEvent {
-
- String getAssignmentType();
-
- String[] getNewUsersId();
-
- String[] getOldUsersId();
-
-}
diff --git a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskAttachmentEvent.java b/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskAttachmentEvent.java
deleted file mode 100644
index 9f82c73605e..00000000000
--- a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskAttachmentEvent.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.kie.api.event.usertask;
-
-public interface UserTaskAttachmentEvent extends UserTaskEvent {
-
- Attachment getOldAttachment();
-
- Attachment getNewAttachment();
-
-}
diff --git a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskCommentEvent.java b/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskCommentEvent.java
deleted file mode 100644
index b51eb3e6bd6..00000000000
--- a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskCommentEvent.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.kie.api.event.usertask;
-
-public interface UserTaskCommentEvent extends UserTaskEvent {
-
- Comment getOldComment();
-
- Comment getNewComment();
-
-}
diff --git a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskDeadlineEvent.java b/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskDeadlineEvent.java
deleted file mode 100644
index c1c46b7a1d0..00000000000
--- a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskDeadlineEvent.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.kie.api.event.usertask;
-
-import java.util.Map;
-
-import org.kie.api.runtime.process.WorkItem;
-
-/**
- * An event when a dealine for task has expired
- */
-public interface UserTaskDeadlineEvent extends UserTaskEvent {
-
- enum DeadlineType {
- Started,
- Completed
- }
-
- /**
- * Returns work item which timeout expires
- *
- * @return work item
- */
- WorkItem getWorkItem();
-
- /**
- * Returns notification data
- *
- * @return key-value pair list
- */
- Map getNotification();
-
- /**
- * Returns dealine type
- *
- * @return not started or not completed
- */
- DeadlineType getType();
-}
\ No newline at end of file
diff --git a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskEvent.java b/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskEvent.java
deleted file mode 100644
index 8f45c48b905..00000000000
--- a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskEvent.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.kie.api.event.usertask;
-
-import java.util.Date;
-
-import org.kie.api.event.KieRuntimeEvent;
-import org.kie.api.runtime.process.NodeInstance;
-import org.kie.api.runtime.process.ProcessInstance;
-import org.kie.api.runtime.process.WorkItem;
-
-/**
- * A runtime event related to the execution of process instances.
- */
-public interface UserTaskEvent
- extends
- KieRuntimeEvent {
-
- /**
- * The ProcessInstance this event relates to.
- *
- * @return the process instance
- */
- ProcessInstance getProcessInstance();
-
- NodeInstance getNodeInstance();
-
- WorkItem getWorkItem();
-
- String getUserTaskId();
-
- String getUserTaskDefinitionId();
-
- /**
- * Returns exact date when the event was created
- * @return time when event was created
- */
- Date getEventDate();
-
- /**
- * @return associated identity that performed the event
- */
- String getEventUser();
-
-}
diff --git a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskStateEvent.java b/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskStateEvent.java
deleted file mode 100644
index 7ed47cc4d37..00000000000
--- a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskStateEvent.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.kie.api.event.usertask;
-
-public interface UserTaskStateEvent extends UserTaskEvent {
-
- String getNewStatus();
-
- String getOldStatus();
-
-
-
-}
diff --git a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskVariableEvent.java b/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskVariableEvent.java
deleted file mode 100644
index a7dab82d79f..00000000000
--- a/kie-api/src/main/java/org/kie/api/event/usertask/UserTaskVariableEvent.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.kie.api.event.usertask;
-
-public interface UserTaskVariableEvent extends UserTaskEvent {
-
- enum VariableEventType {
- INPUT, OUTPUT
- }
-
- String getVariableName();
-
- Object getOldValue();
-
- Object getNewValue();
-
- VariableEventType getVariableType();
-}
diff --git a/kie-api/src/main/java/org/kie/api/runtime/KieRuntime.java b/kie-api/src/main/java/org/kie/api/runtime/KieRuntime.java
index 1ea1669fc18..d8495f069c2 100644
--- a/kie-api/src/main/java/org/kie/api/runtime/KieRuntime.java
+++ b/kie-api/src/main/java/org/kie/api/runtime/KieRuntime.java
@@ -18,53 +18,23 @@
*/
package org.kie.api.runtime;
-import java.util.Map;
-
-import org.kie.api.KieBase;
import org.kie.api.event.KieRuntimeEventManager;
-import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.process.ProcessRuntime;
import org.kie.api.runtime.rule.RuleRuntime;
import org.kie.api.time.SessionClock;
-public interface KieRuntime
- extends
- RuleRuntime,
- ProcessRuntime,
- KieRuntimeEventManager {
+public interface KieRuntime extends RuntimeSession, RuleRuntime, ProcessRuntime, KieRuntimeEventManager {
/**
* @return the session clock instance assigned to this session
*/
T getSessionClock();
- /**
- * Sets a global value in this session
- * @param identifier the global identifier
- * @param value the value assigned to the global identifier
- */
- void setGlobal(String identifier,
- Object value);
-
Object getGlobal(String identifier);
- Globals getGlobals();
-
Calendars getCalendars();
Environment getEnvironment();
- /**
- * @return the KieBase reference from which this stateful session was created.
- */
- KieBase getKieBase();
-
- void registerChannel(String name,
- Channel channel);
-
- void unregisterChannel(String name);
-
- Map< String, Channel> getChannels();
-
KieSessionConfiguration getSessionConfiguration();
}
diff --git a/kie-api/src/main/java/org/kie/api/runtime/KieRuntimeBuilder.java b/kie-api/src/main/java/org/kie/api/runtime/KieRuntimeBuilder.java
index 4628f816bbe..9f4868fa105 100644
--- a/kie-api/src/main/java/org/kie/api/runtime/KieRuntimeBuilder.java
+++ b/kie-api/src/main/java/org/kie/api/runtime/KieRuntimeBuilder.java
@@ -27,6 +27,9 @@ public interface KieRuntimeBuilder {
KieSession newKieSession();
KieSession newKieSession(String sessionName);
+ StatelessKieSession newStatelessKieSession();
+ StatelessKieSession newStatelessKieSession(String sessionName);
+
default KieSession newKieSession(KieSessionConfiguration conf) {
return getKieBase().newKieSession(conf, null);
}
diff --git a/kie-api/src/main/java/org/kie/api/runtime/RuntimeSession.java b/kie-api/src/main/java/org/kie/api/runtime/RuntimeSession.java
new file mode 100644
index 00000000000..60ddf5a957d
--- /dev/null
+++ b/kie-api/src/main/java/org/kie/api/runtime/RuntimeSession.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.api.runtime;
+
+import org.kie.api.KieBase;
+
+import java.util.Map;
+
+public interface RuntimeSession extends CommandExecutor {
+
+ /**
+ * @return the Globals store
+ */
+ Globals getGlobals();
+
+ /**
+ * Sets a global value on the globals store
+ *
+ * @param identifier the global identifier
+ * @param value the value assigned to the global identifier
+ */
+ void setGlobal(String identifier,
+ Object value);
+
+
+ /**
+ * Registers a channel with the given name
+ *
+ * @param name the name of the channel
+ * @param channel the channel instance. It has to be thread safe.
+ */
+ void registerChannel(String name,
+ Channel channel);
+
+ /**
+ * Unregisters the channel with the given name
+ *
+ * @param name
+ */
+ void unregisterChannel(String name);
+
+ /**
+ * @return a map with all registered channels.
+ */
+ Map getChannels();
+
+ /**
+ * @return the KieBase reference from which this stateless session was created.
+ */
+ KieBase getKieBase();
+}
diff --git a/kie-api/src/main/java/org/kie/api/runtime/StatelessKieSession.java b/kie-api/src/main/java/org/kie/api/runtime/StatelessKieSession.java
index 4c7869eb1e6..5f8460d6bb4 100644
--- a/kie-api/src/main/java/org/kie/api/runtime/StatelessKieSession.java
+++ b/kie-api/src/main/java/org/kie/api/runtime/StatelessKieSession.java
@@ -18,9 +18,6 @@
*/
package org.kie.api.runtime;
-import java.util.Map;
-
-import org.kie.api.KieBase;
import org.kie.api.event.KieRuntimeEventManager;
import org.kie.api.runtime.process.StatelessProcessSession;
import org.kie.api.runtime.rule.StatelessRuleSession;
@@ -106,51 +103,6 @@
* results.getValue( "Get People" );// returns the query as a QueryResults instance.
*
*/
-public interface StatelessKieSession
- extends
- StatelessRuleSession,
- StatelessProcessSession,
- CommandExecutor,
- KieRuntimeEventManager {
-
- /**
- * @return the Globals store
- */
- Globals getGlobals();
-
- /**
- * Sets a global value on the globals store
- *
- * @param identifier the global identifier
- * @param value the value assigned to the global identifier
- */
- void setGlobal(String identifier,
- Object value);
-
-
- /**
- * Registers a channel with the given name
- *
- * @param name the name of the channel
- * @param channel the channel instance. It has to be thread safe.
- */
- void registerChannel(String name,
- Channel channel);
-
- /**
- * Unregisters the channel with the given name
- *
- * @param name
- */
- void unregisterChannel(String name);
-
- /**
- * @return a map with all registered channels.
- */
- Map getChannels();
+public interface StatelessKieSession extends StatelessRuleSession, StatelessProcessSession, RuntimeSession, KieRuntimeEventManager {
- /**
- * @return the KieBase reference from which this stateless session was created.
- */
- KieBase getKieBase();
}
diff --git a/kie-dmn/Developer_Guide.md b/kie-dmn/Developer_Guide.md
index 7dee4a57417..33fc6c8933c 100644
--- a/kie-dmn/Developer_Guide.md
+++ b/kie-dmn/Developer_Guide.md
@@ -1,3 +1,22 @@
+
+
# kie-dmn - Developer Guide
This module (and all its submodules) contains the code that make up the DMN engine.
diff --git a/kie-dmn/kie-dmn-core-jsr223/pom.xml b/kie-dmn/kie-dmn-core-jsr223/pom.xml
index b0f93bc3ac2..42c9feff4fa 100644
--- a/kie-dmn/kie-dmn-core-jsr223/pom.xml
+++ b/kie-dmn/kie-dmn-core-jsr223/pom.xml
@@ -112,21 +112,10 @@
kie-dmn-core-jsr223-jq
test
+
+ org.openjdk.nashorn
+ nashorn-core
+ test
+
-
-
-
- add-jdk15plus-dependencies
-
- [15,)
-
-
-
- org.openjdk.nashorn
- nashorn-core
- test
-
-
-
-
\ No newline at end of file
diff --git a/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/0089-nested-inputdata-imports.dmn b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/0089-nested-inputdata-imports.dmn
index e158a086470..feafc13302d 100644
--- a/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/0089-nested-inputdata-imports.dmn
+++ b/kie-dmn/kie-dmn-core/src/test/resources/org/kie/dmn/core/0089-nested-inputdata-imports.dmn
@@ -1,4 +1,23 @@
+
+
+
+
+
+
+
+
org.kie.dmn.feel
2
true
+ 12.5
+
+
+
+ net.sf.saxon
+ Saxon-HE
+ ${version.net.sf.saxon.Saxon-HE}
+
+
+
+
@@ -52,6 +63,10 @@
+
+ net.sf.saxon
+ Saxon-HE
+
org.antlr
antlr4-runtime
diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java
index 79ff2a01368..2acb38ad269 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/MatchesFunction.java
@@ -18,15 +18,9 @@
*/
package org.kie.dmn.feel.runtime.functions;
-import java.security.InvalidParameterException;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-import java.util.stream.Collectors;
-
import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
+import org.kie.dmn.feel.util.XQueryImplUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,58 +38,23 @@ public FEELFnResult invoke(@ParameterName("input") String input, @Param
}
public FEELFnResult invoke(@ParameterName("input") String input, @ParameterName("pattern") String pattern, @ParameterName("flags") String flags) {
- try {
- return matchFunctionWithFlags(input,pattern,flags);
- } catch ( PatternSyntaxException t ) {
- return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "pattern", "is invalid and can not be compiled", t ) );
- } catch (InvalidParameterException t ) {
- return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, t.getMessage(), "cannot be null", t ) );
- } catch (IllegalArgumentException t ) {
- return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "flags", "contains unknown flags", t ) );
- } catch (Throwable t) {
- return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "pattern", "is invalid and can not be compiled", t ) );
- }
- }
-
- static FEELFnResult matchFunctionWithFlags(String input, String pattern, String flags) {
log.debug("Input: {} , Pattern: {}, Flags: {}", input, pattern, flags);
+
if ( input == null ) {
- throw new InvalidParameterException("input");
+ return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "input", "cannot be null" ) );
}
if ( pattern == null ) {
- throw new InvalidParameterException("pattern");
+ return FEELFnResult.ofError( new InvalidParametersEvent( Severity.ERROR, "pattern", "cannot be null" ) );
}
- final String flagsString;
- if (flags != null && !flags.isEmpty()) {
- checkFlags(flags);
- if(!flags.contains("U")){
- flags += "U";
- }
- flagsString = String.format("(?%s)", flags);
- } else {
- flagsString = "";
- }
- log.debug("flagsString: {}", flagsString);
- String stringToBeMatched = flagsString + pattern;
- log.debug("stringToBeMatched: {}", stringToBeMatched);
- Pattern p=Pattern.compile(stringToBeMatched);
- Matcher m = p.matcher( input );
- boolean matchFound=m.find();
- log.debug("matchFound: {}", matchFound);
- return FEELFnResult.ofResult(matchFound);
- }
- static void checkFlags(String flags) {
- Set allowedChars = Set.of('s','i','x','m');
- boolean isValidFlag= flags.chars()
- .mapToObj(c -> (char) c)
- .allMatch(allowedChars::contains)
- && flags.chars()
- .mapToObj(c -> (char) c)
- .collect(Collectors.toSet())
- .size() == flags.length();
- if(!isValidFlag){
- throw new IllegalArgumentException("Not a valid flag parameter " +flags);
- }
+ try {
+ return FEELFnResult.ofResult(XQueryImplUtil.executeMatchesFunction(input, pattern, flags));
+ } catch (Exception e) {
+ String errorMessage = String.format("Provided parameters lead to an error. Input: '%s', Pattern: '%s', Flags: '%s'. ", input, pattern, flags);
+ if (e.getMessage() != null && !e.getMessage().isEmpty()) {
+ errorMessage += e.getMessage();
+ }
+ return FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, errorMessage, e));
+ }
}
}
diff --git a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ReplaceFunction.java b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ReplaceFunction.java
index 723efcbdd36..a7ae497870a 100644
--- a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ReplaceFunction.java
+++ b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/ReplaceFunction.java
@@ -20,6 +20,7 @@
import org.kie.dmn.api.feel.runtime.events.FEELEvent.Severity;
import org.kie.dmn.feel.runtime.events.InvalidParametersEvent;
+import org.kie.dmn.feel.util.XQueryImplUtil;
public class ReplaceFunction
extends BaseFEELFunction {
@@ -30,12 +31,12 @@ private ReplaceFunction() {
super( "replace" );
}
- public FEELFnResult
+
+ org.glassfish.jaxb
+ jaxb-runtime
+
+
org.kie
kie-dmn-validation
@@ -188,19 +193,4 @@
-
-
-
- jdk11
-
- [11,)
-
-
-
- org.glassfish.jaxb
- jaxb-runtime
-
-
-
-
diff --git a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/MultiInstanceDecisionLogic.java b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/MultiInstanceDecisionLogic.java
index d9a11187fc1..542b7c3ff91 100644
--- a/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/MultiInstanceDecisionLogic.java
+++ b/kie-dmn/kie-dmn-signavio/src/main/java/org/kie/dmn/signavio/MultiInstanceDecisionLogic.java
@@ -55,6 +55,8 @@
import org.kie.dmn.feel.runtime.functions.SumFunction;
import org.kie.dmn.feel.util.NumberEvalHelper;
import org.kie.dmn.model.api.DMNElement.ExtensionElements;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
@@ -63,6 +65,8 @@
@XStreamAlias("MultiInstanceDecisionLogic")
public class MultiInstanceDecisionLogic {
+ private static Logger logger = LoggerFactory.getLogger(MultiInstanceDecisionLogic.class);
+
@XStreamAlias("iterationExpression")
private String iterationExpression;
@@ -132,6 +136,12 @@ public void compileEvaluator(DMNNode node, DMNCompilerImpl compiler, DMNCompiler
di.setEvaluator(miEvaluator);
compiler.addCallback((cCompiler, cCtx, cModel) -> {
+ if (cModel != model) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Skipping MID processing for imported model: {}", cModel.getName());
+ }
+ return;
+ }
MIDDependenciesProcessor processor = new MIDDependenciesProcessor(midl, cModel);
addRequiredDecisions(miEvaluator, processor);
removeChildElementsFromIndex(cModel, processor);
diff --git a/kie-dmn/kie-dmn-signavio/src/test/java/org/kie/dmn/signavio/SignavioTest.java b/kie-dmn/kie-dmn-signavio/src/test/java/org/kie/dmn/signavio/SignavioTest.java
index c9e77a9ab6e..e1088266a48 100644
--- a/kie-dmn/kie-dmn-signavio/src/test/java/org/kie/dmn/signavio/SignavioTest.java
+++ b/kie-dmn/kie-dmn-signavio/src/test/java/org/kie/dmn/signavio/SignavioTest.java
@@ -25,6 +25,7 @@
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
@@ -37,6 +38,7 @@
import org.kie.dmn.api.core.DMNModel;
import org.kie.dmn.api.core.DMNResult;
import org.kie.dmn.api.core.DMNRuntime;
+import org.kie.dmn.api.core.ast.DMNNode;
import org.kie.dmn.model.api.DRGElement;
import org.kie.dmn.model.api.Definitions;
import org.slf4j.Logger;
@@ -50,17 +52,17 @@ public class SignavioTest {
@Test
void test() {
DMNRuntime runtime = createRuntime("Test_Signavio_multiple.dmn");
-
+
List models = runtime.getModels();
-
+
DMNContext context = runtime.newContext();
context.set("persons", Arrays.asList("p1", "p2"));
-
+
DMNModel model0 = models.get(0);
LOG.info("EVALUATE ALL:");
DMNResult evaluateAll = runtime.evaluateAll(model0, context);
LOG.info("{}", evaluateAll);
-
+
assertThat((List) evaluateAll.getContext().get("Greeting for each Person in Persons")).contains("Hello p1", "Hello p2");
}
@@ -142,14 +144,14 @@ private void checkSurveryMID(DMNRuntime runtime, Object numbers, Object iteratin
assertThat(evaluateAll.getDecisionResultByName("iterating").getResult()).isEqualTo(iterating);
}
- private DMNRuntime createRuntime(String modelFileName) {
- final KieServices ks = KieServices.Factory.get();
+ private DMNRuntime createRuntime(String... modelFileNames) {
+ final KieServices ks = KieServices.get();
final KieFileSystem kfs = ks.newKieFileSystem();
KieModuleModel kmm = ks.newKieModuleModel();
kmm.setConfigurationProperty("org.kie.dmn.profiles.signavio", "org.kie.dmn.signavio.KieDMNSignavioProfile");
kfs.writeKModuleXML(kmm.toXML());
- kfs.write(ks.getResources().newClassPathResource(modelFileName, this.getClass()));
+ Arrays.stream(modelFileNames).forEachOrdered(f -> kfs.write(ks.getResources().newClassPathResource(f, getClass())));
KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();
Results results = kieBuilder.getResults();
@@ -214,21 +216,21 @@ void zipFunctions() {
@SuppressWarnings("unchecked")
void midTakesCareOfRequirements() {
DMNRuntime runtime = createRuntime("Test_SignavioMID.dmn");
-
+
List models = runtime.getModels();
-
+
DMNContext context = runtime.newContext();
context.set("numbers1", Arrays.asList(1,2));
context.set("numbers2", Arrays.asList(2,3));
-
+
DMNModel model0 = models.get(0);
LOG.info("EVALUATE ALL:");
DMNResult evaluateAll = runtime.evaluateAll(model0, context);
LOG.info("{}", evaluateAll);
-
+
List result = (List) evaluateAll.getDecisionResultByName("calculate").getResult();
assertThat(result).hasSize(6);
-
+
assertThat(result).doesNotContainNull();
}
@@ -236,12 +238,12 @@ void midTakesCareOfRequirements() {
@Test
void signavioConcatFunction() {
DMNRuntime runtime = createRuntime("Signavio_Concat.dmn");
-
+
List models = runtime.getModels();
-
+
DMNContext context = runtime.newContext();
context.set("listOfNames", Arrays.asList("John", "Jane", "Doe"));
-
+
DMNModel model0 = models.get(0);
LOG.info("EVALUATE ALL:");
DMNResult evaluateAll = runtime.evaluateAll(model0, context);
@@ -249,20 +251,20 @@ void signavioConcatFunction() {
assertThat(evaluateAll.getDecisionResultByName("concatNames").getResult()).isEqualTo("JohnJaneDoe");
}
-
-
+
+
private void checkBothFunctionsAreWorking(DMNRuntime runtime) {
List models = runtime.getModels();
-
+
DMNContext context = runtime.newContext();
context.set("names", Arrays.asList("John Doe", "Jane Doe"));
context.set("ages", Arrays.asList(37, 35));
-
+
DMNModel model0 = models.get(0);
LOG.info("EVALUATE ALL:");
DMNResult evaluateAll = runtime.evaluateAll(model0, context);
LOG.info("{}", evaluateAll);
-
+
assertThat((List>) evaluateAll.getDecisionResultByName("zipvararg").getResult()).hasSize(2);
assertThat((List>) evaluateAll.getDecisionResultByName("zipsinglelist").getResult()).hasSize(2);
}
@@ -270,7 +272,7 @@ private void checkBothFunctionsAreWorking(DMNRuntime runtime) {
@Test
void signavioIterateMultiinstanceWithComplexInputs() {
DMNRuntime runtime = createRuntime("Iterate Complex List.dmn");
-
+
DMNContext context = runtime.newContext();
Map johnDoe = new HashMap<>();
johnDoe.put("iD", "id-john");
@@ -279,7 +281,7 @@ void signavioIterateMultiinstanceWithComplexInputs() {
alice.put("iD", "id-alice");
alice.put("name", "Alice");
context.set("customer", Collections.singletonMap("persons", Arrays.asList(johnDoe, alice)));
-
+
DMNModel model0 = runtime.getModels().get(0);
LOG.info("EVALUATE ALL:");
DMNResult evaluateAll = runtime.evaluateAll(model0, context);
@@ -291,31 +293,41 @@ void signavioIterateMultiinstanceWithComplexInputs() {
@Test
void signavioIterateMultiinstanceMultipleDecisions() {
DMNRuntime runtime = createRuntime("MID with multiple inside decisions.dmn");
-
+
DMNContext context = runtime.newContext();
context.set("names", Arrays.asList("John", "Alice"));
-
+
DMNModel model0 = runtime.getModels().get(0);
LOG.info("EVALUATE ALL:");
DMNResult evaluateAll = runtime.evaluateAll(model0, context);
LOG.info("{}", evaluateAll);
-
+
assertThat(evaluateAll.getDecisionResultByName("overallage").getResult()).isEqualTo(new BigDecimal("18"));
}
@Test
void signavioIterateMultiinstanceMultipleDecisionsOutside() {
DMNRuntime runtime = createRuntime("MID with outside requirement.dmn");
-
+
DMNContext context = runtime.newContext();
context.set("numbers", Arrays.asList(1,2,3));
context.set("operand", "PLUS");
-
+
DMNModel model0 = runtime.getModels().get(0);
LOG.info("EVALUATE ALL:");
DMNResult evaluateAll = runtime.evaluateAll(model0, context);
LOG.info("{}", evaluateAll);
-
+
assertThat(evaluateAll.getDecisionResultByName("sumUp").getResult()).isEqualTo(new BigDecimal("6"));
}
+
+ @Test
+ void signavioMultiInstanceDecisionTableWithinMultipleFiles() {
+ DMNRuntime dmnRuntime = createRuntime("MID with outside requirement.dmn", "survey MID SUM.dmn", "Signavio_Concat.dmn");
+
+ assertThat(dmnRuntime.getModels())
+ .flatExtracting(DMNModel::getDecisions)
+ .extracting(DMNNode::getName)
+ .containsOnly("sumUp", "iterating", "determineModifier", "concatNames");
+ }
}
diff --git a/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/LocalHrefs.dmn b/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/LocalHrefs.dmn
index 33542ce25c3..dfc483e8c73 100644
--- a/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/LocalHrefs.dmn
+++ b/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/LocalHrefs.dmn
@@ -1,4 +1,23 @@
+
+
diff --git a/kie-pmml-trusty/kie-pmml-compiler/kie-pmml-compiler-api/pom.xml b/kie-pmml-trusty/kie-pmml-compiler/kie-pmml-compiler-api/pom.xml
index bdbd389a054..e7921b7ce0e 100644
--- a/kie-pmml-trusty/kie-pmml-compiler/kie-pmml-compiler-api/pom.xml
+++ b/kie-pmml-trusty/kie-pmml-compiler/kie-pmml-compiler-api/pom.xml
@@ -53,6 +53,10 @@
org.jpmml
pmml-model
+
+ org.glassfish.jaxb
+ jaxb-runtime
+
org.kie
@@ -74,20 +78,4 @@
-
-
-
- java11-pmml
-
- [11,)
-
-
-
- org.glassfish.jaxb
- jaxb-runtime
-
-
-
-
-
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index c23c483f355..5fae74ed325 100644
--- a/pom.xml
+++ b/pom.xml
@@ -136,7 +136,11 @@
.git-blame-ignore-revs
+ **/dependency-reduced-pom.xml
**/lunr-2.3.9.min.js
+ **/search-ui.js
+ **/branch.yaml
+ **/main.yaml
**/mvel.jj
**/*.csv
**/*.sdo
@@ -159,7 +163,6 @@
**/*.log
**/*.lst
**/checkstyle-cachefile
- **/smoke*.drl.txt
**/test*.txt
**/test*.yml
**/drl.ftl