com.gs.dmn.DMNModelRepository Maven / Gradle / Ivy
/*
* 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;
import com.gs.dmn.ast.*;
import com.gs.dmn.ast.dmndi.DMNDI;
import com.gs.dmn.ast.dmndi.DMNDiagram;
import com.gs.dmn.ast.dmndi.DMNStyle;
import com.gs.dmn.ast.dmndi.DiagramElement;
import com.gs.dmn.runtime.DMNRuntimeException;
import com.gs.dmn.serialization.DMNVersion;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
import static com.gs.dmn.ast.TBuiltinAggregator.COUNT;
import static com.gs.dmn.ast.TBuiltinAggregator.SUM;
public class DMNModelRepository {
public static final String FREE_TEXT_LANGUAGE = "free_text";
protected static final ObjectFactory OBJECT_FACTORY = new ObjectFactory();
protected static final Logger LOGGER = LoggerFactory.getLogger(DMNModelRepository.class);
protected final List definitionsList;
// Derived properties to optimise search
protected final List allDefinitions = new ArrayList<>();
protected final Map namespaceToDefinitions = new LinkedHashMap<>();
protected final Map elementToDefinitions = new LinkedHashMap<>();
protected List businessKnowledgeModels;
protected List itemDefinitions;
protected Map drgElementByName = new LinkedHashMap<>();
protected Map knowledgeModelByName = new LinkedHashMap<>();
protected Map drgElementByRef = new LinkedHashMap<>();
protected Map> drgElementsByModel = new LinkedHashMap<>();
protected Map> decisionsByModel = new LinkedHashMap<>();
protected Map> inputDatasByModel = new LinkedHashMap<>();
protected Map> bkmsByModel = new LinkedHashMap<>();
protected Map> dssByModel = new LinkedHashMap<>();
public DMNModelRepository() {
this(OBJECT_FACTORY.createTDefinitions());
}
public DMNModelRepository(TDefinitions definitions) {
this(Collections.singletonList(definitions));
}
public DMNModelRepository(List definitionsList) {
this.definitionsList = definitionsList;
// Normalize definitions
this.definitionsList.sort(Comparator.comparing((TDefinitions o) -> NameUtils.removeSingleQuotes(o.getName())));
if (definitionsList != null) {
for (TDefinitions definitions: definitionsList) {
this.allDefinitions.add(definitions);
if (!this.namespaceToDefinitions.containsKey(definitions.getNamespace())) {
this.namespaceToDefinitions.put(definitions.getNamespace(), definitions);
} else {
throw new DMNRuntimeException(String.format("Duplicated model namespace '%s'", definitions.getNamespace()));
}
}
}
// Process all definitions
for (TDefinitions definitions: this.getAllDefinitions()) {
// Normalize
normalize(definitions);
// Set derived properties
for (TNamedElement element: findItemDefinitions(definitions)) {
this.elementToDefinitions.put(element, definitions);
}
for (TDRGElement element: findDRGElements(definitions)) {
this.elementToDefinitions.put(element, definitions);
}
}
}
public DMNModelRepository copy() {
return new DMNModelRepository(this.definitionsList);
}
protected void normalize(TDefinitions definitions) {
if (definitions != null) {
sortDRGElements(definitions.getDrgElement());
sortNamedElements(definitions.getItemDefinition());
sortDMNDI(definitions.getDMNDI());
}
}
public Set computeCachedElements(boolean cachingFlag, int cachingThreshold) {
if (!cachingFlag) {
return new LinkedHashSet<>();
}
LOGGER.info("Scanning for decisions to cache ...");
Map map = new LinkedHashMap<>();
Map parentMap = new LinkedHashMap<>();
for (TDefinitions definitions: this.getAllDefinitions()) {
for (TDecision decision: findDecisions(definitions)) {
addCachedChildren(definitions, decision, parentMap, map);
}
for (TDecisionService service: findDSs(definitions)) {
addCachedChildren(definitions, service, parentMap, map);
}
}
Set result = new LinkedHashSet<>();
for (Map.Entry entry: map.entrySet()) {
if (entry.getValue() > cachingThreshold) {
String key = entry.getKey();
TDecision drgElement = this.findDecisionByRef(parentMap.get(key), key);
if (drgElement != null) {
result.add(name(drgElement));
}
}
}
LOGGER.info("Decisions to be cached: {}", String.join(", ", result));
return result;
}
private void addCachedChildren(TDefinitions definitions, TDecision decision, Map parentMap, Map map) {
for (TInformationRequirement ir: decision.getInformationRequirement()) {
TDMNElementReference requiredDecision = ir.getRequiredDecision();
if (requiredDecision != null) {
String href = requiredDecision.getHref();
if (!hasNamespace(href)) {
href = makeRef(definitions.getNamespace(), href);
}
map.compute(href, (k, v) -> v == null ? 1 : v + 1);
parentMap.put(href, decision);
}
}
}
private void addCachedChildren(TDefinitions definitions, TDecisionService decisionService, Map parentMap, Map map) {
for (TDMNElementReference inputDecisionRef: decisionService.getInputDecision()) {
if (inputDecisionRef != null) {
String href = inputDecisionRef.getHref();
if (!hasNamespace(href)) {
href = makeRef(definitions.getNamespace(), href);
}
map.compute(href, (k, v) -> v == null ? 1 : v + 1);
TDecision inputDecision = findDecisionByRef(decisionService, href);
parentMap.put(href, inputDecision);
}
}
}
public TDefinitions getRootDefinitions() {
int size = this.getAllDefinitions().size();
if (size == 1) {
return this.allDefinitions.get(0);
} else {
throw new DMNRuntimeException(String.format("Cannot resolve root DM, there are '%d' DMs", size));
}
}
public List getAllDefinitions() {
return this.allDefinitions;
}
public void addElementMap(TDRGElement element, TDefinitions definitions) {
this.elementToDefinitions.put(element, definitions);
}
public List getImportedNames() {
List names = new ArrayList<>();
for (TDefinitions definitions: this.allDefinitions) {
for (TImport imp: definitions.getImport()) {
names.add(imp.getName());
}
}
return names;
}
public TDefinitions getModel(String namespace) {
return this.namespaceToDefinitions.get(namespace);
}
public TDefinitions getModel(TNamedElement element) {
return this.elementToDefinitions.get(element);
}
public String makeLocation(TDefinitions definitions, TDMNElement element) {
if (definitions == null && element == null) {
return null;
}
List locationParts = new ArrayList<>();
addModelCoordinates(definitions, element, locationParts);
addElementCoordinates(element, locationParts);
return locationParts.isEmpty() ? null : String.format("(%s)", String.join(", ", locationParts));
}
protected void addModelCoordinates(TDefinitions definitions, TDMNElement element, List locationParts) {
if (definitions != null) {
String modelName = definitions.getName();
if (!StringUtils.isBlank(modelName)) {
locationParts.add(String.format("model='%s'", modelName));
}
}
}
protected void addElementCoordinates(TDMNElement element, List locationParts) {
if (element != null) {
String id = element.getId();
String label = element.getLabel();
String name = element instanceof TNamedElement ? ((TNamedElement) element).getName() : null;
if (!StringUtils.isBlank(label)) {
locationParts.add(String.format("label='%s'", label));
}
if (!StringUtils.isBlank(name)) {
locationParts.add(String.format("name='%s'", name));
}
if (!StringUtils.isBlank(id)) {
locationParts.add(String.format("id='%s'", id));
}
}
}
public String getNamespace(TNamedElement element) {
TDefinitions definitions = this.elementToDefinitions.get(element);
return definitions == null ? null : definitions.getNamespace();
}
public String getModelName(TNamedElement element) {
TDefinitions definitions = this.elementToDefinitions.get(element);
return definitions == null ? null : definitions.getName();
}
private List findAllBKMs() {
if (this.businessKnowledgeModels == null) {
this.businessKnowledgeModels = new ArrayList<>();
for (TDefinitions definitions: this.allDefinitions) {
collectBKMs(definitions, this.businessKnowledgeModels);
}
}
return this.businessKnowledgeModels;
}
private List findAllItemDefinitions() {
if (this.itemDefinitions == null) {
this.itemDefinitions = new ArrayList<>();
for (TDefinitions definitions: this.allDefinitions) {
this.itemDefinitions.addAll(definitions.getItemDefinition());
}
}
return this.itemDefinitions;
}
public List findDRGElements(TDefinitions definitions) {
List result = this.drgElementsByModel.get(definitions);
if (result == null) {
result = new ArrayList<>();
collectDRGElements(definitions, result);
this.drgElementsByModel.put(definitions, result);
}
return result;
}
public List findDecisions(TDefinitions definitions) {
List result = this.decisionsByModel.get(definitions);
if (result == null) {
result = new ArrayList<>();
collectDecisions(definitions, result);
this.decisionsByModel.put(definitions, result);
}
return result;
}
public List findInputDatas(TDefinitions definitions) {
List result = this.inputDatasByModel.get(definitions);
if (result == null) {
result = new ArrayList<>();
collectInputDatas(definitions, result);
this.inputDatasByModel.put(definitions, result);
}
return result;
}
public List findBKMs(TDefinitions definitions) {
List result = this.bkmsByModel.get(definitions);
if (result == null) {
result = new ArrayList<>();
collectBKMs(definitions, result);
this.bkmsByModel.put(definitions, result);
}
return result;
}
public List findDSs(TDefinitions definitions) {
List result = this.dssByModel.get(definitions);
if (result == null) {
result = new ArrayList<>();
collectDSs(definitions, result);
this.dssByModel.put(definitions, result);
}
return result;
}
public List findItemDefinitions(TDefinitions definitions) {
return definitions.getItemDefinition();
}
protected void collectDRGElements(TDefinitions definitions, List result) {
for (TDRGElement element: definitions.getDrgElement()) {
result.add(element);
}
}
protected void collectDecisions(TDefinitions definitions, List result) {
for (TDRGElement element: definitions.getDrgElement()) {
if (element instanceof TDecision) {
result.add((TDecision) element);
}
}
}
protected void collectInputDatas(TDefinitions definitions, List result) {
for (TDRGElement element: definitions.getDrgElement()) {
if (element instanceof TInputData) {
result.add((TInputData) element);
}
}
}
protected void collectBKMs(TDefinitions definitions, List result) {
for (TDRGElement element: definitions.getDrgElement()) {
if (element instanceof TBusinessKnowledgeModel) {
result.add((TBusinessKnowledgeModel) element);
}
}
}
protected void collectDSs(TDefinitions definitions, List result) {
for (TDRGElement element: definitions.getDrgElement()) {
if (element instanceof TDecisionService) {
result.add((TDecisionService) element);
}
}
}
public boolean hasComponents(TItemDefinition itemDefinition) {
return !this.isEmpty(itemDefinition.getItemComponent());
}
public List sortItemComponent(TItemDefinition itemDefinition) {
if (itemDefinition == null || itemDefinition.getItemComponent() == null) {
return new ArrayList<>();
}
List children = new ArrayList<>(itemDefinition.getItemComponent());
children.sort((o1, o2) -> {
if (o1 == null && o2 == null) {
return 0;
} else if (o1 == null) {
return 1;
} else if (o2 == null) {
return -1;
} else {
return o1.getName().compareTo(o2.getName());
}
});
return children;
}
public TItemDefinition normalize(TItemDefinition itemDefinition) {
while (true) {
TItemDefinition next = next(itemDefinition);
if (next != null) {
itemDefinition = next;
} else {
break;
}
}
return itemDefinition;
}
protected TItemDefinition next(TItemDefinition itemDefinition) {
if (itemDefinition == null
|| itemDefinition.isIsCollection()
|| !isEmpty(itemDefinition.getItemComponent())
|| itemDefinition.getFunctionItem() != null
|| itemDefinition.getTypeRef() == null) {
return null;
}
TDefinitions model = getModel(itemDefinition);
return lookupItemDefinition(model, QualifiedName.toQualifiedName(model, itemDefinition.getTypeRef()));
}
protected void sortDRGElements(List extends TDRGElement> elements) {
elements.sort(Comparator.comparing((TDRGElement o) -> NameUtils.removeSingleQuotes(o.getName())));
}
public void sortNamedElements(List extends TNamedElement> elements) {
elements.sort(Comparator.comparing((TNamedElement o) -> NameUtils.removeSingleQuotes(o.getName())));
}
private void sortDMNDI(DMNDI dmndi) {
if (dmndi != null) {
sortDMNDiagrams(dmndi);
dmndi.getDMNStyle().sort(Comparator.comparing((DMNStyle s) -> styleKey(s)));
}
}
private String styleKey(DMNStyle s) {
if (s == null) {
return "";
}
return s.getId();
}
private void sortDMNDiagrams(DMNDI dmndi) {
List diagrams = dmndi.getDMNDiagram();
diagrams.sort(Comparator.comparing((DMNDiagram d) -> diagramKey(d)));
for (DMNDiagram d: diagrams) {
d.getDMNDiagramElement().sort(Comparator.comparing((DiagramElement e) -> diagramElementKey(e)));
}
}
private String diagramKey(DMNDiagram d) {
if (d == null) {
return "";
}
return String.format("%s-%s", d.getName(), d.getId());
}
private String diagramElementKey(DiagramElement e) {
if (e == null) {
return "";
}
return String.format("%s-%s", e.getClass().getSimpleName(), e.getId());
}
public void sortNamedElementReferences(List extends DRGElementReference extends TNamedElement>> references) {
references.sort(Comparator.comparing((DRGElementReference extends TNamedElement> o) -> NameUtils.removeSingleQuotes(o.getElementName())));
}
public TDRGElement findDRGElementByRef(TDRGElement parent, String href) {
try {
TDefinitions definitions = findChildDefinitions(parent, href);
if (definitions == null) {
throw new DMNRuntimeException(String.format("Cannot find model for href='%s'", href));
}
String key = makeRef(definitions.getNamespace(), href);
TDRGElement result = this.drgElementByRef.get(key);
if (result == null) {
for (TDRGElement element: findDRGElements(definitions)) {
if (sameId(element, href)) {
result = element;
this.drgElementByRef.put(key, result);
break;
}
}
}
if (result == null) {
throw new DMNRuntimeException(String.format("Cannot find DRG element for href='%s'", href));
} else {
return result;
}
} catch (Exception e) {
throw new DMNRuntimeException(String.format("Cannot find DRG element for href='%s'", href), e);
}
}
public TDecision findDecisionByRef(TDRGElement parent, String href) {
TDRGElement drgElement = findDRGElementByRef(parent, href);
if (drgElement instanceof TDecision) {
return (TDecision) drgElement;
} else {
throw new DMNRuntimeException(String.format("Cannot find Decision element for href='%s'", href));
}
}
public TInputData findInputDataByRef(TDRGElement parent, String href) {
TDRGElement drgElement = findDRGElementByRef(parent, href);
if (drgElement instanceof TInputData) {
return (TInputData) drgElement;
} else {
throw new DMNRuntimeException(String.format("Cannot find InputData element for href='%s'", href));
}
}
public TInvocable findInvocableByRef(TDRGElement parent, String href) {
TDRGElement drgElement = findDRGElementByRef(parent, href);
if (drgElement instanceof TInvocable) {
return (TInvocable) drgElement;
} else {
throw new DMNRuntimeException(String.format("Cannot find TInvocable element for href='%s'", href));
}
}
protected TDefinitions findChildDefinitions(TDRGElement parent, String href) {
String namespace = extractNamespace(href);
if (StringUtils.isEmpty(namespace)) {
return this.elementToDefinitions.get(parent);
} else {
return this.namespaceToDefinitions.get(namespace);
}
}
public TBusinessKnowledgeModel findKnowledgeModelByName(String name) {
TBusinessKnowledgeModel result = this.knowledgeModelByName.get(name);
if (result == null) {
List value = new ArrayList<>();
for (TBusinessKnowledgeModel knowledgeModel: findAllBKMs()) {
if (sameName(knowledgeModel, name)) {
value.add(knowledgeModel);
}
}
if (value.size() == 1) {
result = value.get(0);
this.knowledgeModelByName.put(name, result);
} else if (value.size() > 1) {
throw new DMNRuntimeException(String.format("Found %s business knowledge models for name='%s'", value.size(), name));
}
}
if (result == null) {
throw new DMNRuntimeException(String.format("Cannot find business knowledge model for name='%s'", name));
} else {
return result;
}
}
public TDRGElement findDRGElementByName(String namespace, String name) {
TDefinitions definitions = this.namespaceToDefinitions.get(namespace);
if (definitions == null) {
throw new DMNRuntimeException(String.format("Cannot find model for namespace '%s'", namespace));
}
return findDRGElementByName(definitions, name);
}
public TDRGElement findDRGElementByName(TDefinitions definitions, String name) {
if (definitions == null) {
throw new DMNRuntimeException(String.format("Cannot find element for name='%s'. Missing DM", name));
}
for (TDRGElement element: findDRGElements(definitions)) {
if (element.getName().equals(name)) {
return element;
}
}
throw new DMNRuntimeException(String.format("Cannot find element for name='%s'", name));
}
public TDRGElement findDRGElementByName(String name) {
TDRGElement result = this.drgElementByName.get(name);
if (result == null) {
List value = new ArrayList<>();
for (TDefinitions definitions: getAllDefinitions()) {
for (TDRGElement element: findDRGElements(definitions)) {
if (sameName(element, name)) {
value.add(element);
}
}
}
if (value.size() == 1) {
result = value.get(0);
this.drgElementByName.put(name, result);
} else if (value.size() > 1) {
throw new DMNRuntimeException(String.format("Found %s business knowledge models for name='%s'", value.size(), name));
}
}
if (result == null) {
throw new DMNRuntimeException(String.format("Cannot find element for name='%s'", name));
} else {
return result;
}
}
public boolean sameId(TDMNElement element, String href) {
String id = extractId(href);
return element.getId().equals(id);
}
public boolean sameName(TNamedElement element, String name) {
return element.getName().equals(name);
}
public DRGElementReference makeDRGElementReference(T element) {
return makeDRGElementReference(new ImportPath(), element);
}
public DRGElementReference makeDRGElementReference(String importName, T element) {
return makeDRGElementReference(new ImportPath(importName), element);
}
public DRGElementReference makeDRGElementReference(ImportPath importPath, T element) {
return new DRGElementReference<>(importPath, getNamespace(element), getModelName(element), element);
}
public List> directInputDatas(TDRGElement parent) {
List> result = new ArrayList<>();
// Add reference for direct children
List references = requiredInputDataReferences(parent);
for (TDMNElementReference reference: references) {
TInputData child = findInputDataByRef(parent, reference.getHref());
if (child != null) {
String importName = findImportName(parent, reference);
result.add(makeDRGElementReference(importName, child));
} else {
throw new DMNRuntimeException(String.format("Cannot find InputData for '%s' in parent '%s'", reference.getHref(), parent.getName()));
}
}
return result;
}
public List> inputDataClosure(DRGElementReference extends TDRGElement> parentReference, DRGElementFilter drgElementFilter) {
return drgElementFilter.filterInputs(collectTransitiveInputDatas(parentReference));
}
protected List> collectTransitiveInputDatas(DRGElementReference extends TDRGElement> parentReference) {
TDRGElement parent = parentReference.getElement();
ImportPath parentImportPath = parentReference.getImportPath();
List> result = new ArrayList<>();
// Add reference for direct children
List references = requiredInputDataReferences(parent);
for (TDMNElementReference reference: references) {
TInputData child = findInputDataByRef(parent, reference.getHref());
if (child != null) {
String importName = findImportName(parent, reference);
result.add(makeDRGElementReference(new ImportPath(parentImportPath, importName), child));
} else {
throw new DMNRuntimeException(String.format("Cannot find InputData for '%s' in parent '%s'", reference.getHref(), parent.getName()));
}
}
// Process direct children and update reference
List childReferences = requiredDecisionReferences(parent);
for (TDMNElementReference reference: childReferences) {
TDecision child = findDecisionByRef(parent, reference.getHref());
if (child != null) {
// Update reference for descendants
String importName = findImportName(parent, reference);
List> inputReferences = collectTransitiveInputDatas(makeDRGElementReference(new ImportPath(parentImportPath, importName), child));
result.addAll(inputReferences);
} else {
throw new DMNRuntimeException(String.format("Cannot find Decision for '%s' in parent '%s'", reference.getHref(), parent.getName()));
}
}
return result;
}
public List> directSubDecisions(TDRGElement parent) {
List> result = new ArrayList<>();
if (parent instanceof TDecision) {
// Add reference for direct children
for (TInformationRequirement ir: ((TDecision) parent).getInformationRequirement()) {
TDMNElementReference reference = ir.getRequiredDecision();
if (reference != null) {
TDecision child = findDecisionByRef(parent, reference.getHref());
String importName = findImportName(parent, reference);
result.add(makeDRGElementReference(importName, child));
}
}
} else if (parent instanceof TDecisionService) {
// Add reference for direct children
for (TDMNElementReference outputDecisionRef: ((TDecisionService) parent).getOutputDecision()) {
TDecision child = findDecisionByRef(parent, outputDecisionRef.getHref());
String importName = findImportName(parent, outputDecisionRef);
result.add(makeDRGElementReference(importName, child));
}
}
sortNamedElementReferences(result);
return result;
}
public List> directInputDecisions(TDecisionService parent) {
List> result = new ArrayList<>();
// Add reference for direct children
for (TDMNElementReference inputDecisionRef: parent.getInputDecision()) {
TDecision child = findDecisionByRef(parent, inputDecisionRef.getHref());
String importName = findImportName(parent, inputDecisionRef);
result.add(makeDRGElementReference(importName, child));
}
sortNamedElementReferences(result);
return result;
}
public List> directSubInvocables(TDRGElement element) {
List> result = new ArrayList<>();
// Add reference for direct children
List knowledgeRequirements = knowledgeRequirements(element);
for (TKnowledgeRequirement kr: knowledgeRequirements) {
TDMNElementReference reference = kr.getRequiredKnowledge();
if (reference != null) {
TInvocable invocable = findInvocableByRef(element, reference.getHref());
if (invocable != null) {
String importName = findImportName(element, reference);
result.add(makeDRGElementReference(importName, invocable));
} else {
throw new DMNRuntimeException(String.format("Cannot find Invocable for '%s'", reference.getHref()));
}
}
}
return result;
}
public List> directDRGElements(TDRGElement element) {
List> result = new ArrayList<>();
result.addAll(directInputDatas(element));
result.addAll(directSubDecisions(element));
result.addAll(directSubInvocables(element));
return result;
}
protected List requiredInputDataReferences(TDRGElement parent) {
List references = new ArrayList<>();
if (parent instanceof TDecision) {
List informationRequirements = ((TDecision) parent).getInformationRequirement();
references.addAll(informationRequirements.stream().map(TInformationRequirement::getRequiredInput).filter(Objects::nonNull).collect(Collectors.toList()));
} else if (parent instanceof TDecisionService) {
List inputData = ((TDecisionService) parent).getInputData();
references.addAll(inputData.stream().filter(Objects::nonNull).collect(Collectors.toList()));
}
return references;
}
protected List requiredDecisionReferences(TDRGElement parent) {
List references = new ArrayList<>();
if (parent instanceof TDecision) {
List informationRequirements = ((TDecision) parent).getInformationRequirement();
references.addAll(informationRequirements.stream().map(TInformationRequirement::getRequiredDecision).filter(Objects::nonNull).collect(Collectors.toList()));
} else if (parent instanceof TDecisionService) {
List inputDecisions = ((TDecisionService) parent).getInputDecision();
references.addAll(inputDecisions.stream().filter(Objects::nonNull).collect(Collectors.toList()));
List outputDecisions = ((TDecisionService) parent).getOutputDecision();
references.addAll(outputDecisions.stream().filter(Objects::nonNull).collect(Collectors.toList()));
List encapsulatedDecision = ((TDecisionService) parent).getEncapsulatedDecision();
references.addAll(encapsulatedDecision.stream().filter(Objects::nonNull).collect(Collectors.toList()));
}
return references;
}
protected List knowledgeRequirements(TDRGElement element) {
List knowledgeRequirements;
if (element instanceof TDecision) {
knowledgeRequirements = ((TDecision) element).getKnowledgeRequirement();
} else if (element instanceof TBusinessKnowledgeModel) {
knowledgeRequirements = ((TBusinessKnowledgeModel) element).getKnowledgeRequirement();
} else {
knowledgeRequirements = new ArrayList<>();
}
return knowledgeRequirements;
}
public TDecisionTable decisionTable(TDRGElement element) {
TExpression expression = expression(element);
if (expression instanceof TDecisionTable) {
return (TDecisionTable) expression;
} else {
throw new DMNRuntimeException(String.format("Cannot find decision table in element '%s'", element.getName()));
}
}
public boolean isNull(String typeRef) {
return typeRef == null;
}
public boolean isNull(QualifiedName typeRef) {
return typeRef == null;
}
public boolean isAny(QualifiedName typeRef) {
return typeRef != null && "Any".equals(typeRef.getLocalPart());
}
public boolean isNullOrAny(QualifiedName typeRef) {
return isNull(typeRef) || isAny(typeRef);
}
public TItemDefinition lookupItemDefinition(TDefinitions model, QualifiedName typeRef) {
if (isNull(typeRef)) {
return null;
}
String importName = typeRef.getNamespace();
if (DMNVersion.LATEST.getFeelPrefix().equals(importName)) {
return null;
}
if (model == null) {
return lookupItemDefinition(findAllItemDefinitions(), typeRef);
} else {
for (TImport import_: model.getImport()) {
if (import_.getName().equals(importName)) {
String modelNamespace = import_.getNamespace();
model = this.getModel(modelNamespace);
if (model == null) {
throw new DMNRuntimeException(String.format("Cannot find DM for '%s'", modelNamespace));
}
}
}
return lookupItemDefinition(findItemDefinitions(model), typeRef);
}
}
protected TItemDefinition lookupItemDefinition(List itemDefinitionList, QualifiedName typeRef) {
for (TItemDefinition itemDefinition: itemDefinitionList) {
if (typeRef.getLocalPart().equals(itemDefinition.getName())) {
return itemDefinition;
}
}
return null;
}
public TItemDefinition lookupItemDefinition(String name) {
return lookupItemDefinition(findAllItemDefinitions(), name);
}
protected TItemDefinition lookupItemDefinition(List itemDefinitionList, String name) {
if (name == null) {
return null;
}
for (TItemDefinition itemDefinition: itemDefinitionList) {
if (name.equals(itemDefinition.getName())) {
return itemDefinition;
}
}
return null;
}
public List> sortedUniqueInputs(TDecision decision, DRGElementFilter drgElementFilter) {
List> inputs = new ArrayList<>();
inputs.addAll(directInputDatas(decision));
inputs.addAll(directSubDecisions(decision));
List> result = drgElementFilter.filterDRGElements(inputs);
sortNamedElementReferences(result);
return result;
}
public boolean hasDefaultValue(TDecisionTable decisionTable) {
List outputClauses = decisionTable.getOutput();
for (TOutputClause output: outputClauses) {
TLiteralExpression defaultOutputEntry = output.getDefaultOutputEntry();
if (defaultOutputEntry != null) {
return true;
}
}
return false;
}
public TExpression expression(TDRGElement element) {
if (element instanceof TDecision) {
TExpression expression = ((TDecision) element).getExpression();
return expression;
} else if (element instanceof TBusinessKnowledgeModel) {
TFunctionDefinition encapsulatedLogic = ((TBusinessKnowledgeModel) element).getEncapsulatedLogic();
if (encapsulatedLogic != null) {
TExpression expression = encapsulatedLogic.getExpression();
return expression;
}
} else if (element instanceof TDecisionService) {
return null;
} else {
throw new UnsupportedOperationException(String.format("'%s' is not supported yet", element.getClass().getSimpleName()));
}
return null;
}
public boolean isLiteralExpression(TDRGElement element) {
return expression(element) instanceof TLiteralExpression;
}
public boolean isFreeTextLiteralExpression(TDRGElement element) {
TExpression expression = expression(element);
return expression instanceof TLiteralExpression
&& FREE_TEXT_LANGUAGE.equals(((TLiteralExpression) expression).getExpressionLanguage());
}
public boolean isDecisionTableExpression(TDRGElement element) {
return expression(element) instanceof TDecisionTable;
}
public boolean isCompoundDecisionTable(TDRGElement element) {
TExpression expression = expression(element);
return expression instanceof TDecisionTable
&& ((TDecisionTable) expression).getOutput() != null
&& ((TDecisionTable) expression).getOutput().size() > 1;
}
public boolean isInvocationExpression(TDRGElement element) {
TExpression expression = expression(element);
return expression instanceof TInvocation;
}
public boolean isContextExpression(TDRGElement element) {
TExpression expression = expression(element);
return expression instanceof TContext;
}
public boolean isRelationExpression(TDRGElement element) {
TExpression expression = expression(element);
return expression instanceof TRelation;
}
public boolean isFunctionDefinitionExpression(TDRGElement element) {
TExpression expression = expression(element);
return expression instanceof TFunctionDefinition;
}
//
// Item definition related functions
//
public boolean isEmpty(List list) {
return list == null || list.isEmpty();
}
public QualifiedName variableTypeRef(TDefinitions model, TInformationItem element) {
TInformationItem variable = variable(element);
return variable == null ? null : QualifiedName.toQualifiedName(model, variable.getTypeRef());
}
public QualifiedName variableTypeRef(TDefinitions model, TDRGElement element) {
TInformationItem variable = variable(element);
QualifiedName typeRef = variable == null ? null : QualifiedName.toQualifiedName(model, variable.getTypeRef());
// Derive from expression
if (isNull(typeRef) && element instanceof TDecision) {
typeRef = inferExpressionTypeRef(model, element);
}
return typeRef;
}
public QualifiedName outputTypeRef(TDefinitions model, TDRGElement element) {
// Derive from variable
TInformationItem variable = variable(element);
QualifiedName typeRef = variable == null ? null : QualifiedName.toQualifiedName(model, variable.getTypeRef());
// Derive from expression
if (isNull(typeRef)) {
typeRef = inferExpressionTypeRef(model, element);
}
return typeRef;
}
public QualifiedName inferExpressionTypeRef(TDefinitions model, TDRGElement element) {
QualifiedName typeRef = null;
// Derive from expression
TExpression expression = expression(element);
if (expression != null) {
typeRef = QualifiedName.toQualifiedName(model, expression.getTypeRef());
if (isNull(typeRef)) {
if (expression instanceof TContext) {
// Derive from return entry
List contextEntryList = ((TContext) expression).getContextEntry();
for (TContextEntry ce: contextEntryList) {
if (ce.getVariable() == null) {
TExpression returnExp = ce.getExpression();
if (returnExp != null) {
typeRef = QualifiedName.toQualifiedName(model, returnExp.getTypeRef());
}
}
}
} else if (expression instanceof TDecisionTable) {
// Derive from output clauses and rules
TDecisionTable dt = (TDecisionTable) expression;
List outputList = dt.getOutput();
if (outputList.size() == 1) {
typeRef = QualifiedName.toQualifiedName(model, outputList.get(0).getTypeRef());
if (isNull(typeRef)) {
// Derive from rules
List ruleList = dt.getRule();
List outputEntry = ruleList.get(0).getOutputEntry();
typeRef = QualifiedName.toQualifiedName(model, outputEntry.get(0).getTypeRef());
}
// Apply aggregation and hit policy
if (dt.getHitPolicy() == THitPolicy.COLLECT) {
// Type is list
typeRef = null;
}
TBuiltinAggregator aggregation = dt.getAggregation();
if (aggregation == SUM || aggregation == COUNT) {
typeRef = QualifiedName.toQualifiedName(null, "number");
}
}
}
}
}
return typeRef;
}
//
// Decision Service related functions
//
public TDecision getOutputDecision(TDecisionService decisionService) {
List outputDecisionList = decisionService.getOutputDecision();
if (outputDecisionList.size() != 1) {
throw new DMNRuntimeException(String.format("Missing or more than one decision services in BKM '%s'", decisionService.getName()));
}
return this.findDecisionByRef(decisionService, outputDecisionList.get(0).getHref());
}
//
// DecisionTable related functions
//
public boolean isSingleHit(THitPolicy policy) {
return policy == THitPolicy.FIRST
|| policy == THitPolicy.UNIQUE
|| policy == THitPolicy.ANY
|| policy == THitPolicy.PRIORITY
|| policy == null;
}
public boolean isFirstSingleHit(THitPolicy policy) {
return policy == THitPolicy.FIRST;
}
public boolean atLeastTwoRules(TDecisionTable expression) {
return expression.getRule() != null && expression.getRule().size() >= 2;
}
public boolean isMultipleHit(THitPolicy hitPolicy) {
return THitPolicy.COLLECT == hitPolicy
|| THitPolicy.RULE_ORDER == hitPolicy
|| THitPolicy.OUTPUT_ORDER == hitPolicy
;
}
public boolean isOutputOrderHit(THitPolicy hitPolicy) {
return THitPolicy.PRIORITY == hitPolicy
|| THitPolicy.OUTPUT_ORDER == hitPolicy
;
}
public boolean hasAggregator(TDecisionTable decisionTable) {
return decisionTable.getAggregation() != null;
}
public int rulesCount(TDRGElement element) {
TExpression expression = expression(element);
if (expression instanceof TDecisionTable) {
List rules = ((TDecisionTable) expression).getRule();
return rules == null ? 0 : rules.size();
} else {
return -1;
}
}
public String outputClauseName(TDRGElement element, TOutputClause output) {
// Try TOutputClause.typeRef
String outputClauseName = output.getName();
if (StringUtils.isBlank(outputClauseName)) {
// Try variable.typeRef from parent
if (!isCompoundDecisionTable(element)) {
TInformationItem variable = variable(element);
if (variable != null) {
outputClauseName = variable.getName();
}
}
if (StringUtils.isBlank(outputClauseName)) {
throw new DMNRuntimeException(String.format("Cannot resolve name for outputClause '%s' in element '%s'", output.getId(), element.getName()));
}
}
return outputClauseName;
}
public TInformationItem variable(TNamedElement element) {
if (element instanceof TInputData) {
return ((TInputData) element).getVariable();
} else if (element instanceof TDecision) {
return ((TDecision) element).getVariable();
} else if (element instanceof TInvocable) {
return ((TInvocable) element).getVariable();
} else if (element instanceof TInformationItem) {
return (TInformationItem) element;
}
return null;
}
public String name(TNamedElement element) {
String name = null;
if (element != null) {
name = element.getName();
}
if (StringUtils.isBlank(name)) {
throw new DMNRuntimeException(String.format("Display name cannot be null for element '%s'", element == null ? null : element.getId()));
}
return name.trim();
}
public String label(TDMNElement element) {
String label = element.getLabel();
return label == null ? "" : label.replace('\"', '\'');
}
public String displayName(TNamedElement element) {
String name = label(element);
if (StringUtils.isBlank(name)) {
name = element.getName();
}
if (StringUtils.isBlank(name)) {
throw new DMNRuntimeException(String.format("Display name cannot be null for element '%s'", element.getId()));
}
return name.trim();
}
public String registryId(TDRGElement element) {
if (this.allDefinitions.size() == 1) {
return displayName(element);
} else {
TDefinitions model = this.getModel(element);
String modelId = model.getNamespace();
return String.format("%s#%s", modelId, displayName(element));
}
}
public String findChildImportName(TDRGElement parent, TDRGElement child) {
// Collect references
List references = new ArrayList<>();
if (parent instanceof TDecision) {
for (TInformationRequirement ir: ((TDecision) parent).getInformationRequirement()) {
TDMNElementReference reference = ir.getRequiredDecision();
if (reference != null) {
references.add(reference);
}
reference = ir.getRequiredInput();
if (reference != null) {
references.add(reference);
}
}
for (TKnowledgeRequirement bkr: ((TDecision) parent).getKnowledgeRequirement()) {
TDMNElementReference reference = bkr.getRequiredKnowledge();
if (reference != null) {
references.add(reference);
}
}
} else if (parent instanceof TBusinessKnowledgeModel) {
for (TKnowledgeRequirement bkr: ((TBusinessKnowledgeModel) parent).getKnowledgeRequirement()) {
TDMNElementReference reference = bkr.getRequiredKnowledge();
if (reference != null) {
references.add(reference);
}
}
} else if (parent instanceof TDecisionService) {
references.addAll(((TDecisionService) parent).getInputData());
references.addAll(((TDecisionService) parent).getInputDecision());
references.addAll(((TDecisionService) parent).getOutputDecision());
references.addAll(((TDecisionService) parent).getEncapsulatedDecision());
}
// Find reference for child
String childNamespace = getNamespace(child);
String childRefSuffix = childNamespace + "#" + child.getId();
for (TDMNElementReference reference: references) {
if (reference.getHref().endsWith(childRefSuffix)) {
return findImportName(parent, reference);
}
}
return null;
}
public String findImportName(TDRGElement parent, TDMNElementReference reference) {
TDefinitions parentDefinitions = this.elementToDefinitions.get(parent);
String referenceNamespace = extractNamespace(reference.getHref());
if (referenceNamespace == null) {
return null;
} else if (parentDefinitions.getNamespace().equals(referenceNamespace)) {
return null;
} else {
for (TImport import_: parentDefinitions.getImport()) {
if (import_.getNamespace().equals(referenceNamespace)) {
return import_.getName();
}
}
throw new DMNRuntimeException(String.format("Cannot find import prefix for '%s' in model '%s'", reference.getHref(), parentDefinitions.getName()));
}
}
protected static String makeRef(String namespace, String href) {
if (StringUtils.isEmpty(namespace)) {
return href;
} else {
return namespace + href;
}
}
protected String extractNamespace(String href) {
String namespace = null;
if (hasNamespace(href)) {
namespace = href.substring(0, href.indexOf('#'));
}
return namespace;
}
public static String extractId(String href) {
if (hasNamespace(href)) {
href = href.substring(href.indexOf('#') + 1);
} else if (href != null && href.startsWith("#")) {
href = href.substring(1);
}
return href;
}
protected static boolean hasNamespace(String href) {
return href != null && href.indexOf('#') > 0;
}
public List compositeItemDefinitions(TDefinitions definitions) {
List accumulator = new ArrayList<>();
collectCompositeItemDefinitions(definitions.getItemDefinition(), accumulator);
return accumulator;
}
private void collectCompositeItemDefinitions(List itemDefinitions, List accumulator) {
if (itemDefinitions != null) {
for (TItemDefinition itemDefinition: itemDefinitions) {
if (hasComponents(itemDefinition)) {
accumulator.add(itemDefinition);
collectCompositeItemDefinitions(itemDefinition.getItemComponent(), accumulator);
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy