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

com.regnosys.rosetta.translate.ROMParseHandler Maven / Gradle / Ivy

There is a newer version: 11.25.1
Show newest version
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;
	}
}