org.nuiton.topia.templates.EntityDaoTransformer Maven / Gradle / Ivy
package org.nuiton.topia.templates;
/*
* #%L
* ToPIA :: Templates
* $Id$
* $HeadURL$
* %%
* Copyright (C) 2004 - 2014 CodeLutin
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.nuiton.eugene.GeneratorUtil;
import org.nuiton.eugene.java.ObjectModelTransformerToJava;
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.ObjectModelDependency;
import org.nuiton.eugene.models.object.ObjectModelInterface;
import org.nuiton.eugene.models.object.ObjectModelJavaModifier;
import org.nuiton.eugene.models.object.ObjectModelOperation;
import org.nuiton.topia.persistence.TopiaDao;
import org.nuiton.topia.persistence.TopiaEntity;
import org.nuiton.topia.persistence.TopiaException;
import org.nuiton.topia.persistence.TopiaQueryBuilderAddCriteriaOrRunQueryStep;
import org.nuiton.topia.persistence.TopiaQueryBuilderRunQueryWithUniqueResultStep;
import org.nuiton.topia.persistence.internal.AbstractTopiaDao;
import org.nuiton.topia.persistence.internal.support.HibernateTopiaJpaSupport;
import org.nuiton.topia.persistence.support.TopiaHibernateSupport;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* To generate all DAO related classes for a given entity.
*
* @author Tony Chemit - [email protected]
* @since 2.5.4
* @plexus.component role="org.nuiton.eugene.Template" role-hint="org.nuiton.topia.templates.EntityDaoTransformer"
*/
public class EntityDaoTransformer extends ObjectModelTransformerToJava {
/** Logger. */
private static final Log log =
LogFactory.getLog(EntityDaoTransformer.class);
/**
* map of direct usages (values) for each entity (key).
*
* This map is used to generate the findUsages methods for DAOAbstract.
*/
protected Map> usages;
/**
* All entities fqn of the model (used to detect if an attribute is not
* an entity).
*/
protected Set allEntitiesFqn;
protected String entityEnumName;
protected String entityEnumPackage;
protected TopiaTemplateHelper templateHelper;
protected TopiaTagValues topiaTagValues;
/**
* Map of extra operations for DAO. The key of the map is the qualified
* name of the entity relative to the DAO.
*/
protected Map> extraOperations =
new HashMap>();
@Override
public void transformFromModel(ObjectModel model) {
if (templateHelper == null) {
templateHelper = new TopiaTemplateHelper(model);
}
if (topiaTagValues == null) {
topiaTagValues = templateHelper.getTopiaTagValues();
}
String modelName = model.getName();
entityEnumName = modelName + "EntityEnum";
String packageName = getDefaultPackageName();
entityEnumPackage = packageName + "." + entityEnumName;
usages = templateHelper.searchDirectUsages(model);
generateParentDao();
// keep all classifiers on the model which are entities
List allEntities =
templateHelper.getEntityClasses(model, true);
allEntitiesFqn = new HashSet(allEntities.size());
for (ObjectModelClass entity : allEntities) {
String fqn = entity.getQualifiedName();
allEntitiesFqn.add(fqn);
Collection daoOperations =
new HashSet();
for (ObjectModelOperation op : entity.getOperations()) {
if (TopiaStereoTypes.hasDaoStereotype(op)) {
daoOperations.add(op);
}
}
if (daoOperations.isEmpty()) {
// found some dao operations
extraOperations.put(fqn, daoOperations);
}
}
}
@Override
public void transformFromInterface(ObjectModelInterface interfacez) {
if (!TopiaStereoTypes.hasDaoStereotype(interfacez)) {
return;
}
/**
* EVO #636 : Manage extra operations for DAO from "dao" dependency
* between an interface with stereotype <> (dependency client) and
* a class with stereotype <> (dependency supplier).
*/
ObjectModelDependency dependency =
interfacez.getDependency(TopiaTemplateHelper.DEPENDENCIES_DAO);
if (dependency == null) {
if (log.isWarnEnabled()) {
log.warn("Could not find dependency " +
TopiaTemplateHelper.DEPENDENCIES_DAO +
" but DAO stereotype was placed on the interface " +
interfacez.getName());
}
return;
}
ObjectModelClassifier classifier = dependency.getSupplier();
if (!templateHelper.isEntity(classifier)) {
// dependency supplier is not an entity...
if (log.isWarnEnabled()) {
log.warn("Dependency supplier " +
classifier.getQualifiedName() +
" is not an entity.");
}
return;
}
// keep only direct operations
Collection operations =
interfacez.getOperations();
if (CollectionUtils.isEmpty(operations)) {
// no operations on interface, this is not normal
if (log.isWarnEnabled()) {
log.warn("No operation found on interface with DAO " +
"stereotype "+classifier.getQualifiedName());
}
return;
}
if (log.isDebugEnabled()) {
log.debug("add "+operations.size()+" extra operation(s) for DAO");
}
extraOperations.put(classifier.getQualifiedName(), operations);
}
@Override
public void transformFromClass(ObjectModelClass clazz) {
if (!templateHelper.isEntity(clazz)) {
// not an entity
return;
}
String clazzName = clazz.getName();
String clazzFQN = clazz.getQualifiedName();
if (isGenerateGeneratedDao(clazz)) {
generateGeneratedDao(clazz, clazzName, clazzFQN);
}
if (isGenerateAbstractDao(clazz)) {
generateAbstractDao(clazz, clazzName, clazzFQN);
}
if (isGenerateConcreteDao(clazz)) {
generateConcreteDao(clazz, clazzName, clazzFQN);
}
}
protected boolean isGenerateConcreteDao(ObjectModelClass input) {
String daoConcreteFqn = templateHelper.getConcreteDaoFqn(input);
if (isInClassPath(daoConcreteFqn)) {
// already in class-path
return false;
}
// can safely generate the dao impl
return true;
}
protected boolean isGenerateGeneratedDao(ObjectModelClass input) {
String daoGeneratedFqn = templateHelper.getGeneratedDaoFqn(input);
if (isInClassPath(daoGeneratedFqn)) {
// already in class-path
return false;
}
// can safely generate the dao impl
return true;
}
protected boolean isGenerateAbstractDao(ObjectModelClass input) {
String fqn = templateHelper.getAbstractDaoFqn(input);
if (isInClassPath(fqn)) {
// already in class-path
return false;
}
Collection moreOperations =
extraOperations.get(input.getQualifiedName());
if (CollectionUtils.isNotEmpty(moreOperations)) {
// no user operations, can not generate it
return false;
}
// can safely generate the dao impl
return true;
}
protected void generateConcreteDao(ObjectModelClass clazz, String clazzName, String clazzFQN) {
String concreteDaoName = templateHelper.getConcreteDaoName(clazz);
ObjectModelClass daoClass = createClass(concreteDaoName, clazz.getPackageName());
setDocumentation(daoClass, "/**\n" +
" * Cette classe etend le DAOImpl pour parametrer la classe avec le bon type\n" +
" * Cette classe est marque finale car l'heritage entre les DAO se fait\n" +
" * sur les DOAImpl, c-a-d que DAOAbstract peut etendre le DAOImpl\n" +
" */");
String superclassQualifiedName = templateHelper.getAbstractDaoFqn(clazz) + "<" + clazzName + ">";
setSuperClass(daoClass, superclassQualifiedName);
// TODO AThimel 25/10/13 Remove the next lines in ToPIA 3.1
// Look for legacy Dao class, then warn user if found in classpath
String legacyConcreteDaoName = templateHelper.getLegacyDaoName(clazz);
warnOnLegacyClassDetected(clazz.getPackageName(), legacyConcreteDaoName, concreteDaoName, null,
templateHelper.getAbstractDaoFqn(clazz) + "<" + clazzName + ">");
}
protected void generateAbstractDao(ObjectModelClass clazz,
String clazzName,
String clazzFQN) {
Collection moreOperations =
extraOperations.get(clazz.getQualifiedName());
if (CollectionUtils.isEmpty(moreOperations)) {
// no business Dao found, can safely generate the abstract Dao class
String abstractDaoName = templateHelper.getAbstractDaoName(clazz);
String daoGenerics = "";
ObjectModelClass abstractDaoClass = createClass(abstractDaoName + daoGenerics, clazz.getPackageName());
String documentation = String.format("/**%n" +
" * Implantation du Dao pour l'entité '%s'.%n" +
" * L'utilisateur peut remplacer cette classe par la sienne en la mettant%n" +
" * simplement dans ses sources. Cette classe générée sera alors simplement%n" +
" * ignorée à la génération suivante.%n" +
" */", clazzName);
setDocumentation(abstractDaoClass, documentation);
String superclassQualifiedName = templateHelper.getGeneratedDaoFqn(clazz) + "";
setSuperClass(abstractDaoClass, superclassQualifiedName);
// TODO AThimel 25/10/13 Remove the next lines in ToPIA 3.1
// Look for legacy Dao class, then warn user if found in classpath
String legacyDaoImplName = templateHelper.getLegacyDaoName(clazz) + "Impl";
warnOnLegacyClassDetected(clazz.getPackageName(), legacyDaoImplName, abstractDaoName, daoGenerics,
superclassQualifiedName);
}
}
// TODO AThimel 25/10/13 Remove this method in ToPIA 3.1
protected void warnOnLegacyClassDetected(String packageName,
String legacyDaoName,
String daoName,
String daoGenerics,
String superclassQualifiedName) {
String legacyDaoFqn = String.format("%s.%s", packageName, legacyDaoName);
// AThimel 25/10/13 Not using isInClassPath(fqn) because this method logs that file won't be generated
if (log.isWarnEnabled() && getFileInClassPath(legacyDaoFqn) != null) {
String format = "public class %s%s extends %s {";
String superclassName = superclassQualifiedName.substring(superclassQualifiedName.lastIndexOf('.') + 1);
String daoDeclaration = String.format(format, daoName, Strings.nullToEmpty(daoGenerics), superclassName);
String warnMessage = "Legacy DAO detected : %s !%n" +
" - You should consider renaming '%s' to '%s'%n" +
" - Expected class declaration is : %s%n" +
"%n"; // AThimel 29/10/13 Add a new line for log clearness
log.warn(String.format(warnMessage, legacyDaoFqn, legacyDaoName, daoName, daoDeclaration));
}
}
protected void generateParentDao() {
String parentDaoFqn = templateHelper.getParentDaoFqn(this, model);
if ( ! isInClassPath(parentDaoFqn)) {
ObjectModelClass parentDao =
createAbstractClass(
templateHelper.getParentDaoName(model) + "",
templateHelper.getDaoPackage(this, model)
);
addImport(parentDao, TopiaEntity.class);
// super class
setSuperClass(parentDao, AbstractTopiaDao.class.getName() + "");
}
}
protected void generateGeneratedDao(ObjectModelClass clazz,
String clazzName,
String clazzFQN) {
ObjectModelClass daoAbstractClass = createAbstractClass(templateHelper.getGeneratedDaoName(clazz) + "',
clazz.getPackageName());
// super class
String superClassName = null;
for (ObjectModelClass parent : clazz.getSuperclasses()) {
if (templateHelper.isEntity(parent)) {
superClassName = templateHelper.getAbstractDaoFqn(parent) + "";
// in java no multi-inheritance
break;
}
}
if (superClassName == null) {
superClassName = topiaTagValues.getDaoSuperClassTagValue(clazz, getPackage(clazz), model);
if (superClassName == null) {
superClassName = templateHelper.getParentDaoFqn(this, model);
addImport(daoAbstractClass, superClassName);
}
superClassName += "";
}
if (log.isDebugEnabled()) {
log.debug("super class = " + superClassName);
}
setSuperClass(daoAbstractClass, superClassName);
String prefix = getConstantPrefix(clazz, "");
setConstantPrefix(prefix);
// imports
Collection daoOperations = getDaoOperations(clazz);
if (templateHelper.isCollectionNeeded(daoOperations)) {
addImport(daoAbstractClass, Collection.class);
}
if (templateHelper.isSetNeeded(daoOperations)) {
addImport(daoAbstractClass, Set.class);
}
addImport(daoAbstractClass, List.class);
addImport(daoAbstractClass, TopiaQueryBuilderAddCriteriaOrRunQueryStep.class);
ObjectModelOperation op;
// getEntityClass
op = addOperation(daoAbstractClass,
"getEntityClass",
"Class",
ObjectModelJavaModifier.PUBLIC);
addAnnotation(daoAbstractClass, op,Override.class);
setOperationBody(op, ""
+"\n"
+" return (Class) "+clazzName+".class;\n"
+" "
);
// getTopiaEntityEnum
addImport(daoAbstractClass, entityEnumPackage);
op = addOperation(daoAbstractClass,
"getTopiaEntityEnum",
entityEnumName,
ObjectModelJavaModifier.PUBLIC);
addAnnotation(daoAbstractClass, op,Override.class);
setOperationBody(op, ""
+"\n"
+" return "+entityEnumName+"."+clazzName+";\n"
+" "
);
generateDAOOperations(daoAbstractClass, daoOperations);
generateDelete(clazz, daoAbstractClass);
generateNaturalId(daoAbstractClass, clazz);
generateNotNull(daoAbstractClass, clazz);
for (ObjectModelAttribute attr : clazz.getAttributes()) {
if (!attr.isNavigable()) {
continue;
}
if (!GeneratorUtil.isNMultiplicity(attr)) {
generateNoNMultiplicity(clazzName, daoAbstractClass, attr, false);
} else {
generateNMultiplicity(clazzName, daoAbstractClass, attr);
}
}
if (clazz instanceof ObjectModelAssociationClass) {
ObjectModelAssociationClass assocClass =
(ObjectModelAssociationClass) clazz;
for (ObjectModelAttribute attr : assocClass.getParticipantsAttributes()) {
if (attr != null) {
if (!GeneratorUtil.isNMultiplicity(attr)) {
generateNoNMultiplicity(clazzName, daoAbstractClass, attr, true);
} else {
generateNMultiplicity(clazzName, daoAbstractClass, attr);
}
}
}
}
Set usagesForclass = usages.get(clazz);
generateFindUsages(clazz, daoAbstractClass, usagesForclass);
generateAggregateOperation(daoAbstractClass, clazz);
generateCompositeOperation(daoAbstractClass, clazz);
}
protected void generateDelete(ObjectModelClass clazz,
ObjectModelClass result) {
StringBuilder body = new StringBuilder();
String modelName = StringUtils.capitalize(model.getName());
String providerFQN = getDefaultPackageName() + '.' + modelName +
"DAOHelper.getImplementationClass";
body.append(""
+"\n"
+" if ( ! entity.isPersisted()) {\n"
+" throw new IllegalArgumentException(\"entity \" + entity + \" is not persisted, you can't delete it\");\n"
+" }\n"
+""
);
boolean hibernateSupportGenerated = false;
for (ObjectModelAttribute attr : clazz.getAttributes()) {
String attrType = GeneratorUtil.getSimpleName(attr.getType());
String reverseAttrName = attr.getReverseAttributeName();
ObjectModelAttribute reverse = attr.getReverseAttribute();
if (attr.hasAssociationClass() ||
reverse == null || !reverse.isNavigable()) {
// never treate a non reverse and navigable attribute
// never treate an association class attribute
continue;
}
// at this point we are sure to have a attribute which is
// - reverse
// - navigable
// - not from an association class
if (!allEntitiesFqn.contains(attr.getType())) {
// this attribute is not from an entity, don't treate it
if (log.isDebugEnabled()) {
log.debug("[" + result.getName() + "] Skip attribute [" +
attr.getName() + "] with type " + attr.getType());
}
continue;
}
// At this point, the attribute type is a entity
if (GeneratorUtil.isNMultiplicity(attr) &&
GeneratorUtil.isNMultiplicity(reverse)) {
// On doit absolument supprimer pour les relations many-to-many
// le this de la collection de l'autre cote
String attrDBName = templateHelper.getDbName(attr);
String attrClassifierDBName = templateHelper.getDbName(attr.getClassifier());
String attrJoinTableName = templateHelper.getManyToManyTableName(attr);
String attrReverseDBName = templateHelper.getReverseDbName(attr);
//FIXME_-FC-20100413 Use a TopiaQuery (use HQLin elements)
// // Add DAOHelper
// String daoHelper = modelName + "DAOHelper";
// String daoHelperFQN = getOutputProperties().
// getProperty(PROP_DEFAULT_PACKAGE) + '.' + daoHelper;
// addImport(result, daoHelperFQN);
//
// // Add import for TopiaQuery
// addImport(result, TopiaQuery.class);
//
// // Entity DAO and reversePropertyName
// String entityDAO = attrType + "DAO";
// String reverseAttrNameProperty =
// attrType + "." + getConstantName(reverseAttrName);
//
//
// <%=entityDAO%> dao = <%=daoHelper%>.get<%=entityDAO%>(getTopiaContext());
// TopiaQuery query = dao.createQuery("B").
// addFrom(entity.getClass(), "A").
// add("A", entity).
// addInElements("A", "B." + <%=reverseAttrNameProperty%>);
//
// System.out.println("Query : " + query);
// List<<%=attrType%>> list = dao.findAllByQuery(query);
if (!hibernateSupportGenerated) {
hibernateSupportGenerated = true;
addImport(result, TopiaHibernateSupport.class);
addImport(result, HibernateTopiaJpaSupport.class);
addImport(result, Session.class);
body.append(""
+"\n"
+" TopiaHibernateSupport hibernateSupport = ((HibernateTopiaJpaSupport) topiaJpaSupport).getHibernateSupport();\n"
+" Session hibernateSession = hibernateSupport.getHibernateSession();\n"
+""
);
}
String removeName = getJavaBeanMethodName("remove", reverseAttrName);
body.append(""
+"\n"
+" {\n"
+" String sql = \"SELECT main.topiaid \" +\n"
+" \" FROM "+attrClassifierDBName+" main, "+attrJoinTableName+" secondary \" +\n"
+" \" WHERE main.topiaid=secondary."+attrDBName+" \" +\n"
+" \" AND secondary."+attrReverseDBName+"='\" + entity.getTopiaId() + \"'\";\n"
+" List<"+attrType+"> list = hibernateSession\n"
+" .createSQLQuery(sql)\n"
+" .addEntity(\"main\", "+entityEnumName+"."+attrType+".getImplementation())\n"
+" .list();\n"
+"\n"
+" for ("+attrType+" item : list) {\n"
+" item."+removeName+"(entity);\n"
+" }\n"
+" }\n"
+""
);
} else if (!GeneratorUtil.isNMultiplicity(reverse)) {
// On doit mettre a null les attributs qui ont cet objet sur les
// autres entites en one-to-*
// TODO peut-etre qu'hibernate est capable de faire ca tout seul ?
// THIMEL: J'ai remplacé reverse.getName() par reverseAttrName sans certitude
addImport(result, attrType);
addImport(result, attr.getType() + "TopiaDao"); // AThimel 30/10/13 Not using attrType because we need FQN // Can use TopiaTemplateHelper.getConcreteDaoFqn(...) ?
String attrSimpleType = GeneratorUtil.getClassNameFromQualifiedName(attrType);
// XXX brendan 04/10/13 do not hard code concrete dao name
String attrConcreteDaoClassName = attrSimpleType + "TopiaDao";
String getName = getJavaBeanMethodName("get", reverseAttrName);
String setName = getJavaBeanMethodName("set", reverseAttrName);
body.append(""
+"\n"
+" {\n"
+" "+attrConcreteDaoClassName+" dao = topiaDaoSupplier\n"
+" .getDao("+attrSimpleType+".class, "+attrConcreteDaoClassName+".class);\n"
+" List<"+attrSimpleType+"> list = dao\n"
+" .forProperties("+attrSimpleType+"."+getConstantName(reverseAttrName)+", entity)\n"
+" .findAll();\n"
+" for ("+attrSimpleType+" item : list) {\n"
+"\n"
+" // sletellier : Set null only if target is concerned by deletion\n"
+" if (entity.equals(item."+getName+"())) {\n"
+" item."+setName+"(null);\n"
+" }\n"
+" "
);
if (attr.isAggregate()) {
body.append(""
+"\n"
+" topiaDaoSupplier.getDao("+attrSimpleType+".class).delete(item);\n"
+""
);
}
body.append(""
+"\n"
+" }\n"
+" }\n"
+""
);
}
}
if (body.length()>0) {
// something specific was done, need to generate the method
ObjectModelOperation op;
op = addOperation(result, "delete", "void", ObjectModelJavaModifier.PUBLIC);
addAnnotation(result, op,Override.class);
addParameter(op, "E", "entity");
body.append(""
+"\n"
+" super.delete(entity);\n"
+" "
);
setOperationBody(op, body.toString());
}
}
protected void generateFindUsages(ObjectModelClass clazz,
ObjectModelClass result,
Set usagesForclass) {
builder.addImport(result, LinkedList.class.getName());
builder.addImport(result, Map.class.getName());
builder.addImport(result, HashMap.class.getName());
builder.addImport(result, TopiaEntity.class.getName());
if (clazz instanceof ObjectModelAssociationClass ||
usagesForclass.isEmpty()) {
// not for an association class
// just let a null method
ObjectModelOperation operation;
operation = addOperation(result,
"findUsages",
" List",
ObjectModelJavaModifier.PUBLIC);
addParameter(operation, "Class", "type");
addParameter(operation, "E", "entity");
addAnnotation(result, operation, Override.class);
setOperationBody(operation, ""
+"\n"
+" return new LinkedList();\n"
+" "
);
operation = addOperation(result,
"findAllUsages",
"Map, List extends TopiaEntity>>",
ObjectModelJavaModifier.PUBLIC);
addParameter(operation, "E", "entity");
addAnnotation(result, operation, Override.class);
setOperationBody(operation, ""
+"\n"
+" return new HashMap, List extends TopiaEntity>>();\n"
+" "
);
return;
}
List allEntities;
Map allEntitiesByFQN;
allEntities = templateHelper.getEntityClasses(model, true);
allEntitiesByFQN = new TreeMap();
// prepare usages map and fill allEntitiesByFQN map
for (ObjectModelClass klass : allEntities) {
allEntitiesByFQN.put(klass.getQualifiedName(), klass);
}
ObjectModelOperation operation;
operation = addOperation(result,
"findUsages",
" List",
ObjectModelJavaModifier.PUBLIC);
addParameter(operation, "Class", "type");
addParameter(operation, "E", "entity");
addAnnotation(result, operation, Override.class);
StringBuilder buffer = new StringBuilder(300);
buffer.append(""
+"\n"
+" List> result = new LinkedList();\n"
+" List tmp;\n"
+""
);
for (ObjectModelClass usageClass : usagesForclass) {
String usageType = usageClass.getQualifiedName();
builder.addImport(result, usageType);
builder.addImport(result, templateHelper.getConcreteDaoFqn(usageClass));
String usageSimpleType =
GeneratorUtil.getClassNameFromQualifiedName(usageType);
String usageSimplePropertyMethod = "findAllBy" + usageSimpleType;
String usageCollectionPropertyMethod = "findAllContaining" + usageSimpleType;
for (ObjectModelAttribute attr : usageClass.getAttributes()) {
if (!attr.isNavigable()) {
// skip this case
continue;
}
String type;
String attrName = attr.getName();
if (attr.hasAssociationClass()) {
//FIXME-TC20100224 dont known how to do this ?
continue;
// type = attr.getAssociationClass().getQualifiedName();
// //FIXME-TC20100224 : this is crazy ??? must find the good name
// // Perhaps need to make different cases?
// attrName = attrName + "_" + templateHelper.toLowerCaseFirstLetter(attr.getAssociationClass().getName());
} else {
type = attr.getType();
}
if (!allEntitiesByFQN.containsKey(type)) {
// not a entity, can skip for this attribute
continue;
}
ObjectModelClass targetEntity = allEntitiesByFQN.get(type);
// if (!type.equals(clazz.getQualifiedName())) {
if (!targetEntity.equals(clazz)) {
// not a good attribute reference
continue;
}
// found something to seek
String methodName;
if (GeneratorUtil.isNMultiplicity(attr)) {
methodName = getJavaBeanMethodName("for", attrName , "Contains");
} else {
methodName = getJavaBeanMethodName("for", attrName, "Equals");
}
String daoName = templateHelper.getConcreteDaoName(usageClass);
builder.addImport(result, usageClass.getPackageName() + '.' + daoName);
buffer.append(""
+"\n"
+" if (type == "+usageSimpleType+".class) {\n"
+" "+daoName+" dao =\n"
+" topiaDaoSupplier.getDao("+usageSimpleType+".class, "+daoName+".class);\n"
+" tmp = dao."+methodName+"(entity).findAll();\n"
+" result.addAll(tmp);\n"
+" }\n"
+""
);
}
}
buffer.append(""
+"\n"
+" return (List) result;\n"
+" "
);
setOperationBody(operation, buffer.toString());
operation = addOperation(result,
"findAllUsages",
"Map, List extends TopiaEntity>>",
ObjectModelJavaModifier.PUBLIC);
addParameter(operation, "E", "entity");
addAnnotation(result, operation, Override.class);
buffer = new StringBuilder(300);
buffer.append(""
+"\n"
+" Map,List extends TopiaEntity>> result;\n"
+" result = new HashMap, List extends TopiaEntity>>("+usagesForclass.size()+");\n"
+"\n"
+" List extends TopiaEntity> list;\n"
+""
);
for (ObjectModelClass usageClass : usagesForclass) {
String fqn = usageClass.getName();
buffer.append(""
+"\n"
+" list = findUsages("+fqn+".class, entity);\n"
+" if (!list.isEmpty()) {\n"
+" result.put("+fqn+".class, list);\n"
+" }\n"
+""
);
}
buffer.append(""
+"\n"
+" return result;\n"
+" "
);
setOperationBody(operation, buffer.toString());
}
/**
* Generation of DAO operations signatures from class. These operations are
* abstract and identified by <> stereotype in the model. The
* developper must defined these methods in the DAOImpl associated to this
* DAOAbstract.
*
* @param result clazz where to add operations
* @param operations operations to generate
* @deprecated will be removed ASAP in topia 3.0
*/
@Deprecated
protected void generateDAOOperations(ObjectModelClass result,
Collection
operations) {
if (CollectionUtils.isEmpty(operations)) {
// no extra operations to generate
return;
}
for (ObjectModelOperation op : operations) {
Set exceptions = op.getExceptions();
cloneOperation(op,
result,
true,
ObjectModelJavaModifier.ABSTRACT,
ObjectModelJavaModifier.fromVisibility(op.getVisibility())
);
}
}
protected void generateNoNMultiplicity(String clazzName,
ObjectModelClass result,
ObjectModelAttribute attr,
boolean isAssoc) {
String attrName = attr.getName();
String attrType = attr.getType();
String propertyName = clazzName + "." + getConstantName(attrName);
String attrTypeForGeneric;
if (GeneratorUtil.isPrimitiveType(attrType)) {
attrTypeForGeneric = templateHelper.getClassForPrimitiveType(attr);
} else {
attrTypeForGeneric = attrType;
}
if (!isAssoc && attr.hasAssociationClass()) {
String assocClassName = attr.getAssociationClass().getName();
String assocAttrName = GeneratorUtil.getAssocAttrName(attr);
// It is about transitivity : use the property to access the
// associationClass + '.' + the property to access the expected
// attribute
// . + '.' + .
propertyName =
clazzName + '.' + getConstantName(assocAttrName) +
" + '.' + " +
assocClassName + '.' + getConstantName(attrName);
}
addImport(result, Collection.class);
ObjectModelOperation op;
op = addOperation(result,
getJavaBeanMethodName("for", attrName, "In"),
"TopiaQueryBuilderAddCriteriaOrRunQueryStep",
ObjectModelJavaModifier.PUBLIC);
addParameter(op, "Collection<" + attrTypeForGeneric + ">", "v");
setOperationBody(op, ""
+"\n"
+" TopiaQueryBuilderAddCriteriaOrRunQueryStep result = forIn("+propertyName+", (Collection) v);\n"
+" return result;\n"
+" "
);
op = addOperation(result,
getJavaBeanMethodName("for", attrName, "Equals"),
"TopiaQueryBuilderAddCriteriaOrRunQueryStep",
ObjectModelJavaModifier.PUBLIC);
addParameter(op, attrType, "v");
setOperationBody(op, ""
+"\n"
+" TopiaQueryBuilderAddCriteriaOrRunQueryStep result = forEquals("+propertyName+", v);\n"
+" return result;\n"
+" "
);
String methodToDelegateName = op.getName();
op = addOperation(result,
getJavaBeanMethodName("findBy", attrName),
"E",
ObjectModelJavaModifier.PUBLIC);
addParameter(op, attrType, "v");
setOperationBody(op, ""
+"\n"
+" return "+methodToDelegateName+"(v).findAnyOrNull();\n"
+" "
);
addAnnotation(result, op, Deprecated.class);
op = addOperation(result,
getJavaBeanMethodName("findAllBy", attrName),
"List",
ObjectModelJavaModifier.PUBLIC);
addParameter(op, attrType, "v");
setOperationBody(op, ""
+"\n"
+" return "+methodToDelegateName+"(v).findAll();\n"
+" "
);
addAnnotation(result, op, Deprecated.class);
if (!isAssoc && attr.hasAssociationClass()) {
String assocClassName = attr.getAssociationClass().getName();
String assocClassFQN = attr.getAssociationClass().getQualifiedName();
String assocAttrName = GeneratorUtil.getAssocAttrName(attr);
String assocPropertyConstantName = getConstantName(assocAttrName);
op = addOperation(result,
getJavaBeanMethodName("findBy", assocClassName),
"E",
ObjectModelJavaModifier.PUBLIC);
addParameter(op, assocClassFQN, "value");
setOperationBody(op, ""
+"\n"
+" E result = forProperties("+clazzName + "." + assocPropertyConstantName+", value).findAnyOrNull();\n"
+" return result;\n"
+" "
);
op = addOperation(result,
getJavaBeanMethodName("findAllBy", assocClassName),
"List",
ObjectModelJavaModifier.PUBLIC);
addParameter(op, assocClassFQN, "value");
setOperationBody(op, ""
+"\n"
+" List result = forProperties("+clazzName + "." + assocPropertyConstantName+", value).findAll();\n"
+" return result;\n"
+" "
);
}
}
protected void generateNMultiplicity(String clazzName,
ObjectModelClass result,
ObjectModelAttribute attr) {
String attrName = attr.getName();
String attrType = attr.getType();
if (attr.hasAssociationClass()) {
// do nothing for association class, too complex...
return;
}
ObjectModelOperation op;
op = addOperation(result,
getJavaBeanMethodName("for", attrName, "Contains"),
"TopiaQueryBuilderAddCriteriaOrRunQueryStep",
ObjectModelJavaModifier.PUBLIC);
addParameter(op, attrType, "v");
setOperationBody(op, ""
+"\n"
+" return forContains("+clazzName + "." + getConstantName(attrName)+", v);\n"
+" "
);
String methodToDelegateName = op.getName();
op = addOperation(result,
getJavaBeanMethodName("findContains", attrName),
"E",
ObjectModelJavaModifier.PUBLIC);
addParameter(op, attrType, "v");
setOperationBody(op, ""
+"\n"
+" return "+methodToDelegateName+"(v).findAnyOrNull();\n"
+" "
);
addAnnotation(result, op, Deprecated.class);
op = addOperation(result,
getJavaBeanMethodName("findAllContains", attrName),
"List",
ObjectModelJavaModifier.PUBLIC);
addParameter(op, attrType, "v");
setOperationBody(op, ""
+"\n"
+" return "+methodToDelegateName+"(v).findAll();\n"
+" "
);
addAnnotation(result, op, Deprecated.class);
}
/**
* Obtain business operations of the DAO.
*
* This operations can not be generated, but must be written by developper.
*
* @param clazz the clazz to test.
* @return collections of extra operations, or empty collection if none found.
* @deprecated Dao operation will not be generated anymore in a very close future
*/
@Deprecated
public Collection getDaoOperations(
ObjectModelClass clazz) {
// // Note : this collection will contains extra operations for DAO.
// // Overriding existing generated methods is not managed yet
// Collection results =
// new ArrayList();
// // This code will be deprecated
// for (ObjectModelOperation op : clazz.getOperations()) {
// if (templateHelper.hasDaoStereotype(op)) {
// results.add(op);
// }
// }
Collection extra =
extraOperations.get(clazz.getQualifiedName());
if (extra != null && !extra.isEmpty() && log.isWarnEnabled()) {
log.warn("Dao contract in model will not be supported in topia 3.0");
}
return extra;
// if (extra != null) {
// for (ObjectModelOperation op : extra) {
// results.add(op);
// }
// }
// return results;
}
private void generateNaturalId(ObjectModelClass result,
ObjectModelClass clazz) {
Set props =
templateHelper.getNaturalIdAttributes(clazz);
if (!props.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("generateNaturalId for " + props);
}
ObjectModelOperation findByNaturalId = addOperation(result,
"findByNaturalId", "E", ObjectModelJavaModifier.PUBLIC);
addAnnotation(result, findByNaturalId, Deprecated.class);
ObjectModelOperation existByNaturalId = addOperation(result,
"existByNaturalId", "boolean", ObjectModelJavaModifier.PUBLIC);
addAnnotation(result, existByNaturalId, Deprecated.class);
ObjectModelOperation createByNaturalId = addOperation(result,
"createByNaturalId", "E", ObjectModelJavaModifier.PUBLIC);
addImport(result, TopiaQueryBuilderRunQueryWithUniqueResultStep.class);
ObjectModelOperation forNaturalId = addOperation(result,
"forNaturalId", "TopiaQueryBuilderRunQueryWithUniqueResultStep", ObjectModelJavaModifier.PUBLIC);
Set < String > properties = Sets.newLinkedHashSet();
String clazzName = clazz.getName();
for (ObjectModelAttribute attr : props) {
String propName = attr.getName();
String type = attr.getType();
addParameter(findByNaturalId, type, propName);
addParameter(existByNaturalId, type, propName);
addParameter(createByNaturalId, type, propName);
addParameter(forNaturalId, type, propName);
String property = clazzName + '.' + getConstantName(propName) + ", " + propName;
properties.add(property);
}
String arguments = StringUtils.join(properties, ", ");
setOperationBody(findByNaturalId, ""
+"\n"
+" return forProperties("+arguments+").findUnique();\n"
+" "
);
setOperationBody(existByNaturalId, ""
+"\n"
+" return forProperties("+arguments+").exists();\n"
+" "
);
setOperationBody(createByNaturalId, ""
+"\n"
+" return create("+arguments+");\n"
+" "
);
setOperationBody(forNaturalId, ""
+"\n"
+" return forProperties("+arguments+");\n"
+" "
);
}
}
protected void generateNotNull(ObjectModelClass result,
ObjectModelClass clazz) {
Set props =
templateHelper.getNotNullAttributes(clazz);
if (!props.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("generateNotNull for " + props);
}
ObjectModelOperation createByNotNull = addOperation(result,
"createByNotNull", "E", ObjectModelJavaModifier.PUBLIC);
String createProperties = "";
// String params = "";
String clazzName = clazz.getName();
for (ObjectModelAttribute attr : props) {
String propName = attr.getName();
// add property as param in both methods
addParameter(createByNotNull, attr.getType(), propName);
createProperties +=
", " + clazzName + '.' + getConstantName(propName) +
", " + propName;
//params += ", " + propName;
}
createProperties = createProperties.substring(2);
//params = params.substring(2);
setOperationBody(createByNotNull, ""
+"\n"
+" return create("+createProperties+");\n"
+" "
);
}
}
protected void generateCompositeOperation(ObjectModelClass outputAbstract, ObjectModelClass input) {
ObjectModelOperation operation =
addOperation(outputAbstract, "getComposite",
List.class.getName() + '<' + TopiaEntity.class.getName() + '>');
addParameter(operation, "E", "entity");
addException(operation, TopiaException.class);
addAnnotation(outputAbstract, operation, Override.class);
StringBuilder body;
addImport(outputAbstract, ArrayList.class);
addImport(outputAbstract, List.class);
addImport(outputAbstract, TopiaDao.class);
body = new StringBuilder(""
+"\n"
+" List tmp = new ArrayList();\n"
+"\n"
+" // pour tous les attributs rechecher les composites et les class d'asso\n"
+" // on les ajoute dans tmp\n"
+""
);
for (ObjectModelAttribute attr : input.getAttributes()) {
if (attr.referenceClassifier() &&
templateHelper.isEntity(attr.getClassifier())) {
if (attr.isComposite() && attr.isNavigable()) {
String attrName = attr.getName();
String getterName = getJavaBeanMethodName("get", attrName);
if (GeneratorUtil.isNMultiplicity(attr)) {
body.append(""
+" if (entity."+getterName+"() != null) {\n"
+" tmp.addAll(entity."+getterName+"());\n"
+" }\n"
+""
);
} else {
body.append(""
+" tmp.add(entity."+getterName+"());\n"
+""
);
}
} else if (attr.hasAssociationClass()) {
if (!GeneratorUtil.isNMultiplicity(attr)) {
String assocAttrName = GeneratorUtil.getAssocAttrName(attr);
String entityAbstractName = templateHelper.getEntityAbstractName(input);
// Use the protected access to entity field
body.append(""
+"\n"
+" "+entityAbstractName+" entityAbstract = ("+entityAbstractName+")entity;\n"
+" if (entityAbstract."+assocAttrName+" != null) {\n"
+" tmp.add(entityAbstract."+assocAttrName+");\n"
+" }\n"
+""
);
} else {
ObjectModelAttribute reverse = attr.getReverseAttribute();
String reverseAttrName = reverse.getName();
// On utilise pas l'attribut car il n'est potentiellement
// pas à jour, car pour les asso avec cardinalité
// personne ne fait de add. Ce qui est normal, mais
// pour pouvoir faire tout de même des delete en cascade
// sur les asso, le champs est dans le mapping
// hibernate et donc il le faut aussi dans la classe
// sinon hibernate râle lorsqu'il charge l'objet
// if (<%=ref%> != null) {
// tmp.addAll(<%=ref%>);
// }
String assocClassFQN = attr.getAssociationClass().getQualifiedName();
String assocClassName = GeneratorUtil.getSimpleName(assocClassFQN);
String assocConcreteDaoClassFQN = templateHelper.getConcreteDaoFqn(attr.getAssociationClass());
String assocConcreteDaoClassName = GeneratorUtil.getSimpleName(assocConcreteDaoClassFQN);
addImport(outputAbstract, assocClassFQN);
addImport(outputAbstract, assocConcreteDaoClassFQN);
body.append(""
+"\n"
+" {\n"
+" "+assocConcreteDaoClassName+" dao = topiaDaoSupplier\n"
+" .getDao("+assocClassName+".class, "+assocConcreteDaoClassName+".class);\n"
+" List<"+assocClassName+"> findAllByProperties = dao.forProperties(\""+reverseAttrName+"\", entity).findAll();\n"
+" if (findAllByProperties != null) {\n"
+" tmp.addAll(findAllByProperties);\n"
+" }\n"
+" }\n"
+""
);
}
}
}
}
body.append(""
+"\n"
+" // on refait un tour sur chaque entity de tmp pour recuperer leur\n"
+" // composite\n"
+" List result = new ArrayList();\n"
+" for (TopiaEntity e : tmp) {\n"
+" if (e != null) {\n"
+" result.add(e);\n"
+" TopiaDao dao = (TopiaDao) topiaDaoSupplier.getDao(e.getClass());\n"
+" result.addAll(dao.getComposite(e));\n"
+" }\n"
+" }\n"
+" return result;\n"
+" "
);
setOperationBody(operation, body.toString());
}
protected void generateAggregateOperation(ObjectModelClass outputAbstract, ObjectModelClass input) {
ObjectModelOperation operation =
addOperation(outputAbstract, "getAggregate",
List.class.getName() + '<' + TopiaEntity.class.getName() + '>');
addParameter(operation, "E", "entity");
addException(operation, TopiaException.class);
addAnnotation(outputAbstract, operation, Override.class);
StringBuilder body = new StringBuilder();
addImport(outputAbstract, ArrayList.class);
addImport(outputAbstract, List.class);
addImport(outputAbstract, TopiaDao.class);
body .append(""
+"\n"
+" List tmp = new ArrayList();\n"
+"\n"
+" // pour tous les attributs rechecher les composites et les class d'asso\n"
+" // on les ajoute dans tmp\n"
+""
);
for (ObjectModelAttribute attr : input.getAttributes()) {
if (attr.referenceClassifier() &&
templateHelper.isEntity(attr.getClassifier()) &&
attr.isAggregate()) {
String attrName = attr.getName();
String getterName = getJavaBeanMethodName("get", attrName);
if (GeneratorUtil.isNMultiplicity(attr)) {
body.append(""
+" tmp.addAll(entity."+getterName+"());\n"
+""
);
} else {
body.append(""
+" tmp.add(entity."+getterName+"());\n"
+""
);
}
}
}
body.append(""
+"\n"
+" // on refait un tour sur chaque entity de tmp pour recuperer leur\n"
+" // composite\n"
+" List result = new ArrayList();\n"
+" for (TopiaEntity e : tmp) {\n"
+" result.add(e);\n"
+" TopiaDao dao = (TopiaDao) topiaDaoSupplier.getDao(e.getClass());\n"
+" result.addAll(dao.getAggregate(e));\n"
+" }\n"
+" return result;\n"
+" "
);
setOperationBody(operation, body.toString());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy