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

com.regnosys.rosetta.common.hashing.ReferenceResolverProcessStep Maven / Gradle / Ivy

Go to download

Rune Common is a java library that is utilised by Rosetta Code Generators and models expressed in the Rosetta DSL.

There is a newer version: 11.27.1
Show newest version
package com.regnosys.rosetta.common.hashing;

/*-
 * ==============
 * Rune Common
 * ==============
 * Copyright (C) 2018 - 2024 REGnosys
 * ==============
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ==============
 */

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
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.common.util.SimpleProcessor;
import com.rosetta.lib.postprocess.PostProcessorReport;
import com.rosetta.model.lib.GlobalKey;
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.GlobalKeyFields;
import com.rosetta.model.lib.meta.ReferenceWithMeta.ReferenceWithMetaBuilder;
import com.rosetta.model.lib.path.RosettaPath;
import com.rosetta.model.lib.process.AttributeMeta;
import com.rosetta.model.lib.process.PostProcessStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;

import static java.util.Optional.of;
import static java.util.Optional.ofNullable;

public class ReferenceResolverProcessStep implements PostProcessStep {

    private final ReferenceConfig referenceConfig;

    public ReferenceResolverProcessStep(ReferenceConfig referenceConfig) {
        this.referenceConfig = referenceConfig;
    }

    @Override
    public Integer getPriority() {
        return 2;
    }

    @Override
    public String getName() {
        return "Reference Resolver";
    }

    @Override
    public  ReferenceResolverPostProcessorReport runProcessStep(
            Class topClass,
            T instance) {
        RosettaPath path = RosettaPath.valueOf(topClass.getSimpleName());
        ReferenceCollector collector = new ReferenceCollector(referenceConfig);
        instance.process(path, collector);
        ReferenceResolver resolver =
                new ReferenceResolver(referenceConfig, collector.globalReferences, collector.helper);
        RosettaModelObjectBuilder builder = instance.toBuilder();
        builder.process(path, resolver);
        return new ReferenceResolverPostProcessorReport((T) builder.build());
    }

    private static class ReferenceCollector extends SimpleProcessor {

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

        // Table:
        // - Class: referenced Class (e.g. Quantity or QuantityBuilder)
        // - String: reference key value (e.g. "quantity-1")
        // - Object: referenced object (e.g. populated Quantity object to be set on ReferenceWithMetaQuantity.value)
        private final Table, String, Object> globalReferences = HashBasedTable.create();
        private final ScopeReferenceHelper, String, Object>> helper;

        public ReferenceCollector(ReferenceConfig referenceConfig) {
            this.helper = new ScopeReferenceHelper<>(referenceConfig, () -> HashBasedTable.create());
        }

        @Override
        public  boolean processRosetta(RosettaPath path,
                                                                     Class rosettaType,
                                                                     R instance,
                                                                     RosettaModelObject parent,
                                                                     AttributeMeta... metas) {
            helper.collectScopePath(path, rosettaType);

            if (instance instanceof GlobalKey && instance != null) {
                GlobalKey globalKey = (GlobalKey) instance;
                Object value = getValue(instance);
                Class valueClass = getValueType(instance);
                if (value != null && valueClass != null) {
                    ofNullable(globalKey.getMeta())
                            .map(GlobalKeyFields::getGlobalKey)
                            .ifPresent(gk -> globalReferences.put(valueClass, gk, value));
                    of(globalKey)
                            .map(GlobalKey::getMeta)
                            .map(GlobalKeyFields::getKey)
                            .ifPresent(keys -> keys.stream()
                                    .filter(k -> k.getKeyValue() != null)
                                    .forEach(k -> {
                                        String keyValue = k.getKeyValue();
                                        Path keyPath = PathUtils.toPath(path);
                                        LOGGER.debug("Collecting object [key={}, type={}, path={}]",
                                                keyValue, valueClass.getName(), path);
                                        helper.getDataForModelPath(keyPath)
                                                .put(valueClass, keyValue, value);
                                    }));
                }
            }
            return true;
        }

        private Object getValue(RosettaModelObject instance) {
            if (instance instanceof FieldWithMeta) {
                return ((FieldWithMeta) instance).getValue();
            } else
                return instance;
        }

        private Class getValueType(RosettaModelObject builder) {
            if (builder instanceof FieldWithMeta) {
                return ((FieldWithMeta) builder).getValueType();
            } else
                return builder.getType();
        }

        @Override
        public Report report() {
            return null;
        }
    }

    private static class ReferenceResolver extends SimpleBuilderProcessor {

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

        private final Table, String, Object> globalReferences;
        private final ScopeReferenceHelper, String, Object>> helper;
        private final ReferenceConfig config;

        private ReferenceResolver(
                ReferenceConfig config,
                Table, String, Object> globalReferences,
                ScopeReferenceHelper, String, Object>> helper) {
            this.config = config;
            this.globalReferences = globalReferences;
            this.helper = helper;
        }

        @SuppressWarnings({"unchecked", "rawtypes"})
        @Override
        public  boolean processRosetta(RosettaPath path,
                                                                     Class rosettaType,
                                                                     RosettaModelObjectBuilder builder,
                                                                     RosettaModelObjectBuilder parent,
                                                                     AttributeMeta... metas) {
            if (config.getExcludedPaths().stream().anyMatch(endsWithPathElement -> path.endsWith(endsWithPathElement))) {
                return false;
            }
            if (builder instanceof ReferenceWithMetaBuilder) {
                ReferenceWithMetaBuilder referenceWithMetaBuilder = (ReferenceWithMetaBuilder) builder;
                if (referenceWithMetaBuilder.getGlobalReference() != null) {
                    setReferenceValue(referenceWithMetaBuilder.getGlobalReference(),
                            globalReferences,
                            referenceWithMetaBuilder,
                            path);
                } else if (referenceWithMetaBuilder.getReference() != null) {
                    Path currentModelPath = PathUtils.toPath(path);
                    Table, String, Object> currentScopeReferences = helper.getDataForModelPath(currentModelPath);
                    if (currentScopeReferences != null) {
                        setReferenceValue(referenceWithMetaBuilder.getReference().getReference(),
                                currentScopeReferences,
                                referenceWithMetaBuilder,
                                path);
                    }
                }
            }
            return true;
        }

        private void setReferenceValue(String keyValue, Table, String, Object> references, ReferenceWithMetaBuilder referenceWithMeta, RosettaPath path) {
            if (keyValue != null) {
                Map, Object> clazzToReferencedObjectMap = references.column(keyValue);
                if (clazzToReferencedObjectMap != null) {
                    List, Object>> clazzToReferencedObjectEntries = clazzToReferencedObjectMap.entrySet().stream()
                            .filter(e -> doTest(referenceWithMeta.getValueType(), e.getKey()))
                            .collect(Collectors.toList());
                    clazzToReferencedObjectEntries.stream()
                            .map(Entry::getValue)
                            .forEach(referencedObject -> {
                                LOGGER.debug("Setting resolved object [key={}, type={}, path={}, scope={}]",
                                        keyValue, referenceWithMeta.getValueType().getName(), path,
                                        Optional.ofNullable(config).map(ReferenceConfig::getScopeType).orElse(null));
                                referenceWithMeta.setValue(referencedObject);
                            });
                }
            }
        }

        private boolean doTest(Class valueType, Class clazz) {
            return valueType.isAssignableFrom(clazz);
        }

        @Override
        public Report report() {
            return null;
        }
    }

    public static class ReferenceResolverPostProcessorReport implements PostProcessorReport {
        private final T instance;

        private ReferenceResolverPostProcessorReport(T instance) {
            this.instance = instance;
        }

        @Override
        public T getResultObject() {
            return this.instance;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy