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

fr.ird.observe.toolkit.eugene.templates.DtoReferenceTransformer Maven / Gradle / Ivy

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

/*
 * #%L
 * ObServe Toolkit :: Eugene Templates Extension
 * %%
 * Copyright (C) 2017 - 2018 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.DtoReferenceBinder;
import fr.ird.observe.binder.data.DataDtoReferenceBinder;
import fr.ird.observe.binder.referential.ReferentialDtoReferenceBinder;
import fr.ird.observe.dto.IdDto;
import fr.ird.observe.dto.IdHelper;
import fr.ird.observe.dto.data.DataDto;
import fr.ird.observe.dto.reference.DataDtoReference;
import fr.ird.observe.dto.reference.DataDtoReferenceDefinition;
import fr.ird.observe.dto.reference.DtoReference;
import fr.ird.observe.dto.reference.DtoReferenceAware;
import fr.ird.observe.dto.reference.DtoReferenceDefinition;
import fr.ird.observe.dto.reference.ReferentialDtoReference;
import fr.ird.observe.dto.reference.ReferentialDtoReferenceAware;
import fr.ird.observe.dto.reference.ReferentialDtoReferenceDefinition;
import fr.ird.observe.dto.referential.ReferentialDto;
import fr.ird.observe.spi.initializer.DtoReferencesInitializerSupport;
import io.ultreia.java4all.bean.spi.GenerateJavaBeanDefinition;
import io.ultreia.java4all.i18n.spi.builder.I18nKeySet;
import org.nuiton.eugene.TemplateConfiguration;
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.java.extension.ObjectModelAnnotation;
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 org.nuiton.eugene.models.object.xml.ObjectModelAttributeImpl;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;

/**
 * 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.DtoReferenceTransformer" * @since 1.04 */ public class DtoReferenceTransformer extends ObjectModelTransformerToJava { private final EugeneJavaTagValues javaTemplatesTagValues; private final BeanTransformerTagValues beanTagValues; private final ObserveTagValues observeTagValues; private BeanTransformerContext context; public DtoReferenceTransformer() { javaTemplatesTagValues = new EugeneJavaTagValues(); beanTagValues = new BeanTransformerTagValues(); observeTagValues = new ObserveTagValues(); } @Override public void transformFromModel(ObjectModel model) { super.transformFromModel(model); context = new BeanTransformerContext(model, javaTemplatesTagValues, beanTagValues, false, false, input -> { ObjectModelPackage aPackage = model.getPackage(input.getPackageName()); boolean referential = IdHelper.isReferentialFromPackageName(aPackage.getName()); String referencesTagValue = observeTagValues.getReferencesTagValue(input); return referencesTagValue != null || referential; }, getLog()); context.report(); I18nKeySet i18nGetterFile = getConfiguration().getI18nGetterFile(); ImmutableSet.Builder withReferencesBuilder = ImmutableSet.builder(); for (ObjectModelClass input : context.selectedClasses) { ObjectModelPackage aPackage = getPackage(input); boolean referential = IdHelper.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(","))); Set properties = getProperties(input, availableProperties); String prefix = getConstantPrefix(input); setConstantPrefix(prefix); String dtoName = context.classesNameTranslation.get(input); String className = IdHelper.cleanId(dtoName) + "Reference"; String generatedClassName = "Generated" + className; Class superClass = referential ? ReferentialDtoReference.class : DataDtoReference.class; generateGeneratedClass(input, className, generatedClassName, dtoName, String.format("%s<%s,%s>", superClass.getName(), dtoName, className), properties, referential); boolean generateClass = notFoundInClassPath(input.getPackageName(), className); if (generateClass) { generateClass(input, className, generatedClassName, properties, referential); } } ImmutableSet withReferenceFqns = withReferencesBuilder.build(); String initializerName = "DtoReferencesInitializer"; String generatedInitializerName = "Generated" + initializerName; ObjectModelPackage aPackage = getModel().getPackage(getDefaultPackageName()); String binderPackageName = DtoReferenceBinder.class.getPackage().getName(); String initializerPackageName = DtoReferencesInitializerSupport.class.getPackage().getName(); generateGeneratedInitializer(initializerPackageName,aPackage, binderPackageName, generatedInitializerName, withReferenceFqns, i18nGetterFile); boolean generateInitializer = notFoundInClassPath(binderPackageName, initializerName); if (generateInitializer) { generateInitializer(initializerPackageName,generatedInitializerName, initializerName); } // generate service loader file generateMetaInfService(getConfiguration(), initializerPackageName + "." + initializerName, DtoReferencesInitializerSupport.class); } private void generateGeneratedInitializer(String initializerPackageName,ObjectModelPackage aPackage, String binderPackageName, String generatedInitializerName, ImmutableSet withReferenceFqns,I18nKeySet i18nGetterFile) { String packageName = aPackage.getName() + "."; int defaultPackageNameLength = packageName.length(); String modelName = getModel().getName(); ObjectModelClass output = createAbstractClass(generatedInitializerName, initializerPackageName); setSuperClass(output, DtoReferencesInitializerSupport.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, ImmutableClassMapping.class); addImport(output, ReferentialDtoReferenceBinder.class); addImport(output, DataDtoReferenceBinder.class); // addImport(output, ImmutableClassMapping.class.getName() + ".Builder"); // addImport(output, I18n.class); addImport(output, packageName + modelName + "ModelInitializer"); addImport(output, packageName + 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" +" " ); for (String fqn : context.classesFqn) { ObjectModelClass beanClass = context.classesByFqn.get(fqn); if (BeanTransformer.skipForInitializer(getModel().getPackage(beanClass), beanClass)) { continue; } String dtoName = context.classesNameTranslation.get(beanClass); ObjectModelOperation operation = addOperation(output, "init" + dtoName, "void", ObjectModelJavaModifier.PUBLIC); addAnnotation(output, operation, Override.class); if (context.selectedClasses.contains(beanClass)) { addImport(output, fqn + "Reference"); boolean referential = IdHelper.isReferentialFromPackageName(beanClass.getPackageName()); String flushMethodName = referential ? "flushReferential" : "flushData"; String referenceName = beanClass.getName() + "Reference"; i18nGetterFile.addKey("observe.common." + dtoName + ".type"); i18nGetterFile.addKey("observe.common." + dtoName + ".types"); StringBuilder body = new StringBuilder(); body.append("" +"\n" +" "+flushMethodName+"("+referenceName+".DEFINITION);"); if (withReferenceFqns.contains(fqn)) { String binderMethodName = referential ? "registerReferentialBinder" : "registerDataBinder"; String binderName = BinderHelper.generateBinderName(defaultPackageNameLength, binderPackageName, fqn, dtoName + "Reference", referential); addImport(output, binderName); binderName = JavaGeneratorUtil.getSimpleName(binderName); body.append("" +"\n" +" "+binderMethodName+"(new "+binderName+"());\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()); } protected static void generateMetaInfService(TemplateConfiguration configuration, String outputName, Class type) { Path outputDirectory = configuration.getProperty(TemplateConfiguration.PROP_OUTPUT_DIRECTORY, File.class).toPath(); Path file = outputDirectory.resolve("META-INF").resolve("services"); try { if (!Files.exists(file)) { Files.createDirectories(file); } Files.write(file.resolve(type.getName()), outputName.getBytes()); } catch (IOException e) { throw new IllegalStateException("Could not create file: " + file); } } private void generateClass(ObjectModelClass input, String className, String abstractClassName, Set properties, boolean referential) { ObjectModelClass output = createClass(className, input.getPackageName()); setSuperClass(output, abstractClassName); getLog().debug("will generate " + output.getQualifiedName()); ObjectModelOperation constructor = addConstructor(output, ObjectModelJavaModifier.PUBLIC); addParameter(constructor, referential ? ReferentialDtoReferenceAware.class : DtoReferenceAware.class, "dto"); StringBuilder body = new StringBuilder("\n super(dto, "); for (ObjectModelAttribute attr : properties) { addParameter(constructor, attr.getType(), attr.getName()); body.append(String.format("%s, ", attr.getName())); } String body1 = body.toString(); setOperationBody(constructor, body1.substring(0, body1.length() - 2) + ");\n"); } private void generateGeneratedClass(ObjectModelClass input, String className, String abstractClassName, String dtoName, String superClass, Set properties, boolean referential) { ObjectModelClass output = createAbstractClass(abstractClassName, input.getPackageName()); ObjectModelAnnotation objectModelAnnotation = addAnnotation(output, output, GenerateJavaBeanDefinition.class); addAnnotationParameter(output, objectModelAnnotation, "types", "{\"" + input.getPackageName() + "." + className + "\"}"); setSuperClass(output, superClass); Class builderMethodName = referential ?ReferentialDtoReferenceDefinition.class:DataDtoReferenceDefinition.class; addImport(output, builderMethodName); StringBuilder definition = new StringBuilder("" +"\n" +" "+builderMethodName.getSimpleName()+"\n" +" .builder("+dtoName+".class, "+className+".class) " ); for (ObjectModelAttribute attr : properties) { addImport(output, attr.getType()); String type = JavaGeneratorUtil.getSimpleName(attr.getType()); String name = attr.getName(); String getterName; boolean booleanProperty = JavaGeneratorUtil.isBooleanPrimitive(attr); if (booleanProperty) { getterName = JavaGeneratorUtil.OPERATION_GETTER_BOOLEAN_PREFIX; } else { getterName = JavaGeneratorUtil.OPERATION_GETTER_DEFAULT_PREFIX; } getterName += JavaGeneratorUtil.capitalizeJavaBeanPropertyName(name); definition.append("" +"\n" +" .addProperty("+type+".class, \""+name+"\", "+className+"::"+getterName+")" ); } definition.append(""+"\n" +" .build()" ); String definitionType = String.format("%s<%s, %s>", builderMethodName.getName(), dtoName, className); addAttribute(output, "DEFINITION", definitionType, definition.toString(), ObjectModelJavaModifier.PUBLIC, ObjectModelJavaModifier.STATIC, ObjectModelJavaModifier.FINAL); getLog().debug("will generate " + output.getQualifiedName()); ObjectModelOperation constructor = addConstructor(output, ObjectModelJavaModifier.PROTECTED); addParameter(constructor, referential ? ReferentialDtoReferenceAware.class : DtoReferenceAware.class, "dto"); StringBuilder body = new StringBuilder(""+"\n" +" super(dto);"); for (ObjectModelAttribute attr : properties) { createProperty(output, attr); addParameter(constructor, attr.getType(), attr.getName()); String name = attr.getName(); body.append(""+"\n" +" this."+name+" = "+name+";" ); } body.append(""+"\n" +" "); setOperationBody(constructor, body.toString()); ObjectModelOperation getDefinition = addOperation(output, "getDefinition", definitionType, ObjectModelJavaModifier.PUBLIC); addAnnotation(output, getDefinition, Override.class); setOperationBody(getDefinition, ""+"\n" +" return DEFINITION;\n" +" " ); } private String getAttributeType(ObjectModelAttribute attr) { String attrType = attr.getType(); return getAttributeType(attrType); } 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 boolean notFoundInClassPath(String input, String className) { String fqn = input + "." + className; boolean inClassPath = getResourcesHelper().isJavaFileInClassPath(fqn); return !inClassPath; } private void createProperty(ObjectModelClass output, ObjectModelAttribute attr) { String attrName = attr.getName(); String attrType = getAttributeTypeWithGeneric(attr); boolean booleanProperty = JavaGeneratorUtil.isBooleanPrimitive(attr); if (booleanProperty) { createGetMethod(output, attrName, attrType, JavaGeneratorUtil.OPERATION_GETTER_BOOLEAN_PREFIX); } else { createGetMethod(output, attrName, attrType, JavaGeneratorUtil.OPERATION_GETTER_DEFAULT_PREFIX); } addAttribute(output, attrName, attrType, "", ObjectModelJavaModifier.PRIVATE, ObjectModelJavaModifier.FINAL); } private Set getProperties(ObjectModelClass input, Set availableProperties) { Collection attributes = new LinkedList<>(input.getAttributes()); attributes.addAll(input.getAllOtherAttributes()); Map properties = new TreeMap<>(); for (ObjectModelAttribute attr : attributes) { if (attr.isNavigable()) { String attrName = attr.getName(); String type = attr.getType(); if (context.selectedClassesFqn.contains(IdHelper.cleanId(type))) { // Dto if (availableProperties.contains(attrName + "Label")) { ObjectModelAttributeImpl newAttr = new ObjectModelAttributeImpl(); newAttr.setName(attrName + "Label"); newAttr.setType("String"); // only keep navigable attributes properties.put(newAttr.getName(), newAttr); } if (availableProperties.contains(attrName + "Id")) { ObjectModelAttributeImpl newAttr = new ObjectModelAttributeImpl(); newAttr.setName(attrName + "Id"); newAttr.setType("String"); // only keep navigable attributes properties.put(newAttr.getName(), newAttr); } // Get a ref if (availableProperties.contains(attrName)) { ObjectModelAttributeImpl newAttr = new ObjectModelAttributeImpl(); newAttr.setName(attrName); if (!type.endsWith("Reference")) { // not a ref, get a ref type = IdHelper.cleanId(type) + "Reference"; } newAttr.setType(getAttributeType(type)); properties.put(attrName, newAttr); } continue; } // Simple type if (availableProperties.contains(attrName)) { ObjectModelAttributeImpl newAttr = new ObjectModelAttributeImpl(); newAttr.setName(attrName); newAttr.setType(type); properties.put(attrName, newAttr); } } } if (availableProperties.contains("label") && properties.values().stream().noneMatch(p -> p.getName().equals("label"))) { ObjectModelAttributeImpl attr = new ObjectModelAttributeImpl(); attr.setName("label"); attr.setType("String"); properties.put("label", attr); } Set result = new LinkedHashSet<>(); for (String availableProperty : availableProperties) { ObjectModelAttribute e = properties.get(availableProperty); if (e == null) { ObjectModelAttributeImpl ee = new ObjectModelAttributeImpl(); ee.setName(availableProperty); ee.setType("String"); e = ee; } Objects.requireNonNull(e, "Cant' find property " + availableProperty + " on " + input.getQualifiedName()); result.add(e); } return result; } private void createGetMethod(ObjectModelClass output, String attrName, String attrType, String methodPrefix) { ObjectModelOperation operation = addOperation( output, getJavaBeanMethodName(methodPrefix, attrName), attrType, ObjectModelJavaModifier.PUBLIC ); setOperationBody(operation, "" +"\n" +" return "+attrName+";\n" +" " ); } private String getAttributeTypeWithGeneric(ObjectModelAttribute attr) { String attrType = getAttributeType(attr); String generic = eugeneTagValues.getAttributeGenericTagValue(attr); if (generic != null) { attrType += "<" + getAttributeType(generic) + ">"; } return attrType; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy