com.regnosys.rosetta.translate.ROMParseHandler Maven / Gradle / Ivy
package com.regnosys.rosetta.translate;
import static com.regnosys.rosetta.translate.GeneratorPathUtil.anyMatch;
import static com.regnosys.rosetta.translate.GeneratorPathUtil.matches;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Multimap;
import com.google.inject.Injector;
import com.regnosys.rosetta.common.translation.MappingContext;
import com.regnosys.rosetta.common.translation.MappingProcessor;
import com.regnosys.rosetta.common.translation.Path;
import com.regnosys.rosetta.translate.basic.BasicParseHandler;
import com.rosetta.model.lib.RosettaModelObjectBuilder;
import com.rosetta.model.lib.path.RosettaPath;
/**
* RosettaModelObject parse handler.
*
* Note: ROM is a misspelt acronym for Rosetta Model Object.
*/
public abstract class ROMParseHandler extends ParseHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(ROMParseHandler.class);
private final Map> conditionPathCache = new HashMap<>();
public static
void evaluateConditionalPaths(ROMParseHandler rmoXmlParseHandler,
HandlerCache underlyers,
Consumer> setter,
Collection path) {
rmoXmlParseHandler.evaluateConditionalPaths(underlyers, setter, path);
}
protected final Injector injector;
protected final MappingContext mappingContext;
protected Multimap, HandlerSupplier> handlers;
protected Multimap, MappingProcessorSupplier> mappingProcessors;
private T underlying;
public ROMParseHandler(Injector injector, MappingContext mappingContext) {
this.rosettaPath = new Path();
this.injector = injector;
this.mappingContext = mappingContext;
}
public T getUnderlying() {
return underlying;
}
public void setUnderlying(T underlying) {
this.underlying = underlying;
}
@SuppressWarnings("unchecked")
protected > H findOrNew(HandlerCache underlyers,
String attribute,
Path fullPath,
Supplier supplier) {
return (H) underlyers.getOrCreateHandler(attribute, fullPath, supplier);
}
protected List toStrings(Path path) {
return path.getElements().stream()
.map(p -> p.getPathName())
.collect(Collectors.toList());
}
public Collection> getMappingProcessorForPath(Path localPath,
Path parentPath,
MappingContext mappingContext) {
return mappingProcessors.get(toStrings(localPath)).stream()
.map(mp -> mp.apply(parentPath, mappingContext))
.collect(Collectors.toList());
}
public Collection> getMappingProcessorMatchPaths() {
return mappingProcessors.keySet();
}
public Collection> getHandlerMatchPaths() {
return handlers.keySet();
}
public Collection getHandlersForPath(Path localPath, Path parentPath) {
return handlers.get(toStrings(localPath)).stream()
.map(h -> h.apply(localPath, parentPath))
.collect(Collectors.toList());
}
protected H useOrNew(H handlerField, Supplier supplier) {
if (handlerField == null) {
H handler = supplier.get();
return handler;
}
return handlerField;
}
protected void evaluateConditionalPaths(HandlerCache underlyers,
Consumer> setter,
Collection conditionalPaths) {
evaluateConditionalPaths(underlyers, setter, conditionalPaths, a -> true);
}
protected void evaluateConditionalPaths(ROMParseHandler underlyer,
Set xmlPathsToHere,
Consumer> setter,
List conditionalPaths) {
evaluateConditionalPaths(underlyer, xmlPathsToHere, setter, conditionalPaths.stream()
.map(p -> Path.parse(p))
.collect(Collectors.toList()), a -> true);
}
protected void evaluateConditionalPaths(HandlerCache underlyers,
Consumer> setter,
Collection conditionalPaths,
Predicate> additionalTest) {
for (ROMParseHandler handler : underlyers.getAllHandlers()) {
if (matches(handler.getXmlPathsToHere(), conditionalPaths) && additionalTest.test(handler.getXmlPathsToHere())) {
setter.accept(handler);
}
}
}
protected void evaluateConditionalPaths(ROMParseHandler handler,
Set xmlPathsToHere,
Consumer> setter,
List conditionalPaths,
Predicate> additionalTest) {
if (handler != null && xmlPathsToHere.stream().anyMatch(p -> anyMatch(p, conditionalPaths)) && additionalTest.test(handler.getXmlPathsToHere())) {
setter.accept(handler);
}
}
protected void useConditionalCache(BasicParseHandler handler, Path path, Map values) {
handler.setParentSetter(v -> values.put(path, v));
handler.setParentSupplier(() -> Optional.ofNullable(values.get(path)));
}
protected boolean areEqual(String a, String b) {
if (a == null) return b == null;
return a.equals(b);
}
protected boolean areEqual(String a, Boolean b) {
if (a == null) return b == null;
return Boolean.valueOf(a).equals(b);
}
protected boolean areEqual(Boolean b, String a) {
return areEqual(a, b);
}
protected boolean areEqual(String a, Integer b) {
if (a == null) return b == null;
return Integer.valueOf(a).equals(b);
}
protected boolean areEqual(Integer b, String a) {
return areEqual(a, b);
}
protected static class AnonHandler extends ROMParseHandler {
public AnonHandler(Injector injector, MappingContext mappingContext, Path rosettaPath, T underlying) {
super(injector, mappingContext);
this.rosettaPath = rosettaPath;
setUnderlying(underlying);
}
}
protected int getMappingListIndex(Collection> listAttribute, List mergeSynonyms) {
if (!mergeSynonyms.isEmpty()) {
// Merge (e.g. map onto same list item, rather than create new list item), unless excluded path
List excludedPathElements = mergeSynonyms.stream()
.map(MergeSynonymValue::getExcludePath)
.collect(Collectors.toList());
boolean excludedPath = getXmlPathsToHere().stream()
.flatMap(synPath -> synPath.getElements().stream())
.map(Path.PathElement::getPathName)
.anyMatch(pathElementName -> excludedPathElements.contains(pathElementName));
// If excluded, use index of the list size (e.g. map on to a new list item at the end of the list)
// If included, use index of the list size minus one (e.g. map on to the last existing item of the list)
return Math.max(0, sizeOf(listAttribute) - (excludedPath ? 0 : 1));
}
// if not merge synonym is specified then always create a new list item
return sizeOf(listAttribute);
}
/**
* I'm not sure if getting the last path is the correct thing to do, but there should be only one path for this.
*
* @param synonymPaths - the synonym paths to this attribute (not including what is inside [synonym value="..."]
* @param synonymValue - the synonym path specified inside the attribute synonym [synonym value="..."] - dot separated string representing path
* @return the last synonym path and the synonym value combined
*/
protected String getSynonymPathForConditionFunc(Set synonymPaths, String synonymValue) {
Iterator iterator = synonymPaths.iterator();
Path lastPath = null;
while (iterator.hasNext()) {
lastPath = iterator.next();
}
if (lastPath != null) {
Path fullPath = lastPath.append(Path.parse(synonymValue));
return formatPathWithNoIndexesAndSeparators(fullPath);
}
return ""; // top level
}
protected String formatPathWithNoIndexesAndSeparators(Path path) {
return path.getElements().stream()
.map(e -> e.getPathName())
.collect(Collectors.joining("->"));
}
// for backwards compatibility
protected String getValueFromConditionPath(String... conditionPathEndsWith) {
return Optional.ofNullable(getValuesFromConditionPath(conditionPathEndsWith))
.flatMap(values -> values.stream().findFirst())
.orElse(null);
}
protected List getValuesFromConditionPath(String... conditionPathEndsWith) {
if (conditionPathEndsWith == null || conditionPathEndsWith.length == 0) {
return null;
}
String conditionPathEndsWithAsStr = Arrays.toString(conditionPathEndsWith);
return conditionPathCache.computeIfAbsent(Arrays.toString(conditionPathEndsWith), key -> {
List values = mappingContext.getMappings().stream()
.filter(m -> m.getXmlValue() != null)
.filter(m -> m.getXmlPath().endsWith(conditionPathEndsWith))
.map(m -> m.getXmlValue())
.map(o -> String.valueOf(o))
.distinct()
.collect(Collectors.toList());
LOGGER.debug("Condition-func path {} found values {}", conditionPathEndsWithAsStr, values);
return values;
});
}
public Injector getInjector() {
return injector;
}
public MappingContext getMappingContext() {
return mappingContext;
}
}