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

org.nuiton.eugene.java.JavaGenerator Maven / Gradle / Ivy

There is a newer version: 3.0
Show newest version
/*
 * #%L
 * EUGene :: EUGene
 * %%
 * Copyright (C) 2004 - 2011 CodeLutin, Chatellier Eric
 * %%
 * 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%
 */

package org.nuiton.eugene.java;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.eugene.GeneratorUtil;
import org.nuiton.eugene.java.extension.AnnotationsManagerExtension;
import org.nuiton.eugene.java.extension.ImportsManagerExtension;
import org.nuiton.eugene.java.extension.ObjectModelAnnotation;
import org.nuiton.eugene.java.extension.ObjectModelAnnotationParameter;
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.ObjectModelElement;
import org.nuiton.eugene.models.object.ObjectModelEnumeration;
import org.nuiton.eugene.models.object.ObjectModelGenerator;
import org.nuiton.eugene.models.object.ObjectModelInterface;
import org.nuiton.eugene.models.object.ObjectModelOperation;
import org.nuiton.eugene.models.object.ObjectModelParameter;

import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;





/**
 * JavaGenerator
 *
 * Stupid generation of an ObjectModel with Java classes and interfaces.
 * Use of ImportsManager to get imports for a classifier (added in model in the JavaBuilder which construct
 * the ObjectModel).
 *
 * The JavaGenerator is based on a ObjectModelGenerator : Java classes are represented by ObjectModelClass, ...
 * Created: 22 oct. 200
 * 9
 *
 * @author Florian Desbois - [email protected]
 * @plexus.component role="org.nuiton.eugene.Template" role-hint="org.nuiton.eugene.java.JavaGenerator"
 */
public class JavaGenerator extends ObjectModelGenerator {

    private static final Log log = LogFactory.getLog(JavaGenerator.class);

    protected int innerLevel;

    protected String prefix;

    @Override
    public String getFilenameForClass(ObjectModelClass clazz) {
        return getFilenameForClassifier(clazz);
    }

    @Override
    public String getFilenameForInterface(ObjectModelInterface interfacez) {
        return getFilenameForClassifier(interfacez);
    }

    @Override
    public String getFilenameForEnumeration(ObjectModelEnumeration enumeration) {
        return getFilenameForClassifier(enumeration);
    }

    @Override
    public String getFilenameForClassifier(ObjectModelClassifier clazz) {
        String s = clazz.getQualifiedName();
        int index = s.indexOf("<");
        if (index > -1) {
            s = s.substring(0, index);
        }
        return s.replace('.', File.separatorChar) + ".java";
    }

    /**
     * Generate from all classes.
     *
     * @param output Writer for generating the java file
     * @param input  Class to manage for creating an output file
     * @throws IOException if any pb while writing file
     */
    @Override
    public void generateFromClass(Writer output, ObjectModelClass input)
            throws IOException {

        if (isVerbose()) {
            log.info("Will generate class " + input.getQualifiedName());
        }
        preparePrefix(input);

        // Imports, package et documentation
        generateHeader(output, input);

        String abstractStr = input.isAbstract() ? " abstract" : "";
        String staticStr = input.isStatic() ? " static" : "";
        String className = input.getName();

        String extend = "";
        Iterator j = input.getSuperclasses().iterator();
        if (j.hasNext()) {
            ObjectModelClassifier p = j.next();
            extend += GeneratorUtil.getSimpleName(p.getQualifiedName());
        }

        String implement = "";
        for (Iterator i =
             input.getInterfaces().iterator(); i.hasNext(); ) {
            ObjectModelClassifier parentInterface = i.next();
            String interfaceName = GeneratorUtil.getSimpleName(
                    parentInterface.getQualifiedName());
            implement += interfaceName;
            if (i.hasNext()) {
                implement += ", ";
            }
        }
        if (log.isDebugEnabled()) {
            log.debug(className + " : super : " + extend + ", interfaces : "
                      + implement);
        }
        generateAnnotations(output, input, input);

output.write(""+prefix+"public"+staticStr+""+abstractStr+" class "+className+"");

/*
 * Définition de la super classe : il ne doit y avoir qu'une
 */
        if (extend.length() > 0) {
output.write(" extends "+extend+"");
        }

        if (implement.length() > 0) {
output.write(" implements "+implement+"");
        }

output.write(" {\n");
output.write("");
        generateInnerClassifiers(output, input.getInnerClassifiers());
        preparePrefix(input);
        generateAttributes(output, input, input.getAttributes());
        generateOperations(output, input, input.getOperations());

output.write(""+prefix+"} //"+className+"\n");
output.write("");
    }

    @Override
    public void generateFromInterface(Writer output,
                                      ObjectModelInterface input)
            throws IOException {
        if (isVerbose()) {
            log.info("Will generate interface " + input.getQualifiedName());
        }
        preparePrefix(input);

        // Imports, package et documentation
        generateHeader(output, input);

        String interfaceName = input.getName();

        String extend = "";
        Iterator j = input.getInterfaces().iterator();
        while (j.hasNext()) {
            ObjectModelClassifier p = j.next();
            extend += GeneratorUtil.getSimpleName(p.getQualifiedName());
            if (j.hasNext()) {
                extend += ", ";
            }
        }
        generateAnnotations(output, input, input);
output.write(""+prefix+"public interface "+interfaceName+"");

/*
 * Définition de la super interface : il peut y en avoir autant qu'on veut
 */
        if (extend.length() > 0) {
output.write(" extends "+extend+"");
        }
output.write(" {\n");
output.write("");
        generateAttributes(output, input, input.getAttributes());
        generateOperations(output, input, input.getOperations());
output.write(""+prefix+"} //"+interfaceName+"\n");
output.write("");
    }

    public void generateAnnotations(Writer output,
                                    ObjectModelClassifier clazz,
                                    ObjectModelElement element)
            throws IOException {
        AnnotationsManagerExtension managers = getModel().getExtension(
                AnnotationsManagerExtension.OBJECTMODEL_EXTENSION,
                AnnotationsManagerExtension.class);
        List annotations =
                managers.getAnnotations(clazz, element);
        for (ObjectModelAnnotation annotation : annotations) {
//            if (!annotation.trim().startsWith("@")) {
//                // add @ prefix
//                annotation = "@" + annotation.trim();
//            }
            StringBuilder annotationBuilder = new StringBuilder("@" + annotation.getType());
            List annotationParameters = annotation.getParameters();
            if (CollectionUtils.isNotEmpty(annotationParameters)) {
                annotationBuilder.append('(');
                List params = Lists.newArrayList();
                for (ObjectModelAnnotationParameter annotationParameter : annotationParameters) {
                    String paramStr = annotationParameter.getName() + " = ";
                    Object value = annotationParameter.getValue();
                    if (value instanceof String) {
                        paramStr += "\"" + value + "\"";
                    } else if (value instanceof Enum) {
                        Enum anEnum = (Enum) value;

                        paramStr += anEnum.getClass().getSimpleName() + "." + value;
                    } else {
                        paramStr += value.toString();
                    }
                    params.add(paramStr);
                }
                Joiner.on(", ").appendTo(annotationBuilder, params);

                annotationBuilder.append(')');
            }
            String annotationStr = annotationBuilder.toString();

            if (element instanceof ObjectModelOperation || element instanceof ObjectModelAttribute) {
output.write(""+prefix+"");
                annotationStr = "    " + annotationStr;
            }
output.write(""+annotationStr+"");
            if (element instanceof ObjectModelClassifier || element instanceof ObjectModelOperation || element instanceof ObjectModelAttribute) {
output.write("\n");
output.write("");
            }
        }
    }

    @Override
    public void generateFromEnumeration(Writer output,
                                        ObjectModelEnumeration input) throws IOException {
        //FIXME tchemit 20100718 I don't understand why having two methods FromEnum and FromEnumeration ?
        generateFromEnum(output, input);
    }

    @Override
    public void generateFromEnum(Writer output, ObjectModelEnumeration input)
            throws IOException {
        if (isVerbose()) {
            log.info("Will generate enumeration " + input.getQualifiedName());
        }
        preparePrefix(input);
        generateHeader(output, input); // Imports, package et documentation

        String enumzName = input.getName();

        String extend = "";
        Iterator j = input.getInterfaces().iterator();
        if (j.hasNext()) {
            ObjectModelClassifier p = j.next();
            extend += GeneratorUtil.getSimpleName(p.getQualifiedName());
        }
        generateAnnotations(output, input, input);
output.write("\n");
output.write(""+prefix+"public enum "+enumzName+"");

        if (extend.length() > 0) {
output.write(" implements "+extend+" {\n");
output.write("");
        } else {
            output.write(" {\n");
output.write("");
        }
        // generation of literal
        if (input.getLiterals().isEmpty()) {
            output.write(" ; ");
        } else {
            Iterator i = input.getLiterals().iterator();
            while (i.hasNext()) {
                String literal = i.next();
output.write(""+prefix+"    "+literal+""+(i.hasNext() ? "," : ";")+"\n");
output.write("");
            }
        }
        generateAttributes(output, input, input.getAttributes());
        generateOperations(output, input, input.getOperations());
output.write(""+prefix+"} //"+enumzName+"\n");
output.write("");
    }

    public void generateInnerClassifiers(Writer output,
                                         Collection
                                                 innerClassifiers)
            throws IOException {
        if (innerClassifiers == null || innerClassifiers.isEmpty()) {
            return;
        }
        for (ObjectModelClassifier innerClassifier : innerClassifiers) {
            if (innerClassifier.isClass()) {
                generateFromClass(output, (ObjectModelClass) innerClassifier);
                innerLevel--;
                continue;
            }
            if (innerClassifier.isInterface()) {
                generateFromInterface(output, (ObjectModelInterface)
                        innerClassifier);
                innerLevel--;
                continue;
            }
            if (innerClassifier.isEnum()) {
                generateFromEnum(output, (ObjectModelEnumeration)
                        innerClassifier);
                innerLevel--;
            }
        }
    }

    protected void preparePrefix(ObjectModelClassifier clazz) {
        if (!clazz.isInner()) {
            innerLevel = 0;
            prefix = "";
        } else {
            innerLevel++;
            char[] tmp = new char[innerLevel * 4];
            Arrays.fill(tmp, ' ');
            prefix = new String(tmp);
        }
        if (log.isDebugEnabled()) {
            log.debug("prefix to use for classifier " +
                      clazz.getName() + " : [" + prefix + "]");
        }
    }


    /**
     * Generate Header for a classifier : Package, Documentation, Imports and Classifier signature.
     *
     * @param output     Writer for generating the java file
     * @param classifier Classifier for generate header
     * @throws IOException if any pb while writing file
     */
    protected void generateHeader(Writer output,
                                  ObjectModelClassifier classifier)
            throws IOException {
        if (classifier.isInner()) {
            return;
        }
        String packageName = classifier.getPackageName();
output.write("package "+packageName+";\n");
output.write("\n");
output.write("");
        // potentiel crash si imports non defini -> IllegalArgumentException on "imports"
        ImportsManagerExtension managers = getModel().getExtension(
                ImportsManagerExtension.OBJECTMODEL_EXTENSION,
                ImportsManagerExtension.class);

        List imports = managers.getImports(classifier);
        for (String singleImport : imports) {
output.write("import "+singleImport+";\n");
output.write("");
        }
        if (CollectionUtils.isNotEmpty(imports)) {
output.write("\n");
output.write("");
        }
    }

    /**
     * Generate attributes from a collection of ObjectModelAttribute.
     *
     * @param output     Writer for generating the java file
     * @param clazz      classifier in generation
     * @param attributes Collection of ObjectModelAttribute to generate
     * @throws IOException if any pb while writing file
     */
    protected void generateAttributes(Writer output, ObjectModelClassifier clazz,
                                      Collection
                                              attributes)
            throws IOException {

        for (ObjectModelAttribute attr : attributes) {

output.write("\n");
output.write("");
            String documentation = attr.getDocumentation();
            if (StringUtils.isNotEmpty(documentation)) {
output.write(""+prefix+"    /**\n");
output.write("");
                String[] lines = documentation.split("\n");
                for (String line : lines) {
output.write(""+prefix+"     * "+line+"\n");
output.write("");
                }
output.write(""+prefix+"     */\n");
output.write("");
            }

            generateAnnotations(output, clazz, attr);
            String attrName = attr.getName();
            String attrVisibility = attr.getVisibility();
            String attrType = GeneratorUtil.getSimpleName(attr.getType());
            String attrStatic = attr.isStatic() ? "static " : "";
            String attrFinal = attr.isFinal() ? "final " : "";
            String attrTransient = attr.isTransient() ? "transient " : "";
            if (clazz instanceof ObjectModelInterface) {

                //tchemit 20100507 no modifier for constants in interfaces
                attrStatic = "";
                attrFinal = "";
                attrTransient = "";
                attrVisibility = "";
            }

            if (StringUtils.isNotEmpty(attrVisibility)) {
                attrVisibility += " ";
            }

            String attrValue = StringUtils.isNotEmpty(attr.getDefaultValue()) ?
                               // ANO#474 FD-20100408 : Don't do any simplification for
                               // defaultValue, must be managed when the attribute is added
                               // to the class in the Transformer.
                               " = " + attr.getDefaultValue() : "";
//                " = " + GeneratorUtil.getSimpleName(attr.getDefaultValue()) : "";

output.write(""+prefix+"    "+attrVisibility+""+attrStatic+""+attrFinal+""+attrTransient+""+attrType+" "+attrName+""+attrValue+";\n");
output.write("");
        }
    }

    /**
     * Generate operations from a collection of ObjectModelOperation
     *
     * @param output     Writer for generating the java file
     * @param clazz      classifier in generation
     * @param operations Collection of ObjectModelOperation to generate
     * @throws IOException if any pb while writing file
     */
    protected void generateOperations(Writer output, ObjectModelClassifier clazz,
                                      Collection
                                              operations) throws IOException {
        if (!operations.isEmpty()) {
output.write("\n");
output.write("");
        }

        // Ano #493 : FD-20100412
        // Use a boolean to know if the classifier is an interface
        // Used to avoid generating visibility not needed for interface
        boolean interfacez =
                ObjectModelInterface.class.isAssignableFrom(clazz.getClass());

        for (ObjectModelOperation op : operations) {
            String opName = op.getName();
            if (opName == null) {
                generateBlock(output, clazz, op);
                continue;
            }
            generateOperationDocumentation(output, op);

            generateAnnotations(output, clazz, op);

            String opVisibility = !interfacez ? op.getVisibility() : "";
            String opStatic = op.isStatic() ? "static " : "";
            String opAbstract = op.isAbstract() ? "abstract " : "";

            ObjectModelParameter returnParam = op.getReturnParameter();
            String opReturn = "";
            if (returnParam != null) {
                opReturn = GeneratorUtil.getSimpleName(
                        returnParam.getType()) + " ";
            }
            if (StringUtils.isNotEmpty(opVisibility)) {
                opVisibility += " ";
            }

output.write(""+prefix+"    "+opVisibility+""+opStatic+""+opAbstract+""+opReturn+""+opName+"(");
            String comma = "";
            Collection params = op.getParameters();
            for (ObjectModelParameter param : params) {
                String paramName = param.getName();
                String paramType = GeneratorUtil.getSimpleName(param.getType());
output.write(""+comma+""+paramType+" "+paramName+"");
                comma = ", ";
            }
output.write(")");

            comma = " throws ";
            Set exceptions = op.getExceptions();
            for (String exception : exceptions) {
                String exceptionName = GeneratorUtil.getSimpleName(exception);
output.write(""+comma+""+exceptionName+"");
                comma = ", ";
            }
            // tchemit 2010-08-14 fix http://www.nuiton.org/issues/show/809
//            if (!op.getBodyCode().isEmpty()) {
            if (!(clazz instanceof ObjectModelInterface) && !op.isAbstract()) {
                String body = op.getBodyCode() == null ? "" : op.getBodyCode();
output.write(""+prefix+" {"+body+""+prefix+"}\n");
output.write("\n");
output.write("");
            } else {
output.write(";\n");
output.write("\n");
output.write("");
            }
        }
    }

    protected void generateOperationDocumentation(Writer output,
                                                  ObjectModelOperation op) throws IOException {
        String documentation = op.getDocumentation();
        if (StringUtils.isEmpty(documentation)) {

            // no documentation for this operation
            return;
        }
output.write(""+prefix+"    /**\n");
output.write(""+prefix+"");

        String[] documentationLines = documentation.split("\n");
        for (String documentationLine : documentationLines) {
output.write(""+prefix+"     * "+documentationLine+"\n");
output.write("");
        }
        Collection params = op.getParameters();
        for (ObjectModelParameter param : params) {
            String paramName = param.getName();
            String paramDocumentation = param.getDocumentation();
            if (paramDocumentation == null) {
                paramDocumentation = "";
            }
output.write(""+prefix+"     * @param "+paramName+" "+paramDocumentation+"\n");
output.write("");
        }

        ObjectModelParameter returnParam = op.getReturnParameter();
        String opReturn = "";
        if (returnParam != null) {
            opReturn = GeneratorUtil.getSimpleName(
                    returnParam.getType()) + " ";
            if (!opReturn.contains("void")) {
                String paramDocumentation = returnParam.getDocumentation();
                if (paramDocumentation == null) {
                    paramDocumentation = "";
                }
output.write(""+prefix+"     * @return "+paramDocumentation+"\n");
output.write("");
            }
        }
        Set exceptions = op.getExceptions();
        for (String exception : exceptions) {
            String exceptionName = GeneratorUtil.getSimpleName(exception);
output.write(""+prefix+"     * @throws "+exceptionName+"\n");
output.write("");
        }
output.write(""+prefix+"     */\n");
output.write("");

    }

    protected void generateBlock(Writer output,
                                 ObjectModelClassifier clazz,
                                 ObjectModelOperation op) throws IOException {
        String opStatic = op.isStatic() ? "static " : " ";
        
output.write(""+prefix+"    "+opStatic+"{\n");
output.write(""+prefix+"    "+op.getBodyCode()+"\n");
output.write(""+prefix+"    }\n");
output.write("\n");
output.write("");
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy