Skip to content

Commit

Permalink
[#651] Annotations: Add evaluation for TRuleAnnotations
Browse files Browse the repository at this point in the history
  • Loading branch information
opatrascoiu committed Apr 10, 2024
1 parent 95491aa commit 508f17e
Show file tree
Hide file tree
Showing 15 changed files with 590 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -408,18 +408,20 @@ public List<String> annotations(TDRGElement element, List<String> annotationText
if (StringUtils.isBlank(annotationText)) {
annotationStatements.add("\"\"");
} else {
Statement statement = this.expressionToNativeTransformer.literalExpressionToNative(element, annotationText, context);
Statement statement = annotation(element, annotationText, context);
annotationStatements.add(statement.getText());
}
} catch (Exception e) {
LOGGER.error(String.format("Cannot process annotation '%s' for element '%s'", annotationText, element == null ? "" : element.getName()));
// Add unevaluated annotation text
annotationStatements.add(String.format("\"%s\"", annotationText.replaceAll("\"", "\\\\\"")));
throw new DMNRuntimeException(String.format("Cannot process annotation '%s' for element '%s'", annotationText, element == null ? "" : element.getName()), e);
}
}
return annotationStatements;
}

protected Statement annotation(TDRGElement element, String annotationText, DMNContext context) {
return this.expressionToNativeTransformer.literalExpressionToNative(element, annotationText, context);
}

@Override
public boolean canGenerateApplyWithMap(TDRGElement element) {
if (element instanceof TDecision) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,11 +400,24 @@ String annotationEscapedText(TDecisionRule rule) {
return description == null ? "" : StringEscapeUtil.escapeInString(description);
}

List<String> annotations(TDRGElement element, TDecisionRule rule) {
protected List<String> annotations(TDRGElement element, TDecisionRule rule) {
// Collect annotation texts
List<String> annotations = collectAnnotationTexts(rule);
// Translate annotations
return this.dmnTransformer.annotations(element, annotations);
}

protected List<String> collectAnnotationTexts(TDecisionRule rule) {
List<String> annotations = new ArrayList<>();
String description = rule.getDescription();
annotations.add(description);
return this.dmnTransformer.annotations(element, annotations);
for (TRuleAnnotation ruleAnnotation : rule.getAnnotationEntry()) {
String text = ruleAnnotation.getText();
if (!StringUtils.isBlank(text)) {
annotations.add(text);
}
}
return annotations;
}

String ruleAnnotationClassName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,10 @@ protected String getExpectedPath() {
public void testOther() throws Exception {
doSingleModelTest("1.2","composite-decision-type-any");
}

@Test
public void testAnnotations() throws Exception {
doSingleModelTest("1.4","decision-table-with-annotations");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.gs.dmn.transformation.lazy.LazyEvaluationDetector;
import com.gs.dmn.transformation.native_.statement.Statement;
import com.gs.dmn.transformation.proto.ProtoBufferJavaFactory;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -265,6 +266,31 @@ public List<ExtensionElement> makeMetadataExtensions(TDecision decision) {
return extensions;
}

//
// Annotations
//
@Override
public List<String> annotations(TDRGElement element, List<String> annotationTexts) {
List<String> annotationStatements = new ArrayList<>();
DMNContext context = this.makeGlobalContext(element);
for (String annotationText : annotationTexts) {
try {
// Add rule annotation
if (StringUtils.isBlank(annotationText)) {
annotationStatements.add("\"\"");
} else {
Statement statement = annotation(element, annotationText, context);
annotationStatements.add(statement.getText());
}
} catch (Exception e) {
LOGGER.error(String.format("Cannot process annotation '%s' for element '%s'", annotationText, element == null ? "" : element.getName()));
// Add unevaluated annotation text
annotationStatements.add(String.format("\"%s\"", annotationText.replaceAll("\"", "\\\\\"")));
}
}
return annotationStatements;
}

//
// Multi Instance Decision
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,15 @@ protected Statement invocationExpressionToNative(TDRGElement element, TInvocatio
throw new DMNRuntimeException(String.format("Not supported '%s'", body.getClass().getSimpleName()));
}
}

//
// Annotations
//
@Override
protected List<String> collectAnnotationTexts(TDecisionRule rule) {
List<String> annotations = new ArrayList<>();
String description = rule.getDescription();
annotations.add(description);
return annotations;
}
}
36 changes: 36 additions & 0 deletions dmn-tck-it/dmn-tck-it-translator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2670,6 +2670,42 @@
</configuration>
</execution>

<!-- annotations -->
<execution>
<id>annotation-decision-table-with-annotations</id>
<phase>generate-sources</phase>
<goals>
<goal>dmn-to-java</goal>
</goals>
<configuration>
<templateProvider>com.gs.dmn.transformation.template.TreeTemplateProvider</templateProvider>
<lazyEvaluationDetectors>
<lazyEvaluatorDetector>com.gs.dmn.transformation.lazy.SparseDecisionDetector</lazyEvaluatorDetector>
</lazyEvaluationDetectors>
<inputFileDirectory>${other.14.diagram.folder}/decision-table-with-annotations/translator/decision-table-with-annotations.dmn</inputFileDirectory>
<outputFileDirectory>${generated.source.code.folder}</outputFileDirectory>
<inputParameters>
<javaRootPackage>${generated.root.package}.other.decision_table_with_annotations</javaRootPackage>
</inputParameters>
</configuration>
</execution>
<execution>
<id>test-annotation-decision-table-with-annotations</id>
<phase>generate-sources</phase>
<goals>
<goal>tck-to-java</goal>
</goals>
<configuration>
<templateProvider>com.gs.dmn.transformation.template.TreeTemplateProvider</templateProvider>
<inputTestFileDirectory>${other.14.diagram.folder}/decision-table-with-annotations/translator/decision-table-with-annotations-test-01.xml</inputTestFileDirectory>
<inputModelFileDirectory>${other.14.diagram.folder}/decision-table-with-annotations/translator/decision-table-with-annotations.dmn</inputModelFileDirectory>
<outputFileDirectory>${generated.test.code.folder}</outputFileDirectory>
<inputParameters>
<javaRootPackage>${generated.root.package}.other.decision_table_with_annotations</javaRootPackage>
</inputParameters>
</configuration>
</execution>

<!-- non-compliant-->
<!--
<execution>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.gs.dmn.generated.other.decision_table_with_annotations;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.assertEquals;

@javax.annotation.Generated(value = {"junit.ftl", "decision-table-with-annotations.dmn"})
public class HandWrittenDecisionTableWithAnnotationsTest extends com.gs.dmn.runtime.DefaultDMNBaseDecision {
@org.junit.Test
public void testCase001() {
com.gs.dmn.runtime.ExecutionContext context_ = new com.gs.dmn.runtime.ExecutionContext();
com.gs.dmn.runtime.cache.Cache cache_ = context_.getCache();
// Initialize input data
com.gs.dmn.generated.other.decision_table_with_annotations.type.TA structA = new com.gs.dmn.generated.other.decision_table_with_annotations.type.TAImpl("A", number("5"));

// Check 'priceGt10'
checkValues(Boolean.FALSE, new PriceGt10().apply(structA, context_));
List<String> actualAnnotations = context_.getAnnotations().stream().map(a -> a.toString()).collect(Collectors.toList());
List<String> expectedAnnotations = Arrays.asList(
"Annotation('priceGt10', 2, 'Price 5 is <= 0')",
"Annotation('priceGt10', 2, 'Since this is a CDATA section I can use all sorts of reserved characters like > < \" and & or write things like <foo></bar> but my document is still well formed!')"
);
assertEquals(expectedAnnotations, actualAnnotations);
}

@org.junit.Test
public void testCase002() {
com.gs.dmn.runtime.ExecutionContext context_ = new com.gs.dmn.runtime.ExecutionContext();
com.gs.dmn.runtime.cache.Cache cache_ = context_.getCache();
// Initialize input data
com.gs.dmn.generated.other.decision_table_with_annotations.type.TA structA = new com.gs.dmn.generated.other.decision_table_with_annotations.type.TAImpl("A", number("11"));

// Check 'priceGt10'
checkValues(Boolean.TRUE, new PriceGt10().apply(structA, context_));
List<String> actualAnnotations = context_.getAnnotations().stream().map(a -> a.toString()).collect(Collectors.toList());
List<String> expectedAnnotations = Arrays.asList(
"Annotation('priceGt10', 1, 'Logging')",
"Annotation('priceGt10', 1, 'Price 11 is >= 0')"
);
assertEquals(expectedAnnotations, actualAnnotations);
}

private void checkValues(Object expected, Object actual) {
com.gs.dmn.runtime.Assert.assertEquals(expected, actual);
}
}
1 change: 1 addition & 0 deletions dmn-tck-it/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<tck.13.diagram.folder>${project.basedir}/../../dmn-test-cases/standard/tck/1.3</tck.13.diagram.folder>
<tck.14.diagram.folder>${project.basedir}/../../dmn-test-cases/standard/tck/1.4</tck.14.diagram.folder>
<composite.12.diagram.folder>${project.basedir}/../../dmn-test-cases/standard/composite/1.2</composite.12.diagram.folder>
<other.14.diagram.folder>${project.basedir}/../../dmn-test-cases/standard/other/1.4</other.14.diagram.folder>
<proto.11.diagram.folder>${project.basedir}/../../dmn-test-cases/standard/proto/1.1</proto.11.diagram.folder>

<line.coverage.minimum>0.00</line.coverage.minimum>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<testCases xmlns="http://www.omg.org/spec/DMN/20160719/testcase" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<modelName>decision-table-with-annotations.dmn</modelName>
<testCase id="001">
<inputNode name="structA">
<component name="name">
<value xsi:type="xsd:string">A</value>
</component>
<component name="price">
<value xsi:type="xsd:decimal">5</value>
</component>
</inputNode>
<resultNode name="priceGt10" type="decision">
<expected>
<value xsi:type="xsd:boolean">false</value>
</expected>
</resultNode>
</testCase>

<testCase id="002">
<inputNode name="structA">
<component name="name">
<value xsi:type="xsd:string">A</value>
</component>
<component name="price">
<value xsi:type="xsd:decimal">11</value>
</component>
</inputNode>
<resultNode name="priceGt10" type="decision">
<expected>
<value xsi:type="xsd:boolean">true</value>
</expected>
</resultNode>
</testCase>
</testCases>
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions exporter="DMN Modeler; Method and Style trisofix.xslt" exporterVersion="5.0.35; 1.0"
namespace="http://www.trisotech.com/definitions/_92a0c25f-707e-4fc8-ae2d-2ab51ebe6bb6" name="tableTest"
triso:logoChoice="Default" id="_92a0c25f-707e-4fc8-ae2d-2ab51ebe6bb6"
xmlns="https://www.omg.org/spec/DMN/20211108/MODEL/"
xmlns:triso="http://www.trisotech.com/2015/triso/modeling">
<itemDefinition name="tA" id="tA">
<itemComponent name="name" id="_adf6f96a-c574-4ba7-a305-ea14ad9852b1">
<typeRef>string</typeRef>
</itemComponent>
<itemComponent name="price" id="_d297adac-f086-42a0-989e-04c431270f77">
<typeRef>number</typeRef>
</itemComponent>
</itemDefinition>
<inputData name="structA" id="_18b9d486-1ec0-436d-af4b-3e4567e8bca9">
<variable typeRef="tA" name="structA"/>
</inputData>
<decision name="priceGt10" id="_2683ec7f-fa17-4a1e-9151-8077a10c561f">
<variable typeRef="boolean" name="priceGt10"/>
<informationRequirement id="_1a34b197-0218-447f-8fa4-204517c0f851">
<requiredInput href="#_18b9d486-1ec0-436d-af4b-3e4567e8bca9"/>
</informationRequirement>
<decisionTable hitPolicy="UNIQUE" outputLabel="priceGt10">
<input id="_bfb04e56-12dc-461f-a341-f5522efc7388" label="structA.price">
<inputExpression typeRef="number">
<text>structA.price</text>
</inputExpression>
</input>
<output id="_89841156-1ca0-4704-9551-39205fdb7ae2"/>
<rule id="_543c9e93-e815-41df-8884-b40f726a847e">
<inputEntry id="_543c9e93-e815-41df-8884-b40f726a847e-0">
<text>&gt;10</text>
</inputEntry>
<outputEntry id="_543c9e93-e815-41df-8884-b40f726a847e-1">
<text>true</text>
</outputEntry>
<annotationEntry>
<text>"Logging"</text>
</annotationEntry>
<annotationEntry>
<text>string join(["Price ", string(structA.price), " is >= 0"], " ")</text>
</annotationEntry>
</rule>
<rule id="_41adf645-547d-4c65-97c1-355c297d02d6">
<inputEntry id="_41adf645-547d-4c65-97c1-355c297d02d6-0">
<text>&lt;=10</text>
</inputEntry>
<outputEntry id="_41adf645-547d-4c65-97c1-355c297d02d6-1">
<text>false</text>
</outputEntry>
<annotationEntry>
<text>"Price " + string(structA.price) + " is &lt;= 0"</text>
</annotationEntry>
<annotationEntry>
<text><![CDATA[
"Since this is a CDATA section I can use all sorts of reserved characters like > < \" and & or write things like <foo></bar> but my document is still well formed!"
]]></text>
</annotationEntry>
</rule>
</decisionTable>
</decision>
</definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

public class ModelElementRegistry extends com.gs.dmn.runtime.discovery.ModelElementRegistry {
public ModelElementRegistry() {
// Register elements from model 'tableTest'
register("priceGt10", "PriceGt10");
}
}
Loading

0 comments on commit 508f17e

Please sign in to comment.