/* 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(); } }