org.eclipse.qvt.declarative.relations.atlvm.ATLVMExecutor.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.qvt.declarative.relations.atlvm.ATLVMExecutor.java

Source

/**
 * <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);
    }
}