![JAR search and dependency download from the Maven repository](/logo.png)
com.regnosys.rosetta.translate.ParserParent Maven / Gradle / Ivy
package com.regnosys.rosetta.translate;
import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.xml.validation.Schema;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.regnosys.rosetta.common.hashing.ReferenceConfig;
import com.regnosys.rosetta.common.hashing.ScopeReferenceHelper;
import com.regnosys.rosetta.common.translation.Mapping;
import com.regnosys.rosetta.common.translation.MappingProcessorStep;
import com.regnosys.rosetta.common.translation.Path;
import com.regnosys.rosetta.common.util.PathUtils;
import com.regnosys.rosetta.common.util.SimpleBuilderProcessor;
import com.regnosys.rosetta.translate.ParserResult.Context;
import com.rosetta.model.lib.GlobalKey;
import com.rosetta.model.lib.GlobalKey.GlobalKeyBuilder;
import com.rosetta.model.lib.RosettaModelObject;
import com.rosetta.model.lib.RosettaModelObjectBuilder;
import com.rosetta.model.lib.meta.FieldWithMeta;
import com.rosetta.model.lib.meta.Key;
import com.rosetta.model.lib.meta.Reference.ReferenceBuilder;
import com.rosetta.model.lib.meta.ReferenceWithMeta.ReferenceWithMetaBuilder;
import com.rosetta.model.lib.path.RosettaPath;
import com.rosetta.model.lib.process.AttributeMeta;
// TODO there is a lot more common code in the xml and json parsers that can be factored out
public abstract class ParserParent {
private static final Logger LOGGER = LoggerFactory.getLogger(ParserParent.class);
private static final Path EMPTY_SCOPE = Path.valueOf("emptyScope");
protected final HandlerFactory factory;
protected final SynonymToEnumMapBuilder synonymToEnumMap;
private final ReferenceConfig referenceConfig;
public ParserParent(HandlerFactory factory, SynonymToEnumMapBuilder synonymToEnumMap, ReferenceConfig referenceConfig) {
this.factory = factory;
this.synonymToEnumMap = synonymToEnumMap;
this.referenceConfig = referenceConfig;
}
public ParserResult parseDocument(Reader xml, Schema schema, Class returnClass) {
ParserResult resultDoc = parseTheDocument(xml, schema, returnClass);
if (resultDoc.getRosettaInstance()!=null) {
LOGGER.debug("About to run conditional mapping post processor");
resultDoc.getRosettaInstance().process(new RosettaPath.NullPath(), new SimpleBuilderProcessor() {
//conditionals are evaluated in the process method so evaluate them now by passing in an empty processor
@Override
public Report report() {
return null;
}
@Override
public boolean processRosetta(RosettaPath path, Class rosettaType,
RosettaModelObjectBuilder builder, RosettaModelObjectBuilder parent, AttributeMeta... metas) {
return true;
}
});
LOGGER.debug("Finished running conditional mapping post processor");
}
Optional.ofNullable(resultDoc.getRosettaInstance())
.ifPresent(builder -> {
Context context = resultDoc.getContext();
new MappingProcessorStep(context.getMappingProcessors().values(), context.getMappingContext())
.runProcessStep(returnClass, builder);
});
if (resultDoc.getRosettaInstance()!=null) {
postProcessReferences(resultDoc);
}
return resultDoc;
}
private void postProcessReferences(ParserResult resultDoc) {
RosettaModelObjectBuilder rosettaInstance = resultDoc.getRosettaInstance();
// Find all keyed objects and their model path in result object
KeyedCollector keyCollector = new KeyedCollector(referenceConfig);
rosettaInstance.process(new RosettaPath.NullPath(), keyCollector);
Map> modelPathToKeyMap = keyCollector.helper.getScopeToDataMap();
Map> keyPathToValueTypeMap = keyCollector.keyPathToTypeMap;
// Find all referenced objects and their model path in result object
ReferenceCollector referenceCollector = new ReferenceCollector(referenceConfig);
rosettaInstance.process(new RosettaPath.NullPath(), referenceCollector);
Map> referencePathToTypeMap = referenceCollector.referencePathToTypeMap;
modelPathToKeyMap.entrySet().forEach(entry -> {
Path currentScopePath = entry.getKey();
Map scopedModelPathToKeyMap = entry.getValue();
LOGGER.info("Building key/references for scope {}", currentScopePath);
// Generate key based on type and counter
Map typeCounters = new HashMap<>();
scopedModelPathToKeyMap.entrySet()
.forEach(k -> updateKeyBuilder(k.getKey(), k.getValue(), typeCounters));
// Find all Reference objects in mappings - builds map of xmlPath->referenceBuilder
List mappings = resultDoc.getContext().getMappingContext().getMappings();
Multimap, ReferenceBuilder> references = findReferences(mappings, currentScopePath);
LOGGER.debug("Found reference model paths {}", references.keySet());
// Find keys with a synonym path that matches the reference, and copy the key label on to the reference
references.entries()
.forEach(r -> {
Path referenceSynonymPath = r.getKey().getLeft();
Path referenceModelPath = r.getKey().getRight();
ReferenceBuilder referenceBuilder = r.getValue();
Class> referenceValueType = referencePathToTypeMap.get(referenceModelPath);
if (referenceValueType != null) {
updateReferenceBuilder(referenceSynonymPath, referenceModelPath, referenceBuilder, referenceValueType, mappings, scopedModelPathToKeyMap, keyPathToValueTypeMap);
} else {
LOGGER.debug("Path {} not found in reference model paths {}", referenceModelPath, referencePathToTypeMap.keySet());
}
});
});
}
/**
* Generate key label and set it on keyBuilder object.
*/
private void updateKeyBuilder(Path keyModelPath, GlobalKey.GlobalKeyBuilder keyBuilder, Map typeCounters) {
// Generate key label
String name = keyModelPath.getLastElement().getPathName();
Integer counter = typeCounters.compute(name, (n, i) -> i == null ? 1 : i + 1);
String label = name + "-" + counter;
// Update key object
keyBuilder.getMeta().getKey().stream()
.filter(k -> "DOCUMENT".equals(k.getScope()))
.forEach(k -> {
LOGGER.debug("Adding key {} for model path [{}]", label, keyModelPath);
k.setKeyValue(label);
});
}
/**
* Find keys with a synonym path that matches the reference, and copy the key label on to the reference.
*
* For the given referenceBuilder object:
* - find all the mappings that match the reference synonym path (e.g. all the mappings that are mapped to the same external document field)
* - from those mappings, look up the key in the modelPathToKeyMap
* - copy the key label on to the reference
*/
private void updateReferenceBuilder(Path referenceSynonymPath,
Path referenceModelPath,
ReferenceBuilder referenceBuilder,
Class> referenceValueType,
List mappings,
Map modelPathToKeyMap,
Map> keyPathToValueTypeMap) {
// Find mappings with a synonym path that matches this reference
List mappingsWithReferenceSynonymPath = mappings.stream()
.filter(m -> m.getXmlPath().equals(referenceSynonymPath))
.filter(m -> m.getRosettaPath() != null && m.getError() == null)
.collect(Collectors.toList());
for (Mapping mappingWithReferenceSynonymPath : mappingsWithReferenceSynonymPath) {
Path modelPath = mappingWithReferenceSynonymPath.getRosettaPath();
// For each mapping (that has the reference synonym path), find the corresponding key (by matching on model path)
for (Entry keyed : modelPathToKeyMap.entrySet()) {
Class> keyType = keyPathToValueTypeMap.get(keyed.getKey());
if (!referenceValueType.equals(keyType)) {
LOGGER.trace("Key and reference types do no match [referenceType {}, keyType {}]", referenceValueType.getName(), keyType.getName());
continue;
}
Path keyModelPath = keyed.getKey().prefixWithWildcard();
if (keyModelPath.fullStartMatches(modelPath, true)) {
// Once the corresponding key has been found, copy the label from the key to the reference mapping
GlobalKeyBuilder keyBuilder = keyed.getValue();
Key key = keyBuilder.getOrCreateMeta().getKey().stream()
.filter(k -> "DOCUMENT".equals(k.getScope()))
.findFirst().get();
String label = key.getKeyValue();
LOGGER.debug("Setting reference {} for type {} at path {}", label, referenceValueType.getName(), referenceModelPath);
referenceBuilder.setReference(label);
referenceBuilder.setScope("DOCUMENT");
}
}
}
}
private Multimap, ReferenceBuilder> findReferences(List mappings, Path scopePath) {
Optional filterPath = Optional.ofNullable(!scopePath.equals(EMPTY_SCOPE) ? scopePath.prefixWithWildcard() : null);
return mappings.stream()
.filter(m->(m.getRosettaValue() instanceof ReferenceBuilder))
// filter to mappings that are inside the scope path (or do not filter if empty scope)
.filter(m -> filterPath.map(p -> p.fullStartMatches(m.getRosettaPath(), true)).orElse(true))
.collect(Multimaps.toMultimap(
m->Pair.of(m.getXmlPath(), m.getRosettaPath().trimFirst()),
m->(ReferenceBuilder)m.getRosettaValue(),
ArrayListMultimap::create));
}
private static class KeyedCollector extends SimpleBuilderProcessor {
private final Map> keyPathToTypeMap;
private final ScopeReferenceHelper
© 2015 - 2025 Weber Informatics LLC | Privacy Policy