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]

Reply via email to