com.crispico.flower.mp.codesync.code.java.adapter.JavaAbstractAstNodeModelAdapter.java Source code

Java tutorial

Introduction

Here is the source code for com.crispico.flower.mp.codesync.code.java.adapter.JavaAbstractAstNodeModelAdapter.java

Source

/* license-start
 * 
 * Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>.
 * 
 * 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 version 3.
 * 
 * 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, at <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *   Crispico - Initial API and implementation
 *
 * license-end
 */
package com.crispico.flower.mp.codesync.code.java.adapter;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IExtendedModifier;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MemberRef;
import org.eclipse.jdt.core.dom.MethodRef;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.TagElement;
import org.eclipse.jdt.core.dom.TextElement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

import com.crispico.flower.mp.codesync.code.adapter.AstModelElementAdapter;
import com.crispico.flower.mp.model.astcache.code.AstCacheCodePackage;
import com.crispico.flower.mp.model.codesync.CodeSyncPackage;

/**
 * Mapped to {@link ASTNode}.
 * 
 * @author Mariana
 */
@SuppressWarnings("unchecked")
public abstract class JavaAbstractAstNodeModelAdapter extends AstModelElementAdapter {

    @Override
    public boolean hasChildren(Object modelElement) {
        return getChildren(modelElement).size() > 0;
    }

    @Override
    public Object removeFromMap(Object element, Map<Object, Object> leftOrRightMap, boolean isRight) {
        return leftOrRightMap.remove(getMatchKey(element));
    }

    /**
     * Must handle all the containment features provided by <code>common</code>.
     */
    @Override
    public Iterable<?> getContainmentFeatureIterable(Object element, Object feature,
            Iterable<?> correspondingIterable) {
        if (CodeSyncPackage.eINSTANCE.getCodeSyncElement_Children().equals(feature)) {
            return getChildren(element);
        }

        // handle modifiers here to avoid using the same code in multiple adapters
        if (AstCacheCodePackage.eINSTANCE.getModifiableElement_Modifiers().equals(feature)) {
            if (element instanceof BodyDeclaration) {
                return ((BodyDeclaration) element).modifiers();
            }
            if (element instanceof SingleVariableDeclaration) {
                return ((SingleVariableDeclaration) element).modifiers();
            }
            return Collections.emptyList();
        }

        return Collections.emptyList();
    }

    /**
     * Must handle all the features provided by <code>common</code>, except for containment features.
     */
    @Override
    public Object getValueFeatureValue(Object element, Object feature, Object correspondingValue) {
        if (AstCacheCodePackage.eINSTANCE.getDocumentableElement_Documentation().equals(feature)) {
            return getJavaDoc(element);
        }
        return null;
    }

    @Override
    public void setValueFeatureValue(Object element, Object feature, Object value) {
        if (AstCacheCodePackage.eINSTANCE.getDocumentableElement_Documentation().equals(feature)) {
            setJavaDoc(element, value);
        }
    }

    @Override
    public Object createChildOnContainmentFeature(Object element, Object feature, Object correspondingChild) {
        if (AstCacheCodePackage.eINSTANCE.getModifiableElement_Modifiers().equals(feature)) {
            if (!(element instanceof BodyDeclaration || element instanceof SingleVariableDeclaration)) {
                return null;
            } else {
                IExtendedModifier extendedModifier = null;

                if (correspondingChild instanceof com.crispico.flower.mp.model.astcache.code.Modifier) {
                    ASTNode parent = (ASTNode) element;
                    AST ast = parent.getAST();
                    com.crispico.flower.mp.model.astcache.code.Modifier modifier = (com.crispico.flower.mp.model.astcache.code.Modifier) correspondingChild;

                    extendedModifier = ast.newModifier(Modifier.ModifierKeyword.fromFlagValue(modifier.getType()));
                    if (parent instanceof BodyDeclaration) {
                        ((BodyDeclaration) parent).modifiers().add(extendedModifier);
                    } else {
                        ((SingleVariableDeclaration) parent).modifiers().add(extendedModifier);
                    }
                }

                if (correspondingChild instanceof com.crispico.flower.mp.model.astcache.code.Annotation) {
                    ASTNode parent = (ASTNode) element;
                    AST ast = parent.getAST();
                    com.crispico.flower.mp.model.astcache.code.Annotation annotation = (com.crispico.flower.mp.model.astcache.code.Annotation) correspondingChild;
                    if (annotation.getValues().size() == 0) {
                        MarkerAnnotation markerAnnotation = ast.newMarkerAnnotation();
                        extendedModifier = markerAnnotation;
                    }
                    if (annotation.getValues().size() == 1) {
                        SingleMemberAnnotation singleMemberAnnotation = ast.newSingleMemberAnnotation();
                        extendedModifier = singleMemberAnnotation;
                    } else {
                        NormalAnnotation normalAnnotation = ast.newNormalAnnotation();
                        extendedModifier = normalAnnotation;
                    }
                    if (parent instanceof BodyDeclaration) {
                        ((BodyDeclaration) parent).modifiers().add(extendedModifier);
                    } else {
                        ((SingleVariableDeclaration) parent).modifiers().add(extendedModifier);
                    }
                }
                return extendedModifier;
            }
        }

        return null;
    }

    @Override
    public void removeChildrenOnContainmentFeature(Object parent, Object feature, Object child) {
        ((ASTNode) child).delete();
    }

    @Override
    abstract public List<?> getChildren(Object modelElement);

    @Override
    public String getLabel(Object modelElement) {
        return (String) getMatchKey(modelElement);
    }

    @Override
    public List<String> getIconUrls(Object modelElement) {
        return null;
    }

    @Override
    public boolean save(Object element) {
        // nothing to do, the changes to the AST will be saved when the file is saved
        return false;
    }

    @Override
    public boolean discard(Object element) {
        // nothing to do, the changes to the AST will be discarded when the file is discarded
        return false;
    }

    @Override
    protected void updateUID(Object element, Object correspondingElement) {
        if (element instanceof BodyDeclaration) {
            BodyDeclaration node = (BodyDeclaration) element;
            Javadoc javadoc = node.getJavadoc();
            // if it doesn't have any doc, create it
            if (javadoc == null) {
                javadoc = node.getAST().newJavadoc();
                node.setJavadoc(javadoc);
            }
            // first remove the existing flower tag, this way we also make sure that it's the last tag
            // note: if we only change the id, the rewriter won't format it correctly
            for (Object obj : javadoc.tags()) {
                if (FLOWER_UID.equals(((TagElement) obj).getTagName())) {
                    javadoc.tags().remove(obj);
                    break;
                }
            }
            // create new tag element for UID
            TagElement tag = javadoc.getAST().newTagElement();
            tag.setTagName(FLOWER_UID);
            javadoc.tags().add(tag);
            TextElement text = javadoc.getAST().newTextElement();
            tag.fragments().add(text);
            EObject eObject = (EObject) correspondingElement;
            text.setText(eObject.eResource().getURIFragment(eObject));
            System.out.println(javadoc);
        }
    }

    protected Object getJavaDoc(Object element) {
        if (element instanceof BodyDeclaration) {
            BodyDeclaration node = (BodyDeclaration) element;
            if (node.getJavadoc() != null) {
                String docComment = null;
                for (Object o : node.getJavadoc().tags()) {
                    TagElement tag = (TagElement) o;
                    String tagName = tag.getTagName();
                    if (getModelAdapterFactorySet().useUIDs() && FLOWER_UID.equals(tagName)) {
                        continue;
                    }
                    if (docComment == null) {
                        docComment = new String();
                    }
                    if (tagName != null) {
                        docComment += tag.getTagName() + " ";
                    }
                    for (Object o2 : tag.fragments()) {
                        docComment += getTextFromDocElement(o2);
                    }
                    docComment += "\n";
                }
                return docComment;
            }
        }
        return null;
    }

    /**
     * @param node an IDocElement
     */
    private String getTextFromDocElement(Object node) {
        if (node instanceof MemberRef) {
            return ((MemberRef) node).getName().getIdentifier();
        }
        if (node instanceof MethodRef) {
            return ((MethodRef) node).getName().getIdentifier();
        }
        if (node instanceof SimpleName) {
            return ((SimpleName) node).getIdentifier();
        }
        if (node instanceof QualifiedName) {
            return ((QualifiedName) node).getFullyQualifiedName();
        }
        if (node instanceof TagElement) {
            return ((TagElement) node).getTagName();
        }
        if (node instanceof TextElement) {
            return ((TextElement) node).getText();
        }
        return "";
    }

    protected void setJavaDoc(Object element, Object docComment) {
        if (element instanceof BodyDeclaration) {
            BodyDeclaration node = (BodyDeclaration) element;
            ASTParser parser = ASTParser.newParser(AST.JLS4);
            parser.setKind(ASTParser.K_CLASS_BODY_DECLARATIONS);
            parser.setSource(("/** " + docComment + "*/ int x;").toCharArray());
            TypeDeclaration type = (TypeDeclaration) parser.createAST(null);
            BodyDeclaration x = (BodyDeclaration) type.bodyDeclarations().get(0);
            Javadoc javadoc = x.getJavadoc();
            node.setJavadoc((Javadoc) ASTNode.copySubtree(node.getAST(), javadoc));
        }
    }

    /**
     * Creates an {@link Expression} from the given string, owned by the given AST. 
     */
    protected Expression getExpressionFromString(AST ast, String expression) {
        if (expression == null) {
            return null;
        }
        ASTParser parser = ASTParser.newParser(AST.JLS4);
        parser.setKind(ASTParser.K_EXPRESSION);
        parser.setSource(expression.toCharArray());
        ASTNode node = parser.createAST(null);
        return (Expression) ASTNode.copySubtree(ast, node);
    }

    protected String getStringFromExpression(Expression expression) {
        if (expression == null) {
            return null;
        }
        return expression.toString();
    }

    /**
     * Creates a {@link Type} from the given name, owned by the given AST.
     */
    protected Type getTypeFromString(AST ast, String name) {
        if (name == null) {
            return ast.newPrimitiveType(PrimitiveType.VOID);
        }
        PrimitiveType.Code primitiveTypeCode = PrimitiveType.toCode(name);
        if (primitiveTypeCode != null) {
            return ast.newPrimitiveType(primitiveTypeCode);
        }

        ASTParser parser = ASTParser.newParser(AST.JLS4);
        parser.setKind(ASTParser.K_STATEMENTS);
        parser.setSource((name + " a;").toCharArray());

        Block block = (Block) parser.createAST(null);
        VariableDeclarationStatement declaration = (VariableDeclarationStatement) block.statements().get(0);
        return (Type) ASTNode.copySubtree(ast, declaration.getType());
    }

    protected String getStringFromType(Type type) {
        if (type == null) {
            return null;
        }
        return type.toString();
    }

}