fr.ird.observe.toolkit.eugene.templates.EntityReferenceTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eugene-templates-extension Show documentation
Show all versions of eugene-templates-extension Show documentation
ObServe Eugene templates extension module
package fr.ird.observe.toolkit.eugene.templates;
/*
* #%L
* ObServe Toolkit :: Eugene Templates Extension
* %%
* Copyright (C) 2017 - 2019 IRD, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import fr.ird.observe.binder.EntityReferenceBinderSupport;
import fr.ird.observe.binder.data.DataDtoReferenceBinder;
import fr.ird.observe.binder.data.DataEntityReferenceBinderSupport;
import fr.ird.observe.binder.referential.ReferentialDtoReferenceBinder;
import fr.ird.observe.binder.referential.ReferentialEntityReferenceBinderSupport;
import fr.ird.observe.dto.IdDto;
import fr.ird.observe.dto.data.DataDto;
import fr.ird.observe.dto.reference.DataDtoReference;
import fr.ird.observe.dto.reference.DtoReference;
import fr.ird.observe.dto.reference.DtoReferenceDefinition;
import fr.ird.observe.dto.reference.ReferentialDtoReference;
import fr.ird.observe.dto.referential.ReferentialDto;
import fr.ird.observe.dto.referential.ReferentialLocale;
import fr.ird.observe.spi.initializer.EntitiesBinderInitializerSupport;
import org.apache.commons.lang3.StringUtils;
import org.nuiton.eugene.EugeneCoreTagValues;
import org.nuiton.eugene.java.BeanTransformer;
import org.nuiton.eugene.java.BeanTransformerContext;
import org.nuiton.eugene.java.BeanTransformerTagValues;
import org.nuiton.eugene.java.EugeneJavaTagValues;
import org.nuiton.eugene.java.JavaGeneratorUtil;
import org.nuiton.eugene.java.ObjectModelTransformerToJava;
import org.nuiton.eugene.models.object.ObjectModel;
import org.nuiton.eugene.models.object.ObjectModelAttribute;
import org.nuiton.eugene.models.object.ObjectModelClass;
import org.nuiton.eugene.models.object.ObjectModelJavaModifier;
import org.nuiton.eugene.models.object.ObjectModelOperation;
import org.nuiton.eugene.models.object.ObjectModelPackage;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import static fr.ird.observe.toolkit.eugene.templates.DtoReferenceTransformer.generateMetaInfService;
/**
* Generates a reference of a bean.
*
* For example:
*
* GeneratedBoatReference
* BoatReference
*
*
* @author Tony Chemit - [email protected]
* @plexus.component role="org.nuiton.eugene.Template" role-hint="fr.ird.observe.toolkit.eugene.templates.EntityReferenceTransformer"
* @since 1.04
*/
public class EntityReferenceTransformer extends ObjectModelTransformerToJava {
private final EugeneCoreTagValues coreTagValues;
private final EugeneJavaTagValues javaTemplatesTagValues;
private final ObserveTagValues observeTagValues;
private final BeanTransformerTagValues beanTagValues;
private BeanTransformerContext context;
public EntityReferenceTransformer() {
coreTagValues = new EugeneCoreTagValues();
javaTemplatesTagValues = new EugeneJavaTagValues();
beanTagValues = new BeanTransformerTagValues();
observeTagValues = new ObserveTagValues();
}
@Override
public void transformFromModel(ObjectModel model) {
super.transformFromModel(model);
ImmutableSet.Builder withReferencesBuilder = ImmutableSet.builder();
ImmutableSet.Builder withFormBuilder = ImmutableSet.builder();
context = new BeanTransformerContext(model, coreTagValues, javaTemplatesTagValues, beanTagValues, false, false, input -> {
ObjectModelPackage aPackage = model.getPackage(input.getPackageName());
boolean referential = BinderHelper.isReferentialFromPackageName(aPackage.getName());
String referencesTagValue = observeTagValues.getReferencesTagValue(input);
String formTagValue = observeTagValues.getFormTagValue(input, getModel().getPackage(input.getPackageName())).trim();
boolean withReference = referencesTagValue != null || referential;
boolean withForm = StringUtils.isNotEmpty(formTagValue);
boolean keep = false;
if (withForm) {
withFormBuilder.add(input.getQualifiedName());
keep = true;
}
if (withReference) {
withReferencesBuilder.add(input.getQualifiedName());
keep = true;
}
return keep;
}, getLog());
context.report();
ImmutableSet withReferenceFqns = withReferencesBuilder.build();
ImmutableSet withFormFqns = withFormBuilder.build();
boolean useRelativeName = context.useRelativeName;
String binderPackageName = EntityReferenceBinderSupport.class.getPackage().getName();
ObjectModelPackage defaultPackage = getModel().getPackage(getDefaultPackageName());
String packageName = defaultPackage.getName() + ".";
int defaultPackageNameLength = packageName.length();
for (ObjectModelClass input : context.selectedClasses) {
if (!withReferenceFqns.contains(input.getQualifiedName())) {
continue;
}
ObjectModelPackage aPackage = getPackage(input);
boolean referential = BinderHelper.isReferentialFromPackageName(aPackage.getName());
String referencesTagValue = observeTagValues.getReferencesTagValue(input);
if (referencesTagValue == null && referential) {
referencesTagValue = "code,label,uri";
}
Objects.requireNonNull(referencesTagValue);
withReferencesBuilder.add(input.getQualifiedName());
Set availableProperties = new LinkedHashSet<>(Arrays.asList(referencesTagValue.split(",")));
Map binderProperties = DtoReferenceTransformer.getBinderProperties(context.selectedClassesFqn, input, availableProperties, this::getAttributeType);
String prefix = getConstantPrefix(input);
setConstantPrefix(prefix);
String entityName = input.getName();
String dtoName = context.classesNameTranslation.get(input);
String className = BinderHelper.cleanId(dtoName) + "Reference";
Class> binderSuperClass = referential ? ReferentialEntityReferenceBinderSupport.class : DataEntityReferenceBinderSupport.class;
String binderName = BinderHelper.generateBinderName(binderPackageName, aPackage.getName() + "." + entityName, entityName + "EntityReference");
boolean generateBinder = !getResourcesHelper().isJavaFileInClassPath(binderName);
if (generateBinder) {
generateBinderClass(input, useRelativeName, dtoName, className, binderName, String.format("%s<%s, %s, %s>", binderSuperClass.getName(), dtoName, className, entityName), binderProperties);
}
}
String initializerName = "EntityBindersInitializer";
String generatedInitializerName = "Generated" + initializerName;
String initializerPackageName = EntitiesBinderInitializerSupport.class.getPackage().getName();
ObjectModelPackage aPackage = getModel().getPackage(getDefaultPackageName());
generateGeneratedInitializer(initializerPackageName, aPackage.getName(), binderPackageName, generatedInitializerName, withReferenceFqns, withFormFqns);
boolean generateInitializer = notFoundInClassPath(binderPackageName, initializerName);
if (generateInitializer) {
generateInitializer(initializerPackageName, generatedInitializerName, initializerName);
}
generateMetaInfService(getConfiguration(), initializerPackageName + "." + initializerName, EntitiesBinderInitializerSupport.class);
}
private void generateGeneratedInitializer(String initializerPackageName, String defaultPackageName, String binderPackageName, String generatedInitializerName, ImmutableSet withReferenceFqns, ImmutableSet withFormFqns) {
int defaultPackageNameLength = defaultPackageName.length();
String modelName = getModel().getName();
ObjectModelClass output = createAbstractClass(generatedInitializerName, initializerPackageName);
setSuperClass(output, EntitiesBinderInitializerSupport.class);
addImport(output, Map.class);
addImport(output, ImmutableMap.class);
addImport(output, ImmutableSet.class);
addImport(output, Set.class);
addImport(output, LinkedHashSet.class);
addImport(output, TreeMap.class);
addImport(output, ReferentialDto.class);
addImport(output, DataDto.class);
addImport(output, IdDto.class);
addImport(output, DtoReference.class);
addImport(output, ReferentialDtoReference.class);
addImport(output, DataDtoReference.class);
addImport(output, DtoReferenceDefinition.class);
addImport(output, ReferentialDtoReferenceBinder.class);
addImport(output, DataDtoReferenceBinder.class);
addImport(output, defaultPackageName + "." + modelName + "ModelInitializer");
addImport(output, defaultPackageName + "." + modelName + "ModelInitializerRunner");
addInterface(output, modelName + "ModelInitializer");
ObjectModelOperation constructor = addConstructor(output, ObjectModelJavaModifier.PUBLIC);
setOperationBody(constructor, ""+"\n"
+" "+modelName+"ModelInitializerRunner.init(this);\n"
+" "
);
ObjectModelOperation startMethod = addOperation(output, "start", "void", ObjectModelJavaModifier.PUBLIC);
addAnnotation(output, startMethod, Override.class);
ObjectModelOperation endMethod = addOperation(output, "end", "void", ObjectModelJavaModifier.PUBLIC);
addAnnotation(output, endMethod, Override.class);
setOperationBody(endMethod, ""+"\n"
+" super.end();\n"
+" "
);
boolean useRelativeName = context.useRelativeName;
String[] relativeNameExcludes = context.relativeNameExcludes;
for (String fqn : context.selectedClassesFqn) {
ObjectModelClass beanClass = context.selectedClassesByFqn.get(fqn);
ObjectModelPackage thisPackage = getModel().getPackage(beanClass);
if (BeanTransformer.skipForInitializer(thisPackage, beanClass)) {
continue;
}
String dtoName = thisPackage.getName() + "." + context.classesNameTranslation.get(beanClass);
String simpleDtoName = JavaGeneratorUtil.getSimpleName(dtoName);
String methodName = getMethodName(useRelativeName, relativeNameExcludes, "init", null, dtoName);
ObjectModelOperation operation = addOperation(output, methodName, "void", ObjectModelJavaModifier.PUBLIC);
addAnnotation(output, operation, Override.class);
if (context.selectedClasses.contains(beanClass)) {
boolean referential = BinderHelper.isReferentialFromPackageName(beanClass.getPackageName());
StringBuilder body = new StringBuilder();
boolean withReference = withReferenceFqns.contains(fqn);
boolean withForm = withFormFqns.contains(fqn);
if (withForm) {
// add dto binder
String binderMethodName = referential ? "registerDtoReferentialBinder" : "registerDtoDataBinder";
String binderName = BinderHelper.generateBinderName(binderPackageName, fqn, beanClass.getName() + "EntityDto");
if (!useRelativeName) {
addImport(output, binderName);
binderName = JavaGeneratorUtil.getSimpleName(binderName);
}
body.append("" +"\n"
+" "+binderMethodName+"(new "+binderName+"());");
}
if (withReference) {
// add reference binder
String binderMethodName = referential ? "registerReferenceReferentialBinder" : "registerReferenceDataBinder";
String binderName = BinderHelper.generateBinderName(binderPackageName, fqn, beanClass.getName() + "EntityReference");
if (!useRelativeName) {
addImport(output, fqn + "Reference");
addImport(output, binderName);
binderName = JavaGeneratorUtil.getSimpleName(binderName);
}
body.append("" +"\n"
+" "+binderMethodName+"(new "+binderName+"());");
}
setOperationBody(operation, body.toString()+"\n"
+" ");
}
}
}
private void generateBinderClass(ObjectModelClass input, boolean useRelativeName, String dtoName, String className, String binderFullClassName, String superClass, Map properties) {
String binderClassName = JavaGeneratorUtil.getSimpleName(binderFullClassName);
ObjectModelClass output = createClass(binderClassName, binderFullClassName.substring(0, binderFullClassName.lastIndexOf(".")));
String entityName = input.getName();
ObjectModelClass entityClass = context.selectedClassesByFqn.get(BinderHelper.cleanId(input.getQualifiedName()));
String entityTypePackage = getEntityPackage(entityClass);
setSuperClass(output, superClass);
addImport(output, input.getPackageName() + "." + dtoName);
addImport(output, input.getPackageName() + "." + className);
addImport(output, entityTypePackage + "." + input.getName());
getLog().debug("will generate " + output.getQualifiedName());
ObjectModelOperation constructor = addConstructor(output, ObjectModelJavaModifier.PUBLIC);
setOperationBody(constructor, ""+"\n"
+" super("+dtoName+".class, "+className+".class, "+entityName+".class);\n"
+" ");
ObjectModelOperation operation = addOperation(output, "toReference", className, ObjectModelJavaModifier.PUBLIC);
addAnnotation(output, operation, Override.class);
addParameter(operation, ReferentialLocale.class, "referentialLocale");
addParameter(operation, input.getName(), "entity");
int prefixLength = (" return new " + className + "(").length();
String prefix = StringUtils.leftPad("", prefixLength, " ");
StringBuilder body = new StringBuilder(""+"\n"
+" return new "+className+"(entity,");
Iterator> iterator = properties.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = iterator.next();
ObjectModelAttribute attr = entry.getKey();
ObjectModelAttribute dtoAttr = entry.getValue();
String content = "";
if (dtoAttr != null) {
String getterName;
String type = JavaGeneratorUtil.getSimpleName(dtoAttr.getType());
String dtoAttrname = dtoAttr.getName();
boolean booleanProperty = JavaGeneratorUtil.isBooleanPrimitive(dtoAttr);
if (booleanProperty) {
getterName = JavaGeneratorUtil.OPERATION_GETTER_BOOLEAN_PREFIX;
} else {
getterName = JavaGeneratorUtil.OPERATION_GETTER_DEFAULT_PREFIX;
}
getterName += JavaGeneratorUtil.capitalizeJavaBeanPropertyName(dtoAttrname);
content = "entity." + getterName + "()";
if (context.selectedClassesFqn.contains(BinderHelper.cleanId(dtoAttr.getType()))) {
entityClass = context.selectedClassesByFqn.get(BinderHelper.cleanId(dtoAttr.getType()));
entityTypePackage = getEntityPackage(entityClass);
String entityType = entityClass.getName();
// Dto
if (!type.endsWith("Reference")) {
// not a ref, get a ref
type = BinderHelper.cleanId(type) + "Reference";
}
String entityTypeFqn = useRelativeName ? entityTypePackage + "." + entityType : entityType;
if (attr.getName().equals(dtoAttrname + "Id")) {
if (!useRelativeName) {
addImport(output, entityTypeFqn);
}
addImport(output, Optional.class);
addImport(output, IdDto.class);
content = String.format("Optional.ofNullable(%s).map(%s::getTopiaId).orElse(null)", content, entityTypeFqn);
} else if (attr.getName().equals(dtoAttrname + "Label")) {
if (!useRelativeName) {
addImport(output, entityTypeFqn);
}
addImport(output, Optional.class);
addImport(output, IdDto.class);
String method = "getLabel(referentialLocale)";
if (type.equals("SpeciesReference")) {
method = "getScientificLabel()";
}
content = String.format("Optional.ofNullable(%s).map(e-> e.%s).orElse(null)", content, method);
} else if (attr.getName().equals(dtoAttrname + "Code")) {
if (!useRelativeName) {
addImport(output, entityTypeFqn);
}
addImport(output, Optional.class);
addImport(output, IdDto.class);
content = String.format("Optional.ofNullable(%s).map(%s::getCode).orElse(null)", content, entityTypeFqn);
} else {
// Reference
content = "toDataReference(referentialLocale, " + content + ")";
}
}
} else {
if (attr.getName().equals("label")) {
content = "entity.getLabel(referentialLocale)";
} else {
content = "null";
}
}
content = prefix + content;
String coma = iterator.hasNext() ? "," : "";
body.append(""+"\n"
+""+content+""+coma+""
);
}
body.append(""+");\n"
+" ");
setOperationBody(operation, body.toString());
}
private void generateInitializer(String initializerPackageName, String generatedInitializerName, String initializerName) {
ObjectModelClass output = createClass(initializerName, initializerPackageName);
setSuperClass(output, generatedInitializerName);
getLog().debug("will generate " + output.getQualifiedName());
}
private boolean notFoundInClassPath(String input, String className) {
String fqn = input + "." + className;
boolean inClassPath = getResourcesHelper().isJavaFileInClassPath(fqn);
return !inClassPath;
}
private String getAttributeType(String attrType) {
if (!JavaGeneratorUtil.isPrimitiveType(attrType)) {
boolean hasClass = model.hasClass(attrType);
if (hasClass) {
ObjectModelClass attributeClass = model.getClass(attrType);
String attributeType = context.classesNameTranslation.get(attributeClass);
if (attributeType != null) {
attrType = attributeClass.getPackageName() + "." + attributeType;
}
}
}
return attrType;
}
private String getEntityPackage(ObjectModelClass entityClass) {
return "fr.ird.observe.entities" + BinderHelper.getRelativeDtoPackage(entityClass.getPackageName());
}
}