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

fr.ird.observe.toolkit.templates.navigation.MetaModelBuilderFromModel Maven / Gradle / Ivy

There is a newer version: 10.0.1
Show newest version
package fr.ird.observe.toolkit.templates.navigation;

/*-
 * #%L
 * Toolkit :: Templates
 * %%
 * Copyright (C) 2017 - 2024 Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import com.google.common.collect.ArrayListMultimap;
import fr.ird.observe.spi.ProjectPackagesDefinition;
import fr.ird.observe.spi.navigation.model.MetaModel;
import fr.ird.observe.spi.navigation.model.MetaModelBuilder;
import fr.ird.observe.spi.navigation.model.MetaModelNodeLinkMultiplicity;
import fr.ird.observe.spi.navigation.model.MetaModelNodeType;
import fr.ird.observe.spi.navigation.parent.ParentLink;
import fr.ird.observe.toolkit.templates.ToolkitTagValues;
import io.ultreia.java4all.lang.Strings;
import org.nuiton.eugene.GeneratorUtil;
import org.nuiton.eugene.LogProxy;
import org.nuiton.eugene.models.object.ObjectModel;
import org.nuiton.eugene.models.object.ObjectModelAttribute;
import org.nuiton.eugene.models.object.ObjectModelClass;
import org.nuiton.eugene.models.object.ObjectModelClassifier;
import org.nuiton.eugene.models.object.ObjectModelPackage;
import org.nuiton.topia.templates.TopiaExtensionTagValues;
import org.nuiton.topia.templates.TopiaTemplateHelper;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Created on 30/12/2021.
 *
 * @author Tony Chemit - [email protected]
 * @since 5.0.64
 */
public class MetaModelBuilderFromModel extends MetaModelBuilder {

    private final LogProxy log;
    private final ObjectModel model;
    private final ToolkitTagValues observeTagValues;
    private final TopiaExtensionTagValues topiaExtensionTagValues;

    private final List entityClassesWithNode;
    private final LinkedList entityClassesOpen;
    private final ProjectPackagesDefinition def;
    private final List entityClasses;
    private final List entityClassesNames;
    private final Set parentLinks = new LinkedHashSet<>();
    private final ArrayListMultimap referentialClasses;
    private final LinkedList entityClassesEntryPoints;

    MetaModelBuilderFromModel(LogProxy log, ObjectModel model, ProjectPackagesDefinition def) {
        this.log = log;
        this.model = model;
        TopiaTemplateHelper templateHelper = new TopiaTemplateHelper(model);
        this.observeTagValues = new ToolkitTagValues();
        this.topiaExtensionTagValues = new TopiaExtensionTagValues();
        this.entityClasses = templateHelper.getEntityClasses(model, false);
        this.entityClassesNames = entityClasses.stream().map(ObjectModelClass::getQualifiedName).collect(Collectors.toList());
        this.entityClassesWithNode = entityClasses.stream().filter(entityClass -> observeTagValues.getNavigationNodeTypeTagValue(entityClass, null) != null).map(ObjectModelClass::getQualifiedName).collect(Collectors.toCollection(LinkedList::new));
        this.referentialClasses = ArrayListMultimap.create();
        for (ObjectModelClass referentialClass : entityClasses.stream().filter(entityClass -> entityClass.getPackageName().contains("referential.")).collect(Collectors.toList())) {
            this.referentialClasses.put(referentialClass.getPackageName(), referentialClass);
        }
        this.entityClassesOpen = entityClasses.stream().filter(entityClass -> Objects.equals(observeTagValues.getNavigationNodeTypeTagValue(entityClass, null), "Open")).map(ObjectModelClass::getQualifiedName).collect(Collectors.toCollection(LinkedList::new));
        this.entityClassesEntryPoints = entityClasses.stream().filter(topiaExtensionTagValues::isEntryPoint).map(ObjectModelClass::getQualifiedName).collect(Collectors.toCollection(LinkedList::new));
        this.def = def;
    }

    public MetaModel build() {
        entityClassesEntryPoints.stream().map(model::getClass).forEach(input -> addEntryPoint(toNavigationNode(input), MetaModelNodeType.RootOpen, () -> scan(input)));
        referentialClasses.keySet().stream().sorted().forEach(referentialPackageName -> addEntryPoint(toNavigationPackage(referentialPackageName), MetaModelNodeType.ReferentialPackage, () -> {
            List types = referentialClasses.get(referentialPackageName);
            for (ObjectModelClass type : types) {
                String simpleName = toNavigationNodeName(type.getName());
                addChildren(simpleName, MetaModelNodeType.ReferentialType, toNavigationNode(type), MetaModelNodeLinkMultiplicity.ONE, null);
            }
        }));
        return super.build();
    }

    public List getParentLinks() {
        return new ArrayList<>(parentLinks);
    }

    private void scan(ObjectModelClass input) {
        String[] groupByList = topiaExtensionTagValues.getGroupBy(input);
        if (groupByList != null) {
            addGroupBy(input, groupByList);
        }
        ObjectModelPackage clazzPackage = model.getPackage(input);
        String navigationNodeExtraTypeTagValue = observeTagValues.getNavigationNodeExtraTypeTagValue(input);
        if (navigationNodeExtraTypeTagValue != null) {
            for (String typeStr : navigationNodeExtraTypeTagValue.split("\\s*,\\s*")) {
                log.info(String.format("[%-70s] Add extra type %s.", input.getQualifiedName(), typeStr));
                String simpleName = GeneratorUtil.getSimpleName(typeStr);
                String packageName = typeStr.substring(0, typeStr.length() - simpleName.length() - 1);
                String dtoSimpleName = toNavigationNodeName(simpleName);
                String nodeDataType = toNavigationNode(packageName, simpleName);
                addChildren(dtoSimpleName, MetaModelNodeType.Simple, nodeDataType, MetaModelNodeLinkMultiplicity.ONE, null);
            }
        }
        List attributes = input.getAttributes().stream().filter(
                a -> a.isNavigable()
                        && entityClassesNames.contains(a.getType())
                        && !topiaExtensionTagValues.isSkipModelNavigation(clazzPackage, input, a)
        ).collect(Collectors.toCollection(LinkedList::new));
        for (ObjectModelAttribute attribute : attributes) {
            String attributeType = attribute.getType();
            ObjectModelClass dependency = model.getClass(attributeType);
            if (def.isReferentialFromEntityPackageName(dependency.getPackageName())) {
                continue;
            }
            String navigationNodeTypeTagValue = Objects.requireNonNull(observeTagValues.getNavigationNodeTypeTagValue(dependency, attribute));
            MetaModelNodeLinkMultiplicity entityMultiplicity;
            MetaModelNodeLinkMultiplicity multiplicity;
            MetaModelNodeType nodeType = MetaModelNodeType.valueOf(navigationNodeTypeTagValue);
            switch (nodeType) {
                case Open:
                    multiplicity = MetaModelNodeLinkMultiplicity.MANY;
                    entityMultiplicity = MetaModelNodeLinkMultiplicity.MANY;
                    break;
                case Edit:
                    multiplicity = GeneratorUtil.isNMultiplicity(attribute) ? MetaModelNodeLinkMultiplicity.MANY : MetaModelNodeLinkMultiplicity.OPTIONAL;
                    entityMultiplicity = GeneratorUtil.isNMultiplicity(attribute) ? MetaModelNodeLinkMultiplicity.MANY : MetaModelNodeLinkMultiplicity.OPTIONAL;
                    break;
                default:
                    multiplicity = MetaModelNodeLinkMultiplicity.ONE;
                    entityMultiplicity = GeneratorUtil.isNMultiplicity(attribute) ? MetaModelNodeLinkMultiplicity.MANY : MetaModelNodeLinkMultiplicity.OPTIONAL;
            }
            ParentLink parentLink = new ParentLink(attribute.getName(), toNavigationNode(dependency), toNavigationNode(input), entityMultiplicity);
            if (!entityClassesWithNode.contains(attribute.getType())) {
                // no navigation
                parentLinks.add(parentLink);
                scanDependencies(dependency);
                continue;
            }
            if (MetaModelNodeType.Simple.name().equals(navigationNodeTypeTagValue)) {
                parentLinks.add(parentLink);
                scanDependencies(dependency);
                continue;
            }
            String nodeDataType = toNavigationNode(dependency);
            String linkName = attribute.getName();
            if (entityClassesOpen.contains(dependency.getQualifiedName()) && MetaModelNodeType.Edit.name().equals(navigationNodeTypeTagValue)) {
                // special case: use a open data as a edit one
                // must declare a new type
                log.info(String.format("Found a special Open → Edit node on %s.%s", input.getName(), linkName));
                String packageName = dependency.getPackageName();
                String simpleName = input.getName() + Strings.capitalize(dependency.getName());
                nodeDataType = toNavigationNode(packageName, simpleName);
                parentLink = new ParentLink(linkName, nodeDataType, toNavigationNode(input), multiplicity);
            }
            parentLinks.add(parentLink);
            addChildren(linkName, nodeType, nodeDataType, multiplicity, () -> scan(dependency));
        }
    }

    private void scanDependencies(ObjectModelClass input) {
        ObjectModelPackage clazzPackage = model.getPackage(input);

        List attributes = input.getAttributes().stream().filter(
                a -> a.isNavigable()
                        && entityClassesNames.contains(a.getType())
                        && !topiaExtensionTagValues.isSkipModelNavigation(clazzPackage, input, a)
        ).collect(Collectors.toCollection(LinkedList::new));
        for (ObjectModelAttribute attribute : attributes) {
            String attributeType = attribute.getType();
            ObjectModelClass dependency = model.getClass(attributeType);
            if (def.isReferentialFromEntityPackageName(dependency.getPackageName())) {
                continue;
            }
            MetaModelNodeLinkMultiplicity entityMultiplicity = GeneratorUtil.isNMultiplicity(attribute) ? MetaModelNodeLinkMultiplicity.MANY : MetaModelNodeLinkMultiplicity.OPTIONAL;
            ParentLink parentLink = new ParentLink(attribute.getName(), toNavigationNode(dependency), toNavigationNode(input), entityMultiplicity);
            parentLinks.add(parentLink);
            scanDependencies(dependency);
        }
    }

    void addGroupBy(ObjectModelClass input, String[] groupByList) {
        for (String groupByPattern : groupByList) {
            String groupBy = groupByPattern;
            String groupBySecond = null;
            int index = groupByPattern.indexOf(":");
            if (index > -1) {
                groupBy = groupByPattern.substring(0, index);
            } else {
                index = groupByPattern.indexOf(".");
                if (index > -1) {
                    groupBy = groupByPattern.substring(0, index);
                    groupBySecond = groupByPattern.substring(index + 1);
                }
            }
            ObjectModelAttribute parentAttribute = Objects.requireNonNull(input.getAttribute(groupBy));
            ObjectModelClassifier classifier = parentAttribute.getClassifier();
            if (classifier instanceof ObjectModelClass && entityClasses.contains(classifier)) {
                if (groupBySecond == null) {
                    addGroupBy(groupBy, toNavigationNode(classifier));
                } else {
                    ObjectModelAttribute secondClassifier = classifier.getAttribute(groupBySecond);
                    String capitalize = Strings.capitalize(groupBySecond);
                    addGroupBy(groupBy + capitalize, toNavigationNode(secondClassifier.getClassifier()));
                }
            } else {
                addGroupBy(groupBy, parentAttribute.getType());
            }
        }
    }

    private String toNavigationPackage(String packageName) {
        String result = def.getRelativeEntityPackage(packageName);
        result = def.getRelativeDtoPackage(result);
        return result.startsWith(".") ? result.substring(1) : result;
    }

    private String toNavigationNode(String packageName, String name) {
        return toNavigationPackage(packageName) + "." + toNavigationNodeName(name);
    }

    private String toNavigationNode(ObjectModelClassifier clazz) {
        return toNavigationPackage(clazz.getPackageName()) + "." + toNavigationNodeName(clazz.getName());
    }

    private String toNavigationNodeName(String prefix) {
        return Strings.capitalize(prefix.replace("Dto", ""));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy