org.nuiton.topia.templates.EntityHibernateMappingTransformer Maven / Gradle / Ivy
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+" "+collType+">\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+" "+collType+">\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+" "+collType+">\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+" "+collType+">\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