org.gemoc.execution.sequential.javaengine.PlainK3ExecutionEngine.java Source code

Java tutorial

Introduction

Here is the source code for org.gemoc.execution.sequential.javaengine.PlainK3ExecutionEngine.java

Source

/*******************************************************************************
 * Copyright (c) 2016 Inria 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:
 *     Inria - initial API and implementation
 *******************************************************************************/
package org.gemoc.execution.sequential.javaengine;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.gemoc.executionframework.engine.commons.MelangeHelper;
import org.gemoc.executionframework.engine.core.AbstractCommandBasedSequentialExecutionEngine;
import org.gemoc.executionframework.engine.core.EngineStoppedException;
import org.gemoc.xdsmlframework.api.core.IExecutionContext;
import org.kermeta.utils.provisionner4eclipse.Provisionner;
import org.osgi.framework.Bundle;

import fr.inria.diverse.k3.al.annotationprocessor.stepmanager.IStepManager;
import fr.inria.diverse.k3.al.annotationprocessor.stepmanager.StepCommand;
import fr.inria.diverse.k3.al.annotationprocessor.stepmanager.StepManagerRegistry;
import fr.inria.diverse.melange.adapters.EObjectAdapter;

public class PlainK3ExecutionEngine extends AbstractCommandBasedSequentialExecutionEngine implements IStepManager {

    private Method initializeMethod;
    private List<Object> initializeMethodParameters;
    private Method entryPointMethod;
    private List<Object> entryPointMethodParameters;
    private Class<?> entryPointClass;

    @Override
    public String engineKindName() {
        return "GEMOC Kermeta Sequential Engine";
    }

    /**
     * Constructs a PlainK3 execution engine using an entry point (~ a main operation) The entrypoint will register
     * itself as a StepManager into the K3 step manager registry, and unregister itself at the end. As a StepManager,
     * the PlainK3ExecutionEngine will receive callbacks through its "executeStep" operation.
     */
    @Override
    protected void prepareEntryPoint(IExecutionContext executionContext) {
        /*
         * Get info from the RunConfiguration
         */
        String entryPoint = executionContext.getRunConfiguration().getExecutionEntryPoint();
        String mainModelElementURI = executionContext.getRunConfiguration().getModelEntryPoint();

        /*
         * Find the entry point in the workspace
         */
        final String PREFIX = "public static void ";
        int startName = PREFIX.length();
        int endName = entryPoint.lastIndexOf("(");
        String methodFullName = entryPoint.substring(startName, endName);

        String aspectClassName = methodFullName.substring(0, methodFullName.lastIndexOf("."));
        String methodName = methodFullName.substring(methodFullName.lastIndexOf(".") + 1);

        Bundle bundle = findBundle(executionContext, aspectClassName);
        if (bundle == null)
            throw new RuntimeException("Could not find bundle for language \""
                    + executionContext.getRunConfiguration().getLanguageName() + "\"");

        // search the class
        try {
            entryPointClass = bundle.loadClass(aspectClassName);
        } catch (ClassNotFoundException e) {
            String bundleName = bundle.getHeaders().get("Bundle-Name");
            e.printStackTrace();
            throw new RuntimeException(
                    "Could not find class " + executionContext.getRunConfiguration().getExecutionEntryPoint()
                            + " in bundle " + bundleName + ".");
        }

        // search the method
        this.entryPointMethodParameters = new ArrayList<>();
        EObject root = executionContext.getResourceModel().getEObject(mainModelElementURI);
        if (root instanceof EObjectAdapter) {
            entryPointMethodParameters.add(((EObjectAdapter<?>) root).getAdaptee());
        } else {
            entryPointMethodParameters.add(root);
        }
        try {
            this.entryPointMethod = MelangeHelper.findMethod(entryPointClass, root, methodName);
        } catch (Exception e) {
            String msg = "There is no \"" + methodName + "\" method in " + entryPointClass.getName()
                    + " with first parameter able to handle " + entryPointMethodParameters.get(0).toString();
            msg += " from " + ((EObject) entryPointMethodParameters.get(0)).eClass().getEPackage().getNsURI();
            Activator.error(msg, e);
            throw new RuntimeException("Could not find method main with correct parameters.");
        }
    }

    @Override
    protected void prepareInitializeModel(IExecutionContext executionContext) {

        // try to get the initializeModelRunnable
        String modelInitializationMethodQName = executionContext.getRunConfiguration()
                .getModelInitializationMethod();
        if (!modelInitializationMethodQName.isEmpty()) {
            // the current system supposes that the modelInitialization method
            // is in the same class as the entry point
            String modelInitializationMethodName = modelInitializationMethodQName
                    .substring(modelInitializationMethodQName.lastIndexOf(".") + 1);
            boolean isListArgs = false;
            boolean isEListArgs = false;
            try {
                Class<?>[] modelInitializationParamType = new Class[] {
                        entryPointMethodParameters.get(0).getClass().getInterfaces()[0], String[].class };
                initializeMethod = entryPointClass.getMethod(modelInitializationMethodName,
                        modelInitializationParamType);
                isListArgs = false; // this is a java array
            } catch (Exception e) {
                try {
                    Class<?>[] modelInitializationParamType = new Class[] {
                            entryPointMethodParameters.get(0).getClass().getInterfaces()[0], List.class };
                    initializeMethod = entryPointClass.getMethod(modelInitializationMethodName,
                            modelInitializationParamType);
                    isListArgs = true; // this is a List

                } catch (Exception e2) {
                    try {
                        Class<?>[] modelInitializationParamType = new Class[] {
                                entryPointMethodParameters.get(0).getClass().getInterfaces()[0], EList.class };
                        this.initializeMethod = entryPointClass.getMethod(modelInitializationMethodName,
                                modelInitializationParamType);
                        isEListArgs = true; // this is an EList
                    } catch (Exception e3) {

                        String msg = "There is no \"" + modelInitializationMethodName + "\" method in "
                                + entryPointClass.getName() + " with first parameter able to handle "
                                + entryPointMethodParameters.get(0).toString();
                        msg += " and String[] or List<String> or EList<String> args as second parameter";
                        msg += " from "
                                + ((EObject) entryPointMethodParameters.get(0)).eClass().getEPackage().getNsURI();
                        Activator.error(msg, e);
                        // ((EObject)parameters.get(0)).eClass().getEPackage().getNsURI()
                        throw new RuntimeException("Could not find method " + modelInitializationMethodName
                                + " with correct parameters.");
                    }
                }
            }
            final boolean final_isListArgs = isListArgs;
            final boolean final_isEListArgs = isEListArgs;
            this.initializeMethodParameters = new ArrayList<>();
            initializeMethodParameters.add(entryPointMethodParameters.get(0));
            if (final_isListArgs) {
                final ArrayList<Object> modelInitializationListParameters = new ArrayList<>();
                for (String s : executionContext.getRunConfiguration().getModelInitializationArguments()
                        .split("\\r?\\n")) {
                    modelInitializationListParameters.add(s);
                }
                initializeMethodParameters.add(modelInitializationListParameters);
            } else if (final_isEListArgs) {
                final EList<Object> modelInitializationListParameters = new BasicEList<>();
                for (String s : executionContext.getRunConfiguration().getModelInitializationArguments()
                        .split("\\r?\\n")) {
                    modelInitializationListParameters.add(s);
                }
                initializeMethodParameters.add(modelInitializationListParameters);
            } else {
                initializeMethodParameters.add(
                        executionContext.getRunConfiguration().getModelInitializationArguments().split("\\r?\\n"));
            }

        }
    }

    @Override
    protected void initializeModel() {
        StepManagerRegistry.getInstance().registerManager(PlainK3ExecutionEngine.this);
        try {
            initializeMethod.invoke(null, initializeMethodParameters.toArray());
        } catch (EngineStoppedException stopExeception) {
            // not really an error, simply forward the stop exception
            throw stopExeception;
        } catch (java.lang.reflect.InvocationTargetException ite) {
            // not really an error, simply forward the stop exception
            if (ite.getCause() instanceof EngineStoppedException) {
                throw (EngineStoppedException) ite.getCause();
            } else {
                throw new RuntimeException(ite);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            StepManagerRegistry.getInstance().unregisterManager(PlainK3ExecutionEngine.this);
        }
    }

    @Override
    protected void executeEntryPoint() {
        StepManagerRegistry.getInstance().registerManager(PlainK3ExecutionEngine.this);
        try {
            // since aspect's methods are static, first arg is null
            entryPointMethod.invoke(null, entryPointMethodParameters.get(0));
        } catch (EngineStoppedException stopExeception) {
            // not really an error, simply forward the stop exception
            throw stopExeception;
        } catch (java.lang.reflect.InvocationTargetException ite) {
            // not really an error, simply forward the stop exception
            if (ite.getCause() instanceof EngineStoppedException) {
                throw (EngineStoppedException) ite.getCause();
            } else {
                throw new RuntimeException(ite);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            StepManagerRegistry.getInstance().unregisterManager(PlainK3ExecutionEngine.this);
        }
    }

    @Override
    /*
     * This is the operation called from K3 code. We use this callback to pass the command to the generic
     * executeOperation operation. (non-Javadoc)
     * 
     * @see fr.inria.diverse.k3.al.annotationprocessor.stepmanager.IStepManager# executeStep(java.lang.Object,
     * fr.inria.diverse.k3.al.annotationprocessor.stepmanager.StepCommand, java.lang.String)
     */
    public void executeStep(Object caller, final StepCommand command, String className, String methodName) {
        executeOperation(caller, className, methodName, new Runnable() {
            @Override
            public void run() {
                command.execute();
            }
        });
    }

    @Override
    /*
     * This is the operation used to act as a StepManager in K3. We return true if we have the same editing domain as
     * the object. (non-Javadoc)
     * 
     * @see fr.inria.diverse.k3.al.annotationprocessor.stepmanager.IStepManager#canHandle (java.lang.Object)
     */
    public boolean canHandle(Object caller) {
        if (caller instanceof EObject) {
            EObject caller_cast = (EObject) caller;
            org.eclipse.emf.transaction.TransactionalEditingDomain editingDomain = getEditingDomain(caller_cast);
            return editingDomain == this.editingDomain;

        }
        return false;
    }

    /**
     * Return a bundle containing 'aspectClassName'.
     * 
     * Return null if not found.
     */
    private Bundle findBundle(final IExecutionContext executionContext, String aspectClassName) {

        // first look using JavaWorkspaceScope as this is safer and will look in
        // dependencies
        IType mainIType = getITypeMainByWorkspaceScope(aspectClassName);

        Bundle bundle = null;
        String bundleName = null;
        if (mainIType != null) {
            IPackageFragmentRoot packageFragmentRoot = (IPackageFragmentRoot) mainIType.getPackageFragment()
                    .getParent();

            bundleName = packageFragmentRoot.getPath().removeLastSegments(1).lastSegment().toString();
            if (bundleName != null) {

                // First we try to look into an already loaded bundle
                bundle = Platform.getBundle(bundleName);

                // If this doesn't work, we use the provisioner to load
                // the corresponding project
                if (bundle == null) {

                    String projectName = mainIType.getJavaProject().getElementName();
                    IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
                    if (project != null && project.exists()
                            && !project.getFullPath().equals(executionContext.getWorkspace().getProjectPath())) {
                        Provisionner p = new Provisionner();
                        IStatus status = p.provisionFromProject(project, null);
                        if (!status.isOK()) {
                            // return status;
                            throw new RuntimeException("Coudln't provision project.");
                        }
                    }
                    bundleName = project.getName();
                    bundle = Platform.getBundle(bundleName);
                }
            }
        } else {
            // the main isn't visible directly from the workspace, try another
            // method
            bundle = _executionContext.getMelangeBundle();
        }

        return bundle;
    }

    /**
     * search the bundle that contains the Main class. The search is done in the workspace scope (ie. if it is defined
     * in the current workspace it will find it
     * 
     * @return the name of the bundle containing the Main class or null if not found
     */
    private IType getITypeMainByWorkspaceScope(String className) {
        SearchPattern pattern = SearchPattern.createPattern(className, IJavaSearchConstants.CLASS,
                IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH);
        IJavaSearchScope scope = SearchEngine.createWorkspaceScope();

        final List<IType> binaryType = new ArrayList<IType>();

        SearchRequestor requestor = new SearchRequestor() {
            @Override
            public void acceptSearchMatch(SearchMatch match) throws CoreException {
                binaryType.add((IType) match.getElement());
            }
        };
        SearchEngine engine = new SearchEngine();

        try {
            engine.search(pattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, scope,
                    requestor, null);
        } catch (CoreException e1) {
            throw new RuntimeException("Error while searching the bundle: " + e1.getMessage());
            // return new Status(IStatus.ERROR, Activator.PLUGIN_ID, );
        }

        return binaryType.isEmpty() ? null : binaryType.get(0);
    }

    private static TransactionalEditingDomain getEditingDomain(EObject o) {
        return getEditingDomain(o.eResource().getResourceSet());
    }

    private static InternalTransactionalEditingDomain getEditingDomain(ResourceSet rs) {
        TransactionalEditingDomain edomain = org.eclipse.emf.transaction.TransactionalEditingDomain.Factory.INSTANCE
                .getEditingDomain(rs);
        if (edomain instanceof InternalTransactionalEditingDomain)
            return (InternalTransactionalEditingDomain) edomain;
        else
            return null;
    }

    public static Resource loadModel(URI modelURI) {
        Resource resource = null;
        ResourceSet resourceSet;
        resourceSet = new ResourceSetImpl();
        resource = resourceSet.createResource(modelURI);
        try {
            resource.load(null);
        } catch (IOException e) {
            // chut
        }
        return resource;
    }

}