com.testify.ecfeed.ui.common.EclipseModelImplementer.java Source code

Java tutorial

Introduction

Here is the source code for com.testify.ecfeed.ui.common.EclipseModelImplementer.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Testify AS..
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Patryk Chamuczynski (p.chamuczynski(at)radytek.com) - initial implementation
 ******************************************************************************/

package com.testify.ecfeed.ui.common;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.TextEdit;

import com.testify.ecfeed.adapter.AbstractModelImplementer;
import com.testify.ecfeed.adapter.CachedImplementationStatusResolver;
import com.testify.ecfeed.adapter.EImplementationStatus;
import com.testify.ecfeed.adapter.java.JavaUtils;
import com.testify.ecfeed.model.AbstractNode;
import com.testify.ecfeed.model.AbstractParameterNode;
import com.testify.ecfeed.model.ChoiceNode;
import com.testify.ecfeed.model.ClassNode;
import com.testify.ecfeed.model.GlobalParameterNode;
import com.testify.ecfeed.model.MethodNode;
import com.testify.ecfeed.model.MethodParameterNode;

public class EclipseModelImplementer extends AbstractModelImplementer {

    private final IFileInfoProvider fFileInfoProvider;

    public EclipseModelImplementer(IFileInfoProvider fileInfoProvider) {
        super(new EclipseImplementationStatusResolver());
        fFileInfoProvider = fileInfoProvider;
    }

    @Override
    public boolean implement(AbstractNode node) {
        refreshWorkspace();
        boolean result = super.implement(node);
        CachedImplementationStatusResolver.clearCache(node);
        refreshWorkspace();
        return result;
    }

    @Override
    protected boolean implement(AbstractParameterNode node) throws CoreException {
        if (parameterDefinitionImplemented(node) == false) {
            implementParameterDefinition(node, node.getLeafChoiceValues());
        } else {
            List<ChoiceNode> unimplemented = unimplementedChoices(node.getLeafChoices());
            implementChoicesDefinitions(unimplemented);
            for (ChoiceNode choice : unimplemented) {
                CachedImplementationStatusResolver.clearCache(choice);
            }
        }
        return true;
    }

    @Override
    protected boolean implement(ChoiceNode node) throws CoreException {
        AbstractParameterNode parameter = node.getParameter();
        if (parameterDefinitionImplemented(parameter) == false) {
            if (parameterDefinitionImplementable(parameter)) {
                implementParameterDefinition(parameter,
                        new HashSet<String>(Arrays.asList(new String[] { node.getValueString() })));
            } else {
                return false;
            }
        } else {
            if (node.isAbstract()) {
                implementChoicesDefinitions(unimplementedChoices(node.getLeafChoices()));
            } else {
                if (implementable(node) && getImplementationStatus(node) != EImplementationStatus.IMPLEMENTED) {
                    implementChoicesDefinitions(Arrays.asList(new ChoiceNode[] { node }));
                }
            }
        }
        return true;
    }

    @Override
    protected void implementClassDefinition(ClassNode node) throws CoreException {
        String packageName = JavaUtils.getPackageName(node.getName());
        String className = JavaUtils.getLocalName(node.getName());
        String unitName = className + ".java";
        IPackageFragment packageFragment = getPackageFragment(packageName);
        ICompilationUnit unit = packageFragment.getCompilationUnit(unitName);
        unit.createType(classDefinitionContent(node), null, false, null);
        unit.becomeWorkingCopy(null);
        unit.commitWorkingCopy(true, null);
    }

    @Override
    protected void implementMethodDefinition(MethodNode node) throws CoreException {
        if (classDefinitionImplemented(node.getClassNode()) == false) {
            implementClassDefinition(node.getClassNode());
        }
        IType classType = getJavaProject().findType(JavaUtils.getQualifiedName(node.getClassNode()));
        if (classType != null) {
            classType.createMethod(methodDefinitionContent(node), null, false, null);
            for (AbstractParameterNode parameter : node.getParameters()) {
                String type = parameter.getType();
                if (JavaUtils.isUserType(type)) {
                    String packageName = JavaUtils.getPackageName(type);
                    if (packageName.equals(JavaUtils.getPackageName(node.getClassNode())) == false) {
                        classType.getCompilationUnit().createImport(type, null, null);
                    }
                }
            }
        }
        ICompilationUnit unit = classType.getCompilationUnit();
        unit.becomeWorkingCopy(null);
        unit.commitWorkingCopy(true, null);
    }

    @Override
    protected void implementParameterDefinition(AbstractParameterNode node) throws CoreException {
        implementParameterDefinition(node, null);
    }

    protected void implementParameterDefinition(AbstractParameterNode node, Set<String> fields)
            throws CoreException {
        String typeName = node.getType();
        if (JavaUtils.isPrimitive(typeName)) {
            return;
        }
        if (JavaUtils.isValidTypeName(typeName) == false) {
            return;
        }
        String packageName = JavaUtils.getPackageName(typeName);
        String localName = JavaUtils.getLocalName(typeName);
        String unitName = localName + ".java";
        IPackageFragment packageFragment = getPackageFragment(packageName);
        ICompilationUnit unit = packageFragment.getCompilationUnit(unitName);
        unit.createType(enumDefinitionContent(node, fields), null, false, null);
        unit.becomeWorkingCopy(null);
        unit.commitWorkingCopy(true, null);
    }

    @Override
    protected void implementChoiceDefinition(ChoiceNode node) throws CoreException {
        if (implementable(node) && getImplementationStatus(node) != EImplementationStatus.IMPLEMENTED) {
            implementChoicesDefinitions(Arrays.asList(new ChoiceNode[] { node }));
        }
    }

    @SuppressWarnings("unchecked")
    protected void implementChoicesDefinitions(List<ChoiceNode> nodes) throws CoreException {
        refreshWorkspace();
        AbstractParameterNode parent = getParameter(nodes);
        if (parent == null) {
            return;
        }
        String typeName = parent.getType();
        if (parameterDefinitionImplemented(parent) == false) {
            implementParameterDefinition(parent);
        }
        IType enumType = getJavaProject().findType(typeName);
        ICompilationUnit iUnit = enumType.getCompilationUnit();
        CompilationUnit unit = getCompilationUnit(enumType);
        EnumDeclaration enumDeclaration = getEnumDeclaration(unit, typeName);
        if (enumDeclaration != null) {
            for (ChoiceNode node : nodes) {
                EnumConstantDeclaration constant = unit.getAST().newEnumConstantDeclaration();
                constant.setName(unit.getAST().newSimpleName(node.getValueString()));
                enumDeclaration.enumConstants().add(constant);
            }
            saveChanges(unit, enumType.getResource().getLocation());
        }
        enumType.getResource().refreshLocal(IResource.DEPTH_ONE, null);
        iUnit.becomeWorkingCopy(null);
        iUnit.commitWorkingCopy(true, null);
        refreshWorkspace();
    }

    @Override
    protected boolean implementable(ClassNode node) {
        if (classDefinitionImplemented(node)) {
            return hasImplementableNode(node.getMethods());
        }
        return classDefinitionImplementable(node);
    }

    @Override
    protected boolean implementable(MethodNode node) {
        if (methodDefinitionImplemented(node)) {
            return hasImplementableNode(node.getParameters()) || hasImplementableNode(node.getTestCases());
        }
        return methodDefinitionImplementable(node);
    }

    @Override
    protected boolean implementable(MethodParameterNode node) {
        if (parameterDefinitionImplemented(node)) {
            return hasImplementableNode(node.getChoices());
        }
        return parameterDefinitionImplementable(node);
    }

    @Override
    protected boolean implementable(GlobalParameterNode node) {
        if (parameterDefinitionImplemented(node)) {
            return hasImplementableNode(node.getChoices());
        }
        return parameterDefinitionImplementable(node);
    }

    @Override
    protected boolean implementable(ChoiceNode node) {
        if (node.isAbstract()) {
            return hasImplementableNode(node.getChoices());
        }
        if (parameterDefinitionImplemented(node.getParameter())) {
            try {
                IType type = getJavaProject().findType(node.getParameter().getType());
                if (type.isEnum() == false) {
                    return false;
                }
                boolean hasConstructor = false;
                boolean hasParameterlessConstructor = false;
                for (IMethod constructor : type.getMethods()) {
                    if (constructor.isConstructor() == false) {
                        continue;
                    }
                    hasConstructor = true;
                    if (constructor.getNumberOfParameters() == 0) {
                        hasParameterlessConstructor = true;
                    }
                }
                if (hasConstructor && (hasParameterlessConstructor == false)) {
                    return false;
                }
            } catch (CoreException e) {
                return false;
            }
        } else {
            if (parameterDefinitionImplementable(node.getParameter()) == false) {
                return false;
            }
        }

        return JavaUtils.isValidJavaIdentifier(node.getValueString());
    }

    @Override
    protected boolean classDefinitionImplemented(ClassNode node) {
        try {
            IType type = getJavaProject().findType(node.getName());
            return (type != null) && type.isClass();
        } catch (CoreException e) {
        }
        return false;
    }

    @Override
    protected boolean methodDefinitionImplemented(MethodNode node) {
        try {
            IType type = getJavaProject().findType(node.getClassNode().getName());
            if (type == null) {
                return false;
            }
            EclipseModelBuilder builder = new EclipseModelBuilder();
            for (IMethod method : type.getMethods()) {
                MethodNode model = builder.buildMethodModel(method);
                if (model != null && model.getName().equals(node.getName())
                        && model.getParametersTypes().equals(node.getParametersTypes())) {
                    return true;
                }
            }
        } catch (CoreException e) {
        }
        return false;
    }

    @Override
    protected boolean parameterDefinitionImplemented(AbstractParameterNode node) {
        try {
            IType type = getJavaProject().findType(node.getType());
            return (type != null) && type.isEnum();
        } catch (CoreException e) {
        }
        return false;
    }

    protected String classDefinitionContent(ClassNode node) {
        return "public class " + JavaUtils.getLocalName(node) + "{\n\n}";
    }

    protected String methodDefinitionContent(MethodNode node) {
        String args = "";
        String comment = "// TODO Auto-generated method stub";
        String content = "System.out.println(\"" + node.getName() + "(";

        if (node.getParameters().size() > 0) {
            content += "\" + ";
            for (int i = 0; i < node.getParameters().size(); ++i) {
                AbstractParameterNode parameter = node.getParameters().get(i);
                args += JavaUtils.getLocalName(parameter.getType()) + " " + parameter.getName();
                content += node.getParameters().get(i).getName();
                if (i != node.getParameters().size() - 1) {
                    args += ", ";
                    content += " + \", \"";
                }
                content += " + ";
            }
            content += "\")\");";
        } else {
            content += ")\");";
        }
        return "public void " + node.getName() + "(" + args + "){\n\t" + comment + "\n\t" + content + "\n}";
    }

    protected String enumDefinitionContent(AbstractParameterNode node, Set<String> fields) {
        String fieldsDefinition = "";
        if (fields != null && fields.size() > 0) {
            for (String field : fields) {
                fieldsDefinition += field + ", ";
            }
            fieldsDefinition = fieldsDefinition.substring(0, fieldsDefinition.length() - 2);
        }
        String result = "public enum " + JavaUtils.getLocalName(node.getType()) + "{\n\t" + fieldsDefinition
                + "\n}";
        return result;
    }

    private boolean methodDefinitionImplementable(MethodNode node) {
        if (classDefinitionImplemented(node.getClassNode()) == false) {
            if (classDefinitionImplementable(node.getClassNode()) == false) {
                return false;
            }
        }
        try {
            IType type = getJavaProject().findType(node.getClassNode().getName());
            EclipseModelBuilder builder = new EclipseModelBuilder();
            if (type != null) {
                for (IMethod method : type.getMethods()) {
                    MethodNode model = builder.buildMethodModel(method);
                    if (model.getName().equals(node.getName())
                            && model.getParametersTypes().equals(node.getParametersTypes())) {
                        return hasImplementableNode(node.getChildren());
                    }
                }
            }
            return true;
        } catch (CoreException e) {
        }
        return false;
    }

    private boolean classDefinitionImplementable(ClassNode node) {
        try {
            return getJavaProject().findType(node.getName()) == null;
        } catch (CoreException e) {
        }
        return false;
    }

    private boolean parameterDefinitionImplementable(AbstractParameterNode parameter) {
        try {
            String type = parameter.getType();
            if (JavaUtils.isPrimitive(type)) {
                return false;
            } else {
                return getJavaProject().findType(type) == null;
            }
        } catch (CoreException e) {
        }
        return false;
    }

    @SuppressWarnings("deprecation")
    private CompilationUnit getCompilationUnit(IType type) throws CoreException {
        final ASTParser parser = ASTParser.newParser(AST.JLS4);
        parser.setKind(ASTParser.K_COMPILATION_UNIT);
        parser.setSource(type.getCompilationUnit());
        CompilationUnit unit = (CompilationUnit) parser.createAST(null);
        ITextFileBufferManager bufferManager = FileBuffers.getTextFileBufferManager();
        IPath path = type.getResource().getLocation();
        bufferManager.connect(path, LocationKind.LOCATION, null);
        unit.recordModifications();
        return unit;
    }

    private EnumDeclaration getEnumDeclaration(CompilationUnit unit, String typeName) {
        String className = JavaUtils.getLocalName(typeName);
        for (Object object : unit.types()) {
            AbstractTypeDeclaration declaration = (AbstractTypeDeclaration) object;
            if (declaration.getName().toString().equals(className) && declaration instanceof EnumDeclaration) {
                return (EnumDeclaration) declaration;
            }
        }
        return null;
    }

    private void saveChanges(CompilationUnit unit, IPath location) throws CoreException {
        ITextFileBufferManager bufferManager = FileBuffers.getTextFileBufferManager();
        ITextFileBuffer textFileBuffer = bufferManager.getTextFileBuffer(location, LocationKind.LOCATION);
        IDocument document = textFileBuffer.getDocument();
        TextEdit edits = unit.rewrite(document, null);
        try {
            edits.apply(document);
            textFileBuffer.commit(null, false);
            bufferManager.disconnect(location, LocationKind.LOCATION, null);
            refreshWorkspace();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private IJavaProject getJavaProject() throws CoreException {
        if (fFileInfoProvider.getProject().hasNature(JavaCore.NATURE_ID)) {
            return JavaCore.create(fFileInfoProvider.getProject());
        }
        return null;
    }

    private IPackageFragment getPackageFragment(String name) throws CoreException {
        IPackageFragmentRoot packageFragmentRoot = getPackageFragmentRoot();
        IPackageFragment packageFragment = packageFragmentRoot.getPackageFragment(name);
        if (packageFragment.exists() == false) {
            packageFragment = packageFragmentRoot.createPackageFragment(name, false, null);
        }
        return packageFragment;
    }

    private IPackageFragmentRoot getPackageFragmentRoot() throws CoreException {
        IPackageFragmentRoot root = fFileInfoProvider.getPackageFragmentRoot();
        if (root == null) {
            root = getAnySourceFolder();
        }
        if (root == null) {
            root = createNewSourceFolder("src");
        }
        return root;
    }

    private IPackageFragmentRoot getAnySourceFolder() throws CoreException {
        if (fFileInfoProvider.getProject().hasNature(JavaCore.NATURE_ID)) {
            IJavaProject project = JavaCore.create(fFileInfoProvider.getProject());
            for (IPackageFragmentRoot packageFragmentRoot : project.getPackageFragmentRoots()) {
                if (packageFragmentRoot.getKind() == IPackageFragmentRoot.K_SOURCE) {
                    return packageFragmentRoot;
                }
            }
        }
        return null;
    }

    private IPackageFragmentRoot createNewSourceFolder(String name) throws CoreException {
        IProject project = fFileInfoProvider.getProject();
        IJavaProject javaProject = JavaCore.create(project);
        IFolder srcFolder = project.getFolder(name);
        int i = 0;
        while (srcFolder.exists()) {
            String newName = name + i++;
            srcFolder = project.getFolder(newName);
        }
        srcFolder.create(false, true, null);
        IPackageFragmentRoot root = javaProject.getPackageFragmentRoot(srcFolder);

        IClasspathEntry[] entries = javaProject.getRawClasspath();
        IClasspathEntry[] updated = new IClasspathEntry[entries.length + 1];
        System.arraycopy(entries, 0, updated, 0, entries.length);
        updated[entries.length] = JavaCore.newSourceEntry(root.getPath());
        javaProject.setRawClasspath(updated, null);
        return root;
    }

    private List<ChoiceNode> unimplementedChoices(List<ChoiceNode> choices) {
        List<ChoiceNode> unimplemented = new ArrayList<>();
        for (ChoiceNode choice : choices) {
            if (implementable(choice) && getImplementationStatus(choice) != EImplementationStatus.IMPLEMENTED) {
                unimplemented.add(choice);
            }
        }
        return unimplemented;
    }

    private AbstractParameterNode getParameter(List<ChoiceNode> nodes) {
        if (nodes.size() == 0) {
            return null;
        }
        AbstractParameterNode parameter = nodes.get(0).getParameter();
        for (ChoiceNode node : nodes) {
            if (node.getParameter() != parameter) {
                return null;
            }
        }
        return parameter;
    }

    private void refreshWorkspace() {
        try {
            getJavaProject().getProject().getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, null);
        } catch (CoreException e) {
            e.printStackTrace();
        }
    }

}