blob: 250c7585078a499e2d8aa0d759a114974087862e [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2007, 2008 Obeo.
* 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
*
* </copyright>
*
* Contributors:
* Quentin Glineur - initial API and implementation
*
* $Id: ATLVMExecutor.java,v 1.12 2009/02/25 18:23:19 qglineur Exp $
*/
package org.eclipse.qvt.declarative.relations.atlvm;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.InvalidPropertiesFormatException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.m2m.atl.drivers.emf4atl.ASMEMFModel;
import org.eclipse.m2m.atl.drivers.emf4atl.EMFModelLoader;
import org.eclipse.m2m.atl.engine.vm.ASM;
import org.eclipse.m2m.atl.engine.vm.ASMExecEnv;
import org.eclipse.m2m.atl.engine.vm.ASMInterpreter;
import org.eclipse.m2m.atl.engine.vm.ASMXMLReader;
import org.eclipse.m2m.atl.engine.vm.Debugger;
import org.eclipse.m2m.atl.engine.vm.SimpleDebugger;
import org.eclipse.m2m.atl.engine.vm.nativelib.ASMModel;
import org.eclipse.m2m.atl.engine.vm.nativelib.ASMModule;
import org.eclipse.qvt.declarative.common.framework.service.Operation;
import org.eclipse.qvt.declarative.execution.ExecuteOperation;
import org.eclipse.qvt.declarative.execution.ExecutionContext;
import org.eclipse.qvt.declarative.execution.ExecutionProvider;
import org.eclipse.qvt.declarative.execution.LabelledModel;
import org.eclipse.qvt.declarative.execution.QVTRelationsExecutionException;
import org.eclipse.qvt.declarative.execution.ExecutionContext.ExecutionMode;
/**
* A client implementation to provide an execution of QVT Relations by the
* regular ATL VM.
*
* @author Quentin Glineur
*
*/
public class ATLVMExecutor implements ExecutionProvider {
private static final String DEFAULT_DEBUGGER_PROPERTIES_LOCATION = "debugger.properties.xml"; //$NON-NLS-1$
private static final Debugger DEFAULT_DEBUGGER;
private static final String STEP_PROPERTY = "step"; //$NON-NLS-1$
private static final String SHOW_SUMMARY_PROPERTY = "showSummary"; //$NON-NLS-1$
private static final String PROFILE_PROPERTY = "profile"; //$NON-NLS-1$
private static final String CONTINUE_AFTER_ERROR_PROPERTY = "continueAfterError"; //$NON-NLS-1$
static {
// start the static initializations
DEFAULT_DEBUGGER = createDefaultDebugger();
}
// TODO remove duplicate with ATLVM compiler
/**
* Create a default debugger with the parameters stored in the corresponding
* configuration file
*/
private static Debugger createDefaultDebugger() {
Properties debuggerProperties = new Properties();
URL debuggerPropertiesURL = ATLVMExecutor.class
.getResource(DEFAULT_DEBUGGER_PROPERTIES_LOCATION);
try {
debuggerProperties.loadFromXML(debuggerPropertiesURL.openStream());
} catch (InvalidPropertiesFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
boolean showSummary = Boolean.toString(true).equals(
debuggerProperties.get(SHOW_SUMMARY_PROPERTY));
boolean profile = Boolean.toString(true).equals(
debuggerProperties.get(PROFILE_PROPERTY));
boolean continueAfterError = Boolean.toString(true).equals(
debuggerProperties.get(CONTINUE_AFTER_ERROR_PROPERTY));
Debugger result = new SimpleDebugger(Boolean.toString(true).equals(
debuggerProperties.get(STEP_PROPERTY)),
new ArrayList<String>(), new ArrayList<String>(),
new ArrayList<String>(), new ArrayList<String>(), true,
showSummary, profile, continueAfterError);
return result;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.qvt.declarative.common.framework.service.Provider#provides
* (org.eclipse.qvt.declarative.common.framework.service.Operation)
*/
public boolean provides(Operation operation) {
if (operation instanceof ExecuteOperation) {
try {
// TODO
// ExecuteOperation executeOperation = (ExecuteOperation)
// operation;
// IPath abstractSyntaxTreePath =
// executeOperation.getSourceFile()
// .getLocation();
// String direction = executeOperation.getParameters()
// .getDirectionModel().getName();
// IFolder sourceFolder = executeOperation.getSourceFolder();
// IFolder buildFolder = executeOperation.getBinFolder();
// TODO
//
// IPath executablePath =
// ATLVMCompiler.getDefaultExecutablePath(
// abstractSyntaxTreePath,
// direction, sourceFolder, buildFolder);
// return executablePath.toFile().canRead();
return true;
} catch (ClassCastException exception) {
return false;
}
}
return false;
}
Map<String, String> getTransformationParameters(ExecutionContext parameters) {
Map<String, String> transformationParameters = new HashMap<String, String>();
boolean isCheckOnly = parameters.getMode() == ExecutionMode.checkOnly;
transformationParameters
.put("enforce", Boolean.toString(!isCheckOnly));
return transformationParameters;
}
List<ASMModel> getLinkedModels(ExecutionContext parameters)
throws QVTRelationsExecutionException {
List<ASMModel> linkedModels = new ArrayList<ASMModel>();
EMFModelLoader emfModelLoader = new EMFModelLoader();
try {
for (LabelledModel namedModel : parameters.getSourceModels()) {
ASMModel metamodel = emfModelLoader.loadModel(namedModel.getMetamodel().getName(), emfModelLoader.getMOF(), URI.createURI(namedModel.getMetamodel().getAccessor()));
linkedModels.add(metamodel);
URI modelURI = URI.createURI(namedModel.getAccessor());
boolean created = createResourceIfMissing(emfModelLoader, modelURI);
ASMModel model = emfModelLoader.loadModel(namedModel.getName(),metamodel, modelURI);
if (created || "traces".equals(model.getName())) {
model.setIsTarget(true);
((ASMEMFModel)model).setCheckSameModel(false);
}
linkedModels.add(model);
}
LabelledModel directionNamedModel = parameters.getDirectionModel();
ASMModel metamodel = emfModelLoader.loadModel(directionNamedModel.getMetamodel().getName(), emfModelLoader.getMOF(),URI.createURI(directionNamedModel.getMetamodel().getAccessor()));
linkedModels.add(metamodel);
URI modelURI = URI.createURI(directionNamedModel.getAccessor());
createResourceIfMissing(emfModelLoader, modelURI);
ASMModel model = emfModelLoader.loadModel(directionNamedModel.getName(), metamodel, modelURI);
model.setIsTarget(true);
linkedModels.add(model);
} catch (Exception e) {
String message = "Unable to load models into the ATLVM \n"
+ e.getMessage();
throw new QVTRelationsExecutionException(message);
}
return linkedModels;
}
private static boolean createResourceIfMissing (EMFModelLoader emfModelLoader, URI modelURI) {
boolean result = false;
try {
emfModelLoader.getResourceSet().getResource(modelURI, true);
} catch (Exception r) {
emfModelLoader.getResourceSet().createResource(modelURI);
result = true;
}
return result;
}
private static IFile getExecutableFile(IFile sourceFile, String direction) {
IJavaProject javaProject = JavaCore.create(sourceFile.getProject());
IClasspathEntry srcContainer = null;
IPath currentTransformationPath = sourceFile.getFullPath();
try {
for (IClasspathEntry classpathEntry : javaProject.getRawClasspath()) {
if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
IPath classPathEntryPath = classpathEntry.getPath();
if (classPathEntryPath
.isPrefixOf(currentTransformationPath)) {
srcContainer = classpathEntry;
}
}
}
IPath relativeTransformationPath = currentTransformationPath
.removeFirstSegments(srcContainer.getPath().segmentCount());
IPath binPath = srcContainer.getOutputLocation();
IPath relativeExecutablePath = binPath.append(
relativeTransformationPath).removeFileExtension()
.addFileExtension(direction).addFileExtension("asm");
IFile executableFile = ResourcesPlugin.getWorkspace().getRoot()
.getFile(relativeExecutablePath);
return executableFile;
} catch (JavaModelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
ASM getQVTRTransformation(String transformationQualifiedName,
ExecutionContext parameters) throws QVTRelationsExecutionException {
String direction = parameters.getDirectionModel().getName();
IFile transformationFile = ResourcesPlugin.getWorkspace().getRoot()
.getFile(new Path(transformationQualifiedName));
IFile executableFile = getExecutableFile(transformationFile, direction);
ASM qvtrTransformation = null;
try {
qvtrTransformation = new ASMXMLReader()
.read(new BufferedInputStream(executableFile.getContents()));
} catch (CoreException e) {
String message = "Unable to load ASM code in the ATLVM \n"
+ e.getMessage();
throw new QVTRelationsExecutionException(message);
}
return qvtrTransformation;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.qvt.declarative.execution.ExecutionProvider#execute(org.eclipse
* .core.resources.IFile,
* org.eclipse.qvt.declarative.execution.ExecutionContext,
* org.eclipse.core.resources.IFolder, org.eclipse.core.resources.IFolder)
*/
public List<?> execute(String transformationQualifiedName,
ExecutionContext parameters) throws QVTRelationsExecutionException {
Map<String, String> transformationParameters = getTransformationParameters(parameters);
List<ASMModel> linkedModels = getLinkedModels(parameters);
ASM qvtrTransformation = getQVTRTransformation(
transformationQualifiedName, parameters);
List<ASM> librairies = Collections.<ASM> emptyList();
Object result = execute(qvtrTransformation, linkedModels, librairies,
transformationParameters, DEFAULT_DEBUGGER);
for (ASMModel model : linkedModels) {
Map<String, Boolean> serializationParameters = new HashMap<String, Boolean>();
URI metamodelURI = ((ASMEMFModel) model.getMetamodel()).getExtent()
.getURI();
if (metamodelURI.isFile() || metamodelURI.isPlatformResource()) {
serializationParameters.put(XMLResource.OPTION_SCHEMA_LOCATION,
Boolean.TRUE);
}
try {
ASMEMFModel emfModel = (ASMEMFModel) model;
emfModel.getExtent().save(serializationParameters);
} catch (IOException e) {
String message = "Unable to save the model \n" + e.getMessage();
throw new QVTRelationsExecutionException(message);
}
}
return Collections.singletonList(result);
}
protected Object execute(final ASM qvtrTransformation,
final List<ASMModel> linkedModels, final List<ASM> libraries,
final Map<String, String> parameters, final Debugger debugger)
throws QVTRelationsExecutionException {
ASMModule asmModule = new ASMModule(qvtrTransformation);
/*
* Create an execution environment with the handled models
*/
ASMExecEnv env = new ASMExecEnv(asmModule, debugger, true);
env.addPermission("file.read"); //$NON-NLS-1$
env.addPermission("file.write"); //$NON-NLS-1$
for (ASMModel model : linkedModels) {
env.addModel(model.getMetamodel().getName(), model.getMetamodel());
env.addModel(model.getName(), model);
}
env.registerOperations(qvtrTransformation);
/*
* libraries overriding operations
*/
for (ASM asm : libraries) {
env.registerOperations(asm);
}
/*
* Launch the interpretation of the compiler on the QVTR abstract syntax
* tree
*/
try {
new ASMInterpreter(qvtrTransformation, asmModule, env, parameters);
} catch (Exception e) {
String message = "Problem interpreting the compiled transformation \n"
+ e.getMessage();
throw new QVTRelationsExecutionException(message);
}
return linkedModels.get(linkedModels.size() - 1);
}
}