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

fr.ird.observe.toolkit.templates.DtoMetaTransformer Maven / Gradle / Ivy

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

/*-
 * #%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 fr.ird.observe.dto.WithAtLeastOneSelected;
import fr.ird.observe.dto.data.ContainerDto;
import fr.ird.observe.dto.data.InlineDataDto;
import fr.ird.observe.toolkit.templates.io.TagValues;
import fr.ird.observe.toolkit.templates.validation.ValidationTagValues;
import org.nuiton.eugene.AbstractMetaTransformer;
import org.nuiton.eugene.EugeneCoreTagValues;
import org.nuiton.eugene.LogProxy;
import org.nuiton.eugene.Template;
import org.nuiton.eugene.java.BeanTransformerContext;
import org.nuiton.eugene.java.BeanTransformerTagValues;
import org.nuiton.eugene.java.EugeneJavaTagValues;
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.ObjectModelPackage;
import org.nuiton.eugene.models.object.xml.ObjectModelAttributeImpl;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * Created on 24/01/2021.
 *
 * @author Tony Chemit - [email protected]
 * @since 8.0.5
 */
public abstract class DtoMetaTransformer extends AbstractMetaTransformer {

    @Override
    protected void applyTemplates(ObjectModel model, List> templates, File destDir) throws IOException {
        for (Template template : templates) {
            template.setLog(getLog());
        }
        super.applyTemplates(model, templates, destDir);
    }

    @Override
    protected boolean validateModel(ObjectModel model) {
        String packageName = getConfiguration().getProperty(PROP_DEFAULT_PACKAGE);
        ToolkitTagValues observeTagValues = new ToolkitTagValues();
        ValidationTagValues validationTagValues = new ValidationTagValues();
        Path outputDirectory = getConfiguration().getProperty(PROP_OUTPUT_DIRECTORY, File.class).toPath().getParent().getParent();
        TagValues tagValues = new TagValues(model, "dto", getLog());
        try {
            tagValues.load(getClassLoader(), outputDirectory, isVerbose());
        } catch (Exception e) {
            throw new IllegalStateException("Can't load tag-values", e);
        }
        BeanTransformerContext allWithAbstract = new BeanTransformerContext(model, new EugeneCoreTagValues(), new EugeneJavaTagValues(), new BeanTransformerTagValues(), true, false, t -> true, getLog());
        BeanTransformerContext all = new BeanTransformerContext(model, new EugeneCoreTagValues(), new EugeneJavaTagValues(), new BeanTransformerTagValues(), false, false, t -> true, getLog());
        augmentsReferences(allWithAbstract, packageName);
        augmentsTagValues(model, all, observeTagValues);
        consolidateModel(model, all, observeTagValues, getLog());
        augmentsTagValuesFinal(model, all, observeTagValues, validationTagValues);
        return true;
    }

    protected void augmentsTagValues(ObjectModel model, BeanTransformerContext all, ToolkitTagValues observeTagValues) {
        String defaultPackageName = getConfiguration().getProperty(PROP_DEFAULT_PACKAGE);

        for (ObjectModelClass aClass : all.selectedClasses) {
            ObjectModelPackage aPackage = model.getPackage(aClass.getPackageName());
            String mainDtoTagValue = observeTagValues.getMainDtoTagValue(aClass);
            if (observeTagValues.notSkip(mainDtoTagValue) != null) {
                String newValue;
                if (mainDtoTagValue.contains(".")) {
                    // absolute value
                    newValue = defaultPackageName + "." + mainDtoTagValue + "Dto";
                } else {
                    newValue = aPackage.getName() + "." + mainDtoTagValue + "Dto";
                }
                getLog().debug(String.format("Augments tag value %s.mainDto=%s", aClass.getQualifiedName(), newValue));
                aClass.getTagValues().put(ToolkitTagValues.Store.mainDto.name(), newValue);
            }
            String formTagValue = observeTagValues.getFormTagValue(aClass, aPackage);
            if (observeTagValues.notSkip(formTagValue) != null && !Objects.equals("self", formTagValue)) {
                String newValue;
                if (formTagValue.contains(".")) {
                    // absolute value
                    newValue = defaultPackageName + "." + formTagValue + "Dto";
                } else {
                    newValue = aPackage.getName() + "." + formTagValue + "Dto";
                }
                getLog().debug(String.format("Augments tag value %s.form=%s", aClass.getQualifiedName(), newValue));
                aClass.getTagValues().put(ToolkitTagValues.Store.form.name(), newValue);
            }
        }
    }

    protected void augmentsReferences(BeanTransformerContext all, String packageName) {
        for (ObjectModelClass aClass : all.selectedClasses) {
            for (ObjectModelAttribute attribute : aClass.getAttributes()) {
                String attributeType = attribute.getType();
                if (!attributeType.startsWith(packageName) && attributeType.endsWith("Reference")) {
                    // add full package
                    String newValue = packageName + "." + attributeType;
                    getLog().debug(String.format("Augments reference attribute value %s.%s=%s", aClass.getQualifiedName(), attribute.getName(), newValue));
                    ((ObjectModelAttributeImpl) attribute).setType(newValue);
                }
            }
        }
    }

    protected void augmentsTagValuesFinal(ObjectModel model, BeanTransformerContext all, ToolkitTagValues observeTagValues, ValidationTagValues validationTagValues) {
        for (ObjectModelClass aClass : all.selectedClasses) {
            ObjectModelPackage aPackage = model.getPackage(aClass.getPackageName());
            String atLeastOneSelectedTagValue = validationTagValues.getAtLeastOneSelected(aClass);
            if (atLeastOneSelectedTagValue != null) {
                boolean notFound = aClass.getInterfaces().stream().noneMatch(i -> i.getQualifiedName().equals(WithAtLeastOneSelected.class.getName()));
                if (notFound) {
                    // add interface on class
                    getLog().debug(String.format("Add interface %s on %s", WithAtLeastOneSelected.class.getName(), aClass.getQualifiedName()));
                    aClass.getInterfaces().add(model.getInterface(WithAtLeastOneSelected.class.getName()));
                }
            }
            String inlineDataDtoPropertiesTagValue = observeTagValues.getInlineDataDtoPropertiesTagValue(aClass);
            if (inlineDataDtoPropertiesTagValue != null) {
                boolean notFound = aClass.getInterfaces().stream().noneMatch(i -> i.getQualifiedName().equals(InlineDataDto.class.getName()));
                if (notFound) {
                    // add interface on class
                    getLog().debug(String.format("Add interface %s on %s", InlineDataDto.class.getName(), aClass.getQualifiedName()));
                    aClass.getInterfaces().add(model.getInterface(InlineDataDto.class.getName()));
                }
            }
            String formTagValue = observeTagValues.getFormTagValue(aClass, aPackage);
            if (Objects.equals("self", formTagValue)) {
                String newValue = aClass.getQualifiedName() + "Dto";
                getLog().debug(String.format("Augments tag value %s.form=%s", aClass.getQualifiedName(), newValue));
                aClass.getTagValues().put(ToolkitTagValues.Store.form.name(), newValue);
            }
            String mainDtoTagValue = observeTagValues.getMainDtoTagValue(aClass);
            if (mainDtoTagValue == null) {
                String newValue = aClass.getQualifiedName() + "Dto";
                getLog().debug(String.format("Augments tag value %s.mainDto=%s", aClass.getQualifiedName(), newValue));
                aClass.getTagValues().put(ToolkitTagValues.Store.mainDto.name(), newValue);
            }
        }
    }

    protected void consolidateModel(ObjectModel model, BeanTransformerContext all, ToolkitTagValues observeTagValues, LogProxy log) {

        for (ObjectModelClass aClass : all.selectedClasses) {

            ObjectModelPackage aPackage = model.getPackage(aClass.getPackageName());

            boolean containerDto = aClass.getSuperclasses().stream().anyMatch(i -> (i.getQualifiedName() + "Dto").equals(ContainerDto.class.getName()));
            if (containerDto) {
                String mainDtoTagValue = observeTagValues.getMainDtoTagValue(aClass);
                String formTagValue = observeTagValues.getFormTagValue(aClass, aPackage);
                if (mainDtoTagValue == null && (formTagValue == null || Objects.equals("self", formTagValue))) {
                    log.debug(String.format("found ContainerDto without any tagValues, add convention tagValues: %s", aClass.getQualifiedName()));
                    ObjectModelClass childType = guessChildType(all.selectedClasses, aClass);
                    log.debug(String.format("add tag value %s.form=%s", aClass.getQualifiedName(), childType.getQualifiedName()) + "Dto");
                    ObjectModelClass mainType = guessMainType(all.selectedClasses, aClass, childType);
                    log.debug(String.format("add tag value %s.mainDto=%s", aClass.getQualifiedName(), mainType.getQualifiedName()) + "Dto");
                    aClass.getTagValues().put(ToolkitTagValues.Store.form.name(), childType.getQualifiedName() + "Dto");
                    aClass.getTagValues().put(ToolkitTagValues.Store.mainDto.name(), mainType.getQualifiedName() + "Dto");
                }
            }
        }
    }

    private ObjectModelClass guessChildType(Set selectedClasses, ObjectModelClass aClass) {
        String name = aClass.getName();
        String packageName = aClass.getPackageName();
        List candidates = new LinkedList<>();
        for (ObjectModelClass selectedClass : selectedClasses) {
            if (!Objects.equals(packageName, selectedClass.getPackageName())) {
                // not in same package
                continue;
            }
            if (name.equals(selectedClass.getName())) {
                // same class
                continue;
            }
            if (name.endsWith(selectedClass.getName())) {
                if (!candidates.isEmpty()) {
                    ObjectModelClass objectModelClass = candidates.get(0);
                    if (selectedClass.getName().endsWith(objectModelClass.getName())) {
                        candidates.remove(0);
                    } else if (objectModelClass.getName().endsWith(selectedClass.getName())) {
                        // not keeping this one
                        continue;
                    }
                }
                candidates.add(selectedClass);
            }
        }
        if (candidates.isEmpty()) {
            throw new IllegalStateException("Can't guess child type for " + aClass.getQualifiedName());
        }
        if (candidates.size() == 1) {
            // only one candidate, found it!
            return candidates.get(0);
        }
        // should take the biggest matching candidate ?
        candidates.sort(Comparator.comparing(ObjectModelClass::getQualifiedName, Comparator.comparingInt(String::length)).reversed());
        return candidates.get(0);
    }

    private ObjectModelClass guessMainType(Set selectedClasses, ObjectModelClass aClass, ObjectModelClass childType) {
        String name = aClass.getName();
        String childTypeName = childType.getName();
        String packageName = aClass.getPackageName();
        List candidates = new LinkedList<>();
        for (ObjectModelClass selectedClass : selectedClasses) {
            if (!Objects.equals(packageName, selectedClass.getPackageName())) {
                // not in same package
                continue;
            }
            if (name.equals(selectedClass.getName())) {
                // same class
                continue;
            }
            if (name.equals(selectedClass.getName() + childTypeName)) {
                candidates.add(selectedClass);
            }
        }
        if (candidates.isEmpty()) {
            throw new IllegalStateException("Can't guess main type for " + aClass.getQualifiedName());
        }
        if (candidates.size() == 1) {
            // only one candidate, found it!
            return candidates.get(0);
        }
        // should take the smallest matching candidate ?
        candidates.sort(Comparator.comparing(ObjectModelClass::getQualifiedName, Comparator.comparingInt(String::length)).reversed());
        return candidates.get(0);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy