All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.regnosys.rosetta.translate.synonymmap.SynonymMapBuilder Maven / Gradle / Ivy

There is a newer version: 11.35.2
Show newest version
package com.regnosys.rosetta.translate.synonymmap;

import static com.regnosys.rosetta.generator.util.RosettaAttributeExtensions.getExpandedAttributes;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import org.apache.log4j.Logger;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.util.Strings;

import com.codahale.metrics.Timer;
import com.codahale.metrics.Timer.Context;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.regnosys.rosetta.common.util.StreamUtils;
import com.regnosys.rosetta.generator.java.RosettaJavaPackages;
import com.regnosys.rosetta.generator.java.types.JavaTypeTranslator;
import com.regnosys.rosetta.generator.java.types.JavaTypeUtil;
import com.regnosys.rosetta.generator.object.ExpandedAttribute;
import com.regnosys.rosetta.generator.object.ExpandedSynonym;
import com.regnosys.rosetta.generator.object.ExpandedSynonymValue;
import com.regnosys.rosetta.generator.object.ExpandedType;
import com.regnosys.rosetta.generator.util.RosettaAttributeExtensions;
import com.regnosys.rosetta.rosetta.ExternalValueOperator;
import com.regnosys.rosetta.rosetta.RosettaClassSynonym;
import com.regnosys.rosetta.rosetta.RosettaEnumeration;
import com.regnosys.rosetta.rosetta.RosettaExternalClassSynonym;
import com.regnosys.rosetta.rosetta.RosettaExternalEnumValue;
import com.regnosys.rosetta.rosetta.RosettaExternalRegularAttribute;
import com.regnosys.rosetta.rosetta.RosettaExternalSynonymSource;
import com.regnosys.rosetta.rosetta.RosettaFactory;
import com.regnosys.rosetta.rosetta.RosettaMappingInstance;
import com.regnosys.rosetta.rosetta.RosettaMergeSynonymValue;
import com.regnosys.rosetta.rosetta.RosettaModel;
import com.regnosys.rosetta.rosetta.RosettaNamed;
import com.regnosys.rosetta.rosetta.RosettaRootElement;
import com.regnosys.rosetta.rosetta.RosettaType;
import com.regnosys.rosetta.rosetta.RosettaTypeAlias;
import com.regnosys.rosetta.rosetta.TypeCall;
import com.regnosys.rosetta.rosetta.simple.AnnotationRef;
import com.regnosys.rosetta.rosetta.simple.Attribute;
import com.regnosys.rosetta.rosetta.simple.Data;
import com.regnosys.rosetta.rosetta.simple.SimpleFactory;
import com.regnosys.rosetta.translate.IngesterGenerator;
import com.regnosys.rosetta.translate.datamodel.NamespaceName;
import com.regnosys.rosetta.types.TypeSystem;
import com.regnosys.rosetta.types.builtin.RBuiltinTypeService;
import com.rosetta.util.DottedPath;
import com.rosetta.util.types.JavaClass;
import com.rosetta.util.types.JavaReferenceType;
import com.rosetta.util.types.generated.GeneratedJavaClass;

public class SynonymMapBuilder {

	private static final Logger LOGGER = Logger.getLogger(SynonymMapBuilder.class);

	private final List externalSynonyms;
	private final Collection synonymSourceNames;

	private final JavaTypeTranslator typeTranslator; // TODO: inject instead
	private final RosettaJavaPackages packages; // TODO: inject instead
	private final JavaTypeUtil typeUtil;
	private final TypeSystem typeSystem;
	private final RBuiltinTypeService builtins;

	private Map typeCache;

	public SynonymMapBuilder(String synonymSourceName, JavaTypeTranslator typeTranslator) {
		this(Collections.singletonList(synonymSourceName), Collections.emptyList(), typeTranslator);
	}

	public SynonymMapBuilder(Collection synonymSourceNames, List externalSynonyms, JavaTypeTranslator typeTranslator) {
		this(synonymSourceNames, externalSynonyms, null, typeTranslator);
	}

	public SynonymMapBuilder(Collection synonymSourceNames, List externalSynonyms, Map typeCache, JavaTypeTranslator typeTranslator) {
		this.synonymSourceNames = synonymSourceNames;
		this.externalSynonyms = externalSynonyms;
		this.typeCache = typeCache;
		this.typeTranslator = typeTranslator;
		this.packages = getPrivateField(typeTranslator, "packages");
		this.typeUtil = getPrivateField(typeTranslator, "typeUtil");
		this.typeSystem = getPrivateField(typeTranslator, "typeSystem");
		this.builtins = getPrivateField(typeTranslator, "builtins");
	}
	// Hackery
	@SuppressWarnings("unchecked")
	private  T getPrivateField(Object owner, String field) {
		Field f;
		try {
			f = owner.getClass().getDeclaredField(field);
		} catch (NoSuchFieldException | SecurityException | IllegalArgumentException e) {
			try {
				f = owner.getClass().getSuperclass().getDeclaredField(field);
			} catch (NoSuchFieldException | SecurityException e1) {
				throw new RuntimeException(e);
			}
		}
		f.setAccessible(true);
		try {
			return (T)f.get(owner);
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}

	public SynonymMap buildMap(RosettaType topClass) {
		Timer timer = IngesterGenerator.GENERATOR_METRICS.timer("Building synoym map");
		Context time = timer.time();
		if (topClass==null) {
			return null;
		}
		Map maps = new HashMap<>();
		Map enumMaps = new HashMap<>();
		SynonymMap buildMap = buildMap(topClass, maps, enumMaps);
		time.stop();

		return buildMap;
	}


	public SynonymMap buildMap(RosettaType topType, Map classMaps,
							   Map enumMaps) {
		if (topType==null) return null;

		topType = resolveType(topType);
		if (classMaps.containsKey(topType)) {
			return classMaps.get(topType);
		}
		if (enumMaps.containsKey(topType)) {
			return enumMaps.get(topType);
		}

		if (topType instanceof Data) {
			LOGGER.trace("building map for "+topType.getName());
			Data topClass = (Data) topType;
			Data superType = topClass.getSuperType();
			SynonymMap result = classMaps.get(topType);
			if (result == null) {
				result = new SynonymMap(topClass, buildMap(superType, classMaps, enumMaps));
				classMaps.put(topClass, result);
			}
			Map mappings = buildMappings(topClass, 
					Collections.emptyList(), 
					classMaps, 
					enumMaps, 
					false, 
					Collections.emptySet(),
					HashMultimap.create());
			result.addMappings(mappings);

			Multimap conditionCaptures = findCaptures(mappings);
			result.getConditionalCaptures().putAll(conditionCaptures);
			return result;
		}
		else if (topType instanceof RosettaEnumeration) {
			LOGGER.trace("building enum map for "  +topType.getName());
			RosettaEnumeration rEnum = (RosettaEnumeration)topType;
			SynonymMap result = enumMaps.get(topType);
			if (result == null) {
				result = new SynonymMap(rEnum, buildMap(rEnum.getParent(), classMaps, enumMaps));
				enumMaps.put(rEnum, result);
			}
			Map buildMappings = buildEnumMappings(rEnum, Collections.emptyList());
			result.addMappings(buildMappings);
			return result;

		}
		else if (topType instanceof RosettaTypeAlias) {
			return buildMap(((RosettaTypeAlias)topType).getTypeCall().getType(), classMaps, enumMaps);
		}
		else {
			return new SynonymMap();
		}
	}

	private Multimap findCaptures(Map mappings) {
		ArrayListMultimap res = ArrayListMultimap.create();
		//find all the conditional paths that need capturing inside this classes mappings
		for (AttributeGroup pp:mappings.keySet()) {
			for (SynonymGroup sg:pp.getSynonymGroups()) {
				for (SynonymCondition cond:sg.getConditions()) {
					for (SynonymTest test:cond.getCondition()) {
						for (SynonymValue val:test.getPaths()) {
							res.put(val, cond);
						}
					}
				}
			}
		}
		return res;
	}

	private Map buildEnumMappings(RosettaEnumeration rEnum, List attPath) {
		Map result = new HashMap<>();
		for (ExpandedAttribute enumVal:getAllEnumValue(rEnum)) {
			List enumPath = new ArrayList<>(attPath);
			enumPath.add(enumVal);

			List enumSyns = getEnumSynonyms(enumVal);

			List groups = enumSyns.stream().map(s->toGroup(s, rEnum.getModel().getName())).collect(Collectors.toList());
			result.put(new AttributeGroup(groups, enumPath), new SynonymMap((RosettaType)null));
		}
		return result;
	}

	public List getEnumSynonyms(ExpandedAttribute enumVal) {
		List enumSyns = enumVal.getSynonyms().stream()
				.filter(s-> sourcesMatch(s))
				.collect(Collectors.toList());
		
		List copy = new ArrayList<>(externalSynonyms);
		Collections.reverse(copy);
		
		// loop through ext syn srcs from top of heirarchy to bottom
		copy.forEach(extSynSrc -> {
			LOGGER.trace("External Synonym src: " + extSynSrc.getName());

			List externalAttributes = getRosettaExternalEnums(enumVal.getEnclosingType(), enumVal, extSynSrc);
			List additions = externalAttributes.stream().filter(x -> x.getOperator().equals(ExternalValueOperator.PLUS)).collect(Collectors.toList());
			List removals = externalAttributes.stream().filter(x -> x.getOperator().equals(ExternalValueOperator.MINUS)).collect(Collectors.toList());

			enumSyns.removeIf(s -> removals.stream()
									.map(c -> c.getEnumRef())
									.map(c -> c.getName())
									.anyMatch(n -> n.equals(enumVal.getName())));

			// add in extra mappings from a mapping file
			enumSyns.addAll(addExternalEnumSynonyms(additions));
		});
		return enumSyns;
	}

	private Map buildMappings(RosettaType clazz, 
														  List attPath,
														  Map maps, 
														  Map enumMaps, 
														  boolean includeSupers,
														  Collection alreadySearched,
														  Multimap attMergeSyns) {

		Map result = new HashMap<>();
		Collection searchAttributes = new ArrayList<>();

		List copy = new ArrayList<>(externalSynonyms);
		Collections.reverse(copy);
		
		if(clazz instanceof Data) {
			searchAttributes = getAllAttributes((Data)clazz, includeSupers);
			Data data = (Data)clazz;
			if (data.getAnnotations() != null && data.getAnnotations().stream()
					.map(AnnotationRef::getAttribute)
					.filter(Objects::nonNull)
					.map(Attribute::getName)
					.filter(Objects::nonNull)
					.anyMatch(a->a.equals("key"))) {
				addKeySynonyms(
						data.getSynonyms().stream().filter(s->sourcesMatch(s)).collect(Collectors.toList()), 
						getRosettaExternalClassSynonyms(clazz.getName()), 
						attPath, 
						result);
			}
			if (data.getSuperType()!=null && ! includeSupers) {
				searchAttributes.addAll(addsSynonyms(copy, searchAttributes, (Data)clazz));
			}
		}
		

		for (ExpandedAttribute att: searchAttributes) {
			List newPath = new ArrayList<>(attPath);//the path of attributes we have recursed down in order to find synonyms

			if (att.hasMetas()) {
				if (att.refIndex()>=0) {
					//This could be a reference or a value - add the path to map the value
					newPath.add(referenceTo(att));
					newPath.add(metadFieldValue(att));
				}
				else {
					newPath.add(metadField(att));
					newPath.add(metadFieldValue(att));
				}
			}
			else {
				newPath.add(att);
			}
			
			List allAttSyns = att.getSynonyms().stream()
					.filter(s->sourcesMatch(s))
					.collect(Collectors.toList());
			
			// Updates allAttSyns with external synonyms, and returns the delta
			List delta = getSynonymDeltas(att, allAttSyns, copy, clazz);
			
			// exclude any merge syns
			List attSyns = allAttSyns.stream()
					.filter(s->s.getMerge() == null)
					.collect(Collectors.toList());
			
			// include only merge syns
			List mergeSyns = allAttSyns.stream()
					.map(s->s.getMerge())
					.filter(Objects::nonNull)
					.collect(Collectors.toList());
			if (!mergeSyns.isEmpty()) {
				attMergeSyns.putAll(att, mergeSyns);
			}

            TypeCall tc = att.getRosettaType();
            RosettaType type = null;
            if (tc != null) {
                type = tc.getType();
            }
			//TODO check ExpandedType usage
			if (!attSyns.isEmpty()) {
				List groups = attSyns.stream()
						.map(s->toGroup(s, clazz.getModel().getName()))
						.collect(Collectors.toList());

				if (!groups.isEmpty()) {
					SynonymMap map = buildMap(type, maps, enumMaps);
					
					if (!attMergeSyns.isEmpty()) {
						// merge synonyms indicate any mappings for that synonym/attribute should be added to same list item (rather than create a new list item)
						List attMergeSynValues = attMergeSyns.values().stream()
								.map(RosettaMergeSynonymValue::getName)
								.collect(Collectors.toList());
						// determine if the merge synonym matches any of the synonym paths mapped to the current attribute
						boolean matchesSyn = groups.stream()
							.flatMap(group -> group.getSynonymValues().stream())
							.flatMap(synValue -> synValue.getSynonymPath().stream())
							.map(Element::getName)
							.anyMatch(attMergeSynValues::contains);
						// add to the attribute's synonym path
						if (matchesSyn) {
							map.getMergeSynonyms().putAll(attMergeSyns);	
						}
					}
					
					result.put(new AttributeGroup(groups, newPath), map);
				}
				
				if (att.hasMetas()) {
					Map metaSynonyms = metaSynonyms(att, newPath.subList(0, newPath.size()-1), delta, clazz.getModel().getName());
					result.putAll(metaSynonyms);
				}
				
				List hints = attSyns.stream().flatMap(s->s.getHints().stream()).collect(Collectors.toList());
				//this attribute has a hint - that means we search inside it for synonyms starting with the hint
				if (!hints.isEmpty() && type instanceof Data) {
					if (!alreadySearched.contains(type)) {
						Collection searched = new HashSet<>(alreadySearched);
						RosettaType attClazz = type;
						searched.add(attClazz);
						Map hintMappings = buildMappings(attClazz, newPath, maps, enumMaps, true, searched, attMergeSyns);
						hintMappings = filtertoHinted(hintMappings, hints);
						result.putAll(hintMappings);
					}
				}

			}
			else {
				//this attribute has no synonyms - search inside it for synonyms instead
				if (type instanceof Data && att.refIndex()<0) {
					if (!alreadySearched.contains(type)) {
						Collection searched = new HashSet<>(alreadySearched);
						RosettaType attClazz = type;
						searched.add(attClazz);
						result.putAll(buildMappings(attClazz, newPath, maps, enumMaps, true, searched, attMergeSyns));
					}
				}
				else {
					//a basic type with no mapping - ignore it
				}
			}
		}
		return result;
	}

	//add in the attributes from super classes for which the external synonyms have added a mapping in this class
	private Collection addsSynonyms(List copy, Collection searchAttributes, Data clazz) {
		//get all possible additional attributes from super classes
		Collection allSuperAttributes = getAllAttributes(clazz.getSuperType(), true);
		return copy.stream().flatMap(extSynSrc ->{
			//for each external source
			//for each possible addition attribute
			return allSuperAttributes.stream()
			//find the external synonyms added to that attribute
				.filter(a -> addsASynonym(a, extSynSrc, clazz));
			//if they exist then return this attribute
		}).collect(Collectors.toSet());
	}
	
	private boolean addsASynonym(ExpandedAttribute att, RosettaExternalSynonymSource extSynSrc, Data clazz) {

		List externalSynonymsForType = getRosettaExternalRegularAttributes(clazz, att, extSynSrc, false);
		boolean additions = externalSynonymsForType.stream().anyMatch(x->x.getOperator().equals(ExternalValueOperator.PLUS));
		return additions;
	}

	public List getSynonymDeltas(ExpandedAttribute att, List attSyns,
			List copy, RosettaType clazz) {
		List delta = new ArrayList<>();
		
		// loop through ext syn srcs from top of hierarchy to bottom
		copy.forEach(extSynSrc -> {
			LOGGER.trace("External Synonym src: " + extSynSrc.getName());
			
			List externalAttributes = getRosettaExternalRegularAttributes(clazz, att, extSynSrc, true);
			List additions = externalAttributes.stream().filter(x -> x.getOperator().equals(ExternalValueOperator.PLUS)).collect(Collectors.toList());
			List removals = externalAttributes.stream().filter(x -> x.getOperator().equals(ExternalValueOperator.MINUS)).collect(Collectors.toList());
			
			delta.removeIf(s -> removals.stream()
									.map(c -> c.getAttributeRef())
									.map(c -> c.getName())
									.anyMatch(n -> n.equals(att.getName())));
			delta.addAll(additions);
			
			attSyns.removeIf(s -> removals.stream()
									.map(c -> c.getAttributeRef())
									.map(c -> c.getName())
									.anyMatch(n -> n.equals(att.getName())));
			
			//add in extra mappings from a mapping file
			attSyns.addAll(addExternalSynonyms(additions));
		});
		return delta;
	}

	private void addKeySynonyms(List synonyms, List externalSynonyms, List attPath, Map result) {

		List synonymGroups = new ArrayList<>();
		
		// inline synonyms
		List expandedSynonyms = synonyms.stream()
				.filter(syn -> syn.getMetaValue()!=null)
				.map(RosettaAttributeExtensions::toRosettaExpandedSynonym)
				.collect(Collectors.toList());
		// external synonyms
		expandedSynonyms.addAll(externalSynonyms.stream()
				.filter(syn -> syn.getMetaValue()!=null)
				.map(RosettaAttributeExtensions::toRosettaExpandedSynonym)
				.collect(Collectors.toList()));
		
		for (ExpandedSynonym rosettaExpandedSynonym:expandedSynonyms) {
			List synonymValues = Collections.singletonList(toList(rosettaExpandedSynonym.getMetaValues().get(0)));
			SynonymGroup synGroup = new SynonymGroup(synonymValues, Collections.emptyList(), null, null, null, null, false);
			synonymGroups.add(synGroup);
		}
		
		if (!synonymGroups.isEmpty()) {
			List newPath = new ArrayList<>(attPath);
			newPath.add(metaAtt());
			newPath.add(externalKeyAtt());
			AttributeGroup attgroup = new AttributeGroup(synonymGroups, newPath);
			result.put(attgroup, new SynonymMap());
		}
	}

	private Map filtertoHinted(Map hintMappings, List hints) {
		Map result = new HashMap<>();
		for (Map.Entry entry:hintMappings.entrySet()) {
			List filteredGroups = new ArrayList<>();
			for (SynonymGroup group:entry.getKey().getSynonymGroups()) {
				List filteredValues = group.getSynonymValues().stream().filter(v->hints.contains(v.getSynonymPath().get(0).getName())).collect(Collectors.toList());
				if (!filteredValues.isEmpty()) {
					SynonymGroup filteredGroup = new SynonymGroup(filteredValues, group.getConditions(), group.getMapperName(), group.getFormatString(), group.getPatternMatcher(), group.getPatternReplace(), group.isRemoveHtml());
					filteredGroups.add(filteredGroup);
				}
				List filteredConditions = group.getConditions().stream().map(c->filteredCondition(c, hints)).filter(c->!c.getCondition().isEmpty()).collect(Collectors.toList());
				if (!filteredConditions.isEmpty()) {
					SynonymGroup filteredGroup = new SynonymGroup(Collections.emptyList(), filteredConditions, group.getMapperName(), group.getFormatString(), group.getPatternMatcher(), group.getPatternReplace(), group.isRemoveHtml());
					filteredGroups.add(filteredGroup);
				}
			}
			if (!filteredGroups.isEmpty()) {
				AttributeGroup fillteredAtt = new AttributeGroup(filteredGroups, entry.getKey().getAttributePath());
				result.put(fillteredAtt, entry.getValue());
			}
		}
		return result;
	}

	private SynonymCondition filteredCondition(SynonymCondition condition, List hints) {
		List conditions = condition.getCondition().stream().filter(t->filterTest(t, hints)).collect(Collectors.toList());
		return new SynonymCondition(condition.getSetToValue(), conditions);
	}

	private boolean filterTest(SynonymTest test, List hints) {
		return test.getPaths().stream().anyMatch(v->hints.contains(v.getSynonymPath().get(0).getName()));
	}

	private Map metaSynonyms(ExpandedAttribute att, List newPath, List externalRegularAttributes, String enclosingPackageName) {
		Map metaSynonyms = new HashMap<>();
		List metas = att.getMetas();
		for (int metaIndex = 0; metaIndex < metas.size(); metaIndex++) {
			ExpandedAttribute metaAtt = metas.get(metaIndex);
			String name = metaAtt.getName();
			List sourceSyns = metaAtt.getSynonyms().stream()
					.filter(s->sourcesMatch(s))
					.collect(Collectors.toList());
			List addExternalMetaSynonyms = findExternalMetaSynonyms(externalRegularAttributes, metaIndex);
			sourceSyns.addAll(addExternalMetaSynonyms);

			List metaPath = new ArrayList<>(newPath);
			if (name.equals("reference")) {
				metaPath.add(refField());
			}
			else if (name.equals("address")) {
				metaPath.add(addressField());
			} else {
				metaPath.add(metaAtt());
				metaPath.add(metaDataField(metaAtt));
			}
			List groups = sourceSyns.stream()
					.map(s->toGroup(s, enclosingPackageName)).collect(Collectors.toList());
			SynonymMap map = new SynonymMap((RosettaType)null);
			if (!groups.isEmpty()) {
				metaSynonyms.put(new AttributeGroup(groups, metaPath), map);
			}
		}
		return metaSynonyms;
	}

	private List findExternalMetaSynonyms(List externalRegularAttributes, int metaIndex) {

		List expandedSynonyms = new ArrayList<>();
		IntStream.range(0, externalRegularAttributes.size())
				.forEach(i -> {
					RosettaExternalRegularAttribute rosettaExternalRegularAttribute = externalRegularAttributes.get(i);
					List rosettaExpandedSynonym = RosettaAttributeExtensions.toRosettaExpandedSynonym(null,
							rosettaExternalRegularAttribute.getExternalSynonyms(), metaIndex);
					expandedSynonyms.addAll(rosettaExpandedSynonym);
				});

		return expandedSynonyms;
	}

	private List addExternalEnumSynonyms(List externalAttributes) {
		return externalAttributes.stream()
				.map(a -> a.getExternalEnumSynonyms())
				.flatMap(Collection::stream)
				// now convert to a ExpandedSynonym
				.map(RosettaAttributeExtensions::toExpandedSynonym)
				.collect(Collectors.toList());
	}
	
	private List getRosettaExternalEnums(String enclosingTypeName, ExpandedAttribute att, RosettaExternalSynonymSource extSynSrc) {
		return extSynSrc.getExternalEnums().stream()
				// filter to the clazz passed in and get its attributes
				.filter(c -> c.getTypeRef().getName().equals(enclosingTypeName))
				.map(c -> c.getRegularValues())
				.flatMap(Collection::stream)
				// filter to the att passed in and get its synonyms
				.filter(c -> c.getEnumRef().getName().equals(att.getName()))
				.collect(Collectors.toList());
	}

	private List addExternalSynonyms(List externalAttributes) {
		return externalAttributes.stream()
				.map(a -> a.getExternalSynonyms())
				.flatMap(Collection::stream)
				// now convert to a ExpandedSynonym
				.map(RosettaAttributeExtensions::toRosettaExpandedSynonym)
				.collect(Collectors.toList());
	}
	
	private List getRosettaExternalRegularAttributes(RosettaType enclosingType, ExpandedAttribute att, RosettaExternalSynonymSource extSynSrc, boolean includeSupers) {
		Set enclosingTypeNames = getEnclosingTypes(enclosingType, includeSupers).map(RosettaType::getName).collect(Collectors.toSet());
				
		return extSynSrc.getExternalClasses().stream()
				// filter to the clazz passed in and get its attributes
				.filter(c -> enclosingTypeNames.contains(c.getTypeRef().getName()))
				.map(c -> c.getRegularAttributes())
				.flatMap(Collection::stream)
				// filter to the att passed in and get its synonyms
				.filter(c -> c.getAttributeRef().getName().equals(att.getName()))
				.collect(Collectors.toList());
	}

	private Stream getEnclosingTypes(RosettaType enclosingType, boolean includeSupers) {
		if (!includeSupers) return Stream.of(enclosingType);
		if (enclosingType instanceof Data) return StreamUtils.recurse((Data)enclosingType, Data::getSuperType);
		if (enclosingType instanceof RosettaEnumeration) return StreamUtils.recurse((RosettaEnumeration)enclosingType, e->e.getParent());
		else return Stream.of(enclosingType);
	}

	private List getRosettaExternalClassSynonyms(String enclosingTypeName) {
		return externalSynonyms.stream()
				// get the external class cross ref
				.map(RosettaExternalSynonymSource::getExternalClasses)
				.flatMap(Collection::stream)
				// filter to the clazz passed in and get its class synonyms
				.filter(c -> c.getTypeRef().getName().equals(enclosingTypeName))
				.map(c -> c.getExternalClassSynonyms())
				.flatMap(Collection::stream)
				.collect(Collectors.toList());
	}
	
	private Collection getAllAttributes(Data clazz, boolean includeSupers) {
		List result = new ArrayList<>(getExpandedAttributes(clazz));
		if (clazz.getSuperType() != null && includeSupers) {
			result.addAll(getAllAttributes(clazz.getSuperType(), includeSupers));
		}
		return result;
	}

	public Collection getAllEnumValue(RosettaEnumeration rEnum) {
		if (rEnum.getParent()==null) {
			return getExpandedAttributes(rEnum);
		}
		List result = new ArrayList<>(getExpandedAttributes(rEnum));
		result.addAll(getAllEnumValue(rEnum.getParent()));
		return result;
	}

	private SynonymGroup toGroup(ExpandedSynonym synonym, String enclosingPackageName) {
		String mapperName = synonym.getMapperName()==null?null:enclosingPackageName+".processor."+synonym.getMapperName();
		if (synonym.getValues()!=null && synonym.getMetaValues()!=null) {
			return new SynonymGroup(synonym.getValues().stream().map(this::toList).collect(Collectors.toList()),
					toConditions(synonym), mapperName, synonym.getFormat(), synonym.getPatternMatcher(), synonym.getPatternReplace(), synonym.isRemoveHtml());
		}
		//this is a set to style synonym
		return new SynonymGroup(toConditions(synonym));
	}

	private List toConditions(ExpandedSynonym synonym) {
		if (synonym.getMappingLogic()==null) return Collections.emptyList();
		List instances = synonym.getMappingLogic().getInstances();
		return instances.stream().map(i->toCondition(i)).collect(Collectors.toList());
	}

	private SynonymCondition toCondition(RosettaMappingInstance instance) {
		return SynonymCondition.create(instance.getSet(),  instance.getWhen()==null?Collections.emptyList():instance.getWhen().getTests());
	}

	private SynonymValue toList(ExpandedSynonymValue value) {
		if (value.getPath()==null || value.getPath().isEmpty()) {
			return new SynonymValue(ImmutableList.of(new Element(value.getName())), value.getMaps(), value.isMeta());
		}
		List r = Element.toElementList(value.getPath());
		r.add(new Element(value.getName()));
		return new SynonymValue(r, value.getMaps(), value.isMeta());
	}

	private boolean sourcesMatch(ExpandedSynonym s) {
		return s.getSources().stream().anyMatch(ss -> synonymSourceNames.contains(ss.getName()));
	}

	private boolean sourcesMatch(RosettaClassSynonym s) {
		return s.getSources().stream().anyMatch(ss -> synonymSourceNames.contains(ss.getName()));
	}

	private  T resolveType(T typeReference) {
		if (typeCache!=null) {
			NamespaceName name = new NamespaceName(typeReference.getModel().getName(), typeReference.getName());
			RosettaNamed rosettaNamed = typeCache.get(name);
			@SuppressWarnings("unchecked")
			T result = (T) rosettaNamed;
			if (result!=null) return result;
		}
		return typeReference;
	}

	/*
	 * Methods below are moved from RosettaAttributeExtensions
	 */
	private ExpandedAttribute referenceTo(ExpandedAttribute att) {
        return new ExpandedAttribute(att.getName(), att.getEnclosingType(), RosettaAttributeExtensions.toExpandedType(referenceType(att).getType()),
				referenceType(att),
				true, // True to indicate that this is a ReferenceWithMeta
				att.getInf(), att.getSup(), att.isUnbound(),
                Collections.emptyList(), null, Collections.emptyList(), false, Collections.emptyList());
	}

	static private String toFirstUpper(String name) {
		return Strings.toFirstUpper(name);
	}

	static private ExpandedAttribute refField() {
		return new ExpandedAttribute("externalReference", null, provideStringType(), null, false, 1, 1, false, Collections.emptyList(), null, Collections.emptyList(), false, Collections.emptyList());
	}
	
	static private ExpandedAttribute addressField() {
		return new ExpandedAttribute("reference", null, new ExpandedType(null, "ReferenceBuilder", false, false, false), null, false, 1, 1, false, Collections.emptyList(), null, Collections.emptyList(), false, Collections.emptyList());
	}

	static private ExpandedAttribute metadField(ExpandedAttribute att) {
		return new ExpandedAttribute(att.getName(), 
				att.getEnclosingType(),
				RosettaAttributeExtensions.toExpandedType(metadType(att.getType()).getType()), 
				metadType(att.getType()),
				true, // True to indicate that this is a FieldWithMeta
				att.getInf(), 
				att.getSup(), 
				att.isUnbound(), 
				Collections.emptyList(), 
				null, 
				Collections.emptyList(), 
				false,
				Collections.emptyList());
	}

	static private ExpandedAttribute metadFieldValue(ExpandedAttribute att) {
		return new ExpandedAttribute("value", att.getEnclosingType(), att.getType(), att.getRosettaType(), false, 1, 1, false, Collections.emptyList(), null, Collections.emptyList(), false, Collections.emptyList());
	}

	static ExpandedAttribute metaDataField(ExpandedAttribute att) {
		String name = att.getName();
		if ("id".equals(name)) {
			name = "externalKey";//the id meta attribute is implemented as externalkey
		}
		return new ExpandedAttribute(name, att.getEnclosingType(), att.getType(), null, false, 1, 1, false, Collections.emptyList(), null, Collections.emptyList(), false, Collections.emptyList());
	}

	static private ExpandedAttribute metaAtt() {
		return new ExpandedAttribute("meta", null, RosettaAttributeExtensions.toExpandedType(META_TYPE.getType()), META_TYPE, false, 1, 1, false, Collections.emptyList(), null,  Collections.emptyList(),false, Collections.emptyList());
	}

	static private  ExpandedAttribute externalKeyAtt() {
		return new ExpandedAttribute("externalKey", null, provideStringType(), null, false, 1, 1, false, Collections.emptyList(), null,  Collections.emptyList(),false, Collections.emptyList());
	}

	private static ExpandedType provideStringType() {
		return new ExpandedType(null, "string", false, false, false);
	}
	
	private TypeCall referenceType(ExpandedAttribute genAttr) {
		JavaClass metaJavaType = toMetaJavaType(genAttr);
		
		Data res = SimpleFactory.eINSTANCE.createData();
		res.setName(metaJavaType.getSimpleName());
		res.setDefinition(genAttr.getName());

		// Create a model so that the code generator knows which package the reference type is in
		RosettaModel model = RosettaFactory.eINSTANCE.createRosettaModel();
		model.setName(metaJavaType.getPackageName().withDots());
		res.setModel(model);
		
		TypeCall typeCall = RosettaFactory.eINSTANCE.createTypeCall();
		typeCall.setType(res);

		return typeCall;
	}
	private JavaClass toMetaJavaType(ExpandedAttribute expAttr) {
		JavaReferenceType attrType;
		if (expAttr.getRosettaType() != null) {
			attrType = typeTranslator.toJavaReferenceType(typeSystem.typeCallToRType(expAttr.getRosettaType()));
		} else {
			attrType = expandedTypeToJavaType(expAttr.getType());
		}
		DottedPath namespace = getModelPackage(expAttr.getRosettaType().getType());
		return toMetaJavaType(attrType, expAttr.refIndex() < 0, namespace);
	}
	private JavaClass toMetaJavaType(JavaReferenceType base, boolean hasMetaFieldAnnotations, DottedPath namespace) {
		String attributeTypeName = base.getSimpleName();
		String name;
		if (hasMetaFieldAnnotations) {
			name = "FieldWithMeta" + attributeTypeName;
		} else {
			name = "ReferenceWithMeta" + attributeTypeName;
		}
		DottedPath pkg = metaField(namespace);
		return new GeneratedJavaClass<>(pkg, name, Object.class);
	}
	private DottedPath metaField(DottedPath p) {
		return p.child("metafields");
	}
	private DottedPath getModelPackage(RosettaNamed object) {
		RosettaRootElement rootElement = EcoreUtil2.getContainerOfType(object, RosettaRootElement.class);
		RosettaModel model = rootElement.getModel();
		if (model == null)
			// Artificial attributes
			throw new IllegalArgumentException("Can not compute package name for " + object.eClass().getName() + " " + object.getName() + ". Element is not attached to a RosettaModel.");
		return modelPackage(model);
	}
	private DottedPath modelPackage(RosettaModel model) {
		return DottedPath.splitOnDots(model.getName());
	}
	private JavaReferenceType expandedTypeToJavaType(ExpandedType type) {
		if (type.getName().equals(RosettaAttributeExtensions.METAFIELDS_CLASS_NAME) || type.getName().equals(RosettaAttributeExtensions.META_AND_TEMPLATE_FIELDS_CLASS_NAME)) {
			return new GeneratedJavaClass<>(packages.basicMetafields(), type.getName(), Object.class);
		}
		if (type.isMetaType()) {//TODO ExpandedType needs to store the underlying type for meta types if we want them to be anything other than strings
			return typeUtil.STRING;
		}
		if (type.isBuiltInType()) {
			return typeTranslator.toJavaReferenceType(builtins.getType(type.getName(), Collections.emptyMap()));
		}
		return new GeneratedJavaClass<>(modelPackage(type.getModel()), type.getName(), Object.class);
	}

	private static TypeCall metadType(ExpandedType genType) {
		Data res = SimpleFactory.eINSTANCE.createData();
		res.setName("FieldWithMeta"+toFirstUpper(genType.getName()));
		res.setDefinition(genType.getName());
		
		// Create a model so that the code generator knows which package the reference type is in
		RosettaModel model = RosettaFactory.eINSTANCE.createRosettaModel();
		model.setName(genType.getModel().getName() + ".metafields");
		res.setModel(model);
		
		TypeCall typeCall = RosettaFactory.eINSTANCE.createTypeCall();
		typeCall.setType(res);
		
		return typeCall;
	}
	static TypeCall META_TYPE = null;
	{
		Data res = SimpleFactory.eINSTANCE.createData();
		res.setName("MetaFields");
		TypeCall typeCall = RosettaFactory.eINSTANCE.createTypeCall();
		typeCall.setType(res);
		META_TYPE = typeCall;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy