/*******************************************************************************
* 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;
import java.util.HashMap;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
import ca.uwaterloo.gsd.fsml.core.Cause;
import ca.uwaterloo.gsd.fsml.core.FSMLMappingException;
import ca.uwaterloo.gsd.fsml.core.Queries;
import ca.uwaterloo.gsd.fsml.ecore.FSMLEcoreUtil;
import ca.uwaterloo.gsd.fsml.javaMappingInterpreter.analysis.IJavaASTManager;
import ca.uwaterloo.gsd.fsml.stats.Stats;
/**
* Used for creating, maintaining, and querying context hashmaps.
* This class should only be used from JavaMappingInterpreter.
*
* @author Michal Antkiewicz <mantkiew@gsd.uwaterloo.ca>
*/
public class JavaContextManager implements IJavaContextManager {
private IJavaProject project;
// context elements:
// iJavaProjects corresponding to model elements
private HashMap<EObject, IJavaProject> feature2iJavaProject = new HashMap<EObject, IJavaProject>();
// iTypes corresponding to model elements
private HashMap<EObject, IType> feature2iType = new HashMap<EObject, IType>();
// TypeDeclarations corresponding to model elements
private HashMap<EObject, TypeDeclaration> feature2TypeDeclaration = new HashMap<EObject, TypeDeclaration>();
// iMethods corresponding to model elements
private HashMap<EObject, IMethod> feature2iMethod = new HashMap<EObject, IMethod>();
// method declarations corresponding to model elements
private HashMap<EObject, MethodDeclaration> feature2MethodDeclaration = new HashMap<EObject, MethodDeclaration>();
// iFields corresponding to model elements
private HashMap<EObject, IField> feature2iField = new HashMap<EObject, IField>();
// variable declaration fragments corresponding to model elements
private HashMap<EObject, VariableDeclarationFragment> feature2VariableDeclarationFragment = new HashMap<EObject, VariableDeclarationFragment>();
// MethodInvocations corresponding to model elements
private HashMap<EObject, MethodInvocation> feature2MethodInvocation = new HashMap<EObject, MethodInvocation>();
// ClassInstanceCreations corresponding to model elements
private HashMap<EObject, ClassInstanceCreation> feature2ClassInstanceCreation = new HashMap<EObject, ClassInstanceCreation>();
// Annotations corresponding to model elements
private HashMap<EObject, Annotation> feature2Annotation = new HashMap<EObject, Annotation>();
protected IJavaASTManager javaAstManager;
@SuppressWarnings("unused")
private JavaContextManager() {
}
public JavaContextManager(IJavaProject project, IJavaASTManager javaAstManager) {
this.project = project;
this.javaAstManager = javaAstManager;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextIJavaProject(org.eclipse.emf.ecore.EObject)
*/
public IJavaProject getContextIJavaProject(EObject element) {
EObject contextProjectElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_PROJECT);
IJavaProject result = feature2iJavaProject.get(contextProjectElement);
if (result == null)
// TODO: get rid of this hack!
result = project;
return result;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextIType(org.eclipse.emf.ecore.EObject, boolean)
*/
public IType getContextIType(EObject element, boolean required) throws FSMLMappingException {
EObject contextClassElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_CLASS);
if (contextClassElement == null && required)
throw new FSMLMappingException(Cause.MISSING_CONTEXT, element.eContainingFeature());
// try the cache first
IType result = feature2iType.get(contextClassElement);
if (result != null)
return result;
// try the typed declarations cache
TypeDeclaration typeDeclaration = feature2TypeDeclaration.get(contextClassElement);
if (typeDeclaration != null) {
String name = typeDeclaration.getName().getIdentifier();
PackageDeclaration packageNode = ((CompilationUnit)typeDeclaration.getRoot()).getPackage();
String qualifier = null;
if (packageNode != null)
qualifier = packageNode.getName().getFullyQualifiedName();
String fqName = qualifier == null || "".equals(qualifier) ?
name :
qualifier + "." + name;
try {
result = project.findType(fqName);
if (result != null && result.exists()) {
feature2iType.put(contextClassElement, result);
return result;
}
} catch (JavaModelException e) {
e.printStackTrace();
}
}
// retrieve fully qualified name
String fullyQualifiedName = null;
EAttribute fullyQualifiedNameAttribute = (EAttribute) FSMLEcoreUtil.findEStructuralFeatureWithAnnotations(contextClassElement.eClass(), new String[] { JavaMappingInterpreter.QUERY_FULLY_QUALIFIED_NAME });
if (fullyQualifiedNameAttribute != null)
fullyQualifiedName = (String) contextClassElement.eGet(fullyQualifiedNameAttribute);
else {
// try name and qualifier
EAttribute nameAttribute = (EAttribute) FSMLEcoreUtil.findEStructuralFeatureWithAnnotations(contextClassElement.eClass(), new String[] { JavaMappingInterpreter.QUERY_CLASS_NAME });
EAttribute qualifierAttribute = (EAttribute) FSMLEcoreUtil.findEStructuralFeatureWithAnnotations(contextClassElement.eClass(), new String[] { JavaMappingInterpreter.QUERY_QUALIFIER });
if (nameAttribute != null && qualifierAttribute != null) {
String name = (String) contextClassElement.eGet(nameAttribute);
String qualifier = (String) contextClassElement.eGet(qualifierAttribute);
if (qualifier == null || "".equals(qualifier))
fullyQualifiedName = name;
else
fullyQualifiedName = qualifier + "." + name;
}
else {
// look for base concept reference
EReference baseElementReference = FSMLEcoreUtil.findReferenceWithAnnotation(contextClassElement.eClass(), Queries.BASE_CONCEPT);
if (baseElementReference != null) {
EObject baseElement = (EObject) contextClassElement.eGet(baseElementReference);
if (baseElement != null)
return getContextIType(baseElement, required);
}
}
}
try {
if (fullyQualifiedName != null) {
result = project.findType(fullyQualifiedName);
if (result != null && result.exists())
feature2iType.put(contextClassElement, result);
else
return null;
}
} catch (JavaModelException e) {
e.printStackTrace();
}
return result;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextTypeDeclaration(org.eclipse.emf.ecore.EObject, boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public TypeDeclaration getContextTypeDeclaration(EObject element, boolean required, IProgressMonitor progressMonitor) throws FSMLMappingException {
EObject contextClassElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_CLASS);
if (contextClassElement == null && required)
throw new FSMLMappingException(Cause.MISSING_CONTEXT, element.eContainingFeature());
// try the cache first
TypeDeclaration result = feature2TypeDeclaration.get(contextClassElement);
if (result == null) {
// cannot find in the cache retrieve from the IType
IType resultIType = getContextIType(element, required);
if (resultIType != null && resultIType.exists()) {
CompilationUnit cu = javaAstManager.getCompilationUnit(resultIType);
if (cu == null) {
Stats.INSTANCE.logError("Unable to parse the type:" + resultIType.getFullyQualifiedName());
return null;
}
try {
result = ASTNodeSearchUtil.getTypeDeclarationNode(resultIType, cu);
} catch (JavaModelException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// store in the cache
if (result != null)
feature2TypeDeclaration.put(contextClassElement, result);
else {
Stats.INSTANCE.logError("Unable to locate typed declaration in cu:" + resultIType.getFullyQualifiedName());
return null;
}
}
}
return result;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextIMethod(org.eclipse.emf.ecore.EObject, boolean)
*/
public IMethod getContextIMethod(EObject element, boolean required) {
IMethod result = feature2iMethod.get(element);
if (result == null) {
// retrieve the method by name from the context IType
EObject contextMethodElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_METHOD);
if (contextMethodElement != null) {
EStructuralFeature nameFeature = FSMLEcoreUtil.findEStructuralFeatureWithAnnotations(contextMethodElement.eClass(), new String[] {JavaMappingInterpreter.QUERY_METHOD_NAME});
EStructuralFeature signatureFeature = FSMLEcoreUtil.findEStructuralFeatureWithAnnotations(contextMethodElement.eClass(), new String[] {JavaMappingInterpreter.QUERY_SIGNATURE});
if (nameFeature != null && signatureFeature != null) {
String methodName = (String) contextMethodElement.eGet(nameFeature);
String methodSignature = (String) contextMethodElement.eGet(signatureFeature);
try {
IType contextIType = getContextIType(element, false);
if (contextIType != null) {
// TODO: need local and inherited?
}
} catch (FSMLMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
return result;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextMethodDeclaration(org.eclipse.emf.ecore.EObject, boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public MethodDeclaration getContextMethodDeclaration(EObject element, boolean required, IProgressMonitor progressMonitor) throws FSMLMappingException {
EObject contextMethodElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_METHOD);
if (contextMethodElement == null && required)
throw new FSMLMappingException(Cause.MISSING_CONTEXT, element.eContainingFeature());
// try the cache first
MethodDeclaration result = feature2MethodDeclaration.get(contextMethodElement);
if (result == null) {
// cannot find in the cache retrieve from the IType
IMethod resultIMethod = getContextIMethod(element, required);
if (resultIMethod != null && resultIMethod.exists()) {
CompilationUnit cu = javaAstManager.getCompilationUnit(resultIMethod);
if (cu == null) {
Stats.INSTANCE.logError("JavaContextManager.getContextMethodDeclaration(): unable to obtain a compilation unit for " + resultIMethod.getKey());
return null;
}
try {
result = ASTNodeSearchUtil.getMethodDeclarationNode(resultIMethod, cu);
} catch (JavaModelException e) {
e.printStackTrace();
}
// store in the cache
if (result != null)
feature2MethodDeclaration.put(contextMethodElement, result);
}
}
return result;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextIField(org.eclipse.emf.ecore.EObject, boolean)
*/
public IField getContextIField(EObject element, boolean required) throws FSMLMappingException {
EObject contextFieldElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_FIELD);
EStructuralFeature fieldNameAttribute = FSMLEcoreUtil.findEStructuralFeatureWithAnnotations(contextFieldElement.eClass(), new String[] {JavaMappingInterpreter.QUERY_FIELD_NAME} );
String fieldName = (String) contextFieldElement.eGet(fieldNameAttribute);
IField result = null;
if (fieldName != null) {
IType contextType = getContextIType(element, required);
if (contextType == null)
return null;
result = contextType.getField(fieldName);
if (!result.exists())
return null;
}
return result;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextVariableDeclarationFragment(org.eclipse.emf.ecore.EObject, boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public VariableDeclarationFragment getContextVariableDeclarationFragment(EObject element, boolean required, IProgressMonitor progressMonitor) throws FSMLMappingException {
EObject contextFieldElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_FIELD);
EObject contextStatementElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_LOCAL_VARIABLE);
if (contextFieldElement == null && contextStatementElement == null && required)
throw new FSMLMappingException(Cause.MISSING_CONTEXT, element.eContainingFeature());
// try the cache first
VariableDeclarationFragment result = feature2VariableDeclarationFragment.get(contextFieldElement);
if (result == null){
result = feature2VariableDeclarationFragment.get(contextStatementElement);
}
if (result == null) {
//TODO, do this for statements as well.
// cannot find in the cache retrieve from the IType
IField resultIField = getContextIField(element, required);
if (resultIField != null && resultIField.exists()) {
CompilationUnit cu = javaAstManager.getCompilationUnit(resultIField);
FieldDeclaration resultFieldDeclaration;
try {
resultFieldDeclaration = ASTNodeSearchUtil.getFieldDeclarationNode(resultIField, cu);
result = (VariableDeclarationFragment) resultFieldDeclaration.fragments().get(0);
} catch (JavaModelException e) {
e.printStackTrace();
}
// store in the cache
if (result != null)
feature2VariableDeclarationFragment.put(contextFieldElement, result);
}
}
return result;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextMethodInvocation(org.eclipse.emf.ecore.EObject, boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public MethodInvocation getContextMethodInvocation(EObject element, boolean required, IProgressMonitor progressMonitor) throws FSMLMappingException {
EObject contextMethodInvocationElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_METHOD_CALL);
if (contextMethodInvocationElement == null && required)
throw new FSMLMappingException(Cause.MISSING_CONTEXT, element.eContainingFeature());
// try the cache first
MethodInvocation result = feature2MethodInvocation.get(contextMethodInvocationElement);
return result;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextClassInstanceCreation(org.eclipse.emf.ecore.EObject, boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public ClassInstanceCreation getContextClassInstanceCreation(EObject element, boolean required, IProgressMonitor progressMonitor) throws FSMLMappingException {
EObject contextClassInstanceCreationElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_METHOD_CALL);
if (contextClassInstanceCreationElement == null && required)
throw new FSMLMappingException(Cause.MISSING_CONTEXT, element.eContainingFeature());
// try the cache first
ClassInstanceCreation result = feature2ClassInstanceCreation.get(contextClassInstanceCreationElement);
return result;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContextAnnotation(org.eclipse.emf.ecore.EObject, boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public Annotation getContextAnnotation(EObject element, boolean required, IProgressMonitor progressMonitor) throws FSMLMappingException {
EObject contextAnnotationElement = FSMLEcoreUtil.retrieveContextElement(element, JavaMappingInterpreter.CONTEXT_ANNOTATION);
if (contextAnnotationElement == null && required)
throw new FSMLMappingException(Cause.MISSING_CONTEXT, element.eContainingFeature());
// try the cache first
Annotation result = feature2Annotation.get(contextAnnotationElement);
return result;
}
/**
* @param member
* @param progressMonitor
* @return a IClassFile for a binary member or a ICompilationUnit for source member
*/
public static IJavaElement getIClassFileOrICompilationUnitForIMember(IMember member, IProgressMonitor progressMonitor) {
try {
if (!member.isStructureKnown()) {
Stats.INSTANCE.logError("Structure is not known for member:" + member.getElementName());
return null;
}
} catch (JavaModelException e) {
e.printStackTrace();
}
if (member.isBinary()) {
IClassFile classFile = member.getClassFile();
if (classFile == null || !classFile.exists())
Stats.INSTANCE.logError("getIClassFileOrICompilationUnitForIMember(): IClassFile does not exist for member:" + member.getElementName());
return classFile;
}
ICompilationUnit iCompilationUnit = member.getCompilationUnit();
if (iCompilationUnit == null || !iCompilationUnit.exists())
Stats.INSTANCE.logError("getIClassFileOrICompilationUnitForIMember(): ICompilationUnit does not exist for member:" + member.getElementName());
return iCompilationUnit;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#associateContext(org.eclipse.emf.ecore.EObject, java.lang.Object)
*/
public void associateContext(EObject object, Object context) {
if (context instanceof TypeDeclaration)
feature2TypeDeclaration.put(object, (TypeDeclaration) context);
else if (context instanceof IType)
feature2iType.put(object, (IType) context);
else if (context instanceof MethodDeclaration)
feature2MethodDeclaration.put(object, (MethodDeclaration) context);
else if (context instanceof IMethod)
feature2iMethod.put(object, (IMethod) context);
else if (context instanceof VariableDeclarationFragment)
feature2VariableDeclarationFragment.put(object, (VariableDeclarationFragment) context);
else if (context instanceof IField)
feature2iField.put(object, (IField) context);
else if (context instanceof Annotation)
feature2Annotation.put(object,(Annotation)context);
else if (context instanceof MethodInvocation)
feature2MethodInvocation.put(object, (MethodInvocation) context);
else if (context instanceof ClassInstanceCreation)
feature2ClassInstanceCreation.put(object, (ClassInstanceCreation) context);
else if (context instanceof IJavaProject)
feature2iJavaProject.put(object, (IJavaProject) context);
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContext(org.eclipse.emf.ecore.EObject, org.eclipse.core.runtime.IProgressMonitor)
*/
public Object getContext(EObject element, IProgressMonitor progressMonitor) {
try {
Object context = getContextIType(element, true);
if (context == null)
context = getContextTypeDeclaration(element, true, progressMonitor);
else if (context == null)
context = getContextIMethod(element, true);
else if (context == null)
context = getContextMethodDeclaration(element, true, progressMonitor);
else if (context == null)
context = getContextIField(element, true);
else if (context == null)
context = getContextVariableDeclarationFragment(element, true, progressMonitor);
else if (context == null)
context = getContextAnnotation(element, true, progressMonitor);
else if (context == null)
context = getContextMethodInvocation(element, true, progressMonitor);
else if (context == null)
context = getContextClassInstanceCreation(element, true, progressMonitor);
else if (context == null)
context = getContextIJavaProject(element);
return context;
} catch (FSMLMappingException e) {
e.printStackTrace();
}
return null;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#getContext(org.eclipse.emf.ecore.EObject, java.lang.Class, boolean, org.eclipse.core.runtime.IProgressMonitor)
*/
public Object getContext(EObject element, Class contextClass, boolean required, IProgressMonitor progressMonitor) {
try {
if (TypeDeclaration.class.equals(contextClass))
return getContextTypeDeclaration(element, required, progressMonitor);
if (MethodDeclaration.class.equals(contextClass))
return getContextMethodDeclaration(element, required, progressMonitor);
if (VariableDeclarationFragment.class.equals(contextClass))
return getContextVariableDeclarationFragment(element, required, progressMonitor);
if (MethodInvocation.class.equals(contextClass))
return getContextMethodInvocation(element, required, progressMonitor);
if (ClassInstanceCreation.class.equals(contextClass))
return getContextClassInstanceCreation(element, required, progressMonitor);
if (Annotation.class.equals(contextClass))
return getContextAnnotation(element, required, progressMonitor);
if (IJavaProject.class.equals(contextClass))
return getContextIJavaProject(element);
if (IType.class.equals(contextClass))
return getContextIType(element, required);
if (IMethod.class.equals(contextClass))
return getContextIMethod(element, required);
if (IField.class.equals(contextClass))
return getContextIField(element, required);
}
catch (FSMLMappingException e) {
e.printStackTrace();
}
return null;
}
/* (non-Javadoc)
* @see ca.uwaterloo.gsd.fsml.javaMappingInterpreter.IJavaContextManager#removeContext(org.eclipse.emf.ecore.EObject)
*/
public void removeContext(EObject element) {
feature2iJavaProject.remove(element);
feature2iType.remove(element);
feature2TypeDeclaration.remove(element);
feature2iMethod.remove(element);
feature2MethodDeclaration.remove(element);
feature2iField.remove(element);
feature2VariableDeclarationFragment.remove(element);
feature2MethodInvocation.remove(element);
feature2ClassInstanceCreation.remove(element);
feature2Annotation.remove(element);
}
/**
* Called before starting the analysis, so that the manager has a chance to initialize
*/
public void init() {
}
@Override
public void finish() {
// should not clear cache, because it is needed for forward eng (ModelCodeReconcileAction).
/*feature2iJavaProject.clear();
feature2iType.clear();
feature2TypeDeclaration.clear();
feature2iMethod.clear();
feature2MethodDeclaration.clear();
feature2iField.clear();
feature2VariableDeclarationFragment.clear();
feature2MethodInvocation.clear();
feature2ClassInstanceCreation.clear();
feature2Annotation.clear();*/
}
}