From a713f41030c64c25c0fdc7ba77ad88cdaed32198 Mon Sep 17 00:00:00 2001 From: Samuel Beniamin Date: Mon, 30 Sep 2024 13:34:31 +0200 Subject: [PATCH] [incubator-kie-issues#1478] Regiser DRG callbacks to assigned models from DMNCompilerImpl --- .../dmn/core/compiler/DMNCompilerImpl.java | 35 ++++++++++++--- .../core/compiler/DMNCompilerImplTest.java | 45 +++++++++++++++++++ .../signavio/MultiInstanceDecisionLogic.java | 13 +----- 3 files changed, 76 insertions(+), 17 deletions(-) diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java index 078a1158036..6d87003f6ec 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java @@ -41,9 +41,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; - import javax.xml.namespace.QName; - import org.drools.io.FileSystemResource; import org.kie.api.io.Resource; import org.kie.dmn.api.core.DMNCompiler; @@ -113,8 +111,8 @@ public class DMNCompilerImpl implements DMNCompiler { private static final Logger logger = LoggerFactory.getLogger( DMNCompilerImpl.class ); private final DMNDecisionLogicCompiler evaluatorCompiler; - private DMNCompilerConfiguration dmnCompilerConfig; - private Deque drgCompilers = new LinkedList<>(); + private final DMNCompilerConfiguration dmnCompilerConfig; + private final Deque drgCompilers = new LinkedList<>(); { drgCompilers.add( new InputDataCompiler() ); drgCompilers.add( new BusinessKnowledgeModelCompiler() ); @@ -123,6 +121,7 @@ public class DMNCompilerImpl implements DMNCompiler { drgCompilers.add( new KnowledgeSourceCompiler() ); // keep last as it's a void compiler } private final List afterDRGcallbacks = new ArrayList<>(); + private final Map> afterDRGcallbacksForModel = new HashMap<>(); private final static Pattern QNAME_PAT = Pattern.compile("(\\{([^\\}]*)\\})?(([^:]*):)?(.*)"); public DMNCompilerImpl() { @@ -477,6 +476,9 @@ private void processDrgElements(DMNCompilerContext ctx, DMNModelImpl model, Defi } } + afterDRGcallbacksForModel.getOrDefault(model, Collections.emptyList()). + forEach(processDrgElements -> processDrgElements.callback(this, ctx, model)); + for (AfterProcessDrgElements callback : afterDRGcallbacks) { logger.debug("About to invoke callback: {}", callback); callback.callback(this, ctx, model); @@ -491,9 +493,30 @@ private void processDrgElements(DMNCompilerContext ctx, DMNModelImpl model, Defi public interface AfterProcessDrgElements { void callback(DMNCompilerImpl compiler, DMNCompilerContext ctx, DMNModelImpl model); } - + + /** + * Adds a callback that will be invoked after the DRG elements have been processed, for all the following models that are compiled with this compiler instance. + * Which may lead to the callback being called multiple times, and for unrelated models. Unless, the callback is registered to a specific model using: + * {@link #addCallbackForModel(AfterProcessDrgElements, DMNModel)}. + */ public void addCallback(AfterProcessDrgElements callback) { - this.afterDRGcallbacks.add(callback); + afterDRGcallbacks.add(callback); + } + + + /** + * Adds a callback that will be invoked after the DRG elements have been processed, for a given model. + */ + public void addCallbackForModel(AfterProcessDrgElements callback, DMNModel model) { + this.afterDRGcallbacksForModel.compute(model, (k, v) -> { + if (v == null) { + v = new ArrayList<>(); + } + if (callback != null) { + v.add(callback); + } + return v; + }); } private void detectCycles( DMNModelImpl model ) { diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DMNCompilerImplTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DMNCompilerImplTest.java index bc11d10e568..3493f49eb78 100644 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DMNCompilerImplTest.java +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/DMNCompilerImplTest.java @@ -18,22 +18,38 @@ */ package org.kie.dmn.core.compiler; +import java.io.StringReader; +import java.util.Collections; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.kie.dmn.api.core.DMNCompilerConfiguration; +import org.kie.dmn.api.core.DMNModel; +import org.kie.dmn.core.api.DMNFactory; +import org.kie.dmn.core.impl.DMNModelImpl; import org.kie.dmn.model.api.DMNElementReference; import org.kie.dmn.model.api.Definitions; import org.kie.dmn.model.api.InformationRequirement; import org.kie.dmn.model.v1_5.TDMNElementReference; import org.kie.dmn.model.v1_5.TDefinitions; import org.kie.dmn.model.v1_5.TInformationRequirement; +import org.mockito.Mockito; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; class DMNCompilerImplTest { private static final String nameSpace = "http://www.montera.com.au/spec/DMN/local-hrefs"; private static Definitions parent; + private static DMNCompilerImpl dmnCompiler; + private static DMNCompilerImpl.AfterProcessDrgElements mockCallback; + private static DMNCompilerImpl.AfterProcessDrgElements mockCallbackForModel; @BeforeAll static void setup() { @@ -41,6 +57,12 @@ static void setup() { parent = new TDefinitions(); parent.setName(modelName); parent.setNamespace(nameSpace); + + DMNCompilerConfiguration config = DMNFactory.newCompilerConfiguration(); + dmnCompiler = new DMNCompilerImpl(config); + mockCallback = Mockito.mock(DMNCompilerImpl.AfterProcessDrgElements.class); + dmnCompiler.addCallback(mockCallback); + mockCallbackForModel = Mockito.mock(DMNCompilerImpl.AfterProcessDrgElements.class); } @Test @@ -76,4 +98,27 @@ void getRootElement() { retrieved = DMNCompilerImpl.getRootElement(elementReference); assertThat(retrieved).isNotNull().isEqualTo(parent); } + + @Test + void testCompileWithCallback() { + String dmnXml = """ + + + + + """; + DMNModel mockModel = mock(DMNModel.class); + dmnCompiler.addCallbackForModel(mockCallbackForModel, mockModel); + + + Definitions definitions = dmnCompiler.getMarshaller().unmarshal(new StringReader(dmnXml)); + DMNModel model = dmnCompiler.compile(definitions, Collections.emptyList()); + dmnCompiler.addCallbackForModel(mockCallbackForModel, model); + dmnCompiler.compile(definitions, Collections.emptyList()); + + + assertThat(model).isNotNull(); + verify(mockCallback, times(2)).callback(eq(dmnCompiler), any(), any(DMNModelImpl.class)); + verify(mockCallbackForModel, never()).callback(any(), any(), any()); + } } \ No newline at end of file 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 542b7c3ff91..c8091957d8d 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,8 +55,6 @@ 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; @@ -65,7 +63,6 @@ @XStreamAlias("MultiInstanceDecisionLogic") public class MultiInstanceDecisionLogic { - private static Logger logger = LoggerFactory.getLogger(MultiInstanceDecisionLogic.class); @XStreamAlias("iterationExpression") private String iterationExpression; @@ -135,17 +132,11 @@ public void compileEvaluator(DMNNode node, DMNCompilerImpl compiler, DMNCompiler final MultiInstanceDecisionNodeEvaluator miEvaluator = new MultiInstanceDecisionNodeEvaluator(midl, model, di, ctx.getFeelHelper().newFEELInstance()); 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; - } + compiler.addCallbackForModel((cCompiler, cCtx, cModel) -> { MIDDependenciesProcessor processor = new MIDDependenciesProcessor(midl, cModel); addRequiredDecisions(miEvaluator, processor); removeChildElementsFromIndex(cModel, processor); - }); + }, model); } private void addRequiredDecisions(MultiInstanceDecisionNodeEvaluator miEvaluator,