com.gs.dmn.tck.TCKUtil Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2016 Goldman Sachs.
*
* Licensed 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 com.gs.dmn.tck;
import com.gs.dmn.DMNModelRepository;
import com.gs.dmn.DRGElementReference;
import com.gs.dmn.ImportPath;
import com.gs.dmn.QualifiedName;
import com.gs.dmn.ast.*;
import com.gs.dmn.context.DMNContext;
import com.gs.dmn.el.analysis.semantics.type.Type;
import com.gs.dmn.feel.analysis.semantics.type.ItemDefinitionType;
import com.gs.dmn.feel.analysis.syntax.ast.expression.function.FormalParameter;
import com.gs.dmn.feel.lib.StandardFEELLib;
import com.gs.dmn.feel.synthesis.type.NativeTypeFactory;
import com.gs.dmn.runtime.DMNRuntimeException;
import com.gs.dmn.runtime.Pair;
import com.gs.dmn.runtime.interpreter.DMNInterpreter;
import com.gs.dmn.runtime.interpreter.EvaluationContext;
import com.gs.dmn.runtime.interpreter.Result;
import com.gs.dmn.tck.ast.*;
import com.gs.dmn.transformation.basic.BasicDMNToNativeTransformer;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
public class TCKUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(TCKUtil.class);
private final DMNModelRepository dmnModelRepository;
private final BasicDMNToNativeTransformer transformer;
private final StandardFEELLib feelLib;
private final NativeTypeFactory typeFactory;
private final TCKValueInterpreter tckValueInterpreter;
private final TCKValueTranslator tckValueTranslator;
public TCKUtil(BasicDMNToNativeTransformer transformer, StandardFEELLib feelLib) {
this.transformer = transformer;
this.feelLib = feelLib;
this.dmnModelRepository = transformer.getDMNModelRepository();
this.typeFactory = transformer.getNativeTypeFactory();
this.tckValueInterpreter = new TCKValueInterpreter<>(transformer, feelLib);
this.tckValueTranslator = transformer.isMockTesting() ? new MockTCKValueTranslator<>(transformer, feelLib) : new TCKValueTranslator<>(transformer, feelLib);
}
public BasicDMNToNativeTransformer getTransformer() {
return this.transformer;
}
//
// Translator - Input nodes
//
public InputNodeInfo extractInputNodeInfo(TestCases testCases, TestCase testCase, InputNode inputNode) {
TDefinitions definitions = getRootModel(testCases);
if (this.transformer.isSingletonInputData()) {
String namespace = getNamespace(testCases, testCase, inputNode);
DRGElementReference extends TDRGElement> reference = extractInfoFromModel(definitions, namespace, inputNode.getName());
if (reference == null) {
throw new DMNRuntimeException(String.format("Cannot find DRG element for InputNode '%s' for TestCase '%s' in TestCases '%s'", inputNode.getName(), testCase.getId(), testCases.getModelName()));
}
return new InputNodeInfo(testCases.getModelName(), inputNode.getName(), NodeInfo.nodeTypeFrom(reference), reference, inputNode);
} else {
Pair, ValueType> pair = extractInfoFromValue(definitions, inputNode);
if (pair == null || pair.getLeft() == null) {
throw new DMNRuntimeException(String.format("Cannot find DRG element for InputNode '%s' for TestCase '%s' in TestCases '%s'", inputNode.getName(), testCase.getId(), testCases.getModelName()));
}
return new InputNodeInfo(testCases.getModelName(), inputNode.getName(), NodeInfo.nodeTypeFrom(pair.getLeft()), pair.getLeft(), pair.getRight());
}
}
private DRGElementReference extends TDRGElement> extractInfoFromModel(TDefinitions rootDefinitions, String elementNamespace, String elementName) {
if (elementNamespace == null) {
return extractInfoFromModel(rootDefinitions, elementName, new ImportPath());
} else {
return extractInfoFromModel(rootDefinitions, elementNamespace, elementName, new ImportPath());
}
}
private DRGElementReference extends TDRGElement> extractInfoFromModel(TDefinitions definitions, String elementNamespace, String elementName, ImportPath importPath) {
if (definitions.getNamespace().equals(elementNamespace)) {
// Found model, lookup element by name
for (TDRGElement drg: this.dmnModelRepository.findDRGElements(definitions)) {
if (drg.getName().equals(elementName)) {
return this.dmnModelRepository.makeDRGElementReference(importPath, drg);
}
}
} else {
// Lookup in imports
for (TImport imp: definitions.getImport()) {
String namespace = imp.getNamespace();
TDefinitions child = this.dmnModelRepository.getModel(namespace);
DRGElementReference extends TDRGElement> result = extractInfoFromModel(child, elementNamespace, elementName, new ImportPath(importPath, imp.getName()));
if (result != null) {
return result;
}
}
}
return null;
}
private DRGElementReference extends TDRGElement> extractInfoFromModel(TDefinitions definitions, String elementName, ImportPath importPath) {
// Lookup element by name
for (TDRGElement drg: this.dmnModelRepository.findDRGElements(definitions)) {
if (drg.getName().equals(elementName)) {
return this.dmnModelRepository.makeDRGElementReference(importPath, drg);
}
}
// Lookup in imports
for (TImport imp: definitions.getImport()) {
String namespace = imp.getNamespace();
TDefinitions child = this.dmnModelRepository.getModel(namespace);
DRGElementReference extends TDRGElement> result = extractInfoFromModel(child, elementName, new ImportPath(importPath, imp.getName()));
if (result != null) {
return result;
}
}
return null;
}
public Pair, ValueType> extractInfoFromValue(TDefinitions definitions, InputNode node) {
// Navigate the import paths if needed
String name = node.getName();
ImportPath path = new ImportPath();
TImport import_ = getImport(definitions, name);
ValueType value = node;
while (import_ != null) {
path.addPathElement(name);
definitions = this.dmnModelRepository.getModel(import_.getNamespace());
name = null;
if (value.getComponent() != null && value.getComponent().size() == 1) {
Component component = value.getComponent().get(0);
name = component.getName();
value = component;
}
import_ = getImport(definitions, name);
}
// Find DRG element and value
List drgElements = this.dmnModelRepository.findDRGElements(definitions);
TDRGElement element = null;
for (TDRGElement e: drgElements) {
if (e.getName().equals(name)) {
element = e;
break;
}
}
if (element == null) {
throw new DMNRuntimeException(String.format("Cannot find DRG element for node '%s'", node.getName()));
}
// Make result
return new Pair<>(this.dmnModelRepository.makeDRGElementReference(path, element), value);
}
public List> missingArguments(TestCases testCases, TestCase testCase, ResultNode resultNode) {
// Calculate provided inputs
List inputNames = testCase.getInputNode().stream()
.map(in -> this.extractInputNodeInfo(testCases, testCase, in))
.map(this::inputDataVariableName)
.collect(Collectors.toList());
// Calculate missing inputs
ResultNodeInfo resultNodeInfo = extractResultNodeInfo(testCases, testCase, resultNode);
List> parameters = this.transformer.drgElementTypeSignature(resultNodeInfo.getReference(), transformer::nativeName);
List> missingParameters = parameters.stream().filter(pair -> !inputNames.contains(pair.getLeft())).collect(Collectors.toList());
List> missingArgs = missingParameters.stream()
.map(p -> new Pair<>(transformer.getNativeFactory().nullableParameterType(transformer.toNativeType(p.getRight())), p.getLeft()))
.collect(Collectors.toList());
List> result = new ArrayList<>();
for (int i=0; i triplet = new ArrayList<>();
triplet.add(missingArgs.get(i).getLeft());
triplet.add(missingArgs.get(i).getRight());
triplet.add(defaultValue);
result.add(triplet);
}
return result;
}
private TImport getImport(TDefinitions definitions, String name) {
for (TImport imp: definitions.getImport()) {
if (imp.getName().equals(name)) {
return imp;
}
}
return null;
}
public String toNativeType(InputNodeInfo info) {
Type feelType = toFEELType(info);
return this.typeFactory.nullableType(this.transformer.toNativeType(feelType));
}
public String inputDataVariableName(InputNodeInfo info) {
TDRGElement element = info.getReference().getElement();
if (element == null) {
throw new DMNRuntimeException(String.format("Cannot find element '%s'", info.getNodeName()));
} else {
return this.transformer.drgElementReferenceVariableName(info.getReference());
}
}
public String toNativeExpression(InputNodeInfo info) {
Type inputType = toFEELType(info);
return this.tckValueTranslator.toNativeExpression(info.getValue(), inputType, info.getReference().getElement());
}
private Type toFEELType(InputNodeInfo info) {
try {
TDRGElement element = info.getReference().getElement();
return this.transformer.drgElementOutputFEELType(element);
} catch (Exception e) {
throw new DMNRuntimeException(String.format("Cannot resolve FEEL type for node '%s'", info.getNodeName()), e);
}
}
private QualifiedName getTypeRef(InputNodeInfo node) {
TDRGElement element = node.getReference().getElement();
TDefinitions model = this.dmnModelRepository.getModel(element);
QualifiedName typeRef;
if (element == null) {
throw new DMNRuntimeException(String.format("Cannot find element '%s'.", node.getNodeName()));
} else if (element instanceof TInputData) {
String varTypeRef = QualifiedName.toName(((TInputData) element).getVariable().getTypeRef());
typeRef = QualifiedName.toQualifiedName(model, varTypeRef);
} else if (element instanceof TDecision) {
String varTypeRef = QualifiedName.toName(((TDecision) element).getVariable().getTypeRef());
typeRef = QualifiedName.toQualifiedName(model, varTypeRef);
} else {
throw new UnsupportedOperationException(String.format("Cannot resolve FEEL type for node '%s'. '%s' not supported", node.getNodeName(), element.getClass().getSimpleName()));
}
return typeRef;
}
//
// Translator - Result nodes
//
public List findComplexInputDatas(TestCases testCases) {
List drgElementList = findDRGElementsUnderTest(testCases);
Set set = new LinkedHashSet<>();
for (TDRGElement drgElement: drgElementList) {
List moduleNames = this.transformer.drgElementComplexInputClassNames(drgElement);
set.addAll(moduleNames);
}
ArrayList list = new ArrayList<>(set);
Collections.sort(list);
return list;
}
public List findDRGElementsUnderTest(TestCases testCases) {
Set elements = new LinkedHashSet<>();
for (TestCase testCase : testCases.getTestCase()) {
for (ResultNode resultNode : testCase.getResultNode()) {
TDRGElement element = findDRGElement(testCases, testCase, resultNode);
if (element != null) {
elements.add(element);
}
}
}
return new ArrayList<>(elements);
}
public ResultNodeInfo extractResultNodeInfo(TestCases testCases, TestCase testCase, ResultNode resultNode) {
TDRGElement element = findDRGElement(testCases, testCase, resultNode);
DRGElementReference extends TDRGElement> reference = this.dmnModelRepository.makeDRGElementReference(element);
return new ResultNodeInfo(testCases.getModelName(), testCase.getType().value(), resultNode.getName(), reference, resultNode.getExpected());
}
public String toNativeExpression(ResultNodeInfo info) {
Type outputType = toFEELType(info);
if (outputType instanceof ItemDefinitionType) {
String javaExpression = this.tckValueTranslator.toNativeExpression(info.getExpectedValue(), ((ItemDefinitionType) outputType).toContextType(), info.getReference().getElement());
return this.transformer.getNativeFactory().convertToItemDefinitionType(javaExpression, (ItemDefinitionType) outputType);
} else {
return this.tckValueTranslator.toNativeExpression(info.getExpectedValue(), outputType, info.getReference().getElement());
}
}
public String toNativeExpressionProto(ResultNodeInfo info) {
Type resultType = toFEELType(info);
ValueType expectedValue = info.getExpectedValue();
String value = this.tckValueTranslator.toNativeExpression(expectedValue, resultType, info.getReference().getElement());
if (this.transformer.isDateTimeType(resultType) || this.transformer.isComplexType(resultType)) {
return transformer.getNativeFactory().convertValueToProtoNativeType(value, resultType, false);
} else {
return value;
}
}
public String qualifiedName(ResultNodeInfo info) {
TDRGElement element = info.getReference().getElement();
if (element == null) {
throw new DMNRuntimeException(String.format("Cannot find DRG Element for node '%s'", info.getNodeName()));
}
if (info.isDecision()) {
String pkg = this.transformer.nativeModelPackageName(info.getRootModelName());
String cls = this.transformer.drgElementClassName(element);
return this.transformer.qualifiedName(pkg, cls);
} else if (info.isBKM() || info.isDS()) {
return this.transformer.singletonInvocableInstance((TInvocable) element);
} else {
throw new DMNRuntimeException(String.format("Not supported '%s' in '%s'", info.getNodeType(), info.getNodeName()));
}
}
public String drgElementArgumentList(ResultNodeInfo info) {
if (info.isDecision()) {
TDecision decision = (TDecision) info.getReference().getElement();
return this.transformer.drgElementArgumentList(this.dmnModelRepository.makeDRGElementReference(decision));
} else if (info.isBKM()) {
TBusinessKnowledgeModel bkm = (TBusinessKnowledgeModel) info.getReference().getElement();
return this.transformer.drgElementArgumentList(this.dmnModelRepository.makeDRGElementReference(bkm));
} else if (info.isDS()) {
TDecisionService ds = (TDecisionService) info.getReference().getElement();
return this.transformer.drgElementArgumentList(this.dmnModelRepository.makeDRGElementReference(ds));
} else {
throw new DMNRuntimeException(String.format("Not supported node type '%s'", info.getNodeType()));
}
}
private Type toFEELType(ResultNodeInfo resultNode) {
try {
TDRGElement element = resultNode.getReference().getElement();
return this.transformer.drgElementOutputFEELType(element);
} catch (Exception e) {
throw new DMNRuntimeException(String.format("Cannot resolve FEEL type for node '%s'", resultNode.getNodeName()), e);
}
}
private QualifiedName getTypeRef(ResultNodeInfo node) {
TDRGElement element = node.getReference().getElement();
TDefinitions model = this.dmnModelRepository.getModel(element);
QualifiedName typeRef;
if (element == null) {
throw new DMNRuntimeException(String.format("Cannot find element '%s'.", node.getNodeName()));
} else if (element instanceof TDecision) {
typeRef = QualifiedName.toQualifiedName(model, ((TDecision) element).getVariable().getTypeRef());
} else {
throw new UnsupportedOperationException(String.format("Cannot resolve FEEL type for node '%s'. '%s' not supported", node.getNodeName(), element.getClass().getSimpleName()));
}
return typeRef;
}
//
// Translator - helper delegated methods
//
public String testCaseId(TestCase testCase) {
String id = testCase.getId();
return this.transformer.nativeFriendlyName(id);
}
public String assertClassName() {
return this.transformer.assertClassName();
}
public String executionContextClassName() {
return this.transformer.executionContextClassName();
}
public String executionContextVariableName() {
return this.transformer.executionContextVariableName();
}
public String annotationSetClassName() {
return this.transformer.annotationSetClassName();
}
public String annotationSetVariableName() {
return this.transformer.annotationSetVariableName();
}
public String eventListenerClassName() {
return this.transformer.eventListenerClassName();
}
public String defaultEventListenerClassName() {
return this.transformer.defaultEventListenerClassName();
}
public String eventListenerVariableName() {
return this.transformer.eventListenerVariableName();
}
public String externalExecutorClassName() {
return this.transformer.externalExecutorClassName();
}
public String externalExecutorVariableName() {
return this.transformer.externalExecutorVariableName();
}
public String defaultExternalExecutorClassName() {
return this.transformer.defaultExternalExecutorClassName();
}
public String cacheInterfaceName() {
return this.transformer.cacheInterfaceName();
}
public String cacheVariableName() {
return this.transformer.cacheVariableName();
}
public String defaultCacheClassName() {
return this.transformer.defaultCacheClassName();
}
public String defaultConstructor(String className) {
return this.transformer.defaultConstructor(className);
}
public boolean isCached(InputNodeInfo info) {
return this.transformer.isCached(info.getReference().getElementName());
}
//
// Interpreter
//
public Result evaluate(DMNInterpreter interpreter, TestCases testCases, TestCase testCase, ResultNode resultNode) {
ResultNodeInfo info = extractResultNodeInfo(testCases, testCase, resultNode);
DRGElementReference extends TDRGElement> reference = info.getReference();
TDRGElement element = reference.getElement();
if (element == null) {
throw new DMNRuntimeException(String.format("Cannot find DRG elements for node '%s'", info.getNodeName()));
} else if (element instanceof TDecision) {
Map informationRequirements = makeInputs(testCases, testCase);
return interpreter.evaluateDecision(reference.getNamespace(), reference.getElementName(), EvaluationContext.makeDecisionEvaluationContext(element, informationRequirements));
} else if (element instanceof TInvocable) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy