de.crowdcode.kissmda.cartridges.simplejava.EnumGenerator.java Source code

Java tutorial

Introduction

Here is the source code for de.crowdcode.kissmda.cartridges.simplejava.EnumGenerator.java

Source

/*
x * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package de.crowdcode.kissmda.cartridges.simplejava;

import java.util.ArrayList;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Inject;

import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BooleanLiteral;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.NumberLiteral;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.ThisExpression;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.EnumerationLiteral;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Slot;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.ValueSpecification;

import de.crowdcode.kissmda.core.jdt.JdtHelper;
import de.crowdcode.kissmda.core.uml.PackageHelper;

/**
 * Generate enumeration from UML enumeration.
 * 
 * <p>
 * Most important helper classes from kissmda-core which are used in this
 * Transformer: PackageHelper.
 * </p>
 * 
 * @author Lofi Dewanto
 * @version 1.0.0
 * @since 1.0.0
 */
public class EnumGenerator {

    private static final Logger logger = Logger.getLogger(EnumGenerator.class.getName());

    @Inject
    private PackageHelper packageHelper;

    @Inject
    private InterfaceGenerator interfaceGenerator;

    @Inject
    private JdtHelper jdtHelper;

    private String sourceDirectoryPackageName;

    private ArrayList<String> constructorParameterNames = new ArrayList<String>();

    public void setConstructorParameterNames(ArrayList<String> constructorParameterNames) {
        this.constructorParameterNames = constructorParameterNames;
    }

    /**
     * Generate the Class Interface. This is the main generation part for this
     * SimpleJavaTransformer.
     * 
     * @param Class
     *            clazz the UML class
     * @return CompilationUnit the complete class with its content as a String
     */
    public CompilationUnit generateEnum(Classifier clazz, String sourceDirectoryPackageName) {
        this.sourceDirectoryPackageName = sourceDirectoryPackageName;

        AST ast = AST.newAST(AST.JLS3);
        CompilationUnit cu = ast.newCompilationUnit();

        generatePackage(clazz, ast, cu);
        EnumDeclaration ed = generateEnum(clazz, ast, cu);
        generateAttributes(clazz, ast, ed);
        generateConstructor(clazz, ast, ed);
        generateConstants(clazz, ast, ed);
        generateGetterMethod(clazz, ast, ed);

        logger.log(Level.INFO, "Compilation unit: \n\n" + cu.toString());
        return cu;
    }

    /**
     * Generate the attributes.
     * 
     * @param clazz
     *            UML2 class
     * @param ast
     *            JDT AST
     * @param ed
     *            EnumerationDeclaration
     */
    @SuppressWarnings("unchecked")
    public void generateAttributes(Classifier clazz, AST ast, EnumDeclaration ed) {
        EList<Property> properties = clazz.getAttributes();
        for (Property property : properties) {
            ed.bodyDeclarations().add(generateAttribute(clazz, ast, property));
        }
    }

    /**
     * Generate the attribute.
     * 
     * @param clazz
     *            UM2 class
     * @param ast
     *            JDT AST
     * @param property
     *            UML2 property
     * @return FieldDeclaration
     */
    public FieldDeclaration generateAttribute(Classifier clazz, AST ast, Property property) {
        Type type = property.getType();
        logger.log(Level.FINE, "Class: " + clazz.getName() + " - " + "Property: " + property.getName() + " - "
                + "Property Upper: " + property.getUpper() + " - " + "Property Lower: " + property.getLower());
        String umlTypeName = type.getName();
        String umlQualifiedTypeName = type.getQualifiedName();

        // Check whether primitive or array type or simple type?
        org.eclipse.jdt.core.dom.Type chosenType = jdtHelper.getChosenType(ast, umlTypeName, umlQualifiedTypeName,
                sourceDirectoryPackageName);

        VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
        SimpleName variableName = ast.newSimpleName(property.getName());
        fragment.setName(variableName);

        FieldDeclaration fieldDeclaration = ast.newFieldDeclaration(fragment);
        fieldDeclaration.setType(chosenType);

        return fieldDeclaration;
    }

    /**
     * Generate getter method.
     * 
     * @param clazz
     *            UML2 classifier
     * @param ast
     *            JDT AST tree
     * @param ed
     *            EnumDeclaration JDT
     */
    @SuppressWarnings("unchecked")
    public void generateGetterMethod(Classifier clazz, AST ast, EnumDeclaration ed) {
        EList<Property> properties = clazz.getAttributes();
        for (Property property : properties) {
            Type type = property.getType();
            logger.log(Level.FINE, "Class: " + clazz.getName() + " - " + "Property: " + property.getName() + " - "
                    + "Property Upper: " + property.getUpper() + " - " + "Property Lower: " + property.getLower());
            String umlTypeName = type.getName();
            String umlQualifiedTypeName = type.getQualifiedName();
            MethodDeclaration methodDeclaration = interfaceGenerator.generateGetterMethod(ast, ed, property,
                    umlTypeName, umlQualifiedTypeName, sourceDirectoryPackageName);

            // Public
            methodDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));

            // Content of getter method
            Block block = ast.newBlock();
            ReturnStatement returnStatement = ast.newReturnStatement();
            SimpleName simpleName = ast.newSimpleName(property.getName());
            returnStatement.setExpression(simpleName);
            block.statements().add(returnStatement);
            methodDeclaration.setBody(block);
        }
    }

    /**
     * Generate getter method. Use this method if you need to call the method
     * generateGetterMethod from outside this class.
     * 
     * @param clazz
     *            UML2 classifier
     * @param ast
     *            JDT AST tree
     * @param ed
     *            EnumDeclaration JDT
     * @param sourceDirectoryPackageName
     *            root package name of the UML model
     */
    public void generateGetterMethod(Classifier clazz, AST ast, EnumDeclaration ed,
            String sourceDirectoryPackageName) {
        this.sourceDirectoryPackageName = sourceDirectoryPackageName;
        generateGetterMethod(clazz, ast, ed);
    }

    /**
     * Generate constructor.
     * 
     * @param clazz
     *            UML2 class
     * @param ast
     *            JDT AST
     * @param ed
     *            EnumDeclaration JDT
     */
    @SuppressWarnings("unchecked")
    public void generateConstructor(Classifier clazz, AST ast, EnumDeclaration ed) {
        // Constructor
        MethodDeclaration md = ast.newMethodDeclaration();
        md.setConstructor(true);
        md.setName(ast.newSimpleName(clazz.getName()));
        md.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD));
        ed.bodyDeclarations().add(md);

        // We need to build contructor parameters for each properties
        generateContructorParameters(clazz, ast, md);

        // Content of constructor
        Block block = ast.newBlock();

        EList<Property> properties = clazz.getAttributes();
        for (Property property : properties) {
            logger.log(Level.FINE, "Class: " + clazz.getName() + " - " + "Property: " + property.getName() + " - "
                    + "Property Upper: " + property.getUpper() + " - " + "Property Lower: " + property.getLower());

            // Left expression
            SimpleName simpleName = ast.newSimpleName(property.getName());
            ThisExpression thisExpression = ast.newThisExpression();
            FieldAccess fieldAccess = ast.newFieldAccess();
            fieldAccess.setName(simpleName);
            fieldAccess.setExpression(thisExpression);

            // Right expression
            SimpleName parameter = ast.newSimpleName(property.getName());

            Assignment assignment = ast.newAssignment();
            assignment.setOperator(org.eclipse.jdt.core.dom.Assignment.Operator.ASSIGN);
            assignment.setLeftHandSide(fieldAccess);
            assignment.setRightHandSide(parameter);

            // Expression
            ExpressionStatement expressionStatement = ast.newExpressionStatement(assignment);

            block.statements().add(expressionStatement);
        }

        // Set Body to MethodDeclaration
        md.setBody(block);
    }

    @SuppressWarnings("unchecked")
    void generateContructorParameters(Classifier clazz, AST ast, MethodDeclaration md) {
        // Empty the list first
        constructorParameterNames.clear();

        EList<Property> constructorProperties = clazz.getAttributes();
        for (Property constructorProperty : constructorProperties) {
            Type constructorType = constructorProperty.getType();
            // Save the variable declaration for later use
            constructorParameterNames.add(constructorProperty.getName());

            logger.log(Level.FINE,
                    "Class: " + clazz.getName() + " - " + "Constructor property: " + constructorProperty.getName()
                            + " - " + "Constructor property Upper: " + constructorProperty.getUpper() + " - "
                            + "Constructor property Lower: " + constructorProperty.getLower());

            String contructorUmlTypeName = constructorType.getName();
            String constructorUmlQualifiedTypeName = constructorType.getQualifiedName();

            // Check whether primitive or array type or simple type?
            org.eclipse.jdt.core.dom.Type constructorChosenType = jdtHelper.getChosenType(ast,
                    contructorUmlTypeName, constructorUmlQualifiedTypeName, sourceDirectoryPackageName);

            SingleVariableDeclaration variableDeclaration = ast.newSingleVariableDeclaration();
            variableDeclaration.setType(constructorChosenType);
            variableDeclaration.setName(ast.newSimpleName(constructorProperty.getName()));

            md.parameters().add(variableDeclaration);
        }
    }

    /**
     * Generate the Enum from UML.
     * 
     * @param clazz
     *            the UML class
     * @param ast
     *            the JDT Java AST
     * @param cu
     *            the generated Java compilation unit
     * @return EnumDeclaration
     */
    @SuppressWarnings("unchecked")
    public EnumDeclaration generateEnum(Classifier clazz, AST ast, CompilationUnit cu) {
        String className = getClassName(clazz);
        EnumDeclaration ed = ast.newEnumDeclaration();
        ed.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
        ed.setName(ast.newSimpleName(className));
        cu.types().add(ed);
        return ed;
    }

    /**
     * Generate the Java package from UML package.
     * 
     * @param clazz
     *            the UML class
     * @param ast
     *            the JDT Java AST
     * @param cu
     *            the generated Java compilation unit
     */
    public void generatePackage(Classifier clazz, AST ast, CompilationUnit cu) {
        PackageDeclaration pd = ast.newPackageDeclaration();
        String fullPackageName = getFullPackageName(clazz);
        pd.setName(ast.newName(fullPackageName));

        Date now = new Date();
        String commentDate = "Generation date: " + now.toString() + ".";

        interfaceGenerator.generatePackageJavadoc(ast, pd, PackageComment.CONTENT_1.getValue(),
                PackageComment.CONTENT_2.getValue(), " ", PackageComment.CONTENT_3.getValue(), " ", commentDate);

        cu.setPackage(pd);
    }

    /**
     * Generate Enumeration constants.
     * 
     * @param clazz
     *            the UML class
     * @param ast
     *            the JDT Java AST
     * @param ed
     *            Enumeration declaration for Java JDT
     */
    @SuppressWarnings("unchecked")
    public void generateConstants(Classifier clazz, AST ast, EnumDeclaration ed) {
        // Get all properties for this enumeration
        Enumeration enumeration = (Enumeration) clazz;
        EList<EnumerationLiteral> enumerationLiterals = enumeration.getOwnedLiterals();
        for (EnumerationLiteral enumLiteral : enumerationLiterals) {
            EnumConstantDeclaration ec = ast.newEnumConstantDeclaration();
            ec.setName(ast.newSimpleName(enumLiteral.getName().toUpperCase()));

            // We need to sort the arguments so that it match the
            // constructor arguments!
            if (!constructorParameterNames.isEmpty()) {
                for (String constructorParameterName : constructorParameterNames) {
                    logger.log(Level.FINE, "constructorParameterName: " + constructorParameterNames.toString());

                    Slot slot = findSlotByName(constructorParameterName, enumLiteral);
                    if (slot != null) {
                        // We found a slot with the same name
                        Property property = (Property) slot.getDefiningFeature();
                        Type type = property.getType();
                        chooseLiteralTypeAndAddToEnumConstantArguments(ast, ec, slot, type);
                    } else {
                        // We didn't find the slot with the same name as in the
                        // constructor
                        logger.log(Level.SEVERE,
                                "EnumGenerator: Error in Generating Enum: we cannot find the correct slot by its name as it was given by the constructor!");
                        // Doing something intelligent...
                        // So we are adding the literal to the EnumConstant
                        // arguments just as it is, so this is not intelligent
                        // at the moment...
                        getSlotsNotIntelligent(ast, enumLiteral, ec);
                    }
                }
            } else {
                // Constructor parameter types is empty
                // So we are adding the literal to the EnumConstant arguments
                // just as it is
                getSlotsNotIntelligent(ast, enumLiteral, ec);
            }

            ed.enumConstants().add(ec);
        }
    }

    private void getSlotsNotIntelligent(AST ast, EnumerationLiteral enumLiteral, EnumConstantDeclaration ec) {
        EList<Slot> slots = enumLiteral.getSlots();
        for (Slot slot : slots) {
            Property property = (Property) slot.getDefiningFeature();
            Type type = property.getType();
            chooseLiteralTypeAndAddToEnumConstantArguments(ast, ec, slot, type);
        }
    }

    @SuppressWarnings("unchecked")
    void chooseLiteralTypeAndAddToEnumConstantArguments(AST ast, EnumConstantDeclaration ec, Slot slot, Type type) {
        EList<ValueSpecification> valueSpecifications = slot.getValues();
        for (ValueSpecification valueSpecification : valueSpecifications) {
            if (type.getName().equalsIgnoreCase("Integer")) {
                NumberLiteral numberLiteral = ast.newNumberLiteral();
                numberLiteral.setToken(String.valueOf(valueSpecification.integerValue()));
                ec.arguments().add(numberLiteral);
            } else if (type.getName().equalsIgnoreCase("Long")) {
                NumberLiteral numberLiteral = ast.newNumberLiteral();
                numberLiteral.setToken(String.valueOf(valueSpecification.integerValue()).concat("L"));
                ec.arguments().add(numberLiteral);
            } else if (type.getName().equalsIgnoreCase("Boolean")) {
                BooleanLiteral booleanLiteral = ast.newBooleanLiteral(valueSpecification.booleanValue());
                ec.arguments().add(booleanLiteral);
            } else if (type.getName().equalsIgnoreCase("String")) {
                StringLiteral stringLiteral = ast.newStringLiteral();
                stringLiteral.setLiteralValue(valueSpecification.stringValue());
                ec.arguments().add(stringLiteral);
            }
        }
    }

    Slot findSlotByName(String name, EnumerationLiteral enumLiteral) {
        EList<Slot> slots = enumLiteral.getSlots();
        for (Slot slot : slots) {
            Property property = (Property) slot.getDefiningFeature();
            String slotPropertyName = property.getName();

            if (slotPropertyName.equals(name)) {
                // We found it
                return slot;
            }
        }

        // We finished but cannot find it
        return null;
    }

    private String getClassName(Classifier clazz) {
        String className = clazz.getName();
        return className;
    }

    private String getFullPackageName(Classifier clazz) {
        String fullPackageName = packageHelper.getFullPackageName(clazz, sourceDirectoryPackageName);
        return fullPackageName;
    }
}