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

org.nuiton.topia.templates.EntityHibernateMappingTransformer Maven / Gradle / Ivy

There is a newer version: 10.0.1
Show newest version
package org.nuiton.topia.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 org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.codehaus.plexus.component.annotations.Component;
import org.nuiton.eugene.GeneratorUtil;
import org.nuiton.eugene.Template;
import org.nuiton.eugene.java.JavaGeneratorUtil;
import org.nuiton.eugene.models.object.ObjectModel;
import org.nuiton.eugene.models.object.ObjectModelAssociationClass;
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.ObjectModelGenerator;
import org.nuiton.eugene.models.object.ObjectModelPackage;
import org.nuiton.topia.service.sql.metadata.TopiaMetadataModel;
import org.nuiton.topia.templates.hibernate.HibernateClassContext;
import org.nuiton.topia.templates.hibernate.RelationType;
import org.nuiton.topia.templates.sql.TopiaMetadataModelBuilder;
import org.nuiton.topia.templates.sql.TopiaMetadataModelGeneratorSupport;

import java.beans.Introspector;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;




/**
 * @author Benjamin Poussin - [email protected]
 * @author Tony Chemit - [email protected]
 */
@SuppressWarnings("unused")
@Component(role = Template.class, hint = "org.nuiton.topia.templates.EntityHibernateMappingTransformer")
public class EntityHibernateMappingTransformer extends ObjectModelGenerator {

    public static final String HIBERNATE_ATTRIBUTE_LAZY = "lazy";
    public static final String HIBERNATE_ATTRIBUTE_FETCH = "fetch";
    public static final String HIBERNATE_ATTRIBUTE_NOT_NULL = "not-null";
    public static final String HIBERNATE_ATTRIBUTE_SCHEMA = "schema";
    public static final String HIBERNATE_ATTRIBUTE_PROXY = "proxy";
    public static final String HIBERNATE_ATTRIBUTE_INDEX = "index";
    public static final String HIBERNATE_ATTRIBUTE_UNIQUE = "unique";
    public static final String HIBERNATE_ATTRIBUTE_UNIQUE_KEY = "unique-key";
    public static final String HIBERNATE_ATTRIBUTE_LENGTH = "length";
    public static final String HIBERNATE_ATTRIBUTE_ORDER_BY = "order-by";
    public static final String HIBERNATE_ATTRIBUTE_CASCADE = "cascade";
    public static final String HIBERNATE_ATTRIBUTE_INVERSE = "inverse";
    public static final String HIBERNATE_ATTRIBUTE_TABLE = "table";
    public static final String HIBERNATE_ATTRIBUTE_DISCRIMINATOR_VALUE = "discriminator-value";
    public static final String HIBERNATE_ATTRIBUTE_FOREIGN_KEY = "foreign-key";
    public static final String HIBERNATE_ATTRIBUTE_ENTITY_NAME = "entity-name";
    public static final String NATURAL_PREFIX = "    ";
    private static final Logger log = LogManager.getLogger(EntityHibernateMappingTransformer.class);
    private static final String HIBERNATE_ATTRIBUTE_DEFAULT = "default";
    private static final String HIBERNATE_ATTRIBUTE_SQL_TYPE = "sql-type";
    private static final String HIBERNATE_ATTRIBUTE_SCALE = "scale";
    private static final String HIBERNATE_ATTRIBUTE_PRECISION = "precision";
    private static final String HIBERNATE_ATTRIBUTE_NAME = "name";
    protected final TopiaHibernateTagValues topiaHibernateTagValues;
    protected final TopiaExtensionTagValues topiaExtensionTagValues;
    private final Map columnNamesMap = new HashMap<>();
    private final Set queryNames = new TreeSet<>();
    private final Set sqlQueryNames = new TreeSet<>();
    protected TopiaTemplateHelper templateHelper;
    protected TopiaMetadataModel metadataModel;

    public EntityHibernateMappingTransformer() {
        this.topiaHibernateTagValues = new TopiaHibernateTagValues();
        this.topiaExtensionTagValues = new TopiaExtensionTagValues();
    }

    @Override
    public String getFilenameForClass(ObjectModelClass clazz) {
        String DOName = getTemplateHelper().getDOType(clazz, model);
        return DOName.replace('.', File.separatorChar) + ".hbm.xml";
    }

    public TopiaTemplateHelper getTemplateHelper() {
        if (templateHelper == null) {
            templateHelper = new TopiaTemplateHelper(model);
        }
        return templateHelper;
    }

    @Override
    public void generateFromClass(Writer output, ObjectModelClass input) throws IOException {
        TopiaTemplateHelper templateHelper = getTemplateHelper();
        if (!templateHelper.isEntity(input)) {
            return;
        }
        if (templateHelper.isAbstract(input)) {
            return;
        }

        ObjectModelPackage aPackage = model.getPackage(input);
        HibernateClassContext classContext = new HibernateClassContext(templateHelper, topiaHibernateTagValues, model, metadataModel, aPackage, input);

output.write("\n");
output.write("\n");
output.write("");

        String clazzDOType = templateHelper.getDOType(input, model);
        String tableName = classContext.getTableName();
        List naturalAttributes = classContext.getNaturalAttributes();
        List noneNaturalAttributes = classContext.getNoneNaturalAttributes();
        Map optionalAttributesMap = classContext.getOptionalAttributesMap();
        String optionalAttributes = attributesToString(optionalAttributesMap);

output.write("    \n");
output.write("        \n");
output.write("");

        if (!naturalAttributes.isEmpty()) {
            // generation de la clef metier
            boolean mutable = classContext.isMutable();
            String mutableStr = mutable ? " mutable=\"true\"" : "";
output.write("        \n");
output.write("");
            generateAttributes(output, classContext, naturalAttributes, NATURAL_PREFIX);
output.write("        \n");
output.write("");
        }
output.write("        \n");
output.write("           \n");
output.write("               \n");
output.write("           \n");
output.write("");

        generateAttributes(output, classContext, noneNaturalAttributes, "");

        ObjectModelAttribute reverseOneToOneAttribute = classContext.getReverseOneToOneAttribute();
        if (reverseOneToOneAttribute != null) {
            generateHibernateOneToOneReverse(output, classContext, reverseOneToOneAttribute.getReverseAttribute(), "");
        }
output.write("    \n");
output.write("");
        generateSqlQueries(output, classContext);
        generateDatabaseObjects(output, classContext, naturalAttributes);
        generateDatabaseObjects(output, classContext, noneNaturalAttributes);
        generateExtraIndexes(output, classContext);

output.write("\n");
output.write("");
    }

    protected void generateSqlQueries(Writer output, HibernateClassContext classContext) throws IOException {

    }

    protected void generateAttributes(Writer output,
                                      HibernateClassContext classContext,
                                      List attributes,
                                      String prefix) throws IOException {
        boolean natural = NATURAL_PREFIX.equals(prefix);

        List toClean = new LinkedList<>();
        for (ObjectModelAttribute attr : attributes) {
            ObjectModelAttribute reverse = attr.getReverseAttribute();

            // pour les asso quoi qu'il arrive il faut les lier des 2 cotes
            // pour pouvoir supprimer en cascade l'asso lors de la suppression
            // d'un des cotes
            if (attr.isNavigable()
                    || templateHelper.hasUnidirectionalRelationOnAbstractType(reverse, model)
                    || attr.hasAssociationClass()) {
                if (natural && classContext.getNotNullTagValue(attr) == null) {
                    /// in this special cas we want to set not-null
                    attr.getTagValues().put(TopiaHibernateTagValues.Store.notNull.name(), "false");
                    toClean.add(attr);
                }
                if (!GeneratorUtil.isNMultiplicity(attr)) {
                    if (attr.getClassifier() != null && templateHelper.isEntity(attr.getClassifier())) {
                        if (GeneratorUtil.isNMultiplicity(attr.getReverseMaxMultiplicity()) && !attr.hasAssociationClass()) {
                            generateHibernateManyToOne(output, classContext, attr, prefix);
                        } else {
                            if (attr.isComposite() && attr.isUnique()) {

                                // real one-to-one
                                generateHibernateOneToOne(output, classContext, attr, prefix);
                            } else {

                                generateHibernateOneToOneLegacy(output, classContext, attr, prefix);
                            }
                        }
                    } else {
                        generateHibernateProperty(output, classContext, attr, prefix);
                    }
                } else {
                    if (attr.getClassifier() != null && templateHelper.isEntity(attr.getClassifier())) {
                        if (GeneratorUtil.isNMultiplicity(attr.getReverseMaxMultiplicity()) && !attr.hasAssociationClass()) {
                            generateHibernateManyToMany(output, classContext, attr, prefix);
                        } else {
                            generateHibernateOneToMany(output, classContext, attr, prefix);
                        }
                    } else {
                        generateHibernateMany(output, classContext, attr, prefix);
                    }
                }
            }
        }

        toClean.forEach(a -> a.getTagValues().remove(TopiaHibernateTagValues.Store.notNull.name()));

        //Attributs pour les classes d'association
        ObjectModelClass clazz = classContext.getInput();
        ObjectModelPackage aPackage = classContext.getPackage();
        if (clazz instanceof ObjectModelAssociationClass) {
            ObjectModelAssociationClass assoc = (ObjectModelAssociationClass) clazz;
            for (ObjectModelAttribute attr : assoc.getParticipantsAttributes()) {
                if (attr != null) {

// Note(poussin) pour moi quoi qu'il arrive sur la classe d'association il faut
// un many-to-one, sinon on a des problemes.
//                    if ((!attr.getReverseAttribute().isNavigable()) || !Util.isNMultiplicity(attr.getReverseAttribute())) {
// / *{        <%=(attr.isComposite()?" cascade=\"delete\"":"")%>/>
// } */
//                    } else {
//                    String notNull = " " + generateFromTagValue(HIBERNATE_ATTRIBUTE_NOT_NULL, templateHelper.getNotNullTagValue(attr));
                    String notNull = " " + generateFromTagValue(HIBERNATE_ATTRIBUTE_NOT_NULL, "true"); // AThimel 14/03/2014 I think both assoc class participants must always be not-null
                    String attrName = getName(attr, true);
                    String attrType = getType(aPackage, clazz, attr, true);
                    String lazy = generateFromTagValue(HIBERNATE_ATTRIBUTE_LAZY, topiaHibernateTagValues.getLazyTagValue(attr));
                    String attrColumn = templateHelper.getDbName(attr);
                    String foreignKeyName = "";
                    if (classContext.isGenerateForeignKeyNames()) {
                        foreignKeyName = " " + generateFromTagValue(HIBERNATE_ATTRIBUTE_FOREIGN_KEY, classContext.registerForeignKeyName(attr)).trim();
                    }
output.write(""+prefix+"        \n");
output.write("");
//                    }
                    //Ne sert plus grâce à l'utilisation de la navigabilité
//                    if (!attr.getReverseAttribute().isNavigable()) {
//                        String type = templateHelper.getDOType(((ObjectModelClassifier)attr.getDeclaringElement()).getQualifiedName(), model);
//                        String name = Util.toLowerCaseFirstLetter(attr.getDeclaringElement().getName());
//                        if (log.isTraceEnabled()) {log.trace("reverse: " + type + " " + name);}
//                        if (!Util.isNMultiplicity(attr)) {
//{
//}
//                        }
//                    }
                }
            }
        }
    }

    protected String getName(ObjectModelAttribute attr) {
        return getName(attr, false);
    }

    protected String getName(ObjectModelAttribute attr, boolean isAssoc) {
        String result = Introspector.decapitalize(attr.getName());
        if (attr.hasAssociationClass() && !isAssoc) {
            result = GeneratorUtil.getAssocAttrName(attr);
        }
        return result;
    }

    protected String getType(HibernateClassContext clazzContext, ObjectModelAttribute attr) {
        return getType(clazzContext.getPackage(), clazzContext.getInput(), attr, false);
    }

    protected String getType(ObjectModelPackage aPackage, ObjectModelClass clazz, ObjectModelAttribute attr) {
        return getType(aPackage, clazz, attr, false);
    }

    protected String getType(ObjectModelPackage aPackage, ObjectModelClass clazz, ObjectModelAttribute attr, boolean isAssoc) {
        if (attr.hasAssociationClass() && !isAssoc) {
            String type = attr.getAssociationClass().getQualifiedName();
            return templateHelper.getDOType(type, model);
        }

        String type = attr.getType();
        String attrType = topiaHibernateTagValues.getHibernateAttributeType(attr, clazz, aPackage, model);
        if (StringUtils.isNotEmpty(attrType)) {
            // tag value detected of the attribute
            type = attrType;
        } else {

            attrType = topiaHibernateTagValues.getAttributeType(attr, clazz, aPackage, model);
            if (StringUtils.isNotEmpty(attrType)) {
                // tag value detected of the attribute
                type = attrType;
            } else {

                // old code
                attrType = topiaHibernateTagValues.getTypeTagValue(attr);
                if (StringUtils.isNotEmpty(attrType)) {

                    // tag value detected of the attribute
                    if (log.isWarnEnabled()) {
                        String message = topiaHibernateTagValues.getDeprecatedAttributeTagValueMessage(clazz, attr, TopiaHibernateTagValues.Store.type.getName(), TopiaHibernateTagValues.Store.hibernateAttributeType.getName(), attrType);
                        log.warn(message);
                    }
                    type = attrType;
                } else {

                    String modelType = model.getTagValue(type);
                    if (StringUtils.isNotEmpty(modelType)) {

                        // tag value detected of the model
                        String message = topiaHibernateTagValues.getDeprecatedModelTagValueMessage(model, type, TopiaHibernateTagValues.Store.attributeType.getName() + "." + type, modelType);
                        log.warn(message);
                        //TODO tchemit 20100507 Explain What todes it do ? Dont understand the story of columnNamesMap
                        int bracketIndex = modelType.indexOf('(');
                        if (bracketIndex != -1) {
                            type = modelType.substring(0, bracketIndex);
                            int bracketEndIndex = modelType.indexOf(')', bracketIndex + 1);
                            String colmunList;
                            if (bracketEndIndex != -1) {
                                colmunList = modelType.substring(bracketIndex + 1, bracketEndIndex);
                            } else {
                                colmunList = modelType.substring(bracketIndex);
                            }
                            columnNamesMap.put(type, colmunList.split(","));
                        } else {
                            type = modelType;
                        }
                    }
                }
            }
        }

//        if (attr.hasAssociationClass() && !isAssoc) {
//            type = attr.getAssociationClass().getQualifiedName();
//        }
        return templateHelper.getDOType(type, model);
    }

    protected void generateHibernateProperty(Writer output,
                                             HibernateClassContext classContext,
                                             ObjectModelAttribute attr,
                                             String prefix) throws IOException {
        String attrType = getType(classContext, attr);
        if (attrType.equals("java.util.Date")) {
            attrType = "timestamp";
        }
        String accessField = "field";
        String tagValue = topiaHibernateTagValues.getAccessTagValue(attr);
        if (StringUtils.isNotEmpty(tagValue)) {
            accessField = tagValue;
        }
        String attrName = attr.getName();
        String declaringElementDBName = templateHelper.getDbName(attr.getDeclaringElement());
        String tableName = declaringElementDBName + "_" + attrName;

        boolean attrIsEnumeration = attr.getClassifier() != null
                && attr.getClassifier().isEnum();

        if (attrType.trim().endsWith("[]")) {
            attrType = attrType.trim().substring(0, attrType.trim().length() - 2);

            Map optionalAttributesMap = new HashMap<>();

            if (classContext.isUseSchema()) {
                generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_SCHEMA, classContext.getSchema());
            }

            if (JavaGeneratorUtil.isOrdered(attr)) {
                String indexName = tableName + "_idx";
                generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_INDEX, indexName);
            }
            String optionalAttributes = attributesToString(optionalAttributesMap);
output.write(""+prefix+"        \n");
output.write(""+prefix+"          \n");
output.write(""+prefix+"          \n");
output.write(""+prefix+"          \n");
output.write(""+prefix+"        \n");
output.write("");
        } else {

            Map optionalAttributesMap = new HashMap<>();
            if (JavaGeneratorUtil.isOrdered(attr)) {
                String indexName = tableName + "_idx";
                generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_INDEX, indexName);
            }

            if (classContext.isUnique(attr)) {

                generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_UNIQUE, "true");
                //FIXME Could add an index
//                Pair pair = classContext.registerIndexKeyName(attrName);
//                generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_INDEX, pair.getKey());
                Pair uniqueKeyName = classContext.registerUniqueKeyName(attrName);
                String indexId = uniqueKeyName.getKey();
                String createIndex = uniqueKeyName.getValue();
                generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_UNIQUE_KEY, indexId);
            }
            generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_NOT_NULL, classContext.getNotNullTagValue(attr));
            output.write(""+prefix+"         columnAttributes = new TreeMap<>();
            if (StringUtils.isNotEmpty(attr.getDefaultValue())) {
                //TC-20100129 with a default value we must use the column child tag

                String defaultValue = attr.getDefaultValue().trim();
                columnAttributes.put(HIBERNATE_ATTRIBUTE_DEFAULT, defaultValue);
            }
            String sqlType = null;
            if (attrType.equals("timestamp")) {
                sqlType = "timestamp";
            } else if (attrType.equals("java.lang.Float")) {
                sqlType = "numeric";
            }
            if (sqlType != null) {

                // an specific sql type was specified for the attribute, use it
                columnAttributes.put(HIBERNATE_ATTRIBUTE_SQL_TYPE, sqlType);
                Integer digits = topiaExtensionTagValues.getDigits(classContext.getPackage(), classContext.getInput(), attr);
                if (digits != null) {
                    columnAttributes.put(HIBERNATE_ATTRIBUTE_SCALE, digits.toString());
                    //FIXME Should add a new tag value for this
                    columnAttributes.put(HIBERNATE_ATTRIBUTE_PRECISION, "6");
                }
            }

            // add length attribute if required
            String lengthTagValue = topiaHibernateTagValues.getLengthTagValue(attr);
            if (!StringUtils.isEmpty(lengthTagValue)) {
                generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_LENGTH, lengthTagValue);
                columnAttributes.put(HIBERNATE_ATTRIBUTE_LENGTH, lengthTagValue);
            }

            String optionalAttributes = attributesToString(optionalAttributesMap);

            // to know if specific column name mapping is given
            boolean noSpecifiedColumn = columnNames == null || columnNames.length == 0;

            if (noSpecifiedColumn) {

                String attrColumn = templateHelper.getDbName(attr);

                if (columnAttributes.isEmpty()) {

                    // simple case with no column node to generate

                    output.write(" column=\""+attrColumn+"\""+optionalAttributes+"");
                    if (attrIsEnumeration) {
output.write(">\n");
output.write(""+prefix+"            \n");
output.write(""+prefix+"                "+attrType+"");

                        // if the user tuned the model to use name instead of
                        // ordinal to store the values, we must add a clause
                        boolean useEnumerationName = topiaHibernateTagValues.hasUseEnumerationNameTagValue(attr, classContext.getInput(), classContext.getPackage(), model);
                        if (useEnumerationName) {
                            String enumSQLType = String.valueOf(Types.VARCHAR);
output.write("\n");
output.write(""+prefix+"                \n");
output.write(""+prefix+"                "+enumSQLType+"");
                        }

output.write("\n");
output.write(""+prefix+"            \n");
output.write(""+prefix+"        \n");
output.write("");
                    } else {
output.write("/>\n");
output.write("");
                    }
                } else {

                    // there is some attributes to write for the column node

                    columnAttributes.put(HIBERNATE_ATTRIBUTE_NAME, attrColumn);

                    StringBuilder columnAttributesBuilder = new StringBuilder();
                    for (Map.Entry entry : columnAttributes.entrySet()) {
                        String name = entry.getKey();
                        String value = entry.getValue();
                        columnAttributesBuilder.append(generateFromTagValue(name, value, null));
                    }
                    String columnAttributesAsString = " " + columnAttributesBuilder.toString().trim();
output.write(""+optionalAttributes+">\n");
output.write(""+prefix+"            \n");
output.write(""+prefix+"        \n");
output.write("");
                }
            } else {

                // there is a column name mapping specified, must use it
                //FIXME tchemit 2010-12-29 Really don't know how to apply columnAttributes for multi-columns...
output.write(""+optionalAttributes+">\n");
output.write("");
                for (String columnName : columnNames) {
                    columnName = attrName + "_" + columnName.trim();
output.write(""+prefix+"            \n");
output.write("");
                }
output.write(""+prefix+"        \n");
output.write("");
            }
        }
    }

    protected void generateHibernateOneToOne(Writer output,
                                             HibernateClassContext classContext,
                                             ObjectModelAttribute attr,
                                             String prefix) throws IOException {

        String attrName = getName(attr);
        String reverseAttributeName = attr.getReverseAttributeName();
        String attrType = getType(classContext, attr);
        output.write(""+prefix+"        \n");
output.write("");
    }


    protected void generateHibernateOneToOneReverse(Writer output,
                                                    HibernateClassContext classContext,
                                                    ObjectModelAttribute attr,
                                                    String prefix) throws IOException {

        String attrName = getName(attr);
        String attrType = getType(classContext, attr);
        String attrColumn = templateHelper.getDbName(attr);
        Pair uniqueKeyName = classContext.registerUniqueKeyName(attrName);
        String indexId = uniqueKeyName.getKey();
        output.write(""+prefix+"        \n");
output.write("");
    }

    protected void generateHibernateOneToOneLegacy(Writer output,
                                                   HibernateClassContext classContext,
                                                   ObjectModelAttribute attr,
                                                   String prefix) throws IOException {
//      boolean accessField = hasUnidirectionalRelationOnAbstractType(attr.getReverseAttribute(), model);
/// *{        <%=((attr.isComposite() || attr.hasAssociationClass())?" cascade=\"delete\"":"")%><%=((accessField)?" access=\"field\"":"")%> />
//} */

        // for hibernate many-to-one with unique="true" => one-to-one
        // but if it is one-to-zero-or-one unique contraints is violated
        // with null values
        boolean unique = GeneratorUtil.isOneMultiplicity(attr) || attr.isUnique();
        generateHibernateManyToOne(output, classContext, attr, unique, prefix);

    }

    protected void generateHibernateOneToMany(Writer output,
                                              HibernateClassContext classContext,
                                              ObjectModelAttribute attr,
                                              String prefix) throws IOException {
        boolean needsIndex = JavaGeneratorUtil.isOrdered(attr);
        boolean isInverse;
        String inverseValue = topiaHibernateTagValues.getInverseTagValue(attr);
        if (StringUtils.isNotEmpty(inverseValue)) {
            isInverse = Boolean.parseBoolean(inverseValue);
        } else {
            isInverse = attr.getReverseAttribute().isNavigable();
            isInverse |= templateHelper.hasUnidirectionalRelationOnAbstractType(attr, model);
        }
        String attrName = getName(attr); // ???
        String attrType = getType(classContext, attr);
        String reverseAttrDBName = templateHelper.getReverseDbName(attr);
        String orderBy = generateFromTagValue(HIBERNATE_ATTRIBUTE_ORDER_BY, topiaHibernateTagValues.getOrderByTagValue(attr));

        String cascade = "";
        if (attr.isComposite() || attr.hasAssociationClass()) {
            cascade += HIBERNATE_ATTRIBUTE_CASCADE + "=\"all,delete-orphan\" ";
        }

        String lazy = generateFromTagValue(HIBERNATE_ATTRIBUTE_LAZY, topiaHibernateTagValues.getLazyTagValue(attr), "true");
        Boolean notNullTagValue = classContext.getNotNullTagValue(attr);
        if (notNullTagValue == null) {
            notNullTagValue = attr.isComposite();
        }
        String notNull = " ";
        if (notNullTagValue) {
            notNull += generateFromTagValue(HIBERNATE_ATTRIBUTE_NOT_NULL, "true");
        }
        String fetch = generateFromTagValue(HIBERNATE_ATTRIBUTE_FETCH, topiaHibernateTagValues.getFetchTagValue(attr));

        String collType = templateHelper.getNMultiplicityHibernateType(attr);
        String inverse = "";
        if (isInverse) {
            inverse = HIBERNATE_ATTRIBUTE_INVERSE + "=\"true\" ";
        }
        String foreignKeyAttribute = "";
        if (classContext.isGenerateForeignKeyNames()) {
            String columnName = templateHelper.getDbName(attr);
            foreignKeyAttribute = " " + generateFromTagValue(HIBERNATE_ATTRIBUTE_FOREIGN_KEY, classContext.registerForeignKeyName(attr)).trim();
        }
        if (needsIndex) {
output.write(""+prefix+"        <"+collType+" name=\""+attrName+"\" "+inverse+""+lazy+""+cascade+">\n");
output.write(""+prefix+"            \n");
output.write(""+prefix+"            \n");
output.write(""+prefix+"            \n");
output.write(""+prefix+"        \n");
output.write("");
        } else {
output.write(""+prefix+"        <"+collType+" name=\""+attrName+"\" "+inverse+""+orderBy+""+fetch+""+lazy+""+cascade+">\n");
output.write(""+prefix+"            \n");
output.write(""+prefix+"            \n");
output.write(""+prefix+"        \n");
output.write("");
        }
    }

    private String generateFromTagValue(String attributeName, String tagValue) {
        return generateFromTagValue(attributeName, tagValue, null);
    }

    private String generateFromTagValue(String attributeName, Boolean tagValue) {
        return generateFromTagValue(attributeName, tagValue == null ? null : String.valueOf(tagValue), null);
    }

    /**
     * Generate hibernate xml attribute with a final space.
     */
    private String generateFromTagValue(String attributeName, String tagValue, String defaultValue) {
        String result = "";
        if (StringUtils.isNotEmpty(tagValue)) {
            result += attributeName + "=\"" + tagValue + "\" ";
        } else if (defaultValue != null) {
            result += attributeName + "=\"" + defaultValue + "\" ";
        }
        return result;
    }

    private void generateFromTagValue(Map map, String attributeName, String tagValue) {
        generateFromTagValue(map, attributeName, tagValue, null);
    }

    private void generateFromTagValue(Map map, String attributeName, Boolean tagValue) {
        generateFromTagValue(map, attributeName, tagValue == null ? null : String.valueOf(tagValue), null);
    }

    private void generateFromTagValue(Map map, String attributeName, String tagValue, String defaultValue) {
        String value = null;
        if (StringUtils.isNotEmpty(tagValue)) {
            value = tagValue;

        } else if (defaultValue != null) {
            value = defaultValue;
        }
        if (value != null) {
            map.put(attributeName, "\"" + value + "\"");
        }
    }

    private String attributesToString(Map map) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry entry : map.entrySet()) {
            sb.append(" ").append(entry.getKey()).append("=").append(entry.getValue());
        }
        return sb.toString();
    }

    protected void generateHibernateMany(Writer output,
                                         HibernateClassContext classContext,
                                         ObjectModelAttribute attr,
                                         String prefix) throws IOException {
        boolean needsIndex = JavaGeneratorUtil.isOrdered(attr);
        String attrType = getType(classContext, attr);
        String collType = templateHelper.getNMultiplicityHibernateType(attr);
        String attrColumn = templateHelper.getDbName(attr);
        String tableName = templateHelper.getManyToManyTableName(attr);

        boolean attrIsEnumeration = attr.getClassifier() != null && attr.getClassifier().isEnum();
        String reverseAttrDBName = attr.getReverseAttributeName();
        Map optionalAttributesMap = new LinkedHashMap<>();
        generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_NAME, getName(attr));
        if (classContext.isUseSchema()) {
            generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_SCHEMA, classContext.getSchema());
        }
        generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_TABLE, tableName);
        generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_LAZY, topiaHibernateTagValues.getLazyTagValue(attr));
        String orderByTagValue = topiaHibernateTagValues.getOrderByTagValue(attr);
        if (orderByTagValue != null) {
            generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_ORDER_BY, orderByTagValue);
        }
        if (attr.isComposite() || attr.hasAssociationClass()) {
            generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_CASCADE, "all,delete-orphan");
        }
        String optionalAttributes = attributesToString(optionalAttributesMap);
        String foreignKeyName = "";
        if (classContext.isGenerateForeignKeyNames()) {
            foreignKeyName = " " + generateFromTagValue(HIBERNATE_ATTRIBUTE_FOREIGN_KEY, classContext.registerSimpleForeignKeyName(tableName, attr)).trim();
        }
output.write(""+prefix+"        <"+collType+""+optionalAttributes+">\n");
output.write(""+prefix+"            \n");
output.write("");
        if (needsIndex) {
output.write(""+prefix+"            \n");
output.write("");
        }

        if (attrIsEnumeration) {
            boolean useEnumerationName = topiaHibernateTagValues.hasUseEnumerationNameTagValue(attr, classContext.getInput(), classContext.getPackage(), model);
output.write(""+prefix+"            \n");
output.write(""+prefix+"                \n");
output.write(""+prefix+"                    "+attrType+"\n");
output.write("");
            // if the user tuned the model to use name instead of
            // ordinal to store the values, we must add a clause
            if (useEnumerationName) {
                String enumSQLType = String.valueOf(Types.VARCHAR);
output.write(""+prefix+"                    \n");
output.write(""+prefix+"                    "+enumSQLType+"\n");
output.write("");
            }
output.write(""+prefix+"                \n");
output.write(""+prefix+"            \n");
output.write("");
        } else {
output.write(""+prefix+"            \n");
output.write("");
        }
output.write(""+prefix+"        \n");
output.write("");
    }

    protected void generateHibernateManyToOne(Writer output,
                                              HibernateClassContext classContext,
                                              ObjectModelAttribute attr,
                                              String prefix) throws IOException {
        generateHibernateManyToOne(output, classContext, attr, attr.isComposite() && (attr.isUnique() || classContext.isUnique(attr)), prefix);
    }

    protected void generateHibernateManyToOne(Writer output,
                                              HibernateClassContext classContext,
                                              ObjectModelAttribute attr,
                                              boolean isUnique,
                                              String prefix) throws IOException {
        String attrName = getName(attr);
        String attrType = getType(classContext, attr);
        String attrColumn = templateHelper.getDbName(attr);
        output.write(""+prefix+"         indexKeyName = classContext.registerUniqueKeyName(templateHelper.getDbName(attr));
                String indexId = indexKeyName.getKey();
                String createIndex = indexKeyName.getValue();
                output.write("unique-key=\""+indexId+"\" ");
            }
        }
output.write("/>\n");
output.write("");
    }

    protected void generateHibernateManyToMany(Writer output,
                                               HibernateClassContext classContext,
                                               ObjectModelAttribute attr,
                                               String prefix) throws IOException {
        // On ne met le inverse="true" uniquement pour un seul coté de la relation.
        // Dans le cas contraire, les modifications dans la relation ne seront
        // pas sauvegardées. Ceci n'est vrai que si les deux coté sont navigable
        boolean isInverse = attr.isNavigable() && attr.getReverseAttribute().isNavigable();
        //isInverse |= !Util.isFirstAttribute(attr);
        //isInverse = false; // 20070117 poussin: pour du many, jamais de inverse

        // Modification FD-2010-04-01 :
        // Le tagvalue "inverse" permet de spécifier qui possède le
        // inverse="true". Il est impératif de l'utiliser sur les deux
        // extrémités pour ne pas avoir de surprise.
        String inverseValue = topiaHibernateTagValues.getInverseTagValue(attr);
        if (StringUtils.isNotEmpty(inverseValue)) {
            isInverse &= Boolean.parseBoolean(inverseValue);
            // Si aucun tagvalue n'est défini, le choix est arbitraire : le
            // premier attribut dans l'ordre alphabétique sera choisi pour porter le
            // inverse="true"
        } else {
            isInverse &= GeneratorUtil.isFirstAttribute(attr);
        }

        boolean needsIndex = JavaGeneratorUtil.isOrdered(attr);
        String cascade = "";
        if (attr.isComposite() || attr.hasAssociationClass()) {
            cascade = " " + HIBERNATE_ATTRIBUTE_CASCADE + "=\"delete,delete-orphan\"";
        }

        String attrType = getType(classContext, attr);
        String attrName = getName(attr);
        String attrColumn = templateHelper.getDbName(attr);
        String lazy = generateFromTagValue(HIBERNATE_ATTRIBUTE_LAZY, topiaHibernateTagValues.getLazyTagValue(attr), "true");
        String orderBy = generateFromTagValue(HIBERNATE_ATTRIBUTE_ORDER_BY, topiaHibernateTagValues.getOrderByTagValue(attr));
        String collType = templateHelper.getNMultiplicityHibernateType(attr);
        String tableName = templateHelper.getManyToManyTableName(attr);
        String inverse = "";
        if (isInverse) {
            inverse = HIBERNATE_ATTRIBUTE_INVERSE + "=\"true\" ";
        }
        String reverseAttrDBName = templateHelper.getReverseDbName(attr);
        Map optionalAttributesMap = new HashMap<>();
        if (classContext.isUseSchema()) {
            generateFromTagValue(optionalAttributesMap, HIBERNATE_ATTRIBUTE_SCHEMA, classContext.getSchema());
        }
        String optionalAttributes = attributesToString(optionalAttributesMap);
        String foreignKeyName = "";
        String reverseForeignKeyName = "";
        if (classContext.isGenerateForeignKeyNames()) {
            foreignKeyName = " " + generateFromTagValue(HIBERNATE_ATTRIBUTE_FOREIGN_KEY, classContext.registerForeignKeyName(tableName, attr.getReverseAttribute())).trim();
            reverseForeignKeyName = " " + generateFromTagValue(HIBERNATE_ATTRIBUTE_FOREIGN_KEY, classContext.registerForeignKeyName(tableName, attr)).trim();
        }

output.write(""+prefix+"        <"+collType+" name=\""+attrName+"\" table=\""+tableName+"\" "+orderBy+""+inverse+""+lazy+""+cascade+""+optionalAttributes+">\n");
output.write(""+prefix+"            \n");
output.write("");
        if (needsIndex) {
output.write(""+prefix+"            \n");
output.write("");
        }
output.write(""+prefix+"            \n");
output.write(""+prefix+"        \n");
output.write("");
    }

    protected void generateExtraIndexes(Writer output, HibernateClassContext classContext) throws IOException {
        if (classContext.getInput().isAbstract()) {
            // do not generate on abstract entities (all objects must be generated for each concrete entity)
            return;
        }
        TopiaTemplateHelper templateHelper = getTemplateHelper();
        List attributes = new ArrayList<>();
        attributes.addAll(classContext.getInput().getAttributes());
        attributes.addAll(classContext.getInput().getAllInterfaceAttributes());
        attributes.addAll(classContext.getInput().getAllOtherAttributes());
        String tableName1 = classContext.getTableName();
        for (ObjectModelAttribute attribute : new LinkedHashSet<>(attributes)) {
            if (!attribute.isNavigable() || attribute.hasAssociationClass()) {
                // skip for this case (not a nm-multiplicity attribute)
                continue;
            }
            if (topiaExtensionTagValues.isGenerateIndex(classContext.getPackage(), classContext.getInput(), attribute)) {
                String attrColumn;
                String tableName;
                if (GeneratorUtil.isNMultiplicity(attribute) && attribute.getReverseAttribute() == null) {
                    attrColumn = attribute.getReverseAttributeName();
                    tableName = tableName1 + "_" + templateHelper.getDbName(attribute);
                } else {
                    attrColumn = templateHelper.getDbName(attribute);
                    tableName = tableName1;
                }
                classContext.registerIndexKeyName(tableName, attrColumn);
            }
        }
        Map uniqueKeys = classContext.getUniqueKeys();
        String schema = classContext.getSchema();
        for (Map.Entry entry : uniqueKeys.entrySet()) {
            String indexId = entry.getKey();
            String createIndex = entry.getValue();
            getLog().debug(String.format("Add unique index %s: %s", indexId, createIndex));
            String dropIndex = String.format("ALTER TABLE %s.%s DROP CONSTRAINT %s", schema, tableName1, indexId);
            addUniqueKey(output, indexId, createIndex, dropIndex);
        }
        Map indexes = classContext.getIndexes();
        for (Map.Entry entry : indexes.entrySet()) {
            String indexId = entry.getKey();
            String createIndex = entry.getValue();
            getLog().debug(String.format("Add index %s: %s", indexId, createIndex));
            addIndex(output, indexId, createIndex);
        }
    }

    protected void generateDatabaseObjects(Writer output, HibernateClassContext classContext, List attributes) throws IOException {
        if (classContext.getInput().isAbstract()) {
            // do not generate on abstract entities (all objects must be generated for each concrete entity)
            return;
        }
        ObjectModelAttribute reverseOneToOneAttribute = classContext.getReverseOneToOneAttribute();
        if (reverseOneToOneAttribute != null) {
            generateDatabaseObjects(output, classContext, reverseOneToOneAttribute, RelationType.ONE_TO_ONE_REVERSE);
        }
        TopiaTemplateHelper templateHelper = getTemplateHelper();
        for (ObjectModelAttribute attribute : attributes) {
            if (!attribute.isNavigable()
                    || attribute.hasAssociationClass()
                    || attribute.getClassifier() == null
                    || !templateHelper.isEntity(attribute.getClassifier())
                    || templateHelper.isAbstract(attribute.getClassifier())) {
                // skip for this case (not a nm-multiplicity attribute)
                continue;
            }
            boolean indexForeignKeys = topiaHibernateTagValues.getIndexForeignKeysTagValue(attribute, classContext.getPackage(), model);
            if (!indexForeignKeys) {
                // no index to put of the attribute.
                continue;
            }
            RelationType relationType = RelationType.valueOf(attribute);
            if (relationType == null) {
                continue;
            }
            if (relationType == RelationType.ONE_TO_ONE && attribute.isComposite()) {
                continue;
            }
            generateDatabaseObjects(output, classContext, attribute, relationType);
            if (relationType == RelationType.MANY_TO_MANY) {
                generateDatabaseObjects(output, classContext, attribute, RelationType.MANY_TO_MANY_REVERSE);
            }
        }
    }

    protected void generateDatabaseObjects(Writer output, HibernateClassContext classContext, ObjectModelAttribute attribute, RelationType relationType) throws IOException {
        String tableName;
        String propertyName;
        TopiaTemplateHelper templateHelper = getTemplateHelper();
        ObjectModelClassifier attributeClassifier = attribute.getClassifier();
        String schema = classContext.getSchema();
        switch (relationType) {
            case ONE_TO_MANY:
                schema = templateHelper.getSchema(attributeClassifier);
                tableName = templateHelper.getDbName(attributeClassifier);
                propertyName = templateHelper.getReverseDbNameOnReverseAttribute(attribute.getReverseAttribute());
                break;
            case MANY_TO_MANY:
                tableName = templateHelper.getManyToManyTableName(attribute);
                propertyName = templateHelper.getReverseDbNameOnReverseAttribute(attribute);
                break;
            case MANY_TO_MANY_REVERSE:
                tableName = templateHelper.getManyToManyTableName(attribute);
                propertyName = templateHelper.getReverseDbNameOnReverseAttribute(attribute.getReverseAttribute());
                break;
            case ONE_TO_ONE_REVERSE:
//                schema = templateHelper.getSchema(attributeClassifier);
                tableName = classContext.getTableName();
                propertyName = templateHelper.getReverseDbNameOnReverseAttribute(attribute.getReverseAttribute());
                break;
            case MANY_TO_ONE:
            case ONE_TO_ONE:
                tableName = classContext.getTableName();
                propertyName = templateHelper.getReverseDbNameOnReverseAttribute(attribute);
                break;
            default:
                return;
        }
        classContext.registerIndexKeyName(schema, tableName, propertyName);
    }

    @Override
    public void applyTemplate(ObjectModel model, File destDir) throws IOException {
        File realTarget = TopiaMetadataModelGeneratorSupport.getNotGeneratedResourceDirector(destDir);

        this.model = model;
        metadataModel = TopiaMetadataModelBuilder.buildFull(isVerbose(), model, getTemplateHelper());

        super.applyTemplate(model, realTarget);
        Map indexes = getTemplateHelper().getIndexes();
        getLog().info(String.format("[persistence] - %d index(es) detected.", indexes.size()));
        Map foreignKeys = getTemplateHelper().getForeignKeys();
        getLog().info(String.format("[persistence] - %d foreign key(s) detected.", foreignKeys.size()));
        Map uniqueKeys = getTemplateHelper().getUniqueKeys();
        getLog().info(String.format("[persistence] - %d unique key(s) detected.", uniqueKeys.size()));
    }

    @SuppressWarnings("unused")
    private void addIndex(Writer output, String indexId, String createIndex) throws IOException {
   output.write("    \n");
output.write("        "+createIndex+"\n");
output.write("        DROP INDEX "+indexId+"\n");
output.write("    \n");
output.write("");
    }

    @SuppressWarnings("unused")
    private void addUniqueKey(Writer output, String indexId, String createIndex, String dropIndex) throws IOException {
   output.write("    \n");
output.write("        "+createIndex+"\n");
output.write("        "+dropIndex+"\n");
output.write("    \n");
output.write("");
    }

    protected boolean addQuery(Writer output, String queryName, String queryCode, String extraParameters) throws IOException {
        if (!queryNames.add(queryName)) {
            getLog().warn(String.format("This sql query: '%s' already exists, can't add it twice.", queryName));
            return false;
        }
   output.write("    \n");
output.write("");
        return true;
    }

    public boolean addSqlQuery(Writer output, String queryName, String queryCode, String extraParameters, String comment, Map parameters) throws IOException {
        if (!sqlQueryNames.add(queryName)) {
            getLog().warn(String.format("This sql query: '%s' already exists, can't add it twice.", queryName));
            return false;
        }
        if (comment != null && !comment.isEmpty()) {
            extraParameters += "\n               comment=\"" + comment + "\"";
        }
        output.write("    ");
        if (parameters != null && !parameters.isEmpty()) {
            for (Map.Entry entry : parameters.entrySet()) {
                String name = entry.getKey();
                String type = entry.getValue();
        output.write("\n");
output.write("        ");
            }
        }
        output.write("\n");
output.write("");

        return true;
    }

    public boolean addSqlQuery(Writer output, String queryName, String queryCode, String extraParameters) throws IOException {
        return addSqlQuery(output, queryName, queryCode, extraParameters, null, null);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy