This is an automated email from the ASF dual-hosted git repository.

yamer 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 842a2ca88f [incubator-kie-issue#2052] Decision Services doesn't work 
with unnamed imported Elements  (#6425)
842a2ca88f is described below

commit 842a2ca88fb88cd9c3dcb79dfafc5cef8a9c44e5
Author: Yeser Amer <[email protected]>
AuthorDate: Mon Aug 18 22:15:41 2025 +0200

    [incubator-kie-issue#2052] Decision Services doesn't work with unnamed 
imported Elements  (#6425)
    
    * Bug fix - Decision Services doesn't work with unnamed imported Elements
    
    * Code Refactoring and Junits
    
    * Unit test for inputQualifiedNamePrefix method
    
    * Fixing review comments
    
    * Fixing review comments
    
    * Change Request
    
    ---------
    
    Co-authored-by: ChinchuAjith <[email protected]>
---
 .../dmn/core/compiler/DecisionServiceCompiler.java | 116 ++++++++--------
 .../core/compiler/DecisionServiceCompilerTest.java | 147 +++++++++++++++++++++
 2 files changed, 206 insertions(+), 57 deletions(-)

diff --git 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java
 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java
index 7d25b47256..d99ba14127 100644
--- 
a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java
+++ 
b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DecisionServiceCompiler.java
@@ -53,6 +53,8 @@ import org.kie.dmn.model.api.ItemDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.kie.dmn.core.compiler.UnnamedImportUtils.isInUnnamedImport;
+
 public class DecisionServiceCompiler implements DRGElementCompiler {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(DecisionServiceCompiler.class);
@@ -103,12 +105,13 @@ public class DecisionServiceCompiler implements 
DRGElementCompiler {
      * The qualified name of an element named E that is defined in the same 
decision model as S is simply E.
      * Otherwise, the qualified name is I.E, where I is the name of the import 
element that refers to the model where E is defined.
      */
-    private static String inputQualifiedNamePrefix(DMNNode input, DMNModelImpl 
model) {
-        if (input.getModelNamespace().equals(model.getNamespace())) {
+     static String inputQualifiedNamePrefix(DMNNode input, DMNModelImpl model) 
{
+        if (input.getModelNamespace().equals(model.getNamespace()) || 
isInUnnamedImport(input, model)) {
             return null;
         } else {
-            Optional<String> importAlias = 
model.getImportAliasFor(input.getModelNamespace(), input.getModelName());
-            if (importAlias.isEmpty()) {
+            try {
+                return getInputNamePrefix(input, model);
+            } catch (IllegalStateException e) {
                 MsgUtil.reportMessage(LOG,
                                       DMNMessage.Severity.ERROR,
                                       ((DMNBaseNode)input).getSource(),
@@ -120,71 +123,74 @@ public class DecisionServiceCompiler implements 
DRGElementCompiler {
                                       ((DMNBaseNode)input).getSource());
                 return null;
             }
-            return importAlias.get();
         }
+     }
+
+    private static String getInputNamePrefix(DMNNode input, DMNModelImpl 
model) {
+        Optional<String> importAlias = 
model.getImportAliasFor(input.getModelNamespace(), input.getModelName());
+        if (importAlias.isEmpty()) {
+            throw new IllegalStateException("Missing import alias for model " 
+ input.getModelName() +
+                    "with namespace " + input.getModelNamespace());
+        }
+        return importAlias.get();
     }
 
     @Override
     public void compileEvaluator(DMNNode node, DMNCompilerImpl compiler, 
DMNCompilerContext ctx, DMNModelImpl model) {
         DecisionServiceNodeImpl ni = (DecisionServiceNodeImpl) node;
-
         List<DSFormalParameter> parameters = new ArrayList<>();
-        
+        processInputData(ni, model, parameters);
+        processInputDecisions(ni, model, parameters);
+        validateEncapsulatedDecision(ni, model);
+        List<DecisionNode> outputDecisions = getOutputDecisions(ni, model);
+
+        boolean coerceSingleton = ((DMNCompilerConfigurationImpl) 
compiler.getDmnCompilerConfig()).getOption(CoerceDecisionServiceSingletonOutputOption.class).isCoerceSingleton();
+        DMNDecisionServiceFunctionDefinitionEvaluator exprEvaluator = new 
DMNDecisionServiceFunctionDefinitionEvaluator(ni, parameters, coerceSingleton);
+        ni.setEvaluator(exprEvaluator);
+
+        if (ni.getType() != null) {
+            checkFnConsistency(model, ni, ni.getType(), outputDecisions);
+        }
+    }
+
+    private void processInputData(DecisionServiceNodeImpl ni, DMNModelImpl 
model, List<DSFormalParameter> parameters) {
         for (DMNElementReference er : ni.getDecisionService().getInputData()) {
             String id = DMNCompilerImpl.getId(er);
             InputDataNode input = model.getInputById(id);
-            String inputNamePrefix = inputQualifiedNamePrefix(input, model);
             if (input != null) {
+                String inputNamePrefix = inputQualifiedNamePrefix(input, 
model);
                 ni.addInputParameter(inputNamePrefix != null ? inputNamePrefix 
+ "." + input.getName() : input.getName(), input);
                 parameters.add(new DSFormalParameter(inputNamePrefix, 
input.getName(), input.getType()));
             } else {
-                MsgUtil.reportMessage(LOG,
-                                      DMNMessage.Severity.ERROR,
-                                      ni.getDecisionService(),
-                                      model,
-                                      null,
-                                      null,
-                                      Msg.REFERENCE_NOT_FOUND_FOR_DS,
-                                      id,
-                                      node.getName());
+                reportReferenceError(ni, model, id);
             }
         }
+    }
+
+    private void processInputDecisions(DecisionServiceNodeImpl ni, 
DMNModelImpl model, List<DSFormalParameter> parameters) {
         for (DMNElementReference er : 
ni.getDecisionService().getInputDecision()) {
             String id = DMNCompilerImpl.getId(er);
             DecisionNode input = model.getDecisionById(id);
-            String inputNamePrefix = inputQualifiedNamePrefix(input, model);
             if (input != null) {
+                String inputNamePrefix = inputQualifiedNamePrefix(input, 
model);
                 ni.addInputParameter(inputNamePrefix != null ? inputNamePrefix 
+ "." + input.getName() : input.getName(), input);
                 parameters.add(new DSFormalParameter(inputNamePrefix, 
input.getName(), input.getResultType()));
             } else {
-                MsgUtil.reportMessage(LOG,
-                                      DMNMessage.Severity.ERROR,
-                                      ni.getDecisionService(),
-                                      model,
-                                      null,
-                                      null,
-                                      Msg.REFERENCE_NOT_FOUND_FOR_DS,
-                                      id,
-                                      node.getName());
+                reportReferenceError(ni, model, id);
             }
         }
+    }
+
+    private void validateEncapsulatedDecision(DecisionServiceNodeImpl ni, 
DMNModelImpl model) {
         for (DMNElementReference er : 
ni.getDecisionService().getEncapsulatedDecision()) {
             String id = DMNCompilerImpl.getId(er);
-            DecisionNode input = model.getDecisionById(id);
-            if (input != null) {
-                // nothing to do.
-            } else {
-                MsgUtil.reportMessage(LOG,
-                                      DMNMessage.Severity.ERROR,
-                                      ni.getDecisionService(),
-                                      model,
-                                      null,
-                                      null,
-                                      Msg.REFERENCE_NOT_FOUND_FOR_DS,
-                                      id,
-                                      node.getName());
+            if (model.getDecisionById(id) == null) {
+                reportReferenceError(ni, model, id);
             }
         }
+    }
+
+    private List<DecisionNode> getOutputDecisions(DecisionServiceNodeImpl ni, 
DMNModelImpl model) {
         List<DecisionNode> outputDecisions = new ArrayList<>();
         for (DMNElementReference er : 
ni.getDecisionService().getOutputDecision()) {
             String id = DMNCompilerImpl.getId(er);
@@ -192,26 +198,22 @@ public class DecisionServiceCompiler implements 
DRGElementCompiler {
             if (outDecision != null) {
                 outputDecisions.add(outDecision);
             } else {
-                MsgUtil.reportMessage(LOG,
-                                      DMNMessage.Severity.ERROR,
-                                      ni.getDecisionService(),
-                                      model,
-                                      null,
-                                      null,
-                                      Msg.REFERENCE_NOT_FOUND_FOR_DS,
-                                      id,
-                                      node.getName());
+                reportReferenceError(ni, model, id);
             }
         }
+        return outputDecisions;
+    }
 
-        boolean coerceSingleton = ((DMNCompilerConfigurationImpl) 
compiler.getDmnCompilerConfig()).getOption(CoerceDecisionServiceSingletonOutputOption.class).isCoerceSingleton();
-
-        DMNDecisionServiceFunctionDefinitionEvaluator exprEvaluator = new 
DMNDecisionServiceFunctionDefinitionEvaluator(ni, parameters, coerceSingleton);
-        ni.setEvaluator(exprEvaluator);
-
-        if (ni.getType() != null) {
-            checkFnConsistency(model, ni, ni.getType(), outputDecisions);
-        }
+    private void reportReferenceError(DecisionServiceNodeImpl ni, DMNModelImpl 
model, String id) {
+        MsgUtil.reportMessage(LOG,
+                DMNMessage.Severity.ERROR,
+                ni.getDecisionService(),
+                model,
+                null,
+                null,
+                Msg.REFERENCE_NOT_FOUND_FOR_DS,
+                id,
+                ni.getName());
     }
 
     private void checkFnConsistency(DMNModelImpl model, 
DecisionServiceNodeImpl ni, DMNType type, List<DecisionNode> outputDecisions) {
diff --git 
a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java
 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java
new file mode 100644
index 0000000000..8004538c47
--- /dev/null
+++ 
b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DecisionServiceCompilerTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.dmn.core.compiler;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.kie.dmn.api.core.DMNMessage;
+import org.kie.dmn.api.core.ast.DMNNode;
+import org.kie.dmn.core.BaseInterpretedVsCompiledTest;
+import org.kie.dmn.core.ast.DMNBaseNode;
+import org.kie.dmn.core.impl.DMNModelImpl;
+import org.kie.dmn.core.util.Msg;
+import org.kie.dmn.core.util.MsgUtil;
+import org.kie.dmn.model.api.Definitions;
+import org.kie.dmn.model.api.Import;
+import org.kie.dmn.model.api.NamedElement;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import javax.xml.namespace.QName;
+import java.util.List;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+
+public class DecisionServiceCompilerTest extends BaseInterpretedVsCompiledTest 
{
+
+    @ParameterizedTest
+    @MethodSource("params")
+    void inputQualifiedNamePrefixWithSameNameSpace() {
+        DMNNode input = mock(DMNNode.class);
+        DMNModelImpl model = mock(DMNModelImpl.class);
+
+        when(input.getModelNamespace()).thenReturn("modelNamespace");
+        when(model.getNamespace()).thenReturn("modelNamespace");
+
+        String result = 
DecisionServiceCompiler.inputQualifiedNamePrefix(input, model);
+        assertThat(result).isNull();
+
+    }
+
+    @ParameterizedTest
+    @MethodSource("params")
+    void inputQualifiedNamePrefixWithUnnamedImportTrue() {
+
+        DMNNode input = mock(DMNNode.class);
+        when(input.getModelNamespace()).thenReturn("nodeNamespace");
+        when(input.getName()).thenReturn("inputName");
+
+        Import imported = mock(Import.class);
+        when(imported.getName()).thenReturn("");
+        when(imported.getNamespace()).thenReturn("nodeNamespace");
+        Definitions definitions = mock(Definitions.class);
+        when(definitions.getImport()).thenReturn(List.of(imported));
+
+        DMNModelImpl model = mock(DMNModelImpl.class);
+        when(model.getNamespace()).thenReturn("modelNamespace");
+        when(model.getDefinitions()).thenReturn(definitions);
+
+        String result = 
DecisionServiceCompiler.inputQualifiedNamePrefix(input, model);
+        assertThat(result).isNull();
+
+    }
+
+    @ParameterizedTest
+    @MethodSource("params")
+    void inputQualifiedNamePrefixWithImportAlias() {
+        DMNNode input = mock(DMNNode.class);
+        when(input.getModelNamespace()).thenReturn("nodeNamespace");
+        when(input.getName()).thenReturn("inputName");
+
+        Import imported = mock(Import.class);
+        when(imported.getNamespace()).thenReturn("importedNamespace");
+        Definitions definitions = mock(Definitions.class);
+        when(definitions.getImport()).thenReturn(List.of(imported));
+
+        DMNModelImpl model = mock(DMNModelImpl.class);
+        when(model.getNamespace()).thenReturn("modelNamespace");
+        when(model.getDefinitions()).thenReturn(definitions);
+        when(model.getImportAliasFor(any(), 
any())).thenReturn(Optional.of("inputName"));
+
+        String result = 
DecisionServiceCompiler.inputQualifiedNamePrefix(input, model);
+        assertThat(result).isNotNull();
+        assertThat(result).isEqualTo("inputName");
+
+    }
+
+    @ParameterizedTest
+    @MethodSource("params")
+    void inputQualifiedNamePrefixWithEmptyImportAlias() {
+        DMNBaseNode input = mock(DMNBaseNode.class);
+        when(input.getModelNamespace()).thenReturn("nodeNamespace");
+        when(input.getName()).thenReturn("inputName");
+        when(input.getModelName()).thenReturn("modelname");
+        NamedElement source = mock(NamedElement.class);
+        when(input.getSource()).thenReturn(source);
+
+        DMNModelImpl model = mock(DMNModelImpl.class);
+        when(model.getNamespace()).thenReturn("modelNamespace");
+        when(model.getImportAliasFor(any(), 
any())).thenReturn(Optional.empty());
+
+        try (MockedStatic<MsgUtil> msgUtilMock = mockStatic(MsgUtil.class)) {
+            try (MockedStatic<UnnamedImportUtils> unnamedImportMock = 
mockStatic(UnnamedImportUtils.class)) {
+                unnamedImportMock.when(() -> 
UnnamedImportUtils.isInUnnamedImport(input, model)).thenReturn(false);
+                String result = 
DecisionServiceCompiler.inputQualifiedNamePrefix(input, model);
+                assertThat(result).isNull();
+                // Verify error was reported
+                msgUtilMock.verify(() -> MsgUtil.reportMessage(
+                        any(),
+                        eq(DMNMessage.Severity.ERROR),
+                        eq(source),
+                        eq(model),
+                        isNull(),
+                        isNull(),
+                        eq(Msg.IMPORT_NOT_FOUND_FOR_NODE_MISSING_ALIAS),
+                        eq(new QName("nodeNamespace", "modelname")),
+                        eq(source)
+                ));
+            }
+        }
+
+    }
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to