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.runtime.DMNRuntimeException;
import com.gs.dmn.runtime.Pair;
import com.gs.dmn.serialization.DMNVersion;
import com.gs.dmn.serialization.PrefixNamespaceMappings;
import com.gs.dmn.transformation.DMNToJavaTransformer;
import com.gs.dmn.transformation.basic.QualifiedName;
import org.apache.commons.lang3.StringUtils;
import org.omg.spec.dmn._20180521.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.JAXBElement;
import java.util.*;
public class DMNModelRepository {
private static final ObjectFactory OBJECT_FACTORY = new ObjectFactory();
private static final Logger LOGGER = LoggerFactory.getLogger(DMNModelRepository.class);
protected final TDefinitions rootDefinitions;
protected final List importedDefinitions = new ArrayList<>();
protected final List allDefinitions = new ArrayList<>();
protected final Map definitionsMap = new LinkedHashMap<>();
protected final Map elementMap = new LinkedHashMap<>();
protected final PrefixNamespaceMappings prefixNamespaceMappings;
// Derived properties to optimise search
protected List drgElements;
protected List decisions;
protected List inputDatas;
protected List businessKnowledgeModels;
protected List decisionServices;
protected List itemDefinitions;
protected Map drgElementByName = new LinkedHashMap<>();
protected Map knowledgeModelByName = new LinkedHashMap<>();
protected Map decisionServiceByName = new LinkedHashMap<>();
protected Map drgElementByRef = new LinkedHashMap<>();
protected Map inputDataByRef = new LinkedHashMap<>();
protected Map decisionByRef = new LinkedHashMap<>();
protected Map businessKnowledgeModelByRef = new LinkedHashMap<>();
protected Map decisionServiceByRef = new LinkedHashMap<>();
public DMNModelRepository() {
this(OBJECT_FACTORY.createTDefinitions(), new PrefixNamespaceMappings());
}
public DMNModelRepository(TDefinitions definitions) {
this(definitions, new PrefixNamespaceMappings());
}
public DMNModelRepository(TDefinitions rootDefinitions, PrefixNamespaceMappings prefixNamespaceMappings) {
this(rootDefinitions, Arrays.asList(), prefixNamespaceMappings);
}
public DMNModelRepository(TDefinitions rootDefinitions, List importedDefinitions, PrefixNamespaceMappings prefixNamespaceMappings) {
this.rootDefinitions = rootDefinitions;
if (rootDefinitions != null) {
this.definitionsMap.put(this.rootDefinitions.getNamespace(), this.rootDefinitions);
}
if (importedDefinitions != null) {
this.importedDefinitions.addAll(importedDefinitions);
for (TDefinitions definitions: this.importedDefinitions) {
this.definitionsMap.put(definitions.getNamespace(), definitions);
}
}
this.prefixNamespaceMappings = prefixNamespaceMappings;
this.allDefinitions.addAll(this.definitionsMap.values());
// Process all definitions
for(TDefinitions definitions: this.getAllDefinitions()) {
// Normalize
normalize(definitions);
// Set derived properties
for (TDRGElement element: drgElements(definitions)) {
this.elementMap.put(element, definitions);
}
List imports = definitions.getImport();
for(TImport imp: imports) {
this.prefixNamespaceMappings.put(imp.getName(), imp.getNamespace());
}
}
}
public DMNModelRepository(Pair pair) {
this(pair.getLeft(), pair.getRight());
}
protected void normalize(TDefinitions definitions) {
if (definitions != null) {
sortDRGElements(definitions.getDrgElement());
sortNamedElements(definitions.getItemDefinition());
}
}
public Set computeCachedElements(boolean cachingFlag) {
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 : decisions(definitions)) {
addCachedChildren(definitions, decision, parentMap, map);
}
}
Set result = new LinkedHashSet<>();
for(Map.Entry entry: map.entrySet()) {
if (entry.getValue() > 1) {
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);
}
}
}
public String removeSingleQuotes(String name) {
if (isQuotedName(name)) {
name = name.substring(1, name.length() - 1);
}
return name;
}
protected boolean isQuotedName(String name) {
return name != null && name.startsWith("'") && name.endsWith("'");
}
public TDefinitions getRootDefinitions() {
return rootDefinitions;
}
public List getAllDefinitions() {
return this.allDefinitions;
}
public PrefixNamespaceMappings getPrefixNamespaceMappings() {
return prefixNamespaceMappings;
}
public void addElementMap(TDRGElement element, TDefinitions definitions) {
this.elementMap.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 List drgElements() {
if (this.drgElements == null) {
this.drgElements = new ArrayList<>();
for (TDefinitions definitions: this.allDefinitions) {
drgElements(definitions, this.drgElements);
}
}
return this.drgElements;
}
public List decisions() {
if (this.decisions == null) {
this.decisions = new ArrayList<>();
for (TDefinitions definitions: this.allDefinitions) {
decisions(definitions, this.decisions);
}
}
return this.decisions;
}
public List inputDatas() {
if (this.inputDatas == null) {
this.inputDatas = new ArrayList<>();
for (TDefinitions definitions: this.allDefinitions) {
inputDatas(definitions, this.inputDatas);
}
}
return this.inputDatas;
}
public List businessKnowledgeModels() {
if (this.businessKnowledgeModels == null) {
this.businessKnowledgeModels = new ArrayList<>();
for (TDefinitions definitions: this.allDefinitions) {
businessKnowledgeModels(definitions, this.businessKnowledgeModels);
}
}
return this.businessKnowledgeModels;
}
public List decisionServices() {
if (this.decisionServices == null) {
this.decisionServices = new ArrayList<>();
for (TDefinitions definitions: this.allDefinitions) {
decisionServices(definitions, this.decisionServices);
}
}
return this.decisionServices;
}
public List itemDefinitions() {
if (this.itemDefinitions == null) {
this.itemDefinitions = new ArrayList<>();
for (TDefinitions definitions: this.allDefinitions) {
this.itemDefinitions.addAll(definitions.getItemDefinition());
}
}
return this.itemDefinitions;
}
public List drgElements(TDefinitions definitions) {
List result = new ArrayList<>();
drgElements(definitions, result);
return result;
}
public List decisions(TDefinitions definitions) {
List result = new ArrayList<>();
decisions(definitions, result);
return result;
}
public List inputDatas(TDefinitions definitions) {
List result = new ArrayList<>();
inputDatas(definitions, result);
return result;
}
public List businessKnowledgeModels(TDefinitions definitions) {
List result = new ArrayList<>();
businessKnowledgeModels(definitions, result);
return result;
}
public List decisionServices(TDefinitions definitions) {
List result = new ArrayList<>();
decisionServices(definitions, result);
return result;
}
public List itemDefinitions(TDefinitions definitions) {
return definitions.getItemDefinition();
}
protected void drgElements(TDefinitions definitions, List result) {
for (JAXBElement extends TDRGElement> jaxbElement : definitions.getDrgElement()) {
TDRGElement element = jaxbElement.getValue();
result.add(element);
}
}
protected void decisions(TDefinitions definitions, List result) {
for (JAXBElement extends TDRGElement> jaxbElement : definitions.getDrgElement()) {
TDRGElement element = jaxbElement.getValue();
if (element instanceof TDecision) {
result.add((TDecision) element);
}
}
}
protected void inputDatas(TDefinitions definitions, List result) {
for (JAXBElement extends TDRGElement> jaxbElement : definitions.getDrgElement()) {
TDRGElement element = jaxbElement.getValue();
if (element instanceof TInputData) {
result.add((TInputData) element);
}
}
}
protected void businessKnowledgeModels(TDefinitions definitions, List result) {
for (JAXBElement extends TDRGElement> jaxbElement : definitions.getDrgElement()) {
TDRGElement element = jaxbElement.getValue();
if (element instanceof TBusinessKnowledgeModel) {
result.add((TBusinessKnowledgeModel) element);
}
}
}
protected void decisionServices(TDefinitions definitions, List result) {
for (JAXBElement extends TDRGElement> jaxbElement : definitions.getDrgElement()) {
TDRGElement element = jaxbElement.getValue();
if (element instanceof TDecisionService) {
result.add((TDecisionService) element);
}
}
}
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.getTypeRef() == null) {
return null;
}
return lookupItemDefinition(QualifiedName.toQualifiedName(itemDefinition.getTypeRef()));
}
protected void sortDRGElements(List> result) {
result.sort(Comparator.comparing((JAXBElement extends TDRGElement> o) -> removeSingleQuotes(o.getValue().getName())));
}
public void sortNamedElements(List extends TNamedElement> result) {
result.sort(Comparator.comparing((TNamedElement o) -> removeSingleQuotes(o.getName())));
}
public TDRGElement findDRGElementByRef(TDRGElement parent, String href) {
TDefinitions definitions = findChildDefinitions(parent, href);
String key = makeRef(definitions.getNamespace(), href);
if (!this.drgElementByRef.containsKey(key)) {
TDRGElement value = null;
for (TDRGElement element : drgElements(definitions)) {
if (sameId(element, href)) {
value = element;
break;
}
}
this.drgElementByRef.put(key, value);
}
TDRGElement result = this.drgElementByRef.get(key);
if (result == null) {
throw new DMNRuntimeException(String.format("Cannot find DRG element for href='%s'", href));
} else {
return result;
}
}
public TDecision findDecisionByRef(TDRGElement parent, String href) {
TDefinitions definitions = findChildDefinitions(parent, href);
String key = makeRef(definitions.getNamespace(), href);
if (!this.decisionByRef.containsKey(key)) {
TDecision value = null;
for (TDecision decision : decisions(definitions)) {
if (sameId(decision, href)) {
value = decision;
break;
}
}
this.decisionByRef.put(key, value);
}
TDecision result = this.decisionByRef.get(key);
if (result == null) {
throw new DMNRuntimeException(String.format("Cannot find decision for href='%s'", href));
} else {
return result;
}
}
public TInputData findInputDataByRef(TDRGElement parent, String href) {
TDefinitions definitions = findChildDefinitions(parent, href);
String key = makeRef(definitions.getNamespace(), href);
if (!this.inputDataByRef.containsKey(key)) {
TInputData value = null;
for (TInputData inputData : inputDatas(definitions)) {
if (sameId(inputData, href)) {
value = inputData;
break;
}
}
this.inputDataByRef.put(key, value);
}
TInputData result = this.inputDataByRef.get(key);
if (result == null) {
throw new DMNRuntimeException(String.format("Cannot find input data for href='%s'", href));
} else {
return result;
}
}
public TInvocable findInvocableByRef(TDRGElement parent, String href) {
TDefinitions definitions = findChildDefinitions(parent, href);
String key = makeRef(definitions.getNamespace(), href);
if (!this.businessKnowledgeModelByRef.containsKey(key)) {
TBusinessKnowledgeModel value = null;
for (TBusinessKnowledgeModel knowledgeModel : businessKnowledgeModels(definitions)) {
if (sameId(knowledgeModel, href)) {
value = knowledgeModel;
break;
}
}
this.businessKnowledgeModelByRef.put(key, value);
}
TInvocable result = this.businessKnowledgeModelByRef.get(key);
if (result != null) {
return result;
}
if (!this.decisionServiceByRef.containsKey(key)) {
TDecisionService value = null;
for (TDecisionService service : decisionServices(definitions)) {
if (sameId(service, href)) {
value = service;
break;
}
}
this.decisionServiceByRef.put(key, value);
}
result = this.decisionServiceByRef.get(key);
if (result == null) {
throw new DMNRuntimeException(String.format("Cannot find invocable (knowledge model or decision service) for href='%s'", href));
} else {
return result;
}
}
protected TDefinitions findChildDefinitions(TDRGElement parent, String href) {
String namespace = extractNamespace(href);
if (StringUtils.isEmpty(namespace)) {
return this.elementMap.get(parent);
} else {
return this.definitionsMap.get(namespace);
}
}
public TBusinessKnowledgeModel findKnowledgeModelByName(String name) {
if (!this.knowledgeModelByName.containsKey(name)) {
TBusinessKnowledgeModel value = null;
for (TBusinessKnowledgeModel knowledgeModel : businessKnowledgeModels()) {
if (sameName(knowledgeModel, name)) {
value = knowledgeModel;
break;
}
}
this.knowledgeModelByName.put(name, value);
}
TBusinessKnowledgeModel result = this.knowledgeModelByName.get(name);
if (result == null) {
throw new DMNRuntimeException(String.format("Cannot find business knowledge model for name='%s'", name));
} else {
return result;
}
}
public TDecisionService findDecisionServiceByName(String name) {
if (!this.decisionServiceByName.containsKey(name)) {
TDecisionService value = null;
for (TDecisionService service : decisionServices()) {
if (sameName(service, name)) {
value = service;
break;
}
}
this.decisionServiceByName.put(name, value);
}
TDecisionService result = this.decisionServiceByName.get(name);
if (result == null) {
throw new DMNRuntimeException(String.format("Cannot find decision service for name='%s'", name));
} else {
return result;
}
}
public TDRGElement findDRGElementByName(String name) {
if (!this.drgElementByName.containsKey(name)) {
TDRGElement value = null;
for (TDRGElement element : drgElements()) {
if (sameName(element, name)) {
value = element;
break;
}
}
this.drgElementByName.put(name, value);
}
TDRGElement result = this.drgElementByName.get(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);
}
protected boolean sameName(TNamedElement element, String href) {
return element.getName().equals(href);
}
public List directSubDecisions(TDRGElement element) {
List result = new ArrayList<>();
if (element instanceof TDecision) {
for (TInformationRequirement ir : ((TDecision) element).getInformationRequirement()) {
TDMNElementReference requiredDecision = ir.getRequiredDecision();
if (requiredDecision != null) {
TDecision childDecision = findDecisionByRef(element, requiredDecision.getHref());
result.add(childDecision);
}
}
} else if (element instanceof TDecisionService) {
for (TDMNElementReference outputDecisionRef : ((TDecisionService) element).getOutputDecision()) {
TDecision childDecision = findDecisionByRef(element, outputDecisionRef.getHref());
result.add(childDecision);
}
}
sortNamedElements(result);
return result;
}
public Collection allSubDecisions(TDRGElement element) {
Set result = new LinkedHashSet<>();
collectSubDecisions(element, result);
return result;
}
protected void collectSubDecisions(TDRGElement element, Collection decisions) {
decisions.addAll(directSubDecisions(element));
for (TDecision child : directSubDecisions(element)) {
collectSubDecisions(child, decisions);
}
}
public List topologicalSort(TDRGElement decision) {
List result = new ArrayList<>();
topologicalSort((TDecision)decision, result);
result.remove(decision);
return result;
}
protected void topologicalSort(TDecision parent, List decisions) {
if (!decisions.contains(parent)) {
for(TInformationRequirement ir: parent.getInformationRequirement()) {
TDMNElementReference requiredDecision = ir.getRequiredDecision();
if (requiredDecision != null) {
TDecision child = findDecisionByRef(parent, requiredDecision.getHref());
if (child != null) {
topologicalSort(child, decisions);
}
}
}
decisions.add(parent);
}
}
public List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy