From d84b6354ba7ec817b4177d4d4289c6e98c5f8444 Mon Sep 17 00:00:00 2001 From: Gabriele Cardosi Date: Tue, 27 Feb 2024 10:48:44 +0100 Subject: [PATCH 1/3] [incubator-kie-issues#968] Support ConditionalExpr in Drools executable model (#5746) Co-authored-by: Gabriele-Cardosi (cherry picked from commit 7b8a70f67ab2cfad8eec731d864e5e5903ab6596) --- .../expressiontyper/ExpressionTyper.java | 5 ++ .../execmodel/ConditionalExprTest.java | 87 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/ConditionalExprTest.java diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java index e616ac1c5e8..ce4e8f91331 100644 --- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java +++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java @@ -43,6 +43,7 @@ import com.github.javaparser.ast.expr.CastExpr; import com.github.javaparser.ast.expr.CharLiteralExpr; import com.github.javaparser.ast.expr.ClassExpr; +import com.github.javaparser.ast.expr.ConditionalExpr; import com.github.javaparser.ast.expr.DoubleLiteralExpr; import com.github.javaparser.ast.expr.EnclosedExpr; import com.github.javaparser.ast.expr.Expression; @@ -379,6 +380,10 @@ private Optional toTypedExpressionRec(Expression drlxExpr) { return of(new TypedExpression(drlxExpr, type)); } + if (drlxExpr instanceof ConditionalExpr) { + return of(new TypedExpression(drlxExpr, Boolean.class)); + } + if (drlxExpr.isAssignExpr()) { AssignExpr assignExpr = drlxExpr.asAssignExpr(); diff --git a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/ConditionalExprTest.java b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/ConditionalExprTest.java new file mode 100644 index 00000000000..89f89561c7d --- /dev/null +++ b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/ConditionalExprTest.java @@ -0,0 +1,87 @@ +/** + * 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.ArrayList; +import java.util.List; + +import org.drools.model.codegen.execmodel.domain.Person; +import org.junit.Before; +import org.junit.Test; +import org.kie.api.runtime.KieSession; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConditionalExprTest extends BaseModelTest { + + private static final String RULE_STRING = "package constraintexpression\n" + + "\n" + + "import " + Person.class.getCanonicalName() + "\n" + + "import java.util.List; \n" + + "global List booleanListGlobal; \n" + + "rule \"r1\"\n" + + "when \n" + + " $p : Person($booleanVariable: (name != null ? true : false))\n" + + "then \n" + + " System.out.println($booleanVariable); \n" + + " System.out.println($p); \n" + + " booleanListGlobal.add($booleanVariable); \n " + + "end \n"; + + private KieSession ksession; + private List booleanListGlobal; + + public ConditionalExprTest(RUN_TYPE testRunType) { + super(testRunType); + } + + @Before + public void setup() { + ksession = getKieSession(RULE_STRING); + booleanListGlobal = new ArrayList<>(); + ksession.setGlobal("booleanListGlobal", booleanListGlobal); + } + + @Test + public void testConditionalExpressionWithNamedPerson() { + try { + Person person = new Person("someName"); + ksession.insert(person); + int rulesFired = ksession.fireAllRules(); + assertThat(rulesFired).isEqualTo(1); + assertThat(booleanListGlobal).isNotEmpty().containsExactly(Boolean.TRUE); + } finally { + ksession.dispose(); + } + } + + @Test + public void testConditionalExpressionWithUnnamedPerson() { + try { + Person person = new Person(); + ksession.insert(person); + int rulesFired = ksession.fireAllRules(); + assertThat(rulesFired).isEqualTo(1); + assertThat(booleanListGlobal).isNotEmpty().containsExactly(Boolean.FALSE); + } finally { + ksession.dispose(); + } + } + +} \ No newline at end of file From 053729a89e3cf1165d01dbac5dd9fce2acd59115 Mon Sep 17 00:00:00 2001 From: Mario Fusco Date: Tue, 27 Feb 2024 18:40:48 +0100 Subject: [PATCH 2/3] [8.40.x_incubator-kie-issues#988] Fix cherry pick --- .../generator/OOPathExprGenerator.java | 2 +- .../generator/drlxparse/ConstraintParser.java | 47 +++++----- .../codegen/execmodel/ConstraintTest.java | 90 +++++++++++++++++++ 3 files changed, 116 insertions(+), 23 deletions(-) create mode 100644 drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/ConstraintTest.java diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/OOPathExprGenerator.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/OOPathExprGenerator.java index 9d6b00d56e9..81ddb7aa6a1 100644 --- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/OOPathExprGenerator.java +++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/OOPathExprGenerator.java @@ -198,7 +198,7 @@ private void toPatternExpr(String bindingId, List list, DrlxPar expr.setScope( patternExpr ); patternExpr = expr; } - if (singleDrlx.getExpr() != null && !(singleDrlx.getExpr() instanceof NameExpr)) { + if (singleDrlx.getExpr() != null && singleDrlx.isPredicate()) { MethodCallExpr expr = expressionBuilder.buildExpressionWithIndexing( singleDrlx ); expr.setScope( patternExpr ); patternExpr = expr; diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java index a0064a4c024..fca0894878e 100644 --- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java +++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java @@ -1,20 +1,21 @@ -/* - * Copyright 2019 Red Hat, Inc. and/or its affiliates. - * - * Licensed 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 +/** + * 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 * - * Unless required by applicable law or agreed to in writing, software + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * 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.generator.drlxparse; import java.lang.reflect.Type; @@ -505,21 +506,23 @@ private DrlxParseResult parseNameExpr(DrlNameExpr nameExpr, Class patternType Expression withThis = DrlxParseUtil.prepend(new NameExpr(THIS_PLACEHOLDER), converted.getExpression()); if (hasBind) { - return new SingleDrlxParseSuccess(patternType, bindingId, null, converted.getType() ) + return new SingleDrlxParseSuccess(patternType, bindingId, withThis, converted.getType() ) .setLeft( new TypedExpression( withThis, converted.getType() ) ) .addReactOnProperty( lcFirstForBean(nameExpr.getNameAsString()) ); - } else if (context.hasDeclaration( expression )) { - Optional declarationSpec = context.getDeclarationById(expression); + } + + if (context.hasDeclaration( expression )) { + Optional declarationSpec = context.getTypedDeclarationById(expression); if (declarationSpec.isPresent()) { return new SingleDrlxParseSuccess(patternType, bindingId, context.getVarExpr(printNode(drlxExpr)), declarationSpec.get().getDeclarationClass() ).setIsPredicate(true); } else { throw new IllegalArgumentException("Cannot find declaration specification by specified expression " + expression + "!"); } - } else { - return new SingleDrlxParseSuccess(patternType, bindingId, withThis, converted.getType() ) - .addReactOnProperty( nameExpr.getNameAsString() ) - .setIsPredicate(true); } + + return new SingleDrlxParseSuccess(patternType, bindingId, withThis, converted.getType() ) + .addReactOnProperty( nameExpr.getNameAsString() ) + .setIsPredicate(true); } private DrlxParseResult parseFieldAccessExpr( FieldAccessExpr fieldCallExpr, Class patternType, String bindingId ) { @@ -1017,7 +1020,7 @@ private Optional convertBigDecimalArithmetic(MethodCallExpr metho List binaryExprList = methodCallExpr.findAll(BinaryExpr.class); for (BinaryExpr binaryExpr : binaryExprList) { Operator operator = binaryExpr.getOperator(); - boolean arithmeticExpr = ARITHMETIC_OPERATORS.contains(operator); + boolean arithmeticExpr = isArithmeticOperator(operator); if (arithmeticExpr) { final ExpressionTyperContext expressionTyperContext = new ExpressionTyperContext(); final ExpressionTyper expressionTyper = new ExpressionTyper(context, patternType, bindingId, isPositional, expressionTyperContext); diff --git a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/ConstraintTest.java b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/ConstraintTest.java new file mode 100644 index 00000000000..b3475e58c2d --- /dev/null +++ b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/ConstraintTest.java @@ -0,0 +1,90 @@ +/** + * 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.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import org.drools.model.codegen.execmodel.domain.Person; +import org.junit.Before; +import org.junit.Test; +import org.kie.api.runtime.KieSession; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConstraintTest extends BaseModelTest { + + private static final String RULE_STRING = "package constraintexpression\n" + + "\n" + + "import " + Person.class.getCanonicalName() + "\n" + + "import java.util.List; \n" + + "import java.math.BigDecimal; \n" + + "global List bigDecimalListGlobal; \n" + + "rule \"r1\"\n" + + "when \n" + + " $p : Person($amount: (money == null ? BigDecimal.valueOf(100.0) : money))\n" + + "then \n" + + " System.out.println($amount); \n" + + " System.out.println($p); \n" + + " bigDecimalListGlobal.add($amount); \n " + + "end \n"; + + private KieSession ksession; + + private List bigDecimalListGlobal; + + public ConstraintTest(RUN_TYPE testRunType) { + super(testRunType); + } + + @Before + public void setup() { + ksession = getKieSession(RULE_STRING); + bigDecimalListGlobal = new ArrayList<>(); + ksession.setGlobal("bigDecimalListGlobal", bigDecimalListGlobal); + } + + @Test + public void testConstraintWithMoney() { + try { + BigDecimal money = BigDecimal.valueOf(34.45); + Person person = new Person("", money); + ksession.insert(person); + int rulesFired = ksession.fireAllRules(); + assertThat(rulesFired).isEqualTo(1); + assertThat(bigDecimalListGlobal).isNotEmpty().containsExactly(money); + } finally { + ksession.dispose(); + } + } + + @Test + public void testConstraintWithoutMoney() { + try { + Person person = new Person(); + ksession.insert(person); + int rulesFired = ksession.fireAllRules(); + assertThat(rulesFired).isEqualTo(1); + assertThat(bigDecimalListGlobal).isNotEmpty().containsExactly(BigDecimal.valueOf(100.0)); + } finally { + ksession.dispose(); + } + } +} From 6ec076862ee108b941137ba142a6249510f923bf Mon Sep 17 00:00:00 2001 From: Gabriele-Cardosi Date: Tue, 5 Mar 2024 15:14:46 +0100 Subject: [PATCH 3/3] [8.40.x_incubator-kie-issues#988] Fix cherry pick --- .../generator/drlxparse/ConstraintParser.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java index fca0894878e..1ae89fcaa97 100644 --- a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java +++ b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/drlxparse/ConstraintParser.java @@ -48,7 +48,6 @@ import com.github.javaparser.ast.expr.UnaryExpr; import com.github.javaparser.ast.nodeTypes.NodeWithArguments; import com.github.javaparser.ast.nodeTypes.NodeWithOptionalScope; -import org.drools.util.DateUtils; import org.drools.model.Index; import org.drools.model.codegen.execmodel.PackageModel; import org.drools.model.codegen.execmodel.errors.ParseExpressionErrorResult; @@ -73,6 +72,7 @@ import org.drools.mvel.parser.printer.PrintUtil; import org.drools.mvelcompiler.CompiledExpressionResult; import org.drools.mvelcompiler.ConstraintCompiler; +import org.drools.util.DateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -95,10 +95,6 @@ import static org.drools.model.codegen.execmodel.generator.ConstraintUtil.GREATER_THAN_PREFIX; import static org.drools.model.codegen.execmodel.generator.ConstraintUtil.LESS_OR_EQUAL_PREFIX; import static org.drools.model.codegen.execmodel.generator.ConstraintUtil.LESS_THAN_PREFIX; -import static org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper.convertArithmeticBinaryToMethodCall; -import static org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper.getBinaryTypeAfterConversion; -import static org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper.shouldConvertArithmeticBinaryToMethodCall; -import static org.drools.util.StringUtils.lcFirstForBean; import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.THIS_PLACEHOLDER; import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.createConstraintCompiler; import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.getLiteralExpressionType; @@ -108,9 +104,13 @@ import static org.drools.model.codegen.execmodel.generator.DslMethodNames.createDslTopLevelMethod; import static org.drools.model.codegen.execmodel.generator.drlxparse.MultipleDrlxParseSuccess.createMultipleDrlxParseSuccess; import static org.drools.model.codegen.execmodel.generator.drlxparse.SpecialComparisonCase.specialComparisonFactory; +import static org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper.convertArithmeticBinaryToMethodCall; +import static org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper.getBinaryTypeAfterConversion; +import static org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper.shouldConvertArithmeticBinaryToMethodCall; import static org.drools.model.codegen.execmodel.generator.expressiontyper.FlattenScope.transformFullyQualifiedInlineCastExpr; import static org.drools.mvel.parser.printer.PrintUtil.printNode; import static org.drools.mvel.parser.utils.AstUtils.isLogicalOperator; +import static org.drools.util.StringUtils.lcFirstForBean; /** * Parses the MVEL String Constraint and compiles it to a Java Expression @@ -512,7 +512,7 @@ private DrlxParseResult parseNameExpr(DrlNameExpr nameExpr, Class patternType } if (context.hasDeclaration( expression )) { - Optional declarationSpec = context.getTypedDeclarationById(expression); + Optional declarationSpec = context.getDeclarationById(expression); if (declarationSpec.isPresent()) { return new SingleDrlxParseSuccess(patternType, bindingId, context.getVarExpr(printNode(drlxExpr)), declarationSpec.get().getDeclarationClass() ).setIsPredicate(true); } else {