/*******************************************************************************
* Copyright (c) 2007, 2014 Borland Software Corporation and others.
*
* 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:
* Borland Software Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.ast.binding;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalModuleEnv;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalParserUtil;
import org.eclipse.m2m.internal.qvt.oml.common.util.LineNumberProvider;
import org.eclipse.m2m.internal.qvt.oml.cst.MappingModuleCS;
import org.eclipse.m2m.internal.qvt.oml.expressions.Constructor;
import org.eclipse.m2m.internal.qvt.oml.expressions.Module;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.CatchExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.InstantiationExp;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.cst.CSTNode;
import org.eclipse.ocl.ecore.CallOperationAction;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.EcoreEnvironment;
import org.eclipse.ocl.ecore.SendSignalAction;
import org.eclipse.ocl.ecore.Variable;
import org.eclipse.ocl.utilities.ASTNode;
public class ASTBindingHelper {
public static <T> T getAST(CSTNode node, Class<T> type) {
if(type == null) {
throw new IllegalArgumentException();
}
Object astObj = node.getAst();
return (type.isInstance(astObj)) ? type.cast(astObj) : null;
}
public static void createModuleSourceBinding(EObject target, URI sourceURI, LineNumberProvider lineNumberProvider) {
target.eAdapters().add(new ModuleSourceAdapter(sourceURI, lineNumberProvider));
}
public static IModuleSourceInfo getModuleSourceBinding(Module astModule) {
return (IModuleSourceInfo)EcoreUtil.getExistingAdapter(astModule, ModuleSourceAdapter.class);
}
public static void createModuleBinding(MappingModuleCS cstModule, Module astModule, QvtOperationalModuleEnv env, URI unitURI) {
ASTAdapter<ASTNode> astAdapter = new ModuleASTAdapter(cstModule, astModule, env, unitURI);
astModule.eAdapters().add(astAdapter);
cstModule.eAdapters().add(astAdapter);
}
public static URI resolveModuleFile(EObject cstModule) {
ModuleASTAdapter moduleASTAdapter = getModuleASTAdapter(cstModule);
if (moduleASTAdapter != null) {
return moduleASTAdapter.getModuleFile();
}
return null;
}
public static QvtOperationalModuleEnv resolveModuleEnvironment(EObject eObj) {
ModuleASTAdapter moduleASTAdapter = getModuleASTAdapter(eObj);
if (moduleASTAdapter != null) {
return (QvtOperationalModuleEnv) moduleASTAdapter.getEnvironment();
}
List<ASTAdapter<Object>> adapters = getASTBindings(eObj);
for (ASTAdapter<Object> nextAdapter : adapters) {
if(nextAdapter.getEnvironment() instanceof QvtOperationalModuleEnv) {
return (QvtOperationalModuleEnv) nextAdapter.getEnvironment();
}
}
return null;
}
public static void createCST2ASTBinding(CSTNode cstNode, ASTNode astNode) {
createCST2ASTBinding(cstNode, astNode, true, null);
}
public static void createCST2ASTBinding(
CSTNode cstNode,
ASTNode astNode,
Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env) {
createCST2ASTBinding(cstNode, astNode, true, env);
}
public static void createCST2ASTBinding(
CSTNode cstNode,
ASTNode astNode,
boolean isBidirectional,
Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env) {
ASTAdapter<ASTNode> astAdapter = new ASTAdapter<ASTNode>(cstNode, astNode, (EcoreEnvironment)env);
if(isBidirectional) {
astNode.eAdapters().add(astAdapter);
}
cstNode.eAdapters().add(astAdapter);
}
public static <AST> void createCST2ASTBindingUnidirectional(CSTNode cstNode, AST astNode) {
ASTAdapter<AST> astAdapter = new ASTAdapter<AST>(cstNode, astNode, null);
cstNode.eAdapters().add(astAdapter);
}
public static ASTNode resolveASTNode(CSTNode cstNode) {
return resolveASTNode(cstNode, ASTNode.class);
}
public static <AST> AST resolveASTNode(CSTNode cstNode, Class<AST> astType) {
return firstASTNodeOfType(getASTBindings(cstNode), astType);
}
public static final ASTNode resolveEnclosingASTNode(CSTNode cstNode) {
while (cstNode != null) {
ASTNode astNode = resolveASTNode(cstNode);
if (astNode != null) {
return astNode;
}
cstNode = (CSTNode) cstNode.eContainer();
};
return null;
}
public static <AST extends EObject, T extends CSTNode> T resolveCSTNode(AST astNode, Class<T> cstType) {
return firstCSTNodeOfType(getASTBindings(astNode), cstType);
}
public static CSTNode resolveCSTNode(ASTNode astNode) {
return resolveCSTNode(astNode, CSTNode.class);
}
public static EcoreEnvironment resolveEnvironment(ASTNode astNode) {
EObject processedNode = astNode;
EcoreEnvironment env = localResolveEnvironment(astNode);
while(env == null && processedNode.eContainer() != null) {
processedNode = processedNode.eContainer();
if (processedNode instanceof ASTNode) {
env = localResolveEnvironment((ASTNode) processedNode);
}
}
return env;
}
private static <A> EcoreEnvironment localResolveEnvironment(ASTNode astNode) {
List<ASTAdapter<A>> adapters = getASTBindings(astNode);
for (ASTAdapter<A> nextAdapter : adapters) {
if(nextAdapter.getEnvironment() != null) {
return nextAdapter.getEnvironment();
}
}
return null;
}
private static <A, T extends A> T firstASTNodeOfType(List<ASTAdapter<A>> objects, Class<T> type) {
for (ASTAdapter<A> nextAST : objects) {
if(type.isInstance(nextAST.getASTNode())) {
return type.cast(nextAST.getASTNode());
}
}
return null;
}
private static <A, T extends CSTNode> T firstCSTNodeOfType(List<ASTAdapter<A>> objects, Class<T> type) {
for (ASTAdapter<A> nextCST : objects) {
if(type.isInstance(nextCST.getCSTNode())) {
return type.cast(nextCST.getCSTNode());
}
}
return null;
}
private static ModuleASTAdapter getModuleASTAdapter(EObject target) {
List<ModuleASTAdapter> adapters = getASTBindings(target, ModuleASTAdapter.class);
if (!adapters.isEmpty()) {
ModuleASTAdapter moduleAdapter = (ModuleASTAdapter) adapters.get(0);
return moduleAdapter;
}
return null;
}
@SuppressWarnings("unchecked")
static <AST> List<ASTAdapter<AST>> getASTBindings(EObject target) {
return getASTBindings(target, ASTAdapter.class);
}
static <A, T extends ASTAdapter<A>> List<T> getASTBindings(EObject target, Class<T> adapterType) {
List<T> result = Collections.emptyList();
for (Adapter nextAdapter : target.eAdapters()) {
if(adapterType.isInstance(nextAdapter)) {
if(result.isEmpty()) {
result = new ArrayList<T>(3);
}
result.add(adapterType.cast(nextAdapter));
}
}
return result;
}
private static class ASTAdapter<A> extends AdapterImpl {
private A fAstNode;
private CSTNode fCstNode;
private EcoreEnvironment fEnv;
ASTAdapter(CSTNode cstNode, A astNode, EcoreEnvironment env) {
if(astNode == null || cstNode == null) {
throw new IllegalArgumentException();
}
this.fAstNode = astNode;
this.fCstNode = cstNode;
this.fEnv = env;
}
public A getASTNode() {
return fAstNode;
}
public CSTNode getCSTNode() {
return fCstNode;
}
public EcoreEnvironment getEnvironment() {
return fEnv;
}
}
private static class ModuleASTAdapter extends ASTAdapter<ASTNode> {
private URI uri;
protected ModuleASTAdapter(CSTNode cstNode, ASTNode astNode,
QvtOperationalModuleEnv env, URI unitURI) {
super(cstNode, astNode, env);
this.uri = unitURI;
}
public URI getModuleFile() {
return uri;
}
}
private static class ModuleSourceAdapter extends AdapterImpl implements IModuleSourceInfo {
private URI fSourceURI;
private LineNumberProvider fLineNumProvider;
protected ModuleSourceAdapter(URI sourceURI, LineNumberProvider lineNumberProvider) {
if(sourceURI == null || lineNumberProvider == null) {
throw new IllegalArgumentException();
}
fSourceURI = sourceURI;
fLineNumProvider = lineNumberProvider;
}
public URI getSourceURI() {
return fSourceURI;
}
public LineNumberProvider getLineNumberProvider() {
return fLineNumProvider;
}
@Override
public boolean isAdapterForType(Object type) {
return type == ModuleSourceAdapter.class;
}
}
public static void setEnvironment(EObject topLevelElement, EcoreEnvironment elementEnv) {
Adapter adapter = EcoreUtil.getAdapter(topLevelElement.eAdapters(), elementEnv.getClass());
if(adapter != null) {
topLevelElement.eAdapters().remove(adapter);
}
topLevelElement.eAdapters().add(new EnvAdapter(elementEnv));
}
public static <T extends EcoreEnvironment> T getEnvironment(EObject topLevelElement, Class<T> type) {
Adapter adapter = EcoreUtil.getAdapter(topLevelElement.eAdapters(), type);
if(adapter instanceof EnvAdapter) {
EnvAdapter envAdapter = (EnvAdapter) adapter;
return envAdapter.getEnvironment(type);
}
return null;
}
private static class EnvAdapter extends AdapterImpl {
private EcoreEnvironment fEnv;
EnvAdapter(EcoreEnvironment env) {
assert env != null;
fEnv = env;
}
@Override
public boolean isAdapterForType(Object type) {
if(type instanceof Class<?>) {
Class<?> clazz = (Class<?>) type;
return clazz.isInstance(fEnv);
}
return false;
}
<T extends EcoreEnvironment> T getEnvironment(Class<T> type) {
if(isAdapterForType(type)) {
return type.cast(fEnv);
}
return null;
}
}
public static Variable getCatchVariable(CatchExp catchExp) {
EAnnotation annotation = catchExp.getEAnnotation(CATCH_VAR_SOURCE);
if (annotation == null) {
return null;
}
if (annotation.getContents().isEmpty() || false == annotation.getContents().get(0) instanceof Variable) {
return null;
}
return (Variable) annotation.getContents().get(0);
}
public static void setCatchVariable(CatchExp catchExp, Variable catchVar) {
EAnnotation annot = catchExp.getEAnnotation(CATCH_VAR_SOURCE);
if (annot == null) {
annot = EcoreFactory.eINSTANCE.createEAnnotation();
annot.setSource(CATCH_VAR_SOURCE);
catchExp.getEAnnotations().add(annot);
}
annot.getContents().clear();
annot.getContents().add(catchVar);
}
public static Constructor getConstructorOperation(InstantiationExp instExp) {
EAnnotation annot = instExp.getEAnnotation(CONSTRUCTOR_SOURCE);
if(annot != null && !annot.getReferences().isEmpty()) {
EObject refObj = annot.getReferences().get(0);
if(refObj instanceof Constructor) {
return (Constructor) refObj;
}
}
return null;
}
public static void setConstructorOperation(InstantiationExp instExp, Constructor constructorOp) {
EAnnotation annot = instExp.getEAnnotation(CONSTRUCTOR_SOURCE);
if (annot == null) {
annot = EcoreFactory.eINSTANCE.createEAnnotation();
annot.setSource(CONSTRUCTOR_SOURCE);
instExp.getEAnnotations().add(annot);
}
annot.getReferences().clear();
annot.getReferences().add(constructorOp);
}
private static final String CATCH_VAR_SOURCE = QvtOperationalParserUtil.QVT_NAMESPACE_URI + "/catchVar"; //$NON-NLS-1$
private static final String CONSTRUCTOR_SOURCE = QvtOperationalParserUtil.QVT_NAMESPACE_URI + "/constructor"; //$NON-NLS-1$
}