/*******************************************************************************
* Copyright (c) 2010 Michal Antkiewicz.
* 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:
* Michal Antkiewicz - initial API and implementation
******************************************************************************/
package ca.uwaterloo.gsd.fsml.javaMappingInterpreter.mappings;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import ca.uwaterloo.gsd.fsml.core.Context;
import ca.uwaterloo.gsd.fsml.core.FSMLMappingException;
import ca.uwaterloo.gsd.fsml.core.Mode;
import ca.uwaterloo.gsd.fsml.core.Parameter;
import ca.uwaterloo.gsd.fsml.javaMappingInterpreter.CodeTransforms;
import ca.uwaterloo.gsd.fsml.javaMappingInterpreter.JavaMappingInterpreter;
import ca.uwaterloo.gsd.fsml.javaMappingInterpreter.analysis.JavaModelUtils;
import ca.uwaterloo.gsd.fsml.stats.Stats;
import ca.uwaterloo.gsd.fsml.sync.ClassSyncItem;
import ca.uwaterloo.gsd.fsml.sync.SyncItem;
public class MethodsMapping extends JavaMapping {
public MethodsMapping(EObject element, EStructuralFeature feature, EAnnotation annotation, EClass concreteChildType, JavaMappingInterpreter interpreter, IProgressMonitor progressMonitor) throws FSMLMappingException {
super(element, feature, annotation, concreteChildType, interpreter, progressMonitor);
javaInterpreter = interpreter;
// if there is no name for the method, search for a constructor, using the name of the context class.
if (!feature.getEType().getName().equals("EString") && name == null)
name = contextIType != null ? contextIType.getElementName() : contextTypeDeclaration.getName().getIdentifier();
}
public MethodsMapping(SyncItem syncItem, EAnnotation annotation, JavaMappingInterpreter interpreter, IProgressMonitor progressMonitor) throws FSMLMappingException {
super(
syncItem,
(syncItem instanceof ClassSyncItem ?
(syncItem.getModel() != null ?
syncItem.getModel().eContainingFeature().getEAnnotation(JavaMappingInterpreter.QUERY_METHODS) :
syncItem.getCode().eContainingFeature().getEAnnotation(JavaMappingInterpreter.QUERY_METHODS))
: annotation),
interpreter,
progressMonitor);
javaInterpreter = interpreter;
}
@Context(mode=Mode.REVERSE)
public IType contextIType;
@Context(mode=Mode.FORWARD)
public TypeDeclaration contextTypeDeclaration;
@Parameter(name=JavaMappingInterpreter.DETAIL_NAME, mode=Mode.ALL)
public String name;
@Parameter(name=JavaMappingInterpreter.DETAIL_SIGNATURE, mode=Mode.ALL, defaultValue="()V")
public String signature;
@Parameter(name=JavaMappingInterpreter.DETAIL_INHERITED, mode=Mode.REVERSE, defaultValue="true")
public String inherited;
@Override
protected boolean forward() throws FSMLMappingException {
// create the method
boolean result = false;
MethodDeclaration methodDeclaration;
switch (syncItem.getReconciliationAction()) {
case CODE_ADD:
methodDeclaration = CodeTransforms.createMethod(contextIJavaProject, null, contextTypeDeclaration, "public", name, signature, null, progressMonitor);
contextManager.associateContext(element, methodDeclaration);
result = true;
break;
case CODE_REMOVE:
methodDeclaration = contextManager.getContextMethodDeclaration(element, true, progressMonitor);
if (methodDeclaration != null)
CodeTransforms.commentOutASTNode(null, methodDeclaration, element.eClass(), feature, progressMonitor);
break;
}
return result;
}
@Override
protected boolean reverse() throws FSMLMappingException {
try {
// get names of methods with the given signature
if (feature.getEType().getName().equals("EString")) {
boolean found = false;
for (IMethod iMethod : contextIType.getMethods()) {
String iMethodName = iMethod.getElementName();
IMethod potentialTargetMethod = contextIType.getMethod(iMethodName, Signature.getParameterTypes(signature));
if (iMethod.isSimilar(potentialTargetMethod)) {
if (javaInterpreter.analyzeImplVariants()) {
//still need to analyze implementation variants here?
Stats.INSTANCE.logImplVariant(element.eClass(), feature, annotation,"no variants...");
}
found = true;
setFeatureContextAndMarker(iMethodName, iMethod, iMethod, feature.isMany() ? iMethodName : null);
}
}
return setFeature(found);
}
else if (feature.getEType().getName().equals("EBoolean") || feature instanceof EReference) {
if (!feature.isMany()) {
boolean includeInherited = inherited != null && inherited.equals("true");
IMethod iMethod = JavaModelUtils.findMethod(contextIJavaProject, name, signature, contextIType, true, includeInherited, progressMonitor);
if (iMethod != null && iMethod.exists()) {
if (javaInterpreter.analyzeImplVariants()) {
//analyze implementation variants
if (!includeInherited) {
Stats.INSTANCE.logImplVariant(element.eClass(), feature, annotation,"implements (as required)");
} else {
IMethod localMethod = JavaModelUtils.findMethod(contextIJavaProject, name, signature, contextIType, true, false, progressMonitor);
if (localMethod==null) {
Stats.INSTANCE.logImplVariant(element.eClass(), feature, annotation,"inheritsFrom: "+contextIType.getSuperclassName());
} else {
//check if the method is in the super classes
IMethod ancestorMethods = JavaModelUtils.findMethod(contextIJavaProject, name, signature, contextIType, false, true, progressMonitor);
if (ancestorMethods==null) {
Stats.INSTANCE.logImplVariant(element.eClass(), feature, annotation,"implements");
} else {
Stats.INSTANCE.logImplVariant(element.eClass(), feature, annotation,"overrides");
}
}
}
}
return setFeatureContextAndMarker(true, iMethod, iMethod, null);
}
}
}
return setFeature(false);
} catch (JavaModelException e) {
e.printStackTrace();
return setFeature(false);
}
}
}