Skip to content

Commit

Permalink
[incubator-kie-issues#1411] Adapting code to deal with full href defi…
Browse files Browse the repository at this point in the history
…nition (namespace#local_part) for local elements. (#6050)

Co-authored-by: Gabriele-Cardosi <[email protected]>
  • Loading branch information
gitgabrio and Gabriele-Cardosi authored Aug 20, 2024
1 parent 2b991ff commit 3dac669
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ private void processItemDefinitions(DMNCompilerContext ctx, DMNModelImpl model,
if (id.getItemComponent() != null && !id.getItemComponent().isEmpty()) {
DMNCompilerHelper.checkVariableName(model, id, id.getName());
CompositeTypeImpl compType = new CompositeTypeImpl(model.getNamespace(), id.getName(), id.getId(), id.isIsCollection());
DMNType preregistered = model.getTypeRegistry().registerType(compType);
model.getTypeRegistry().registerType(compType);
}
}

Expand Down Expand Up @@ -598,7 +598,31 @@ public void linkRequirements(DMNModelImpl model, DMNBaseNode node) {
*/
public static String getId(DMNElementReference er) {
String href = er.getHref();
return href.startsWith("#") ? href.substring(1) : href;
if (href.startsWith("#")) {
return href.substring(1);
} else {
Definitions rootElement = getRootElement(er);
String toRemove = String.format("%s#", rootElement.getNamespace());
return href.replace(toRemove, "");
}
}

/**
* Recursively navigate the given <code>DMNModelInstrumentedBase</code> until it gets to the root <code>Definitions</code> element.
* it throws a <code>RuntimeException</code> if such element could not be found.
*
* @param toNavigate
* @return
* @throws RuntimeException
*/
public static Definitions getRootElement(DMNModelInstrumentedBase toNavigate) {
if ( toNavigate instanceof Definitions ) {
return (Definitions) toNavigate;
} else if ( toNavigate.getParent() != null ) {
return getRootElement(toNavigate.getParent());
} else {
throw new RuntimeException("Failed to get Definitions parent for " + toNavigate);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,33 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.kie.dmn.api.core.DMNContext;
import org.kie.dmn.api.core.DMNDecisionResult;
import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.api.core.DMNModel;
import org.kie.dmn.api.core.DMNResult;
import org.kie.dmn.api.core.DMNRuntime;
import org.kie.dmn.api.core.DMNType;
import org.kie.dmn.api.core.FEELPropertyAccessible;
import org.kie.dmn.api.core.ast.DecisionNode;
import org.kie.dmn.api.core.ast.ItemDefNode;
import org.kie.dmn.core.api.DMNFactory;
import org.kie.dmn.core.compiler.DMNTypeRegistry;
import org.kie.dmn.core.impl.BaseDMNTypeImpl;
import org.kie.dmn.core.impl.CompositeTypeImpl;
import org.kie.dmn.core.impl.DMNContextFPAImpl;
import org.kie.dmn.core.impl.DMNModelImpl;
import org.kie.dmn.core.impl.DMNResultImpl;
import org.kie.dmn.core.impl.SimpleTypeImpl;
import org.kie.dmn.core.util.DMNRuntimeUtil;
import org.kie.dmn.feel.lang.EvaluationContext;
import org.kie.dmn.feel.lang.types.AliasFEELType;
import org.kie.dmn.feel.lang.types.BuiltInType;
import org.kie.dmn.model.api.Decision;
import org.kie.dmn.model.api.InformationRequirement;
import org.kie.dmn.model.api.KnowledgeRequirement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.InstanceOfAssertFactories.map;
import static org.kie.dmn.api.core.DMNDecisionResult.DecisionEvaluationStatus.SUCCEEDED;
import static org.kie.dmn.core.util.DynamicTypeUtils.entry;
import static org.kie.dmn.core.util.DynamicTypeUtils.mapOf;
Expand Down Expand Up @@ -470,6 +471,32 @@ void allowedValuesForComplexTypeInherited(VariantTestConf conf) {
assertThat(dmnAdultBobPerson.isAssignableValue(instanceYoungJoe)).isFalse();
}

@ParameterizedTest
@MethodSource("params")
void localHrefs(VariantTestConf conf) {
testConfig = conf;
String nameSpace = "http://www.montera.com.au/spec/DMN/local-hrefs";
final DMNRuntime runtime = DMNRuntimeUtil.createRuntime("valid_models/DMNv1_5/LocalHrefs.dmn", this.getClass());
final DMNModel dmnModel = runtime.getModel(
nameSpace,
"LocalHrefs");
assertThat(dmnModel).isNotNull();
assertThat(dmnModel.hasErrors()).as(DMNRuntimeUtil.formatMessages(dmnModel.getMessages())).isFalse();
DecisionNode retrievedDecisionNode = dmnModel.getDecisionByName("decision_002");
assertThat(retrievedDecisionNode).isNotNull();
Decision retrievedDecision = retrievedDecisionNode.getDecision();
assertThat(retrievedDecision).isNotNull();
assertThat(retrievedDecision.getInformationRequirement())
.isNotNull()
.isNotEmpty()
.allSatisfy((Consumer<InformationRequirement>) informationRequirement -> assertThat(informationRequirement).isNotNull());
assertThat(retrievedDecision.getKnowledgeRequirement())
.isNotNull()
.isNotEmpty()
.allSatisfy((Consumer<KnowledgeRequirement>) knowledgeRequirement -> assertThat(knowledgeRequirement).isNotNull());

}

private void commonValidateUnnamedImport(String importingModelRef, String importedModelRef) {
final DMNRuntime runtime = createRuntimeWithAdditionalResources(importingModelRef,
this.getClass(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* 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.api.BeforeAll;
import org.junit.jupiter.api.Test;
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 static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

class DMNCompilerImplTest {

private static final String nameSpace = "http://www.montera.com.au/spec/DMN/local-hrefs";
private static Definitions parent;

@BeforeAll
static void setup() {
String modelName = "LocalHrefs";
parent = new TDefinitions();
parent.setName(modelName);
parent.setNamespace(nameSpace);
}

@Test
void getId() {
String localPart = "reference";
DMNElementReference elementReference = new TDMNElementReference();
elementReference.setHref(String.format("%s#%s", nameSpace, localPart));
elementReference.setParent(parent);
String retrieved = DMNCompilerImpl.getId(elementReference);
assertThat(retrieved).isNotNull().isEqualTo(localPart);

String expected = String.format("%s#%s", "http://a-different-namespace", localPart);
elementReference.setHref(expected);
retrieved = DMNCompilerImpl.getId(elementReference);
assertThat(retrieved).isNotNull().isEqualTo(expected);
}

@Test
void getRootElement() {
String localPart = "reference";
DMNElementReference elementReference = new TDMNElementReference();
String href = String.format("%s#%s", nameSpace, localPart);
elementReference.setHref(href);
elementReference.setParent(parent);
Definitions retrieved = DMNCompilerImpl.getRootElement(elementReference);
assertThat(retrieved).isNotNull().isEqualTo(parent);

InformationRequirement informationRequirement = new TInformationRequirement();
elementReference.setParent(informationRequirement);
assertThrows(RuntimeException.class, () -> DMNCompilerImpl.getRootElement(elementReference));

informationRequirement.setParent(parent);
retrieved = DMNCompilerImpl.getRootElement(elementReference);
assertThat(retrieved).isNotNull().isEqualTo(parent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions namespace="http://www.montera.com.au/spec/DMN/local-hrefs"
name="LocalHrefs"
xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/">

<description>Local (non-imported) qualified hrefs</description>

<inputData name="input_001" id="_input_001">
<variable name="input_001" typeRef="string"/>
</inputData>

<decision name="decision_001" id="_decision_001">
<variable name="decision_001" typeRef="string"/>
<literalExpression>
<text>"decision_001"</text>
</literalExpression>
</decision>

<businessKnowledgeModel name="bkm_001" id="_bkm_001">
<variable name="bkm_001"/>
<encapsulatedLogic>
<literalExpression>
<text>"bkm_001"</text>
</literalExpression>
</encapsulatedLogic>
</businessKnowledgeModel>

<!-- requirements hrefs refer to elements in this model -->
<decision name="decision_002" id="_decision_002">
<variable name="decision_002" typeRef="string"/>
<informationRequirement>
<requiredDecision href="http://www.montera.com.au/spec/DMN/local-hrefs#_decision_001"/>
</informationRequirement>
<informationRequirement>
<requiredInput href="http://www.montera.com.au/spec/DMN/local-hrefs#_input_001"/>
</informationRequirement>
<knowledgeRequirement>
<requiredKnowledge href="http://www.montera.com.au/spec/DMN/local-hrefs#_bkm_001"/>
</knowledgeRequirement>
<literalExpression>
<text>decision_001 + " " + input_001 + " " + bkm_001()</text>
</literalExpression>
</decision>

</definitions>

Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
package org.kie.dmn.validation.DMNv1x;

import org.kie.dmn.model.api.*;
import org.kie.dmn.model.api.DMNElement;
import org.kie.dmn.model.api.DMNElementReference;
import org.kie.dmn.api.core.DMNMessage;
import org.kie.dmn.core.impl.DMNMessageImpl;
import org.kie.dmn.core.compiler.DMNCompilerImpl;
import org.kie.dmn.core.util.MsgUtil;
import org.kie.dmn.feel.lang.types.BuiltInType;
import org.kie.dmn.feel.parser.feel11.FEELParser;
Expand All @@ -45,7 +48,7 @@ end
rule ELEMREF_NOHASH_p2
when
not( Import() )
$oc : DMNElementReference(href contains ":", !href.substring(href.indexOf(":") + 1).startsWith('#'))
$oc : DMNElementReference(href contains ":", !(href contains "#"))
then
reporter.report( DMNMessage.Severity.ERROR, $oc , Msg.ELEMREF_NOHASH, $oc.getParentDRDElement().getIdentifierString() );
end
Expand All @@ -60,7 +63,7 @@ end

rule ELEMREF_MISSING_p2
when
$elemRef: DMNElementReference(!href.startsWith("#"), $href: href, href.contains("#"), $targetId : rightOfHash(href), $targetNS : leftOfHash(href))
$elemRef: DMNElementReference(!href.startsWith("#"), $href: href, href.contains("#"), $targetId : rightOfHash(href), $targetNS : leftOfHash(href), $rootElement: DMNCompilerImpl.getRootElement(this), !$rootElement.namespace.equals($targetNS))
(not (and Import( $importedNS : namespace )
$importDef : Definitions( namespace == $importedNS, namespace == $targetNS ) from entry-point "DMNImports"
DMNElement( id == $targetId ) from $importDef.drgElement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ void typeConstraintsChecksValidation() {
evaluate(modelNamespace, modelName, modelFileName, inputData);
}

@Test
void localHrefsValidation() {
String modelFileName = "valid_models/DMNv1_5/LocalHrefs.dmn";
validate(modelFileName);
}

private void commonUnnamedImportValidation(String importingModelRef, String importedModelRef) {
String modelName = "Importing empty-named Model";
String modelNamespace = "http://www.trisotech.com/dmn/definitions/_f79aa7a4-f9a3-410a-ac95-bea496edabgc";
Expand Down

0 comments on commit 3dac669

Please sign in to comment.