This is an automated email from the ASF dual-hosted git repository.
tkobayas pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
The following commit(s) were added to refs/heads/main by this push:
new c8f84a7427 [incubator-kie-drools-6350] Custom Operator issue with
executable-model (#6354)
c8f84a7427 is described below
commit c8f84a74276d828df96e1807c7e31a6cec91e2ef
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Thu May 29 12:34:12 2025 +0900
[incubator-kie-drools-6350] Custom Operator issue with executable-model
(#6354)
- Removed CustomOperatorOnlyDrlTest. Custom operators with brackets are not
supported. See 'Custom Operators' in the Drools documentation
- Fixed CustomOperatorWrapper and CustomOperatorTest to reflect the correct
arguments order
---
.../org/drools/base/rule/accessor/Evaluator.java | 30 +--
.../operatorspec/CustomOperatorWrapper.java | 4 +-
.../CustomOperatorOnlyDrlTest.java | 204 ---------------------
.../integrationtests/CustomOperatorTest.java | 63 +++++--
4 files changed, 66 insertions(+), 235 deletions(-)
diff --git
a/drools-base/src/main/java/org/drools/base/rule/accessor/Evaluator.java
b/drools-base/src/main/java/org/drools/base/rule/accessor/Evaluator.java
index e31b25f592..3bbe81914b 100644
--- a/drools-base/src/main/java/org/drools/base/rule/accessor/Evaluator.java
+++ b/drools-base/src/main/java/org/drools/base/rule/accessor/Evaluator.java
@@ -99,30 +99,32 @@ public interface Evaluator extends Serializable,
org.kie.api.runtime.rule.Evalua
*
* This method will be used to extract and evaluate both
* the "name" attribute and the "$someName" variable at once.
- *
+ *
+ * Note that in this method signature, 'left' means the left operand and
'right' means the right operand,
+ *
* @param valueResolver
* The current working memory
* @param leftExtractor
- * The extractor to read the left value. In the above example,
+ * The extractor to read the left operand value. In the above
example,
+ * the "name" attribute value.
+ * @param leftOperandFact
+ * The object from where to extract the value. In the
+ * above example, that is the "Person" instance from where to
+ * extract the "name" attribute.
+ * @param rightExtractor
+ * The extractor to read the right operand value. In the above
example,
* the "$someName" variable value.
- * @param left
- * The source object from where the value of the variable is
+ * @param rightOperandFact
+ * The source object from where the value of the variable is
* extracted.
- * @param rightExtractor
- * The extractor to read the right value. In the above example,
- * the "name" attribute value.
- * @param right
- * The right object from where to extract the value. In the
- * above example, that is the "Person" instance from where to
- * extract the "name" attribute.
- *
+ *
* @return Returns true if evaluation is successful. false otherwise.
*/
public boolean evaluate(ValueResolver valueResolver,
ReadAccessor leftExtractor,
- FactHandle left,
+ FactHandle leftOperandFact,
ReadAccessor rightExtractor,
- FactHandle right);
+ FactHandle rightOperandFact);
/**
* Returns true if this evaluator implements a temporal evaluation,
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/CustomOperatorWrapper.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/CustomOperatorWrapper.java
index 1bea9a1509..e3958f4d44 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/CustomOperatorWrapper.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/CustomOperatorWrapper.java
@@ -34,8 +34,8 @@ public class CustomOperatorWrapper implements
Operator.SingleValue<Object, Objec
}
@Override
- public boolean eval( Object o1, Object o2 ) {
- return evaluator.evaluate(null, null, dummyFactHandleOf(o2), null,
dummyFactHandleOf(o1));
+ public boolean eval( Object leftOperand, Object rightOperand ) {
+ return evaluator.evaluate(null, null, dummyFactHandleOf(leftOperand),
null, dummyFactHandleOf(rightOperand));
}
@Override
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/CustomOperatorOnlyDrlTest.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/CustomOperatorOnlyDrlTest.java
deleted file mode 100644
index 6f4404618a..0000000000
---
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/CustomOperatorOnlyDrlTest.java
+++ /dev/null
@@ -1,204 +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.drools.compiler.integrationtests;
-
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.stream.Stream;
-
-import org.drools.base.base.ValueResolver;
-import org.drools.base.base.ValueType;
-import org.drools.compiler.rule.builder.EvaluatorDefinition;
-import org.drools.drl.parser.DrlParser;
-import org.drools.drl.parser.impl.Operator;
-import org.drools.base.rule.accessor.Evaluator;
-import org.drools.base.rule.accessor.FieldValue;
-import org.drools.base.rule.accessor.ReadAccessor;
-import org.drools.mvel.evaluators.BaseEvaluator;
-import org.drools.mvel.evaluators.VariableRestriction;
-import org.drools.testcoverage.common.util.KieBaseTestConfiguration;
-import org.drools.testcoverage.common.util.KieBaseUtil;
-import org.drools.testcoverage.common.util.TestParametersUtil2;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.kie.api.runtime.rule.FactHandle;
-import org.kie.internal.builder.conf.EvaluatorOption;
-
-public class CustomOperatorOnlyDrlTest {
-
- private static final String F_STR = DrlParser.ANTLR4_PARSER_ENABLED ?
"##F_str" : "F_str";
-
- public static Stream<KieBaseTestConfiguration> parameters() {
- // TODO EM DROOLS-6302
- return
TestParametersUtil2.getKieBaseCloudConfigurations(false).stream();
- }
-
- @ParameterizedTest(name = "KieBase type={0}")
- @MethodSource("parameters")
- public void
testCustomOperatorCombiningConstraints(KieBaseTestConfiguration
kieBaseTestConfiguration) {
- // JBRULES-3517
- final String drl =
- "declare GN\n" +
- " gNo : Double\n" +
- "end\n" +
- "\n" +
- "declare t547147\n" +
- " c547148 : String\n" +
- " c547149 : String\n" +
- "end\n" +
- "\n" +
- "declare Tra48\n" +
- " gNo : Double\n" +
- " postCode : String\n" +
- " name : String\n" +
- " cnt : String\n" +
- "end\n" +
- "\n" +
- "rule \"r548695.1\"\n" +
- "no-loop true\n" +
- "dialect \"mvel\"\n" +
- "when\n" +
- " gnId : GN()\n" +
- " la : t547147( )\n" +
- " v1717 : Tra48( gnId.gNo == gNo, name " + F_STR +
"[startsWith] la.c547148 || postCode " + F_STR + "[contains] la.c547149 )\n" +
- "then\n" +
- "end\n";
-
- System.setProperty(EvaluatorOption.PROPERTY_NAME + "str",
F_StrEvaluatorDefinition.class.getName());
- try {
- KieBaseUtil.getKieBaseFromKieModuleFromDrl("custom-operator-test",
kieBaseTestConfiguration, drl);
- } finally {
- System.clearProperty(EvaluatorOption.PROPERTY_NAME + "str");
- }
- }
-
- public static class F_StrEvaluatorDefinition implements
EvaluatorDefinition {
-
- public static final Operator STR_COMPARE =
Operator.addOperatorToRegistry("F_str", false);
- public static final Operator NOT_STR_COMPARE =
Operator.addOperatorToRegistry("F_str", true);
- private static final String[] SUPPORTED_IDS =
{STR_COMPARE.getOperatorString()};
-
- public enum Operations {
-
- startsWith,
- endsWith,
- length,
- contains,
- bidicontains;
- }
-
- private Evaluator[] evaluator;
-
- public String[] getEvaluatorIds() {
- return F_StrEvaluatorDefinition.SUPPORTED_IDS;
- }
-
- public boolean isNegatable() {
- return true;
- }
-
- public Evaluator getEvaluator(final ValueType type, final String
operatorId, final boolean isNegated, final String parameterText, final Target
leftTarget, final Target rightTarget) {
- final F_StrEvaluator evaluatorLocal = new F_StrEvaluator(type,
isNegated);
- evaluatorLocal.setParameterText(parameterText);
- return evaluatorLocal;
- }
-
- public Evaluator getEvaluator(final ValueType type, final String
operatorId, final boolean isNegated, final String parameterText) {
- return getEvaluator(type, operatorId, isNegated, parameterText,
Target.FACT, Target.FACT);
- }
-
- public Evaluator getEvaluator(final ValueType type, final Operator
operator, final String parameterText) {
- return this.getEvaluator(type, operator.getOperatorString(),
operator.isNegated(), parameterText);
- }
-
- public Evaluator getEvaluator(final ValueType type, final Operator
operator) {
- return this.getEvaluator(type, operator.getOperatorString(),
operator.isNegated(), null);
- }
-
- public boolean supportsType(final ValueType vt) {
- return true;
- }
-
- public Target getTarget() {
- return Target.FACT;
- }
-
- public void writeExternal(final ObjectOutput out) throws IOException {
- out.writeObject(evaluator);
- }
-
- public void readExternal(final ObjectInput in) throws IOException,
ClassNotFoundException {
- evaluator = (Evaluator[]) in.readObject();
- }
- }
-
- public static class F_StrEvaluator extends BaseEvaluator {
-
- private F_StrEvaluatorDefinition.Operations parameter;
-
- public void setParameterText(final String parameterText) {
- this.parameter =
F_StrEvaluatorDefinition.Operations.valueOf(parameterText);
- }
-
- public F_StrEvaluatorDefinition.Operations getParameter() {
- return parameter;
- }
-
- public F_StrEvaluator(final ValueType type, final boolean isNegated) {
- super(type, isNegated ? F_StrEvaluatorDefinition.NOT_STR_COMPARE :
F_StrEvaluatorDefinition.STR_COMPARE);
- }
-
- public boolean evaluate(final ValueResolver valueResolver, final
ReadAccessor extractor, final FactHandle factHandle, final FieldValue value) {
- final Object objectValue = extractor.getValue(valueResolver,
factHandle);
- final String objectValueString = (String) objectValue;
- return evaluateAll((String) value.getValue(), objectValueString);
- }
-
- public boolean evaluate(final ValueResolver valueResolver, final
ReadAccessor ira, final FactHandle left, final ReadAccessor ira1, final
FactHandle right) {
- return evaluateAll((String) left.getObject(), (String)
right.getObject());
- }
-
- public boolean evaluateCachedLeft(final ValueResolver valueResolver,
final VariableRestriction.VariableContextEntry context, final FactHandle right)
{
- final Object valRight = context.extractor.getValue(valueResolver,
right);
- return evaluateAll((String)
((VariableRestriction.ObjectVariableContextEntry) context).left, (String)
valRight);
- }
-
- public boolean evaluateCachedRight(final ValueResolver valueResolver,
final VariableRestriction.VariableContextEntry context, final FactHandle left) {
- final Object varLeft =
context.declaration.getExtractor().getValue(valueResolver, left);
- return evaluateAll((String) varLeft, (String)
((VariableRestriction.ObjectVariableContextEntry) context).right);
- }
-
- public boolean evaluateAll(final String leftString, final String
rightString) {
- boolean result = ((leftString != null) && (rightString != null));
-
- if (result) {
- switch (parameter) {
- case startsWith:
- result = this.getOperator().isNegated() ^
(leftString.startsWith(rightString));
- return result;
- case endsWith:
- result = this.getOperator().isNegated() ^
(leftString.endsWith(rightString));
- return result;
- }
- }
- return result;
- }
- }
-}
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/CustomOperatorTest.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/CustomOperatorTest.java
index 5295b801e2..6f7bf9817b 100644
---
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/CustomOperatorTest.java
+++
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/compiler/integrationtests/CustomOperatorTest.java
@@ -57,11 +57,11 @@ public class CustomOperatorTest {
}
@ParameterizedTest(name = "KieBase type={0}")
- @MethodSource("parameters")
+ @MethodSource("parameters")
public void testCustomOperatorUsingCollections(KieBaseTestConfiguration
kieBaseTestConfiguration) {
String constraints =
" $alice : Person(name == \"Alice\")\n" +
- " $bob : Person(name == \"Bob\", addresses " + SUPERSET_OF
+ " $alice.addresses)\n";
+ " $bob : Person(name == \"Bob\", addresses " +
SUPERSET_OF + " $alice.addresses)\n";
customOperatorUsingCollections(kieBaseTestConfiguration, constraints);
}
@@ -75,12 +75,12 @@ public class CustomOperatorTest {
}
@ParameterizedTest(name = "KieBase type={0}")
- @MethodSource("parameters")
+ @MethodSource("parameters")
public void
testNoOperatorInstancesCreatedAtRuntime(KieBaseTestConfiguration
kieBaseTestConfiguration) {
String constraints =
" $alice : Person(name == \"Alice\")\n" +
- " $bob : Person(name == \"Bob\", addresses " + SUPERSET_OF
+ " $alice.addresses)\n" +
- " Person(name == \"Bob\", addresses " + SUPERSET_OF + "
$alice.addresses)\n";
+ " $bob : Person(name == \"Bob\", addresses " +
SUPERSET_OF + " $alice.addresses)\n" +
+ " Person(name == \"Bob\", addresses " + SUPERSET_OF
+ " $alice.addresses)\n";
customOperatorUsingCollections(kieBaseTestConfiguration, constraints);
@@ -88,12 +88,12 @@ public class CustomOperatorTest {
}
@ParameterizedTest(name = "KieBase type={0}")
- @MethodSource("parameters")
+ @MethodSource("parameters")
public void
testCustomOperatorUsingCollectionsInverted(KieBaseTestConfiguration
kieBaseTestConfiguration) {
// DROOLS-6983
String constraints =
" $bob : Person(name == \"Bob\")\n" +
- " $alice : Person(name == \"Alice\", $bob.addresses " +
SUPERSET_OF + " this.addresses)\n";
+ " $alice : Person(name == \"Alice\", $bob.addresses
" + SUPERSET_OF + " this.addresses)\n";
customOperatorUsingCollections(kieBaseTestConfiguration, constraints);
}
@@ -146,42 +146,52 @@ public class CustomOperatorTest {
INSTANCES_COUNTER++;
}
+ @Override
public String[] getEvaluatorIds() {
return SupersetOfEvaluatorDefinition.SUPPORTED_IDS;
}
+ @Override
public boolean isNegatable() {
return true;
}
+ @Override
public Evaluator getEvaluator(final ValueType type, final String
operatorId, final boolean isNegated, final String parameterText, final Target
leftTarget, final Target rightTarget) {
return new SupersetOfEvaluator(type, isNegated);
}
+ @Override
public Evaluator getEvaluator(final ValueType type, final String
operatorId, final boolean isNegated, final String parameterText) {
return getEvaluator(type, operatorId, isNegated, parameterText,
Target.FACT, Target.FACT);
}
+ @Override
public Evaluator getEvaluator(final ValueType type, final Operator
operator, final String parameterText) {
return this.getEvaluator(type, operator.getOperatorString(),
operator.isNegated(), parameterText);
}
+ @Override
public Evaluator getEvaluator(final ValueType type, final Operator
operator) {
return this.getEvaluator(type, operator.getOperatorString(),
operator.isNegated(), null);
}
+ @Override
public boolean supportsType(final ValueType vt) {
return true;
}
+ @Override
public Target getTarget() {
return Target.FACT;
}
+ @Override
public void writeExternal(final ObjectOutput out) throws IOException {
out.writeObject(evaluator);
}
+ @Override
public void readExternal(final ObjectInput in) throws IOException,
ClassNotFoundException {
evaluator = (Evaluator[]) in.readObject();
}
@@ -193,32 +203,55 @@ public class CustomOperatorTest {
super(type, isNegated ?
SupersetOfEvaluatorDefinition.NOT_SUPERSET_OF :
SupersetOfEvaluatorDefinition.SUPERSET_OF);
}
+ // In this method, 'factHandle' is the left operand of the expression.
'value' is the right operand.
+ @Override
public boolean evaluate(final ValueResolver valueResolver, final
ReadAccessor extractor, final FactHandle factHandle, final FieldValue value) {
final Object objectValue = extractor.getValue(valueResolver,
factHandle);
- return evaluateAll((Collection) value.getValue(), (Collection)
objectValue);
+ return evaluateExpression((Collection) objectValue, (Collection)
value.getValue());
}
- public boolean evaluate(final ValueResolver valueResolver, final
ReadAccessor ira, final FactHandle left, final ReadAccessor ira1, final
FactHandle right) {
- return evaluateAll((Collection) left.getObject(), (Collection)
right.getObject());
+ // In this method, 'left' and 'right' literally mean the left and
right operands of the expression. No need to invert.
+ // for example, [addresses supersetOf $alice.addresses]
+ // leftOperandFact.getObject() is addresses
+ // rightOperandFact.getObject() is $alice.addresses
+ @Override
+ public boolean evaluate(final ValueResolver valueResolver, final
ReadAccessor ira, final FactHandle leftOperandFact, final ReadAccessor ira1,
final FactHandle rightOperandFact) {
+ return evaluateExpression((Collection)
leftOperandFact.getObject(), (Collection) rightOperandFact.getObject());
}
+ // In this method, 'left' means leftInput to the JoinNode. 'right'
means RightInput to the JoinNode.
+ // To evaluate the expression, RightInput is the left operand and
leftInput is the right operand. So, need to invert.
+ // for example, [addresses supersetOf $alice.addresses]
+ // valRight is addresses
+ // context.left is $alice.addresses
+ @Override
public boolean evaluateCachedLeft(final ValueResolver valueResolver,
final VariableRestriction.VariableContextEntry context, final FactHandle right)
{
final Object valRight = context.extractor.getValue(valueResolver,
right.getObject());
- return evaluateAll((Collection)
((VariableRestriction.ObjectVariableContextEntry) context).left, (Collection)
valRight);
+ return evaluateExpression((Collection) valRight, (Collection)
((VariableRestriction.ObjectVariableContextEntry) context).left);
}
+ // In this method, 'left' means leftInput to the JoinNode. 'right'
means RightInput to the JoinNode.
+ // To evaluate the expression, RightInput is the left operand and
leftInput is the right operand. So, need to invert.
+ // for example, [addresses supersetOf $alice.addresses]
+ // context.right is addresses
+ // varLeft is $alice.addresses
+ @Override
public boolean evaluateCachedRight(final ValueResolver reteEvaluator,
final VariableRestriction.VariableContextEntry context, final FactHandle left) {
final Object varLeft =
context.declaration.getExtractor().getValue(reteEvaluator, left);
- return evaluateAll((Collection) varLeft, (Collection)
((VariableRestriction.ObjectVariableContextEntry) context).right);
+ return evaluateExpression((Collection)
((VariableRestriction.ObjectVariableContextEntry) context).right, (Collection)
varLeft);
}
- public boolean evaluateAll(final Collection leftCollection, final
Collection rightCollection) {
- return getOperator().isNegated() ^
rightCollection.containsAll(leftCollection);
+ // In this method, 'left' and 'right' literally mean the left and
right operands of the expression.
+ // for example, [addresses supersetOf $alice.addresses]
+ // leftOperandCollection is addresses
+ // rightOperandCollection is $alice.addresses
+ private boolean evaluateExpression(final Collection
leftOperandCollection, final Collection rightOperandCollection) {
+ return getOperator().isNegated() ^
leftOperandCollection.containsAll(rightOperandCollection);
}
}
@ParameterizedTest(name = "KieBase type={0}")
- @MethodSource("parameters")
+ @MethodSource("parameters")
public void testCustomOperatorOnKieModule(KieBaseTestConfiguration
kieBaseTestConfiguration) {
final String drl = "import " + Address.class.getCanonicalName() +
";\n" +
"import " + Person.class.getCanonicalName() + ";\n" +
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]