com.regnosys.rosetta.translate.synonymmap.CardinalityChecker Maven / Gradle / Ivy
package com.regnosys.rosetta.translate.synonymmap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import org.eclipse.xtext.xbase.lib.Pair;
import com.codahale.metrics.Timer;
import com.codahale.metrics.Timer.Context;
import com.regnosys.rosetta.translate.IngesterGenerator;
import com.regnosys.rosetta.translate.MappingError;
import com.regnosys.rosetta.translate.datamodel.Attribute;
import com.regnosys.rosetta.translate.datamodel.Cardinality;
import com.regnosys.rosetta.translate.datamodel.Entity;
import com.regnosys.rosetta.translate.datamodel.EntityImpl;
import com.regnosys.rosetta.translate.datamodel.NamespaceName;
public class CardinalityChecker {
private final static Logger LOGGER = Logger.getLogger(CardinalityChecker.class.getName());
public ListcheckCardinalities(List synonyms) {
Timer timer = IngesterGenerator.GENERATOR_METRICS.timer("checking cardinality");
Context time = timer.time();
Set> checked = new HashSet<>();
LOGGER.trace("Checking cardinality");
Entity top = new EntityImpl(new NamespaceName("top", "TopLevel"), false);
List errors = synonyms.stream().flatMap(s->validCardinalities(s, top, checked).stream()).collect(Collectors.toList());
time.stop();
return errors;
}
private List validCardinalities(SynonymMap s, Entity parentEntity, Set> checked) {
Pair key = new Pair<>(s, parentEntity);
if (checked.contains(key)) return Collections.emptyList();
checked.add(key);
List errors = new ArrayList<>();
for (AttributeGroupMapping mappedGroups : s.getMappedGroups()) {
long rosettaCardinality = mappedGroups.getGroup().getAttributePath().stream().filter(ra -> ra.isMultiple()).count();
for (SynonymGroup sg : mappedGroups.getGroup().getSynonymGroups()) {
for (SynonymValue path : sg.getSynonymValues()) {
long synonymCardinality = getCardinality(parentEntity, path.getSynonymPath());
if (rosettaCardinality>1 && synonymCardinality>0) {
errors.add(new MappingError(MappingError.MappingErrorLevel.WARNING,
"Ambiguous cardinality choices for path " + s.getRosetta().getName() + ":" +
mappedGroups.getGroup().attsToString() + " matching " + path.getSynonymPath().toString()));
} else if (synonymCardinality>=1 && rosettaCardinality==0) {
errors.add(new MappingError(MappingError.MappingErrorLevel.ERROR,
"Invalid cardinality choices for "+ s.getRosetta().getName() +":XSD " +
toPath(parentEntity, path) +" is multiple while Rosetta " +
toPath(s, mappedGroups.getGroup().attsToString()) + " is single "));
}
Entity last = path.getSynonymPath().get(path.getSynonymPath().size()-1).getEntity();
errors.addAll(validCardinalities(mappedGroups.getMappings(), last, checked));
}
}
}
return errors;
}
private String toPath(Entity parentEntity, SynonymValue path) {
StringBuilder builder = new StringBuilder();
builder.append(Optional.ofNullable(parentEntity).map(Entity::getName).map(Object::toString).orElse(""));
for (Element el:path.getSynonymPath()) {
builder.append("->");
builder.append(el.getName());
}
return builder.toString();
}
private String toPath(SynonymMap s, String attsToString) {
StringBuilder builder = new StringBuilder();
builder.append(s.getRosetta().getName());
builder.append("->");
builder.append(attsToString);
return builder.toString();
}
private long getCardinality(Entity parentEntity, List path) {
Entity ent = parentEntity;
long card=0;
for (Element e:path) {
if (ent!=null) {
Optional findFirst = ent.getAllPossibleAttributes().filter(att->att.getName().equals(e.getName())).findFirst();
if (!findFirst.isPresent()) {
return 0;//This path is not valid from this starting entity so its cardinality is effectively 0 (but it might be from another)
}
Attribute link = findFirst.get();
if (link.getCardinality()==Cardinality.MULTIPLE) {
card++;
}
}
ent = e.getEntity();
}
return card;
}
}