/* 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.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import com.crispico.flower.mp.codesync.base.FilteredIterable;
import com.crispico.flower.mp.model.astcache.code.AstCacheCodePackage;
import com.crispico.flower.mp.model.codesync.AstCacheElement;
import com.crispico.flower.mp.model.codesync.CodeSyncElement;
import com.crispico.flower.mp.model.codesync.CodeSyncPackage;
/**
* Mapped to {@link AbstractTypeDeclaration}. Children are {@link BodyDeclaration}s.
*
* @author Mariana
*/
public class JavaTypeModelAdapter extends JavaAbstractAstNodeModelAdapter {
public static final String CLASS = "javaClass";
public static final String INTERFACE = "javaInterface";
public static final String ENUM = "javaEnum";
public static final String ANNOTATION = "javaAnnotation";
/**
* Returns only types, fields and methods.
*/
@Override
public List<?> getChildren(Object modelElement) {
List children = new ArrayList<>();
AbstractTypeDeclaration type = getAbstractTypeDeclaration(modelElement);
children.addAll(type.bodyDeclarations());
if (type instanceof EnumDeclaration) {
children.addAll(((EnumDeclaration) type).enumConstants());
}
Iterator it = new FilteredIterable(children.iterator()) {
@Override
protected boolean isAccepted(Object candidate) {
if (candidate instanceof AbstractTypeDeclaration) {
return true;
}
if (candidate instanceof FieldDeclaration) {
return true;
}
if (candidate instanceof MethodDeclaration) {
return true;
}
// children of EnumDeclaration
if (candidate instanceof EnumConstantDeclaration) {
return true;
}
// children of AnnotationTypeDeclaration
if (candidate instanceof AnnotationTypeMemberDeclaration) {
return true;
}
return false;
}
};
List rslt = new ArrayList();
while (it.hasNext()) {
ASTNode node = (ASTNode) it.next();
// TODO for field declarations, add the list of fragments
// if (node instanceof FieldDeclaration) {
// rslt.addAll(((FieldDeclaration) node).fragments());
// } else {
rslt.add(node);
// }
}
return rslt;
}
@Override
public Object getMatchKey(Object modelElement) {
return getAbstractTypeDeclaration(modelElement).getName().getIdentifier();
}
@Override
public Iterable<?> getContainmentFeatureIterable(Object element, Object feature, Iterable<?> correspondingIterable) {
// declared as containment by JavaFeatureProvider
if (AstCacheCodePackage.eINSTANCE.getClass_SuperInterfaces().equals(feature)) {
if (element instanceof TypeDeclaration) {
return getTypeNames(((TypeDeclaration) element).superInterfaceTypes());
}
if (element instanceof EnumDeclaration) {
return getTypeNames(((EnumDeclaration) element).superInterfaceTypes());
}
return Collections.emptyList();
}
return super.getContainmentFeatureIterable(element, feature, correspondingIterable);
}
@Override
public Object getValueFeatureValue(Object element, Object feature, Object correspondingValue) {
if (CodeSyncPackage.eINSTANCE.getCodeSyncElement_Name().equals(feature)) {
return getLabel(element);
}
if (CodeSyncPackage.eINSTANCE.getCodeSyncElement_Type().equals(feature)) {
if (element instanceof TypeDeclaration) {
if (((TypeDeclaration) element).isInterface()) {
return INTERFACE;
}
return CLASS;
}
if (element instanceof EnumDeclaration) {
return ENUM;
}
return ANNOTATION;
}
if (AstCacheCodePackage.eINSTANCE.getClass_SuperClasses().equals(feature)) {
if (element instanceof TypeDeclaration) {
TypeDeclaration type = (TypeDeclaration) element;
if (type.getSuperclassType() != null) {
return Collections.singletonList(getStringFromType(type.getSuperclassType()));
} else {
return Collections.emptyList();
}
}
return Collections.emptyList();
}
if (AstCacheCodePackage.eINSTANCE.getClass_SuperInterfaces().equals(feature)) {
return Collections.emptyList();
}
return super.getValueFeatureValue(element, feature, correspondingValue);
}
@Override
public void setValueFeatureValue(Object element, Object feature, final Object value) {
if (CodeSyncPackage.eINSTANCE.getCodeSyncElement_Name().equals(feature)) {
AbstractTypeDeclaration type = getAbstractTypeDeclaration(element);
String name = (String) value;
type.setName(type.getAST().newSimpleName(name));
}
if (AstCacheCodePackage.eINSTANCE.getClass_SuperClasses().equals(feature)) {
if (element instanceof TypeDeclaration) {
List<String> superClasses = (List<String>) value;
TypeDeclaration cls = (TypeDeclaration) element;
AST ast = cls.getAST();
Type type = null;
if (superClasses != null && superClasses.size() > 0) {
type = getTypeFromString(ast, superClasses.get(0));
}
cls.setSuperclassType(type);
}
}
super.setValueFeatureValue(element, feature, value);
}
@Override
public Object createChildOnContainmentFeature(Object element, Object feature, Object correspondingChild) {
// declared as containment by JavaFeatureProvider
if (AstCacheCodePackage.eINSTANCE.getClass_SuperInterfaces().equals(feature)) {
if (element instanceof TypeDeclaration || element instanceof EnumDeclaration) {
String superInterface = (String) correspondingChild;
AbstractTypeDeclaration cls = (AbstractTypeDeclaration) element;
AST ast = cls.getAST();
Type type = getTypeFromString(ast, superInterface);
if (cls instanceof TypeDeclaration) {
((TypeDeclaration) cls).superInterfaceTypes().add(type);
}
if (cls instanceof EnumDeclaration) {
((EnumDeclaration) cls).superInterfaceTypes().add(type);
}
return getStringFromType(type);
}
return null;
}
if (AstCacheCodePackage.eINSTANCE.getClass_SuperClasses().equals(feature)) {
if (element instanceof TypeDeclaration) {
String superClass = (String) correspondingChild;
TypeDeclaration cls = (TypeDeclaration) element;
AST ast = cls.getAST();
Type type = getTypeFromString(ast, superClass);
cls.setSuperclassType(type);
return getStringFromType(type);
}
return null;
}
if (CodeSyncPackage.eINSTANCE.getCodeSyncElement_Children().equals(feature)) {
CodeSyncElement cse = (CodeSyncElement) correspondingChild;
AstCacheElement ace = cse.getAstCacheElement();
AbstractTypeDeclaration parent = (AbstractTypeDeclaration) element;
AST ast = parent.getAST();
ASTNode child = (ASTNode) createCorrespondingModelElement(ast, cse);
parent.bodyDeclarations().add(child);
return child;
}
return super.createChildOnContainmentFeature(element, feature, correspondingChild);
}
@Override
public Object createCorrespondingModelElement(Object element) {
return AstCacheCodePackage.eINSTANCE.getAstCacheCodeFactory().createClass();
}
public static Object createCorrespondingModelElement(AST ast, CodeSyncElement cse) {
ASTNode child = null;
if (JavaAttributeModelAdapter.ATTRIBUTE.equals(cse.getType())) {
VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
FieldDeclaration field = ast.newFieldDeclaration(fragment);
child = field;
}
if (JavaOperationModelAdapter.OPERATION.equals(cse.getType())) {
child = ast.newMethodDeclaration();
}
if (CLASS.equals(cse.getType())) {
child = ast.newTypeDeclaration();
}
if (INTERFACE.equals(cse.getType())) {
TypeDeclaration type = ast.newTypeDeclaration();
type.setInterface(true);
child = type;
}
if (ENUM.equals(cse.getType())) {
child = ast.newEnumDeclaration();
}
if (ANNOTATION.equals(cse.getType())) {
child = ast.newAnnotationTypeDeclaration();
}
return child;
}
private AbstractTypeDeclaration getAbstractTypeDeclaration(Object element) {
return (AbstractTypeDeclaration) element;
}
private List<String> getTypeNames(List types) {
List<String> rslt = new ArrayList<String>();
for (Object type : types) {
rslt.add(getStringFromType((Type) type));
}
return rslt;
}
}