org.modelexecution.xmof.gemoc.extension.sirius.ui.command.AddAnimationLayerRunnable.java Source code

Java tutorial

Introduction

Here is the source code for org.modelexecution.xmof.gemoc.extension.sirius.ui.command.AddAnimationLayerRunnable.java

Source

/*
 * Copyright (c) 2017 Vienna University of Technology.
 * 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:
 * Tobias Ortmayr - initial API and implementation
 */

package org.modelexecution.xmof.gemoc.extension.sirius.ui.command;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.edit.command.ChangeCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.sirius.diagram.description.AdditionalLayer;
import org.eclipse.sirius.diagram.description.DiagramDescription;
import org.eclipse.sirius.diagram.description.Layer;
import org.eclipse.sirius.viewpoint.description.Customization;
import org.eclipse.sirius.viewpoint.description.DecorationDescriptionsSet;
import org.eclipse.sirius.viewpoint.description.DescriptionPackage;
import org.eclipse.sirius.viewpoint.description.Group;
import org.eclipse.sirius.viewpoint.description.RepresentationDescription;
import org.eclipse.sirius.viewpoint.description.Viewpoint;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.gemoc.xdsmlframework.extensions.sirius.Activator;
import org.eclipse.gemoc.xdsmlframework.extensions.sirius.command.AddDebugLayerHandler;
import org.osgi.framework.BundleException;

import org.eclipse.gemoc.commons.eclipse.pde.manifest.ManifestChanger;

// TODO: Lots of code is duplicate or similar to the implementation of org.eclipse.gemoc.xdsmlframework.extensions.sirius.command.AddDebugLayerHandler
// -> refactoring
public class AddAnimationLayerRunnable implements IRunnableWithProgress {

    private static final String PACKAGE_TAG = "PACKAGE";
    private static final String CLASS_NAME_TAG = "CLASS_NAME";
    private static final String LANGUAGE_NAME_TAG = "LANGUAGE_NAME";
    private static final String LAYER_NAME_TAG = "LAYER_NAME";

    private static final String ANIMATION_SERVICE_TEMPLATE_PATH = "org/modelexecution/xmof/gemoc/extension/sirius/ui/command/animation_services_template.txt";

    private static final String[] ADDITIONAL_PLUGIN_DEPENDENCIES = {
            "org.eclipse.gemoc.executionframework.extensions.sirius",
            "org.eclipse.gemoc.execution.sequential.javaengine.ui" };

    private static final String REGEX_ACTIVATOR_START_METHOD = "public\\s+void\\s+start\\s*\\"
            + "(\\s*BundleContext\\s+context\\s*\\)\\s*throws\\s+Exception\\s*[^}]*}";
    private static final String REGEX_IMPORT_BLOCK = "import.*;";

    private IFile diagramDescriptionFile;
    private String diagramDescriptionName;
    private ExecutionEvent event;

    public AddAnimationLayerRunnable(IFile diagramDescriptionFile, String diagramDescriptionName) {
        super();
        this.diagramDescriptionFile = diagramDescriptionFile;
        this.diagramDescriptionName = diagramDescriptionName;
    }

    public AddAnimationLayerRunnable(ExecutionEvent event) {
        this.event = event;
    }

    private boolean result = true;

    private IEditorPart editor;

    public boolean getResult() {
        return result;
    }

    @Override
    public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {

        try {
            DiagramDescription diagramDescription = getDiagramDescription();
            if (diagramDescription == null) {
                result = false;
                return;
            }

            final String layerName = "Animation";

            final IProject project = diagramDescriptionFile.getProject();
            final String projectName = project.getName();
            final IFolder srcFolder = project
                    .getFolder(new Path("src/" + projectName.replaceAll("\\.", "/").toLowerCase()));

            final String languageName = diagramDescription.getName();
            final String qualifiedServiceClassName = getOrCreateAnimationServiceClass(srcFolder, projectName,
                    languageName, layerName, monitor);

            EditingDomain editingDomain = ((IEditingDomainProvider) diagramDescription.eResource().getResourceSet())
                    .getEditingDomain();
            editingDomain.getCommandStack().execute(new ChangeCommand(diagramDescription.eResource()) {

                @Override
                protected void doExecute() {
                    emfModifications(monitor, layerName, diagramDescription, languageName,
                            qualifiedServiceClassName);
                }

            });

            ManifestChanger changer = new ManifestChanger(project);
            try {
                for (String dependency : ADDITIONAL_PLUGIN_DEPENDENCIES) {
                    changer.addPluginDependency(dependency);
                }

                changer.commit();
            } catch (BundleException | IOException | CoreException e) {
                Activator.getMessagingSystem().error(e.getMessage(), Activator.PLUGIN_ID, e);
            }

            if (editor != null) {
                editor.doSave(monitor);
            }

        } catch (Exception ex) {
            Activator.getMessagingSystem().error(ex.getMessage(), Activator.PLUGIN_ID, ex);
            result = false;
            throw new InvocationTargetException(ex);

        }

    }

    private DiagramDescription getDiagramDescription() throws PartInitException, ExecutionException {

        if (event != null)
            return getDiagramDescriptionFromEvent();
        return getDiagramDescriptionFromFile();

    }

    private DiagramDescription getDiagramDescriptionFromFile() throws PartInitException {
        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
                .openEditor(new FileEditorInput(diagramDescriptionFile), PlatformUI.getWorkbench()
                        .getEditorRegistry().getDefaultEditor(diagramDescriptionFile.getName()).getId());
        final Group group = getGroup();
        for (Viewpoint viewpoint : group.getOwnedViewpoints()) {
            for (RepresentationDescription representation : viewpoint.getOwnedRepresentations()) {
                if (diagramDescriptionName.equals(representation.getName())) {
                    return (DiagramDescription) representation;

                }
            }
        }
        return null;
    }

    private DiagramDescription getDiagramDescriptionFromEvent() throws ExecutionException {
        ISelection selection = HandlerUtil.getActiveWorkbenchWindow(event).getActivePage().getSelection();
        if (selection != null && selection instanceof IStructuredSelection) {
            DiagramDescription diagramDescription = (DiagramDescription) ((IStructuredSelection) selection)
                    .getFirstElement();
            IEditorInput input = HandlerUtil.getActiveEditorInputChecked(event);
            diagramDescriptionFile = (IFile) input.getAdapter(IFile.class);
            return diagramDescription;
        }
        return null;
    }

    private Group getGroup() {
        final Group res;
        editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();

        if (editor instanceof IEditingDomainProvider) {
            final EditingDomain editingDomain = ((IEditingDomainProvider) editor).getEditingDomain();
            final ResourceSet resourceSet = editingDomain.getResourceSet();
            Group group = null;

            for (Resource resource : resourceSet.getResources()) {
                for (EObject eObj : resource.getContents()) {
                    if (eObj instanceof Group) {
                        group = (Group) eObj;
                        break;
                    }
                }
            }
            res = group;
        } else {
            res = null;
        }

        return res;
    }

    private void emfModifications(IProgressMonitor monitor, String layerName, DiagramDescription description,
            String languageName, String qualifiedServiceClassName) {
        AddDebugLayerHandler.getOrCreateImport(description, qualifiedServiceClassName, monitor);
        getOrCreateAnimationLayer(description, layerName, monitor);
    }

    private Layer getOrCreateAnimationLayer(DiagramDescription description, String layerName,
            IProgressMonitor monitor) {
        final Layer res;
        Layer existingLayer = null;
        for (Layer layer : description.getAdditionalLayers()) {
            if ("Animation".equals(layer.getName())) {
                existingLayer = layer;
                break;
            }
        }

        if (existingLayer != null) {
            res = existingLayer;
        } else {
            res = createLayer(description, layerName, monitor);
        }

        return res;
    }

    private static Layer createLayer(DiagramDescription description, String layerName, IProgressMonitor monitor) {

        // Create Layer
        final AdditionalLayer res = org.eclipse.sirius.diagram.description.DescriptionPackage.eINSTANCE
                .getDescriptionFactory().createAdditionalLayer();
        res.setName("Animation");
        res.setActiveByDefault(true);

        // Add decoration set
        DecorationDescriptionsSet decorationSet = DescriptionPackage.eINSTANCE.getDescriptionFactory()
                .createDecorationDescriptionsSet();
        res.setDecorationDescriptionsSet(decorationSet);
        // Create customization
        Customization customization = DescriptionPackage.eINSTANCE.getDescriptionFactory().createCustomization();
        res.setCustomization(customization);

        description.getAdditionalLayers().add(res);
        return res;
    }

    private static String getOrCreateAnimationServiceClass(IFolder srcFolder, String projectName,
            String languageName, String layerName, IProgressMonitor monitor) throws CoreException, IOException {
        final String className = AddDebugLayerHandler.toCamelCase(languageName.replaceAll("\\W", ""))
                + "AnimationServices";
        final IFolder serviceFolder = srcFolder.getFolder(Path.fromOSString("/services"));
        final IFile classFile = serviceFolder.getFile(new Path(className + ".java"));
        final String packageName = projectName + ".services";
        final String res = packageName + "." + className;

        if (!classFile.exists()) {
            if (!serviceFolder.exists()) {
                AddDebugLayerHandler.createFolder(serviceFolder, monitor);
            }

            createAnimationServiceClass(classFile, packageName, className, languageName, layerName, monitor);
            updateAndSaveActivatorClass(srcFolder, className, res, monitor);
        }

        return res;

    }

    private static void updateAndSaveActivatorClass(IFolder srcFolder, String className, String res,
            IProgressMonitor monitor) throws IOException, CoreException {
        IFile activatorClassFile = srcFolder.getFile("Activator.java");
        if (activatorClassFile.exists()) {
            String activatorClass = AddDebugLayerHandler.getContent(activatorClassFile.getContents(), "UTF8");
            activatorClass = addImportToClass(activatorClass, res);
            activatorClass = updateStartMethod(activatorClass, className);
            activatorClassFile.delete(true, monitor);
            InputStream in = new ByteArrayInputStream(activatorClass.getBytes());
            activatorClassFile.create(in, true, monitor);
        }

    }

    private static String addImportToClass(String activatorClass, String res) {
        Pattern pattern = Pattern.compile(REGEX_IMPORT_BLOCK);
        Matcher matcher = pattern.matcher(activatorClass);
        String insertPoint = null;
        String lastStmnt = null;
        String newStmnt = String.format("import %s;\n", res);
        while (matcher.find()) {
            lastStmnt = matcher.group();
            if (lastStmnt.compareTo(newStmnt) > 0) {
                insertPoint = lastStmnt;
                break;
            }
        }

        if (insertPoint == null)
            insertPoint = lastStmnt;
        return activatorClass.replace(insertPoint, newStmnt.concat(insertPoint));

    }

    private static String updateStartMethod(String activatorClass, String className) {
        Pattern pattern = Pattern.compile(REGEX_ACTIVATOR_START_METHOD);
        Matcher matcher = pattern.matcher(activatorClass);
        if (matcher.find()) {
            String newLine = String.format("\nnew %s();\n}", className);
            String startMethod = matcher.group();
            String replaceString = startMethod.replace("}", "").trim().concat(newLine);
            return activatorClass.replace(startMethod, replaceString);
        }

        return null;
    }

    private static void createAnimationServiceClass(IFile classFile, String packageName, String className,
            String languageName, String layerName, IProgressMonitor monitor) throws IOException, CoreException {

        String content = AddDebugLayerHandler.getContent(AddAnimationLayerRunnable.class.getClassLoader()
                .getResourceAsStream(ANIMATION_SERVICE_TEMPLATE_PATH), "UTF8");

        content = content.replaceFirst(PACKAGE_TAG, packageName);
        content = content.replaceFirst(CLASS_NAME_TAG, className);
        content = content.replaceFirst(LANGUAGE_NAME_TAG, languageName);
        content = content.replaceFirst(LAYER_NAME_TAG, layerName);

        classFile.create(new ByteArrayInputStream(content.getBytes(Charset.forName("UTF8"))), true, monitor);
    }

}