Papyrus EASE generic code
Change-Id: Ifd0b45ba33562acbd72d9b785d5dbf43dc27c55c
Signed-off-by: Pauline DEVILLE <pauline.deville@cea.fr>
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/.classpath b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/.project b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/.project
new file mode 100644
index 0000000..9457dde
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.ease.lang.python.jupyter</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/META-INF/MANIFEST.MF b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..039a87f
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/META-INF/MANIFEST.MF
@@ -0,0 +1,21 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Jupyter
+Bundle-SymbolicName: org.eclipse.papyrus.ease.lang.python.jupyter;singleton:=true
+Bundle-Version: 0.7.0.qualifier
+Bundle-Activator: org.eclipse.papyrus.ease.lang.python.jupyter.Activator
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ py4j-java;bundle-version="0.10.4",
+ py4j-python;bundle-version="0.10.4",
+ org.eclipse.ease;bundle-version="0.7.0",
+ org.eclipse.ease.lang.python;bundle-version="0.7.0",
+ org.eclipse.ease.lang.python.py4j;bundle-version="0.7.0",
+ org.eclipse.core.resources,
+ org.eclipse.core.variables,
+ org.eclipse.debug.core
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Automatic-Module-Name: org.eclipse.papyrus.ease.lang.python.jupyter
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.papyrus.ease.lang.python.jupyter,
+ org.eclipse.papyrus.ease.lang.python.jupyter.internal
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/build.properties b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/build.properties
new file mode 100644
index 0000000..6681634
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ jupyter/
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/.gitignore b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/.gitignore
new file mode 100644
index 0000000..a348e50
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/.gitignore
@@ -0,0 +1 @@
+/__pycache__/
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/ease_init.py b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/ease_init.py
new file mode 100644
index 0000000..c22a73e
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/ease_init.py
@@ -0,0 +1,40 @@
+import sys
+import os
+
+sys.path.insert(0, os.environ["EASE_PY4J_SRC"])
+sys.path.insert(0, os.environ["EASE_PYTHON_COMMON_SRC"])
+sys.path.insert(0, os.environ["PY4J_PATH"])
+
+
+import ease_py4j_main
+
+#in IPyhton __builtins__ is a dict, in CPython there is a __builtins__.__dict__ attribute
+class IPythonScriptEngineExecute(ease_py4j_main._pyease_ScriptEngineExecute):
+ def internalSetVariable(self, name, content):
+ self.locals[name] = content
+ __builtins__[name] = content
+
+
+def connect_to_ease():
+
+ javaport = int(os.environ["EASE_JAVA_PORT"])
+
+ import py4j
+ from py4j.clientserver import ClientServer, JavaParameters, PythonParameters
+
+
+ engine = IPythonScriptEngineExecute()
+ # Bug 517528: Disable memory management until Py4J #275 is resolved
+ enable_memory_management = False
+ java_params = JavaParameters(auto_convert=True, port=javaport,
+ enable_memory_management=enable_memory_management)
+
+ gateway = ClientServer(java_parameters=java_params,
+ python_parameters=PythonParameters(port=0),
+ python_server_entry_point=engine)
+ # retrieve the port on which the python callback server was bound to.
+ python_port = gateway.get_callback_server().get_listening_port()
+ engine.set_gateway(gateway)
+ # tell Java that we are up and running and where to direct
+ # calls to python to.
+ gateway.entry_point.pythonStartupComplete(python_port, engine)
\ No newline at end of file
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/ease_py4j_kernel.py b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/ease_py4j_kernel.py
new file mode 100644
index 0000000..af6ea43
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/ease_py4j_kernel.py
@@ -0,0 +1,54 @@
+
+
+code='''
+import ease_init
+ease_init.connect_to_ease()
+'''
+
+#TODO : manage to use this kind of code to terminate the server when the tab is closed in the browser
+code2 ='''from IPython.display import Javascript
+Javascript(\'\'\'
+window.addEventListener('beforeunload', function() {
+
+ require(['base/js/utils'], function(utils){
+ utils.ajax(utils.url_path_join(
+ utils.get_body_data("baseUrl"),
+ "api",
+ "shutdown"),
+ {
+ type: "POST",
+ }
+ );
+ }
+
+ );
+
+});
+
+window.onbeforeunload = function () {
+
+ require(['base/js/utils'], function(utils){
+ utils.ajax(utils.url_path_join(
+ utils.get_body_data("baseUrl"),
+ "api",
+ "shutdown"
+ ), {
+ type: "POST",
+ });
+
+ });
+}
+\'\'\')'''
+
+if __name__ == '__main__':
+
+ from ipykernel.kernelapp import IPKernelApp
+ import sys
+ if sys.path[0] == '':
+ del sys.path[0]
+ app = IPKernelApp.instance()
+ app.initialize(None)
+ result = app.kernel.do_execute(code, silent=True)
+ #result = app.kernel.do_execute(code2, silent=True)
+ app.start()
+
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/kernel.json b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/kernel.json
new file mode 100644
index 0000000..c523545
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/jupyter/kernels/ease_py4j_kernel/kernel.json
@@ -0,0 +1,5 @@
+{
+ "argv": ["python", "-m", "ease_py4j_kernel", "-f", "{connection_file}"],
+ "display_name": "EASE Py4j Python 3",
+ "language": "python"
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/plugin.xml b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/plugin.xml
new file mode 100644
index 0000000..25e4268
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/plugin.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension
+ point="org.eclipse.ease.language">
+ <engine
+ class="org.eclipse.papyrus.ease.lang.python.jupyter.internal.JupyterEngine"
+ id="org.eclipse.papyrus.ease.lang.python.jupyter.engine"
+ name="Jupyter">
+ <binding
+ scriptType="Jupyter">
+ </binding>
+ </engine>
+ <launchExtension
+ class="org.eclipse.ease.lang.python.py4j.internal.Py4JBootstrap"
+ engineID="org.eclipse.papyrus.ease.lang.python.jupyter.engine">
+ </launchExtension>
+ <launchExtension
+ class="org.eclipse.ease.lang.python.Pep302ModuleImporter"
+ engineID="org.eclipse.papyrus.ease.lang.python.jupyter.engine">
+ </launchExtension>
+
+
+ </extension>
+ <extension
+ id="org.eclipse.ease.lang.python.jupyter.scriptType"
+ name="Jupyter"
+ point="org.eclipse.ease.scriptType">
+ <scriptType
+ codeFactory="org.eclipse.ease.lang.python.PythonCodeFactory"
+ codeParser="org.eclipse.ease.lang.python.PythonCodeParser"
+ defaultExtension="ipynb"
+ name="Jupyter">
+ </scriptType>
+ </extension>
+
+</plugin>
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/pom.xml b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/pom.xml
new file mode 100644
index 0000000..f0e66a4
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/pom.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Parent POM (Tools) -->
+ <parent>
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.bundles.root</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ </parent>
+
+ <!-- POM description -->
+ <artifactId>org.eclipse.papyrus.ease.lang.python.jupyter</artifactId>
+ <packaging>eclipse-plugin</packaging>
+ <name>org.eclipse.papyrus.ease.lang.python.jupyter</name>
+</project>
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/src/org/eclipse/papyrus/ease/lang/python/jupyter/Activator.java b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/src/org/eclipse/papyrus/ease/lang/python/jupyter/Activator.java
new file mode 100644
index 0000000..25d8fb0
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/src/org/eclipse/papyrus/ease/lang/python/jupyter/Activator.java
@@ -0,0 +1,84 @@
+/*****************************************************************************
+ * Copyright (c) 2019 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.ease.lang.python.jupyter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.papyrus.ease.lang.python.jupyter.internal.JupyterProxy;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.papyrus.ease.lang.python.jupyter"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ private List<JupyterProxy> runningProxies = new ArrayList<>();
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ for (JupyterProxy proxy : runningProxies ) {
+ proxy.shutDown();;
+ }
+
+ plugin = null;
+
+
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ public synchronized void registeProxy(JupyterProxy proxy) {
+ runningProxies.add(proxy);
+ }
+
+ public synchronized void unRegisterProxy(JupyterProxy proxy) {
+ runningProxies.remove(proxy);
+ }
+
+}
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/src/org/eclipse/papyrus/ease/lang/python/jupyter/internal/JupyterEngine.java b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/src/org/eclipse/papyrus/ease/lang/python/jupyter/internal/JupyterEngine.java
new file mode 100644
index 0000000..efc6912
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/src/org/eclipse/papyrus/ease/lang/python/jupyter/internal/JupyterEngine.java
@@ -0,0 +1,293 @@
+/*****************************************************************************
+ * Copyright (c) 2019 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.ease.lang.python.jupyter.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.ease.AbstractReplScriptEngine;
+import org.eclipse.ease.Logger;
+import org.eclipse.ease.Script;
+import org.eclipse.ease.ScriptEngineException;
+import org.eclipse.ease.ScriptExecutionException;
+import org.eclipse.ease.debugging.ScriptStackTrace;
+import org.eclipse.ease.lang.python.py4j.internal.IInteractiveReturn;
+import org.eclipse.ease.lang.python.py4j.internal.IPythonSideEngine;
+import org.eclipse.ease.tools.RunnableWithResult;
+import org.eclipse.papyrus.ease.lang.python.jupyter.Activator;
+import org.eclipse.swt.widgets.Display;
+
+public class JupyterEngine extends AbstractReplScriptEngine {
+
+
+ /**
+ * The ID of the Engine, to match the declaration in the plugin.xml
+ */
+ public static final String ENGINE_ID = "org.eclipse.ease.lang.python.jupyter.engine";
+
+
+
+
+ private static final String NOTE_BOOK_EXTENSION = "ipynb";
+
+
+
+
+ private static final long PYTHON_SHUTDOWN_TIMEOUT_SECONDS = 5;
+
+
+
+
+ protected IPythonSideEngine fPythonSideEngine;
+ private Process fPythonProcess;
+ private Thread fInputGobbler, fErrorGobbler;
+
+ private JupyterProxy jupyterProxy;
+
+ /**
+ * Standard StreamGobbler.
+ */
+ private static class StreamGobbler implements Runnable {
+ private final InputStream fReader;
+ private final OutputStream fWriter;
+ private final String fStreamName;
+
+ public StreamGobbler(final InputStream stream, final OutputStream output, final String streamName) {
+ fReader = stream;
+ fWriter = output;
+ fStreamName = streamName;
+ }
+
+ @Override
+ public void run() {
+ try {
+ final byte[] bytes = new byte[512];
+ int readCount;
+ while ((readCount = fReader.read(bytes)) >= 0) {
+ try {
+ fWriter.write(bytes, 0, readCount);
+ } catch (final IOException e) {
+ Logger.error(Activator.PLUGIN_ID, "Failed to write data read from Python's " + fStreamName + " stream.", e);
+ }
+ }
+ } catch (final IOException e) {
+ Logger.error(Activator.PLUGIN_ID, "Failed to read data from Python's " + fStreamName + " stream.", e);
+ }
+ }
+ }
+
+ public JupyterEngine() {
+ super("Jupyter (CEA)");
+ }
+
+ @Override
+ protected void setupEngine() throws ScriptEngineException {
+
+ if( fPythonSideEngine != null )
+ return;
+
+ if (jupyterProxy == null) {
+ initializeJupyterProxy();
+
+ }
+ try {
+ setTerminateOnIdle(false);
+
+ fPythonProcess = jupyterProxy.getJupyterProcess( );
+ Activator.getDefault().registeProxy(jupyterProxy);
+
+ fInputGobbler = new Thread(new StreamGobbler(fPythonProcess.getInputStream(), getOutputStream(), "stdout"),
+ "EASE py4j engine output stream gobbler");
+ fInputGobbler.start();
+
+
+ fErrorGobbler = new Thread(new StreamGobbler(fPythonProcess.getErrorStream(), getErrorStream(), "stderr"),
+ "EASE py4j engine error stream gobbler");
+ fErrorGobbler.start();
+
+
+ jupyterProxy.waitForKernelStartup();
+
+ fPythonSideEngine = jupyterProxy.getPythonSideEngine();
+
+
+
+ } catch (final Exception e) {
+ teardownEngine();
+ throw new ScriptEngineException("Failed to start Python process. Please check the setting for the Python interpreter"
+ + " in Preferences -> Scripting -> Python Scripting:\n" + e.getMessage(), e);
+ }
+ }
+
+
+
+ private void initializeJupyterProxy() {
+ jupyterProxy = new JupyterProxy();
+
+ List<Script> scriptToRemove = new ArrayList<>();
+ for (Script script : getScheduledScripts()) {
+ if (script.getCommand() instanceof IFile ) {
+ IFile scriptFile = (IFile) script.getCommand();
+ if (NOTE_BOOK_EXTENSION.equals(scriptFile.getFileExtension())){
+ jupyterProxy.setNotebook(scriptFile);
+ scriptToRemove.add(script);
+ }
+ }
+
+ }
+ getScheduledScripts().removeAll(scriptToRemove);
+
+ }
+
+ @Override
+ protected Object execute(final Script script, final Object reference, final String fileName, final boolean uiThread) throws Throwable {
+ if (uiThread) {
+ // run in UI thread
+ final RunnableWithResult<Object> runnable = new RunnableWithResult<Object>() {
+
+ @Override
+ public Object runWithTry() throws Throwable {
+ return internalExecute(script, fileName);
+ }
+ };
+
+ Display.getDefault().syncExec(runnable);
+ return runnable.getResultOrThrow();
+
+ } else {
+ return internalExecute(script, fileName);
+ }
+ }
+
+ protected Object internalExecute(final Script script, final String fileName) throws Throwable, Exception {
+ IInteractiveReturn interactiveReturn;
+ if (script.isShellMode()) {
+ interactiveReturn = fPythonSideEngine.executeInteractive(script.getCode());
+ } else {
+ final String code = script.getCode();
+ interactiveReturn = fPythonSideEngine.executeScript(code, fileName);
+ }
+ final Object exception = interactiveReturn.getException();
+ if (exception instanceof Throwable) {
+ throw (Throwable) exception;
+ } else if (exception != null) {
+ throw new ScriptExecutionException(exception.toString(), 0, null, null, new ScriptStackTrace(), null);
+ } else {
+ return interactiveReturn.getResult();
+ }
+ }
+
+ @Override
+ public void terminateCurrent() {
+ setTerminateOnIdle(true);
+
+ }
+
+ @Override
+ protected void teardownEngine() throws ScriptEngineException {
+
+
+ // TODO: this clean shutdown isn't working as intended.
+ // Sometimes (on Linux) the Python process seems to shutdown
+ // before fully acknowledging the call to teardownEngine, leaving
+ // us in a worst state than if we shutdown not-cleanly.
+ // When/if this is resurrected, the fPythonProcess.destroy();
+ // below should be removed.
+ // if (fPythonSideEngine != null) {
+ // // try a clean shutdown
+ // fPythonSideEngine.teardownEngine();
+ // }
+
+ if (jupyterProxy != null) {
+ jupyterProxy.shutDown();
+ }
+
+ Activator.getDefault().unRegisterProxy(jupyterProxy);
+
+
+ try {
+ // Wait until the gobblers have shovelled all their
+ // inputs before allowing the engine to considered terminated
+ if (fInputGobbler != null) {
+ fInputGobbler.join();
+ }
+ if (fErrorGobbler != null) {
+ fErrorGobbler.join();
+ }
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ @Override
+ public void registerJar(final URL url) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object internalGetVariable(final String name) {
+ return fPythonSideEngine.internalGetVariable(name);
+ }
+
+ @Override
+ protected Map<String, Object> internalGetVariables() {
+ return fPythonSideEngine.internalGetVariables();
+ }
+
+ @Override
+ protected boolean internalHasVariable(final String name) {
+ return fPythonSideEngine.internalHasVariable(name);
+ }
+
+ @Override
+ protected void internalSetVariable(final String name, final Object content) {
+ fPythonSideEngine.internalSetVariable(name, content);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T getAdapter(final Class<T> adapter) {
+ System.out.print("Adapted to: " + adapter);
+ if (adapter.isInstance(fPythonProcess)) {
+ System.out.println(" SUCCESS");
+ return (T) fPythonProcess;
+ }
+ System.out.println(" Failed");
+ return super.getAdapter(adapter);
+ }
+
+ @Override
+ public String toString(Object object) {
+ if (object == null)
+ return "None";
+
+ return super.toString(object);
+ }
+
+ public Process getPythonProcess() {
+ return fPythonProcess;
+ }
+
+ public void setJupyterProxy(JupyterProxy jupyterProxy) {
+ this.jupyterProxy= jupyterProxy;
+
+ }
+}
diff --git a/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/src/org/eclipse/papyrus/ease/lang/python/jupyter/internal/JupyterProxy.java b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/src/org/eclipse/papyrus/ease/lang/python/jupyter/internal/JupyterProxy.java
new file mode 100644
index 0000000..ca59e48
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease.lang.python.jupyter/src/org/eclipse/papyrus/ease/lang/python/jupyter/internal/JupyterProxy.java
@@ -0,0 +1,457 @@
+/*****************************************************************************
+ * Copyright (c) 2019 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.ease.lang.python.jupyter.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.SocketAddress;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.channels.SocketChannel;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.URIUtil;
+import org.eclipse.core.variables.IStringVariableManager;
+import org.eclipse.core.variables.VariablesPlugin;
+import org.eclipse.ease.ScriptEngineException;
+import org.eclipse.ease.lang.python.py4j.internal.IPythonSideEngine;
+import org.eclipse.papyrus.ease.lang.python.jupyter.Activator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+
+import py4j.ClientServer;
+import py4j.ClientServer.ClientServerBuilder;
+import py4j.JavaServer;
+
+public class JupyterProxy {
+
+ private static final int PYTHON_SHUTDOWN_TIMEOUT_SECONDS = 10;
+ private static final int PYTHON_STARTUP_TIMEOUT_SECONDS = 60;
+
+ /**
+ * Path within this plug-in to the main python file.
+ */
+ private static final String PYSRC_EASE_PY4J_MAIN_DIR = "/pysrc/";
+
+ /**
+ * The ID of the py4j sources plug-in, needs to match the name of the dependent
+ * plug-in.
+ */
+ private static final String PY4J_PYTHON_BUNDLE_ID = "py4j-python";
+
+ private static final String EASE_PY4J_BUNDLE_ID = "org.eclipse.ease.lang.python.py4j";
+
+ private static final String JUPYTER_PATH = "JUPYTER_PATH";
+
+ private static final String PYTHON_PATH = "PYTHONPATH";
+
+ private static final String EASE_PYTHON_COMMON_BUNDLE_ID = "org.eclipse.ease.lang.python";
+
+ private static final String PY4J_PATH = "PY4J_PATH";
+
+ private static final String EASE_PYTHON_COMMON_SRC = "EASE_PYTHON_COMMON_SRC";
+
+ private static final String EASE_PY4J_SRC = "EASE_PY4J_SRC";
+ private static final String JUPYTER_TOKEN = "JUPYTER_TOKEN";
+ private static final String EASE_JAVA_PORT = "EASE_JAVA_PORT";
+
+ private int notebookPort = -1;
+ private String notebookToken = UUID.randomUUID().toString();
+ private String notebookDirectory = System.getProperty("user.home");
+
+ private boolean startBrowser = false;
+ private boolean debug = false;
+
+ private CountDownLatch pythonStartupComplete;
+ private ClientServer gatewayServer;
+ private IPythonSideEngine pythonSideEngine;
+ private Process jupyterProcess;
+ private String notebookName;
+
+ private String pythonInterpreter = getPythonInterpreterExec();
+
+ public JupyterProxy() {
+
+ }
+
+ public int getNotebookPort() {
+ return notebookPort;
+ }
+
+ public JupyterProxy setNotebookPort(int notebookPort) {
+ this.notebookPort = notebookPort;
+ return this;
+ }
+
+ public String getNotebookToken() {
+ return notebookToken;
+ }
+
+ public JupyterProxy setNotebookToken(String notebookToken) {
+ this.notebookToken = notebookToken;
+ return this;
+ }
+
+ public String getNotebookDirectory() {
+ return notebookDirectory;
+ }
+
+ public JupyterProxy setNotebookDirectory(String notebookDirectory) {
+ this.notebookDirectory = notebookDirectory;
+ return this;
+ }
+
+ public JupyterProxy setStartBrowser(boolean startBrowser) {
+ this.startBrowser = startBrowser;
+ return this;
+ }
+
+ public ClientServer getGatewayServer() {
+ return gatewayServer;
+ }
+
+ public boolean isDebug() {
+ return debug;
+ }
+
+ public JupyterProxy setDebug(boolean debug) {
+ this.debug = debug;
+ return this;
+ }
+
+ public IPythonSideEngine getPythonSideEngine() {
+ return pythonSideEngine;
+ }
+
+ public Process getJupyterProcess() throws MalformedURLException, IOException, URISyntaxException, CoreException,
+ InterruptedException, ScriptEngineException {
+ if (jupyterProcess == null) {
+ startJupyterProcess();
+ }
+ return jupyterProcess;
+ }
+
+ public void startJupyterProcess() throws InterruptedException, ScriptEngineException, IOException, URISyntaxException {
+
+ notebookPort = getFreePort(8888);
+
+
+ gatewayServer = new ClientServerBuilder(this).javaPort(0).pythonPort(0).build();
+ gatewayServer.startServer(true);
+ final int javaListeningPort = ((JavaServer) gatewayServer.getJavaServer()).getListeningPort();
+
+ final ProcessBuilder pb = new ProcessBuilder();
+
+
+
+
+ // we use Py4J python interpreter, should include Jupyter
+ pb.command().add(pythonInterpreter);
+ pb.command().add("-m");
+ pb.command().add("notebook");
+ pb.command().add("--notebook-dir=" + notebookDirectory);
+ if (notebookPort > -1) {
+ pb.command().add("--port=" + notebookPort);
+ }
+ if (!startBrowser) {
+ pb.command().add("--no-browser");
+ }
+
+ if (debug) {
+ pb.command().add("--debug");
+ }
+
+ // JUPYTER_PATH is modified to add our new kernel description
+ // see http://jupyter-client.readthedocs.io/en/stable/kernels.html#kernel-specs
+ pb.environment().put(JUPYTER_PATH,
+ appendToCurrentEnvPath(JUPYTER_PATH, getJupyterPathDirectory().getAbsolutePath()));
+
+ // we also add the kernel directory in PYTHON_PATH in order to allow the
+ // first-level python to load our custom python kernel
+ pb.environment().put(PYTHON_PATH,
+ appendToCurrentEnvPath(PYTHON_PATH, getJupyterKernelDirectory().getAbsolutePath()));
+
+
+ // we now add several environment variable that will be read during our easepy4j
+ // kernel startup to establish connection
+ // with Py4J java side initiated by EASE
+ pb.environment().put(EASE_JAVA_PORT, String.valueOf(javaListeningPort));
+
+ pb.environment().put(JUPYTER_TOKEN, notebookToken);
+
+ pb.environment().put(PY4J_PATH, getPy4jPythonSrc().getAbsolutePath());
+ pb.environment().put(EASE_PYTHON_COMMON_SRC, getEASEPythonCommonSrc().getAbsolutePath());
+ pb.environment().put(EASE_PY4J_SRC, getPy4jEaseMainDir().getAbsolutePath());
+
+ jupyterProcess = pb.start();
+
+
+
+
+ pythonStartupComplete = new CountDownLatch(1);
+
+
+
+ }
+
+ private String getPythonInterpreterExec() {
+ String interpreter = Platform.getPreferencesService().getString("org.eclipse.ease.lang.python.py4j",
+ "org.eclipse.ease.lang.python.py4j.INTERPRETER", "python", null);
+ final IStringVariableManager variableManager = VariablesPlugin.getDefault().getStringVariableManager();
+ try {
+ interpreter = variableManager.performStringSubstitution(interpreter);
+ } catch (CoreException e) {
+ interpreter = "python";
+ }
+ return interpreter;
+ }
+
+ private void waitForJupyterStartup() throws InterruptedException, ScriptEngineException, IOException{
+ boolean scanning=true;
+ SocketAddress address = new InetSocketAddress("localhost", notebookPort);
+
+ int attempts = 0;
+ while(scanning && attempts < 200){
+ try{
+ attempts++;
+ SocketChannel.open(address);
+ scanning=false;
+ }
+ catch(IOException e){
+ Thread.sleep(100);//0.1 second
+ }
+ }
+ if (scanning) {
+ throw new ScriptEngineException("Jupyter notebook did not start within 20 seconds");
+ }
+ }
+
+ public void waitForKernelStartup() throws InterruptedException, ScriptEngineException, IOException {
+
+ waitForJupyterStartup();
+
+ //web browser will start the kernel if a notebook has been selected to be run as EASE script
+ //else user will have to manually start the kernel in the browser
+ openWebBrowser();
+
+ // We wait here for the main notebook python process initialization
+ if (!pythonStartupComplete.await(PYTHON_STARTUP_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
+ throw new ScriptEngineException(
+ "Kernel process did not start within " + PYTHON_STARTUP_TIMEOUT_SECONDS + " seconds");
+ }
+
+ }
+
+ public void pythonStartupComplete(final int pythonPort, final IPythonSideEngine pythonSideEngine) {
+ final JavaServer javaServer = (JavaServer) gatewayServer.getJavaServer();
+ javaServer.resetCallbackClient(javaServer.getCallbackClient().getAddress(), pythonPort);
+
+ this.pythonSideEngine = pythonSideEngine;
+
+ pythonStartupComplete.countDown();
+
+ }
+
+ private void openWebBrowser() {
+
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+
+ try {
+ // even if we wait for python startup, still have to wait for server startup to
+ // avoid to have to refresh the page
+ TimeUnit.SECONDS.sleep(3);
+ IWebBrowser browser = PlatformUI.getWorkbench().getBrowserSupport().createBrowser(null);
+ browser.openURL(getNoteBookURL());
+
+ } catch (PartInitException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (MalformedURLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+ });
+
+ }
+
+ private URL getNoteBookURL() throws MalformedURLException {
+ String urlString = "http://localhost:" + notebookPort;
+ if (notebookName != null) {
+ urlString += "/notebooks/" + notebookName;
+ }
+ urlString += "?token=" + notebookToken;
+
+ return new URL(urlString);
+ }
+
+ private File getEASEPythonCommonSrc() throws IOException {
+
+ final File easePythonCommonBundleFile = FileLocator
+ .getBundleFile(Platform.getBundle(EASE_PYTHON_COMMON_BUNDLE_ID));
+ final File easePythonCommonSrc = new File(easePythonCommonBundleFile, "/pysrc");
+
+ if (!easePythonCommonSrc.exists() || !easePythonCommonSrc.isDirectory()) {
+ throw new IOException(
+ "Failed to find EASE commong python directory, expected it here: " + easePythonCommonSrc);
+ }
+ return easePythonCommonSrc;
+ }
+
+ private File getPy4jPythonSrc() throws IOException {
+ final File py4jPythonBundleFile = FileLocator.getBundleFile(Platform.getBundle(PY4J_PYTHON_BUNDLE_ID));
+ final File py4jPythonSrc = new File(py4jPythonBundleFile, "/src");
+ //final File py4j = new File(py4jPythonSrc, "py4j");
+ if (!py4jPythonSrc.exists() || !py4jPythonSrc.isDirectory()) {
+ throw new IOException("Failed to find py4j python directory, expected it here: " + py4jPythonSrc);
+ }
+ return py4jPythonSrc;
+ }
+
+ private File getPy4jEaseMainDir() throws MalformedURLException, IOException, URISyntaxException {
+ final URL url = new URL("platform:/plugin/" + EASE_PY4J_BUNDLE_ID + PYSRC_EASE_PY4J_MAIN_DIR);
+ final URL fileURL = FileLocator.toFileURL(url);
+ final File py4jEaseMain = new File(URIUtil.toURI(fileURL).normalize());
+ if (!py4jEaseMain.exists() && !py4jEaseMain.isDirectory()) {
+ throw new IOException("Failed to find " + PYSRC_EASE_PY4J_MAIN_DIR + ", expected it here: " + py4jEaseMain);
+ }
+ return py4jEaseMain;
+ }
+ private File getJupyterPathDirectory() throws IOException, URISyntaxException {
+ final URL url = new URL("platform:/plugin/"+Activator.PLUGIN_ID+"/jupyter");
+ final URL fileURL = FileLocator.toFileURL(url);
+ final File rootDir = new File(URIUtil.toURI(fileURL).normalize());
+ if (!rootDir.exists() || !rootDir.isDirectory()) {
+ throw new IOException(
+ "Failed to find ease-py4j Jupyter kernel root directory, expected it here: " + rootDir);
+ }
+ return rootDir;
+ }
+
+ private File getJupyterKernelDirectory() throws IOException, URISyntaxException {
+ final File jupyterPath = getJupyterPathDirectory();
+ final File kernelDirectory = new File(jupyterPath, "/kernels/ease_py4j_kernel");
+ if (!kernelDirectory.exists() || !kernelDirectory.isDirectory()) {
+ throw new IOException(
+ "Failed to find ease-py4j Jupyter kernel directory, expected it here: " + kernelDirectory);
+ }
+ return kernelDirectory;
+ }
+
+ private String appendToCurrentEnvPath(String variableName, String value) {
+ String currentPath = System.getenv(variableName);
+
+ if (currentPath == null) {
+ currentPath = value;
+ } else {
+ currentPath = value + File.pathSeparator + currentPath;
+ }
+ return currentPath;
+ }
+
+ /**
+ * Tries to find a new free port close to the given start port.
+ * <p>
+ * Not that there is a (unlikely but) possible race condition if the returned
+ * port is being used between calling this and actually starting a server.
+ * Handle blocked servers appropriately.
+ *
+ * @param startPort
+ * Lowest desired port number.
+ * @return Free port (hopefully) close to startPort.
+ */
+ public static int getFreePort(int startPort) {
+ ServerSocket socket = null;
+ while (true) {
+ try {
+ // Try to create server for port number
+ socket = new ServerSocket(startPort);
+
+ // Make reusable to timeout state problems
+ socket.setReuseAddress(true);
+
+ // No exception -> port is free
+ return startPort;
+ } catch (IOException ignore) {
+ // IOException most (!) likely because of used port
+ startPort++;
+ } finally {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException ignore) {
+ // Should not occur
+ }
+ }
+ }
+ }
+ }
+
+ public JupyterProxy setNotebook(IFile scriptFile) {
+ notebookDirectory = scriptFile.getParent().getLocation().toOSString();
+ notebookName = scriptFile.getName();
+ return this;
+ }
+
+ public void shutDown() {
+
+
+ ProcessBuilder stopProcess = new ProcessBuilder().command(
+ pythonInterpreter,
+ "-m",
+ "notebook",
+ "stop",
+ Integer.toString(notebookPort)
+ );
+
+ try {
+ Process process =stopProcess.start();
+ process.waitFor(PYTHON_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+
+ } catch (IOException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+
+
+ if (gatewayServer != null) {
+ gatewayServer.shutdown();
+ }
+
+ }
+
+}
diff --git a/bundles/org.eclipse.papyrus.ease/.classpath b/bundles/org.eclipse.papyrus.ease/.classpath
new file mode 100644
index 0000000..43b9862
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/bundles/org.eclipse.papyrus.ease/.project b/bundles/org.eclipse.papyrus.ease/.project
new file mode 100644
index 0000000..4894083
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.ease</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.papyrus.ease/META-INF/MANIFEST.MF b/bundles/org.eclipse.papyrus.ease/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..ad076d4
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/META-INF/MANIFEST.MF
@@ -0,0 +1,27 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Papyrus EASE Integration
+Bundle-SymbolicName: org.eclipse.papyrus.ease;singleton:=true
+Bundle-Version: 0.7.0.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.ease;bundle-version="0.5.0",
+ org.eclipse.ui;bundle-version="3.109.0",
+ org.eclipse.ease.ui.scripts;bundle-version="0.5.0",
+ org.eclipse.osgi.services,
+ org.eclipse.e4.core.services,
+ org.eclipse.core.expressions;bundle-version="3.6.0",
+ org.eclipse.ease.ui,
+ org.eclipse.uml2.uml,
+ org.eclipse.papyrus.infra.core,
+ org.eclipse.ui.ide;bundle-version="3.13.1",
+ org.eclipse.papyrus.editor,
+ org.eclipse.gef,
+ org.eclipse.gmf.runtime.emf.type.core,
+ org.eclipse.papyrus.infra.architecture,
+ org.eclipse.papyrus.infra.types.core,
+ org.eclipse.gmf.runtime.diagram.ui,
+ org.eclipse.papyrus.infra.gmfdiag.common,
+ org.eclipse.papyrus.infra.viewpoints.policy,
+ org.eclipse.papyrus.infra.emf
+Export-Package: org.eclipse.papyrus.ease.module,
+ org.eclipse.papyrus.ease.popup
diff --git a/bundles/org.eclipse.papyrus.ease/build.properties b/bundles/org.eclipse.papyrus.ease/build.properties
new file mode 100644
index 0000000..7cebe16
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ scripts/
diff --git a/bundles/org.eclipse.papyrus.ease/plugin.xml b/bundles/org.eclipse.papyrus.ease/plugin.xml
new file mode 100644
index 0000000..d8e0824
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/plugin.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension
+ point="org.eclipse.ease.ui.scripts.keyword">
+ <handler
+ class="org.eclipse.papyrus.ease.popup.PapyrusPopupHandler"
+ description="Adds scripts to popup : takesEnableFor(<classe name>)"
+ id="org.eclipse.papyrus.ease.test.popup"
+ keywords="papypopup"
+ name="Papyrus Popup Additions">
+ </handler>
+ </extension>
+ <extension
+ point="org.eclipse.ease.modules">
+ <module
+ category="org.eclipse.ease.modules.category.modeling"
+ class="org.eclipse.papyrus.ease.module.PapyrusUtilsModule"
+ id="org.eclipse.papyrus.ease.module"
+ name="PapyrusUtils"
+ visible="true">
+ </module>
+ </extension>
+
+</plugin>
diff --git a/bundles/org.eclipse.papyrus.ease/pom.xml b/bundles/org.eclipse.papyrus.ease/pom.xml
new file mode 100644
index 0000000..f53cffa
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/pom.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Parent POM (Tools) -->
+ <parent>
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.bundles.root</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ </parent>
+
+ <!-- POM description -->
+ <artifactId>org.eclipse.papyrus.ease</artifactId>
+ <packaging>eclipse-plugin</packaging>
+ <name>org.eclipse.papyrus.ease</name>
+</project>
diff --git a/bundles/org.eclipse.papyrus.ease/scripts/python/papyrusutils.py b/bundles/org.eclipse.papyrus.ease/scripts/python/papyrusutils.py
new file mode 100644
index 0000000..c9f745e
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/scripts/python/papyrusutils.py
@@ -0,0 +1,42 @@
+
+loadModule("/Modeling/PapyrusUtils")
+loadModule("/Modeling/ECore")
+import sys
+
+def is_jython():
+ return hasattr(sys, 'subversion') and (sys.subversion[0]== 'Jython')
+
+if (not is_jython()) :
+ class GenericRunnable:
+
+ def __init__(self,func, *args):
+ self.func = func
+ self.args = args
+
+ def run(self):
+ self.result= self.func(*self.args)
+
+
+ class Java:
+ implements=['java.lang.Runnable']
+
+else:
+
+ from java.lang import Runnable
+ class GenericRunnable(Runnable):
+
+ def __init__(self,func, *args):
+ self.func = func
+ self.args = args
+ def run(self):
+ self.result = self.func(*self.args)
+
+
+def papyrun(func, *args):
+ runnable = GenericRunnable(func, *args)
+ runOperation( runnable)
+ return runnable.result
+
+
+
+
diff --git a/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/module/PapyrusUtilsModule.java b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/module/PapyrusUtilsModule.java
new file mode 100644
index 0000000..8dab19d
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/module/PapyrusUtilsModule.java
@@ -0,0 +1,668 @@
+/*****************************************************************************
+ * Copyright (c) 2019 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.ease.module;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.ease.modules.AbstractScriptModule;
+import org.eclipse.ease.modules.ScriptParameter;
+import org.eclipse.ease.modules.WrapToScript;
+import org.eclipse.ease.tools.ResourceTools;
+import org.eclipse.ease.tools.RunnableWithResult;
+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.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.GraphicalViewer;
+import org.eclipse.gef.RequestConstants;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.ui.parts.GraphicalEditor;
+import org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewAndElementRequest;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewAndElementRequest.ConnectionViewAndElementDescriptor;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest.ViewAndElementDescriptor;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor;
+import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
+import org.eclipse.gmf.runtime.emf.type.core.ClientContextManager;
+import org.eclipse.gmf.runtime.emf.type.core.IClientContext;
+import org.eclipse.gmf.runtime.emf.type.core.IElementType;
+import org.eclipse.gmf.runtime.emf.type.core.IHintedType;
+import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.papyrus.editor.PapyrusMultiDiagramEditor;
+import org.eclipse.papyrus.infra.architecture.ArchitectureDescriptionUtils;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServiceMultiException;
+import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.gmfdiag.common.commands.CreateViewCommand;
+import org.eclipse.papyrus.infra.gmfdiag.common.service.palette.AspectUnspecifiedTypeConnectionTool.PapyrusCreateViewRequestFactory;
+import org.eclipse.papyrus.infra.gmfdiag.common.utils.DiagramUtils;
+import org.eclipse.papyrus.infra.types.core.utils.ElementTypeRegistryUtils;
+import org.eclipse.papyrus.infra.viewpoints.policy.PolicyChecker;
+import org.eclipse.papyrus.infra.viewpoints.policy.ViewPrototype;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.uml2.uml.NamedElement;
+import org.eclipse.uml2.uml.Package;
+
+public class PapyrusUtilsModule extends AbstractScriptModule {
+
+
+ private ModelSet currentModelSet = null;
+
+ private IFile getDIFile(IFile inputFile) {
+ IFile result = null;
+ if ("uml".equals(inputFile.getFileExtension())) {
+ result = (IFile) inputFile.getParent().findMember(inputFile.getName().replaceAll(".uml$", ".di"));
+ } else if ("di".equals(inputFile.getFileExtension()) && inputFile.exists()) {
+ result = inputFile;
+ }
+ return result;
+ }
+
+ /**
+ * Access to the root element of an opened Papyrus model in order to modify it
+ * within it's current transactionnal domain, allowing undo/redo
+ *
+ * @param modelPath : path the model to access. The model has to be in the
+ * workspace and opened. The path follows EASE path/URI
+ * conventions: "workspace://" as well as EMF URIs
+ * @return
+ * @throws org.eclipse.papyrus.infra.core.services.ServiceException
+ *
+ */
+ @WrapToScript
+ public org.eclipse.uml2.uml.Package getPapyrusModel(String modelPath)
+ throws RuntimeException, CoreException, URISyntaxException, IOException, ServiceException {
+
+ Object resolved = ResourceTools.resolve(modelPath, getScriptEngine().getExecutedFile());
+
+
+ IFile diFile = null;
+ URI modelURI = null;
+
+ if (resolved instanceof IFile) {
+ diFile = getDIFile((IFile) resolved);
+
+ } else {
+ URI emfURI = null;
+ if (resolved instanceof URL || resolved instanceof java.net.URI) {
+ emfURI = URI.createURI(modelPath);
+ }
+ if (emfURI != null && emfURI.isPlatformResource()) {
+ IResource referencedIFile = ResourcesPlugin.getWorkspace().getRoot()
+ .findMember(emfURI.toPlatformString(true));
+ if ((referencedIFile instanceof IFile)) {
+ diFile = getDIFile((IFile) referencedIFile);
+ }
+ }
+
+ }
+
+ if (diFile != null) {
+
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ FileEditorInput editorInput = new FileEditorInput(diFile);
+ IEditorPart editorPart = null;
+ winloop: for (IWorkbenchWindow win : workbench.getWorkbenchWindows()) {
+ for (IWorkbenchPage page : win.getPages()) {
+ editorPart = page.findEditor(editorInput);
+ if (editorPart != null) {
+ final IEditorPart papyPart = editorPart;
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ page.activate(papyPart);
+
+ }
+ });
+
+ break winloop;
+ }
+ }
+
+ }
+
+ if (editorPart != null) {
+ ServicesRegistry servicesRegistry = editorPart.getAdapter(ServicesRegistry.class);
+ if (servicesRegistry != null) {
+ currentModelSet = servicesRegistry.getService(ModelSet.class);
+ }
+ }
+
+ if (currentModelSet != null) {
+
+ modelURI = URI.createPlatformResourceURI(diFile.getFullPath().toString(), true).trimFileExtension()
+ .appendFileExtension("uml");
+ Resource res = currentModelSet.getResource(modelURI, true);
+ if (res != null && !res.getContents().isEmpty()) {
+ EObject rootObject = res.getContents().get(0);
+ if (rootObject instanceof org.eclipse.uml2.uml.Package) {
+ return (Package) rootObject;
+ }
+ }
+ }
+
+ }
+
+ throw new RuntimeException("Failed to find an opened Papyrus session for file: " + modelPath);
+ }
+
+ /**
+ * Gets a the first Named elements found in a Papyrus ModelSet. The named
+ * element can be in an imported model or profile.
+ *
+ * @param context : the context can be a String with a path following EASE
+ * path/URI conventions: "workspace://" as well as EMF
+ * URIs, pointing either to an UML or DI file. It can also
+ * be a model element of an already opened model.
+ * @param qualifiedName : the full qualified name of the named element to find.
+ * @return the first object found with the given qualified name.
+ */
+ @WrapToScript
+ public NamedElement getPapyrusNamedElement(Object context, String qualifiedName)
+ throws RuntimeException, CoreException, URISyntaxException, IOException, ServiceException {
+ ResourceSet resSet = null;
+ if (context instanceof String) {
+ org.eclipse.uml2.uml.Package pack = getPapyrusModel((String) context);
+ if (pack != null) {
+ resSet = pack.eResource().getResourceSet();
+ }
+ } else if (context instanceof EObject && ((EObject) context).eResource() != null) {
+ resSet = ((EObject) context).eResource().getResourceSet();
+ }
+ if (resSet != null) {
+ Collection<NamedElement> elems = org.eclipse.uml2.uml.util.UMLUtil.findNamedElements(resSet, qualifiedName);
+ if (!elems.isEmpty()) {
+ return elems.iterator().next();
+ } else {
+ throw new RuntimeException("Failed to find a NamedElement with qualified name: " + qualifiedName);
+ }
+ } else {
+ throw new RuntimeException("Failed to find a contextual resource for object " + context.toString()
+ + " when searching Named Element " + qualifiedName);
+ }
+
+ }
+
+ static WeakReference<PapyrusMultiDiagramEditor> papyrus = null;
+
+ @WrapToScript
+ public static void setPapyrusSession(PapyrusMultiDiagramEditor editor) {
+ papyrus = new WeakReference<PapyrusMultiDiagramEditor>(editor);
+ }
+
+ public static PapyrusMultiDiagramEditor getPapyrusSession() {
+
+ if (papyrus != null && papyrus.get() != null) {
+ return papyrus.get();
+ } else {
+ PapyrusMultiDiagramEditor result = getActivePapyrusEditor();
+ setPapyrusSession(result);
+ return result;
+ }
+
+ }
+
+
+ @WrapToScript
+ public static void createDiagram(EObject owner, String diagramArchitectureLabel, String diagramName) {
+ // Collection<ViewPrototype> protos = PolicyChecker.getFor(owner).getPrototypesFor(owner);
+
+ try {
+ ViewPrototype proto = PolicyChecker.getFor(owner).getPrototypesFor(owner).stream().
+ filter(prototype ->
+ diagramArchitectureLabel.equals(
+ prototype.getLabel()))
+ .findAny().get();
+
+ if (proto != null) {
+ boolean instanciateOk =proto.instantiateOn(owner, diagramName);
+ if (instanciateOk ) {
+
+ }
+ }
+
+
+ }catch (NoSuchElementException e) {
+ throw new RuntimeException("Failed to find a diagram kind named "+diagramArchitectureLabel);
+ }
+
+ }
+
+ @WrapToScript
+ public static EObject createSemanticElement(EObject owner, String elementTypeIdToCreate) {
+
+ PapyrusMultiDiagramEditor papyrus = getPapyrusSession();
+ IElementType elementType = getElementType(papyrus, elementTypeIdToCreate);
+ if (elementType != null) {
+ return RequestUtils.createElementWithRequest(owner, elementType);
+ }
+ return null;
+ }
+
+ @WrapToScript
+ public static ViewAndElementHandler createSemanticElementAndLinkView(String graphicalElementTypeIdToCreate,
+ Node sourceNode, Double relativeXSource, Double relativeYSource, Node targetNode, Double relativeXTarget,
+ Double relativeYTarget) {
+
+ PapyrusMultiDiagramEditor papyrus = getPapyrusSession();
+ IElementType elementType = getElementType(papyrus, graphicalElementTypeIdToCreate);
+
+ GraphicalEditPart diagramEditPart = (GraphicalEditPart) getActivePapyrusViewer(papyrus).getContents();
+
+ GraphicalEditPart sourceEditPart = (GraphicalEditPart) getActivePapyrusViewer(papyrus).getEditPartRegistry()
+ .get(sourceNode);
+ GraphicalEditPart targetEditPart = (GraphicalEditPart) getActivePapyrusViewer(papyrus).getEditPartRegistry()
+ .get(targetNode);
+ CreateConnectionViewAndElementRequest request = (CreateConnectionViewAndElementRequest) PapyrusCreateViewRequestFactory
+ .getCreateConnectionRequest(elementType, diagramEditPart.getDiagramPreferencesHint());
+
+ request.setSourceEditPart(sourceEditPart);
+
+ request.setType(RequestConstants.REQ_CONNECTION_START);
+ // Point sourcePoint = getRelativePoint(sourceNode, relativeXSource,
+ // relativeYSource);
+
+ Point sourcePoint = getAbsolutePoint(sourceNode, relativeXSource, relativeYSource);
+ sourceEditPart.getFigure().translateToAbsolute(sourcePoint);
+ request.setLocation(sourcePoint);
+
+ Command command = sourceEditPart.getTargetEditPart(request).getCommand(request);
+
+ if (command instanceof CompoundCommand) {
+ for (Object subCommand : ((CompoundCommand) command).getCommands()) {
+ if (subCommand instanceof ICommandProxy) {
+ request.setStartCommand((ICommandProxy) subCommand);
+ break;
+ }
+ }
+ }
+
+ request.setType(RequestConstants.REQ_CONNECTION_END);
+
+ request.setTargetEditPart(targetEditPart);
+ // Point targetPoint = getRelativePoint(targetNode, relativeXTarget,
+ // relativeYTarget);
+ Point targetPoint = getAbsolutePoint(targetNode, relativeXTarget, relativeYTarget);
+
+ targetEditPart.getFigure().translateToAbsolute(targetPoint);
+ request.setLocation(targetPoint);
+
+ command = targetEditPart.getTargetEditPart(request).getCommand(request);
+
+ if (command != null && command.canExecute()) {
+
+ command.execute();
+ }
+
+ ConnectionViewAndElementDescriptor descriptor = request.getConnectionViewAndElementDescriptor();
+ View view = (View) descriptor.getAdapter(View.class);
+ EObject semanticElement = descriptor.getElementAdapter().getAdapter(EObject.class);
+
+ return new ViewAndElementHandler(view, semanticElement);
+
+ }
+
+ @WrapToScript
+ public static ViewAndElementHandler createSemanticElementAndView(String graphicalElementTypeIdToCreate, Integer x,
+ Integer y, @ScriptParameter(defaultValue = ScriptParameter.NULL) Integer width,
+ @ScriptParameter(defaultValue = ScriptParameter.NULL) Integer height) {
+
+ PapyrusMultiDiagramEditor papyrus = getPapyrusSession();
+ IElementType elementType = getElementType(papyrus, graphicalElementTypeIdToCreate);
+ EditPart targetEditPart = calculateTargetEditPart(papyrus, (double) x, (double) y);
+
+ if (elementType instanceof IHintedType && targetEditPart instanceof GraphicalEditPart) {
+
+ ViewAndElementDescriptor viewDescriptor = new ViewAndElementDescriptor(
+ new CreateElementRequestAdapter(new CreateElementRequest(elementType)), Node.class,
+ ((IHintedType) elementType).getSemanticHint(),
+ ((GraphicalEditPart) targetEditPart).getDiagramPreferencesHint());
+
+ CreateViewAndElementRequest request = new CreateViewAndElementRequest(viewDescriptor);
+
+ Command command = targetEditPart.getTargetEditPart(request).getCommand(request);
+
+ if (command != null && command.canExecute()) {
+
+ // getPapyrusSession().getEditingDomain().getCommandStack().execute(new
+ // GEFtoEMFCommandWrapper(command));
+ command.execute();
+ }
+ View view = (View) viewDescriptor.getAdapter(View.class);
+ EObject semanticElement = viewDescriptor.getElementAdapter().getAdapter(EObject.class);
+
+ updateBounds(viewDescriptor, (TransactionalEditingDomain) papyrus.getEditingDomain(), new Point(x, y),
+ width, height);
+
+ return new ViewAndElementHandler(view, semanticElement);
+ }
+ return null;
+ }
+
+ @WrapToScript
+ public static void refreshPapyrus() {
+ // Runnable refresh = ((TransactionalEditingDomain)
+ // getPapyrusSession().getEditingDomain()).createPrivilegedRunnable(new
+ // Runnable() {
+ Runnable refresh = new Runnable() {
+ @Override
+ public void run() {
+
+ getActivePapyrusViewer(getPapyrusSession()).flush();
+
+ }
+ };
+ Display.getDefault().syncExec(refresh);
+
+ }
+
+ public static void updateBounds(IAdaptable iAdaptable, TransactionalEditingDomain domain, Point location,
+ Integer width, Integer height) {
+ SetBoundsCommand setBoundsCommand = null;
+
+ if (width != null && height != null) {
+ Dimension dimension = new Dimension(width, height);
+ Rectangle rectangle = new Rectangle(location, dimension);
+
+ setBoundsCommand = new SetBoundsCommand(domain, "move", iAdaptable, rectangle);
+ } else {
+ setBoundsCommand = new SetBoundsCommand((TransactionalEditingDomain) domain, "move", iAdaptable, location);
+ }
+
+ // getPapyrusSession().getEditingDomain().getCommandStack().execute(new
+ // GMFtoEMFCommandWrapper(setBoundsCommand));
+ try {
+ setBoundsCommand.execute(null, null);
+ } catch (ExecutionException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
+ @WrapToScript
+ public static View createView(EObject element, String graphicalElementTypeIdToCreate, Integer x, Integer y,
+ @ScriptParameter(defaultValue = ScriptParameter.NULL) Integer width,
+ @ScriptParameter(defaultValue = ScriptParameter.NULL) Integer height) {
+
+ PapyrusMultiDiagramEditor papyrus = getPapyrusSession();
+ IElementType elementType = getElementType(papyrus, graphicalElementTypeIdToCreate);
+ EditPart targetEditPart = calculateTargetEditPart(papyrus, (double) x, (double) y);
+
+ if (elementType instanceof IHintedType && targetEditPart instanceof GraphicalEditPart) {
+
+ ViewDescriptor descriptor = new ViewDescriptor(new EObjectAdapter(element), Node.class,
+ ((IHintedType) elementType).getSemanticHint(),
+ ((GraphicalEditPart) targetEditPart).getDiagramPreferencesHint());
+
+ CreateViewCommand createCommand = new CreateViewCommand(
+ (TransactionalEditingDomain) papyrus.getEditingDomain(), descriptor,
+ ((GraphicalEditPart) targetEditPart).getNotationView());
+
+ try {
+ createCommand.execute(null, null);
+ IAdaptable commandResult = (IAdaptable) createCommand.getCommandResult().getReturnValue();
+ View result = commandResult.getAdapter(View.class);
+
+ updateBounds(commandResult, (TransactionalEditingDomain) papyrus.getEditingDomain(), new Point(x, y),
+ width, height);
+ return result;
+
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+
+ }
+ return null;
+
+ }
+
+ @WrapToScript
+ public static View createRelativeView(EObject element, String graphicalElementTypeIdToCreate, Node parentNode,
+ Double relativeX, Double relativeY, @ScriptParameter(defaultValue = ScriptParameter.NULL) Integer width,
+ @ScriptParameter(defaultValue = ScriptParameter.NULL) Integer height) {
+
+ PapyrusMultiDiagramEditor papyrus = getPapyrusSession();
+ IElementType elementType = getElementType(papyrus, graphicalElementTypeIdToCreate);
+
+ Diagram diagram = DiagramUtils.getContainingDiagram(parentNode);
+ GraphicalEditPart diagramEditPart = (GraphicalEditPart) getActivePapyrusViewer(papyrus).getEditPartRegistry()
+ .get(diagram);
+
+ if (elementType instanceof IHintedType && diagramEditPart instanceof GraphicalEditPart) {
+
+ ViewDescriptor descriptor = new ViewDescriptor(new EObjectAdapter(element), Node.class,
+ ((IHintedType) elementType).getSemanticHint(),
+ ((GraphicalEditPart) diagramEditPart).getDiagramPreferencesHint());
+
+ CreateViewCommand createCommand = new CreateViewCommand(
+ (TransactionalEditingDomain) papyrus.getEditingDomain(), descriptor, parentNode);
+
+ try {
+ createCommand.execute(null, null);
+ IAdaptable commandResult = (IAdaptable) createCommand.getCommandResult().getReturnValue();
+ View result = commandResult.getAdapter(View.class);
+
+ updateBounds(commandResult, (TransactionalEditingDomain) papyrus.getEditingDomain(),
+ getRelativePoint(parentNode, relativeX, relativeY), width, height);
+ return result;
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+
+ }
+ return null;
+
+ }
+
+ @WrapToScript
+ public static ViewAndElementHandler createRelativeSemanticElementAndView(String graphicalElementTypeIdToCreate,
+ Node parentNode, Double relativeX, Double relativeY,
+ @ScriptParameter(defaultValue = ScriptParameter.NULL) Integer width,
+ @ScriptParameter(defaultValue = ScriptParameter.NULL) Integer height) {
+
+ PapyrusMultiDiagramEditor papyrus = getPapyrusSession();
+ IElementType elementType = getElementType(papyrus, graphicalElementTypeIdToCreate);
+
+ if (elementType instanceof IHintedType && parentNode instanceof Node) {
+
+ GraphicalEditPart targetEditPart = null;
+
+ if ((relativeX == 0.0) || relativeY == 0.0 || relativeX == 1.0 || relativeY == 1.0) {
+ targetEditPart = (GraphicalEditPart) getActivePapyrusViewer(papyrus).getEditPartRegistry()
+ .get(parentNode);
+ } else {
+ PrecisionPoint absoluteLocation = getAbsolutePoint(parentNode, relativeX, relativeY);
+ targetEditPart = (GraphicalEditPart) calculateTargetEditPart(getPapyrusSession(),
+ absoluteLocation.preciseX(), absoluteLocation.preciseY());
+ }
+
+ if (targetEditPart instanceof GraphicalEditPart) {
+ ViewAndElementDescriptor viewDescriptor = new ViewAndElementDescriptor(
+ new CreateElementRequestAdapter(new CreateElementRequest(elementType)), Node.class,
+ ((IHintedType) elementType).getSemanticHint(),
+ ((GraphicalEditPart) targetEditPart).getDiagramPreferencesHint());
+
+ CreateViewAndElementRequest request = new CreateViewAndElementRequest(viewDescriptor);
+
+ Command command = targetEditPart.getTargetEditPart(request).getCommand(request);
+
+ if (command != null && command.canExecute()) {
+ command.execute();
+ View view = (View) viewDescriptor.getAdapter(View.class);
+ EObject semanticElement = viewDescriptor.getElementAdapter().getAdapter(EObject.class);
+
+ updateBounds(viewDescriptor, (TransactionalEditingDomain) papyrus.getEditingDomain(),
+ getRelativePoint(parentNode, relativeX, relativeY), width, height);
+
+ return new ViewAndElementHandler(view, semanticElement);
+ }
+
+ }
+
+ }
+ return null;
+
+ }
+
+ private static Point getRelativePoint(Node parentNode, Double relativeX, Double relativeY) {
+
+ LayoutConstraint constraint = parentNode.getLayoutConstraint();
+ if (constraint instanceof Bounds) {
+
+ Bounds bounds = (Bounds) constraint;
+ double newX = (relativeX * bounds.getWidth());
+ double newY = (relativeY * bounds.getHeight());
+
+ return new PrecisionPoint(newX, newY);
+ }
+ return null;
+
+ }
+
+ private static PrecisionPoint getAbsolutePoint(Node parentNode, Double relativeX, Double relativeY) {
+
+ LayoutConstraint constraint = parentNode.getLayoutConstraint();
+ if (constraint instanceof Bounds) {
+ Bounds bounds = (Bounds) constraint;
+ Double newX = (relativeX * bounds.getWidth()) + bounds.getX();
+ Double newY = (relativeY * bounds.getHeight()) + bounds.getY();
+
+ return new PrecisionPoint(newX, newY);
+ }
+ return null;
+
+ }
+
+ public static EditPart calculateTargetEditPart(PapyrusMultiDiagramEditor papyrus, Double x, Double y) {
+ PrecisionPoint location = new PrecisionPoint(x, y);
+
+ GraphicalViewer currentViewer = getActivePapyrusViewer(papyrus);
+
+ if (currentViewer != null) {
+ GraphicalEditPart diagramPart = (GraphicalEditPart) currentViewer.getContents();
+
+ IFigure targetFigure = diagramPart.getFigure().findFigureAt(location);
+ if (targetFigure != null) {
+ EditPart targetEditPart = (EditPart) currentViewer.getVisualPartMap().get(targetFigure);
+ while (targetEditPart == null && targetFigure.getParent() != null) {
+ targetFigure = targetFigure.getParent();
+ targetEditPart = (EditPart) currentViewer.getVisualPartMap().get(targetFigure);
+ }
+ return targetEditPart;
+
+ }
+
+ }
+ return null;
+
+ }
+
+ public static IElementType getElementType(PapyrusMultiDiagramEditor papyrus, String id) {
+ ModelSet modelSet;
+ try {
+ modelSet = papyrus.getServicesRegistry().getService(ModelSet.class);
+ ArchitectureDescriptionUtils utils = new ArchitectureDescriptionUtils(modelSet);
+ IClientContext currentClientContext = ClientContextManager.getInstance()
+ .getClientContext(utils.getArchitectureContextId());
+
+ return ElementTypeRegistryUtils.getType(currentClientContext, id);
+ } catch (ServiceException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return null;
+
+ }
+
+ public static PapyrusMultiDiagramEditor getActivePapyrusEditor() {
+
+
+ RunnableWithResult<IWorkbenchWindow> runnable = new RunnableWithResult<IWorkbenchWindow>() {
+ @Override
+ public IWorkbenchWindow runWithTry() throws Throwable {
+ IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ return workbenchWindow;
+ }
+ };
+ PlatformUI.getWorkbench().getDisplay().syncExec(runnable);
+ IWorkbenchWindow workbenchWindow =runnable.getResult();
+ IWorkbenchPage page = workbenchWindow.getActivePage();
+ IEditorPart editorPart = page.getActiveEditor();
+ if (editorPart != null && editorPart instanceof PapyrusMultiDiagramEditor) {
+ try {
+ if (!((PapyrusMultiDiagramEditor) editorPart).getServicesRegistry().isStarted(ModelSet.class.getName())){
+ ((PapyrusMultiDiagramEditor) editorPart).getServicesRegistry().startServicesByClassKeys(ModelSet.class);
+
+ }
+ } catch (ServiceMultiException | ServiceNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return (PapyrusMultiDiagramEditor) editorPart;
+ }
+
+
+ return null;
+ }
+
+ public static GraphicalViewer getActivePapyrusViewer(PapyrusMultiDiagramEditor papyrusEditor) {
+
+ IEditorPart currentEditor = papyrusEditor.getActiveEditor();
+ if (currentEditor instanceof GraphicalEditor) {
+ return (GraphicalViewer) ((GraphicalEditor) currentEditor).getAdapter(GraphicalViewer.class);
+ }
+
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/module/RequestUtils.java b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/module/RequestUtils.java
new file mode 100644
index 0000000..e695802
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/module/RequestUtils.java
@@ -0,0 +1,161 @@
+/*****************************************************************************
+ * Copyright (c) 2019 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.ease.module;
+
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.emf.type.core.IElementType;
+import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
+import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest;
+import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest;
+import org.eclipse.papyrus.infra.services.edit.service.ElementEditServiceUtils;
+import org.eclipse.papyrus.infra.services.edit.service.IElementEditService;
+
+/**
+ * @author SR246418
+ *
+ */
+public class RequestUtils {
+
+ /**
+ * @param targetElement
+ * @param eObject
+ * @return
+ */
+ public static Command getSetFeatureCommand(EObject targetElement, Object value, EStructuralFeature featureToSet) {
+ SetRequest req = new SetRequest(targetElement, featureToSet, value);
+ IElementEditService provider = ElementEditServiceUtils.getCommandProvider(targetElement);
+
+ if (provider != null) {
+ ICommand setCommand = provider.getEditCommand(req);
+
+ if (setCommand != null && setCommand.canExecute()) {
+ return new ICommandProxy(setCommand);
+ }
+ }
+ return null;
+ }
+
+ public static void setFeatureWithRequest(EObject objectToModify, Object value, EStructuralFeature featureToSet) {
+ Command setFeatureCommand = getSetFeatureCommand(objectToModify, value, featureToSet);
+ if (setFeatureCommand != null && setFeatureCommand.canExecute()) {
+ setFeatureCommand.execute();
+
+ }
+ }
+
+ public static <T extends EObject> T createElementWithRequest(EObject receiver, IElementType elementTypeToCreate, EReference containmentFeature) {
+ CreateElementRequest createElementRequest;
+ if (containmentFeature == null) {
+ createElementRequest = new CreateElementRequest(receiver, elementTypeToCreate);
+ } else {
+ createElementRequest = new CreateElementRequest(receiver, elementTypeToCreate, containmentFeature);
+ }
+
+ IElementEditService provider = ElementEditServiceUtils.getCommandProvider(receiver);
+ if (provider != null) {
+ ICommand createCommand = provider.getEditCommand(createElementRequest);
+
+ if (createCommand != null && createCommand.canExecute()) {
+ try {
+ createCommand.execute(new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+
+ e.printStackTrace();
+ }
+ CommandResult result = createCommand.getCommandResult();
+ return getCreatedObject(result);
+ }
+
+ }
+ return null;
+ }
+
+ /**
+ * @param targetEditPart
+ * @param targetActivity
+ * @param elementTypeToCreate
+ * @return
+ */
+ public static <T extends EObject> T createElementWithRequest(EObject receiver, IElementType elementTypeToCreate) {
+ return createElementWithRequest(receiver, elementTypeToCreate, null);
+
+ }
+
+ public static <T extends EObject> T getCreatedObject(CommandResult commandResult) {
+ Object objectResult = commandResult.getReturnValue();
+ if (objectResult instanceof List) {
+ // Result of the semantic + graphical creation command
+ List<?> listResult = (List<?>) objectResult;
+ for (Object elementResult : listResult) {
+ if (elementResult instanceof CreateElementRequestAdapter) {
+ CreateElementRequest request = (CreateElementRequest) ((CreateElementRequestAdapter) elementResult).getAdapter(CreateElementRequest.class);
+ if (request != null) {
+ EObject newElement = request.getNewElement();
+ if (newElement instanceof EObject) {
+ return (T) newElement;
+ }
+ }
+ }
+ }
+ } else if (commandResult.getReturnValue() instanceof EObject) {
+ // Result of the semantic creation command
+ return (T) commandResult.getReturnValue();
+ }
+
+ return null;
+ }
+
+ /**
+ * @param pinsToDelete
+ */
+ public static void deleteObjectsWithRequest(List<EObject> objectsDelete) {
+ for (EObject objectToDelete : objectsDelete) {
+ deleteObjectWithRequest(objectToDelete);
+ }
+
+ }
+
+ /**
+ * @param objectToDelete
+ */
+ public static void deleteObjectWithRequest(EObject objectToDelete) {
+ IElementEditService provider = ElementEditServiceUtils.getCommandProvider(objectToDelete);
+ DestroyElementRequest request = new DestroyElementRequest(objectToDelete, true);
+ if (provider != null) {
+ ICommand deleteCommand = provider.getEditCommand(request);
+
+ if (deleteCommand != null && deleteCommand.canExecute()) {
+ try {
+ deleteCommand.execute(new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+
+ e.printStackTrace();
+ }
+ }
+
+ }
+ }
+}
diff --git a/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/module/ViewAndElementHandler.java b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/module/ViewAndElementHandler.java
new file mode 100644
index 0000000..0188082
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/module/ViewAndElementHandler.java
@@ -0,0 +1,51 @@
+/*****************************************************************************
+ * Copyright (c) 2019 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.ease.module;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.View;
+
+public class ViewAndElementHandler {
+
+ private View view;
+ private EObject element;
+ // private GraphicalEditPart editPart;
+
+ public ViewAndElementHandler(View view, EObject element) {
+ this.view= view;
+ this.element= element;
+ }
+
+ public ViewAndElementHandler() {
+
+ }
+
+ public void setView(View view) {
+ this.view = view;
+ }
+
+ public void setElement(EObject element) {
+ this.element = element;
+ }
+
+ public View getView() {
+ return view;
+ }
+ public EObject getElement() {
+ return element;
+ }
+
+
+}
diff --git a/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/popup/PapyrusPopupHandler.java b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/popup/PapyrusPopupHandler.java
new file mode 100644
index 0000000..ea252e7
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/popup/PapyrusPopupHandler.java
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * Copyright (c) 2019 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.ease.popup;
+
+import org.eclipse.ease.ui.scripts.keywordhandler.ScriptContributionFactory;
+
+public class PapyrusPopupHandler extends org.eclipse.ease.ui.scripts.keywordhandler.PopupHandler {
+
+ @Override
+ protected String getHandlerType() {
+ return "papypopup";
+ }
+
+ @Override
+ protected ScriptContributionFactory getContributionFactory(final String location) {
+
+ if (!fContributionFactories.containsKey(location))
+ fContributionFactories.put(location, new PapyrusPopupScriptContributionFactory(location));
+
+ return fContributionFactories.get(location);
+ }
+}
diff --git a/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/popup/PapyrusPopupScriptContributionFactory.java b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/popup/PapyrusPopupScriptContributionFactory.java
new file mode 100644
index 0000000..32e6949
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/popup/PapyrusPopupScriptContributionFactory.java
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ * Copyright (c) 2019 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.ease.popup;
+
+import org.eclipse.ease.ui.scripts.keywordhandler.ScriptContributionFactory;
+import org.eclipse.ease.ui.scripts.repository.IScript;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.ui.menus.IContributionRoot;
+import org.eclipse.ui.services.IServiceLocator;
+
+public class PapyrusPopupScriptContributionFactory extends ScriptContributionFactory {
+
+ public PapyrusPopupScriptContributionFactory(final String location) {
+ super(location);
+
+ }
+
+ @Override
+ public void createContributionItems(final IServiceLocator serviceLocator, final IContributionRoot additions) {
+
+ // if we added contributions manually before, do not add them a 2nd time
+ // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=452203 for details
+ boolean rendered = (fContributionManager instanceof MenuManager) && (((MenuManager) fContributionManager).getMenu() != null);
+ rendered |= (fContributionManager instanceof ToolBarManager) && (((ToolBarManager) fContributionManager).getControl() != null);
+
+ if (rendered) {
+ for (IContributionItem item : fContributionManager.getItems()) {
+ if (item instanceof PapyrusScriptContributionItem) {
+ // contributions already added to toolbar, do not add again
+ return;
+ }
+ }
+ }
+
+ if (getLocation().endsWith(PapyrusPopupHandler.POPUP_LOCATION)) {
+ for (IScript script : sortScripts(fScripts))
+ additions.addContributionItem(new PapyrusScriptContributionItem(script, script.getKeywords().get("papypopup")), null);
+
+ } else {
+ for (IScript script : fScripts)
+ additions.addContributionItem(new PapyrusScriptContributionItem(script), null);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/popup/PapyrusScriptContributionItem.java b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/popup/PapyrusScriptContributionItem.java
new file mode 100644
index 0000000..9653584
--- /dev/null
+++ b/bundles/org.eclipse.papyrus.ease/src/org/eclipse/papyrus/ease/popup/PapyrusScriptContributionItem.java
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ * Copyright (c) 2019 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.ease.popup;
+
+import java.util.regex.Matcher;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.internal.expressions.AdaptExpression;
+import org.eclipse.core.internal.expressions.InstanceofExpression;
+import org.eclipse.core.internal.expressions.IterateExpression;
+import org.eclipse.core.internal.expressions.WithExpression;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ease.ui.scripts.keywordhandler.ScriptContributionItem;
+import org.eclipse.ease.ui.scripts.repository.IScript;
+
+public class PapyrusScriptContributionItem extends ScriptContributionItem {
+
+ public PapyrusScriptContributionItem(final IScript script) {
+ super(script);
+ }
+
+ public PapyrusScriptContributionItem(final IScript script, final String enablement) {
+ this(script);
+
+ Matcher matcher = ENABLE_PATTERN.matcher(enablement);
+ if (matcher.matches()) {
+ try {
+ WithExpression withExpression = new WithExpression("selection");
+ IterateExpression iteratorExpression = new IterateExpression(null, Boolean.FALSE.toString());
+ AdaptExpression adaptExpression = new AdaptExpression("org.eclipse.emf.ecore.EObject");
+ InstanceofExpression instanceofExpression = new InstanceofExpression(matcher.group(1));
+
+ withExpression.add(iteratorExpression);
+ iteratorExpression.add(adaptExpression);
+ adaptExpression.add(instanceofExpression);
+
+ fVisibleExpression = withExpression;
+ } catch (CoreException e) {
+ // TODO provide log message to user
+
+ fVisibleExpression = Expression.FALSE;
+ }
+ }
+ }
+
+}
diff --git a/bundles/pom.xml b/bundles/pom.xml
new file mode 100644
index 0000000..9ed0102
--- /dev/null
+++ b/bundles/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Parent of this POM -->
+ <parent>
+ <version>0.7.0-SNAPSHOT</version>
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.root</artifactId>
+ </parent>
+
+ <!-- EASE project root POM (aggregator) -->
+ <artifactId>org.eclipse.papyrus.ease.bundles.root</artifactId>
+ <name>EASE Bundles</name>
+ <packaging>pom</packaging>
+
+ <!-- Children modules to build -->
+ <modules>
+ <module>org.eclipse.papyrus.ease</module>
+ <module>org.eclipse.papyrus.ease.lang.python.jupyter</module>
+ </modules>
+
+</project>
diff --git a/features/org.eclipse.papyrus.ease.feature/.project b/features/org.eclipse.papyrus.ease.feature/.project
new file mode 100644
index 0000000..8c33a26
--- /dev/null
+++ b/features/org.eclipse.papyrus.ease.feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.ease.feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
diff --git a/features/org.eclipse.papyrus.ease.feature/build.properties b/features/org.eclipse.papyrus.ease.feature/build.properties
new file mode 100644
index 0000000..b3a611b
--- /dev/null
+++ b/features/org.eclipse.papyrus.ease.feature/build.properties
@@ -0,0 +1,2 @@
+bin.includes = feature.xml,\
+ feature.properties
diff --git a/features/org.eclipse.papyrus.ease.feature/feature.properties b/features/org.eclipse.papyrus.ease.feature/feature.properties
new file mode 100644
index 0000000..72a2a2a
--- /dev/null
+++ b/features/org.eclipse.papyrus.ease.feature/feature.properties
@@ -0,0 +1,31 @@
+###############################################################################
+# Copyright (c) 2019 CEA LIST.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+###############################################################################
+
+# "featureName" property - name of the feature
+featureName=EASE (Incubation)
+
+# "providerName" property - name of the company that provides the feature
+providerName=Eclipse Modeling Project
+
+# description property - text of the "Feature Description"
+description=EASE in Papyrus
+################ end of description property ##################################
+
+# "copyright" property - text of the "Feature Update Copyright"
+copyright=\
+Copyright (c) 2019 CEA LIST.\n\
+All rights reserved. This program and the accompanying materials\n\
+are made available under the terms of the Eclipse Public License 2.0\n\
+which accompanies this distribution, and is available at\n\
+https://www.eclipse.org/legal/epl-2.0/\n\
+\n\
+SPDX-License-Identifier: EPL-2.0\n
+################ end of copyright property ####################################
+
diff --git a/features/org.eclipse.papyrus.ease.feature/feature.xml b/features/org.eclipse.papyrus.ease.feature/feature.xml
new file mode 100644
index 0000000..41d6bca
--- /dev/null
+++ b/features/org.eclipse.papyrus.ease.feature/feature.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.eclipse.papyrus.ease.feature"
+ version="0.7.0.qualifier"
+ label="%featureName"
+ provider-name="%providerName"
+ license-feature="org.eclipse.license"
+ license-feature-version="2.0.0">
+
+ <description url="http://www.example.com/description">
+ %description
+ </description>
+
+ <copyright>
+ %copyright
+ </copyright>
+
+ <license url="%licenseURL">
+ %license
+ </license>
+
+ <requires>
+ <import plugin="org.eclipse.core.filesystem"/>
+ <import plugin="org.eclipse.core.expressions" version="3.6.0" match="compatible"/>
+ <import plugin="org.eclipse.core.runtime" version="3.13.0" match="compatible"/>
+ <import plugin="org.eclipse.debug.ui" version="3.12.50" match="compatible"/>
+ <import plugin="org.eclipse.e4.core.services"/>
+ <import plugin="org.eclipse.ease" version="0.7.0" match="compatible"/>
+ <import plugin="org.eclipse.ease.lang.python.py4j" version="0.7.0" match="compatible"/>
+ <import plugin="org.eclipse.ease.ui.scripts" version="0.7.0" match="compatible"/>
+ <import plugin="org.eclipse.osgi.services"/>
+ <import plugin="org.eclipse.papyrus.uml.tools.utils" match="compatible"/>
+ <import plugin="org.eclipse.ui" version="3.109.0" match="compatible"/>
+ <import plugin="org.eclipse.ui.workbench"/>
+ <import plugin="org.eclipse.uml2.uml" version="5.3.0" match="compatible"/>
+ </requires>
+
+
+ <plugin
+ id="org.eclipse.papyrus.ease"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.papyrus.ease.lang.python.jupyter"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
diff --git a/features/org.eclipse.papyrus.ease.feature/pom.xml b/features/org.eclipse.papyrus.ease.feature/pom.xml
new file mode 100644
index 0000000..f3c51ce
--- /dev/null
+++ b/features/org.eclipse.papyrus.ease.feature/pom.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Parent POM (Tools) -->
+ <parent>
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.feature.root</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ </parent>
+
+ <!-- POM description -->
+ <artifactId>org.eclipse.papyrus.ease.feature</artifactId>
+ <packaging>eclipse-feature</packaging>
+ <name>org.eclipse.papyrus.ease.feature</name>
+</project>
diff --git a/features/pom.xml b/features/pom.xml
new file mode 100644
index 0000000..cd380fd
--- /dev/null
+++ b/features/pom.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Parent of this POM -->
+ <parent>
+ <version>0.7.0-SNAPSHOT</version>
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.root</artifactId>
+ </parent>
+
+ <!-- EASE project root POM (aggregator) -->
+ <artifactId>org.eclipse.papyrus.ease.feature.root</artifactId>
+ <name>EASE Features</name>
+ <packaging>pom</packaging>
+
+ <!-- Children modules to build -->
+ <modules>
+ <module>org.eclipse.papyrus.ease.feature</module>
+ </modules>
+
+</project>
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..6914e8e
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Parent of this POM -->
+ <parent>
+ <version>0.7.0-SNAPSHOT</version>
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.releng.configuration</artifactId>
+ <relativePath>./releng/org.eclipse.papyrus.ease.configuration</relativePath>
+ </parent>
+
+ <!-- EASE project root POM (aggregator) -->
+ <artifactId>org.eclipse.papyrus.ease.root</artifactId>
+ <name>EASE</name>
+ <packaging>pom</packaging>
+
+ <!-- Children modules to build -->
+ <modules>
+ <module>bundles</module>
+ <module>features</module>
+ <module>releng</module>
+ </modules>
+
+</project>
diff --git a/releng/org.eclipse.papyrus.ease.configuration/.project b/releng/org.eclipse.papyrus.ease.configuration/.project
new file mode 100644
index 0000000..63e3f62
--- /dev/null
+++ b/releng/org.eclipse.papyrus.ease.configuration/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.ease.configuration</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
diff --git a/releng/org.eclipse.papyrus.ease.configuration/pom.xml b/releng/org.eclipse.papyrus.ease.configuration/pom.xml
new file mode 100644
index 0000000..65f3171
--- /dev/null
+++ b/releng/org.eclipse.papyrus.ease.configuration/pom.xml
@@ -0,0 +1,146 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- EASE depends on generic Papyrus component POM file -->
+ <parent>
+ <groupId>org.eclipse.papyrus.components</groupId>
+ <artifactId>org.eclipse.papyrus.components.parent</artifactId>
+ <version>0.0.26</version>
+ <relativePath></relativePath>
+ </parent>
+
+ <!-- EASE root POM: general information -->
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.releng.configuration</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>EASE</name>
+ <description>Papyrus EASE (Incubation)</description>
+ <inceptionYear>2019</inceptionYear>
+
+ <!-- EASE properties -->
+ <properties>
+ <component.shortname>ease</component.shortname>
+ <component.hudson.tabname>EASE</component.hudson.tabname>
+ <component.fullartifactId>org.eclipse.papyrus.ease</component.fullartifactId>
+ <component.bugzilla.name>EASE</component.bugzilla.name>
+ <component.package.rootname>org.eclipse.papyrus.ease</component.package.rootname>
+ <component.apibaseline.url>http://download.eclipse.org/modeling/mdt/papyrus/components/ease/</component.apibaseline.url>
+ <eclipse.targetrelease>2019-03</eclipse.targetrelease>
+ <target.version>0.7.0-SNAPSHOT</target.version>
+ <jboss.version>1.3.0</jboss.version>
+ </properties>
+
+ <!-- EASE CI system -->
+ <ciManagement>
+ <system>Hudson</system>
+ <url>https://hudson.eclipse.org/papyrus/view/${component.hudson.tabname}/</url>
+ </ciManagement>
+
+ <!-- EASE Bugzilla -->
+ <issueManagement>
+ <url>https://bugs.eclipse.org/bugs/buglist.cgi?product=Papyrus&component=${component.bugzilla.name}</url>
+ </issueManagement>
+
+ <!-- EASE Developpers -->
+ <developers>
+ <developer>
+ <name>Sebastien REVOL</name>
+ <organization>CEA Tech LIST</organization>
+ <organizationUrl>http://www-list.cea.fr/</organizationUrl>
+ <id>srevol</id>
+ </developer>
+ <developer>
+ <name>Arnaud CUCCURU</name>
+ <organization>CEA Tech LIST</organization>
+ <organizationUrl>http://www-list.cea.fr/</organizationUrl>
+ <id>acucurru</id>
+ </developer>
+ <developer>
+ <name>Jeremie TATIBOUET</name>
+ <organization>CEA Tech LIST</organization>
+ <organizationUrl>http://www-list.cea.fr/</organizationUrl>
+ <id>jtatibouet</id>
+ </developer>
+ </developers>
+
+ <!-- EASE Contributors -->
+ <contributors>
+ <contributor>
+ <name>David LOPEZ BETANCUR</name>
+ </contributor>
+ </contributors>
+
+ <scm>
+ <url>http://git.eclipse.org/c/papyrus/org.eclipse.papyrus-ease.git/</url>
+ <connection>scm:git:http://git.eclipse.org/gitroot/papyrus/org.eclipse.papyrus-ease.git</connection>
+ <developerConnection>scm:git:ssh://git.eclipse.org/gitroot/papyrus/org.eclipse.papyrus-ease.git</developerConnection>
+ </scm>
+
+ <distributionManagement>
+ <site>
+ <id>git.eclipse.org.server</id>
+ <url>scm:git:https://git.eclipse.org/gitroot/www.eclipse.org/papyrus/components/${component.shortname}</url>
+ </site>
+ </distributionManagement>
+
+
+ <!-- Location to resolve Papyrus tools -->
+ <repositories>
+ <repository>
+ <id>pap.repo.eclipse.org</id>
+ <name>Papyrus Repository - Releases</name>
+ <url>https://repo.eclipse.org/content/repositories/papyrus-releases/</url>
+ <releases>
+ <enabled>true</enabled>
+ <updatePolicy>daily</updatePolicy>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ <repository>
+ <id>paps.repo.eclipse.org</id>
+ <name>Papyrus Repository - Snapshots</name>
+ <url>https://repo.eclipse.org/content/repositories/papyrus-snapshots/</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ <updatePolicy>daily</updatePolicy>
+ </snapshots>
+ </repository>
+ <repository>
+ <id>license-feature</id>
+ <url>http://download.eclipse.org/cbi/updates/license/</url>
+ <layout>p2</layout>
+ </repository>
+ </repositories>
+
+ <pluginRepositories>
+ <!-- Location to find out maven plugins -->
+ <pluginRepository>
+ <id>org.eclipse.cbi.maven.plugins</id>
+ <name>Eclipse CBI</name>
+ <url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </pluginRepository>
+ <pluginRepository>
+ <id>jboss-public-repository-group</id>
+ <name>JBoss Public Repository Group</name>
+ <url>http://repository.jboss.org/nexus/content/groups/public/</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+</project>
diff --git a/releng/org.eclipse.papyrus.ease.p2/.project b/releng/org.eclipse.papyrus.ease.p2/.project
new file mode 100644
index 0000000..dd98585
--- /dev/null
+++ b/releng/org.eclipse.papyrus.ease.p2/.project
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.moka.incubation.p2</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.UpdateSiteBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.pde.UpdateSiteNature</nature>
+ </natures>
+</projectDescription>
diff --git a/releng/org.eclipse.papyrus.ease.p2/category.xml b/releng/org.eclipse.papyrus.ease.p2/category.xml
new file mode 100644
index 0000000..99d65a3
--- /dev/null
+++ b/releng/org.eclipse.papyrus.ease.p2/category.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+ <feature url="org.eclipse.papyrus.ease.feature_0.7.0.qualifier.jar" id="org.eclipse.papyrus.ease.feature" version="0.7.0.qualifier">
+ <category name="org.eclipse.papyrus.ease"/>
+ </feature>
+ <category-def name="org.eclipse.papyrus.ease" label="Papyrus EASE (Incubation)">
+ <description>
+ Papyrus EASE Tools
+ </description>
+ </category-def>
+</site>
diff --git a/releng/org.eclipse.papyrus.ease.p2/pom.xml b/releng/org.eclipse.papyrus.ease.p2/pom.xml
new file mode 100644
index 0000000..b5e2491
--- /dev/null
+++ b/releng/org.eclipse.papyrus.ease.p2/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Parent POM (i.e., the one owned by the releng folder) -->
+ <parent>
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.releng.root</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ </parent>
+
+ <!-- POM description -->
+ <artifactId>org.eclipse.papyrus.ease.releng.p2</artifactId>
+ <name>Papyrus EASE update site</name>
+ <packaging>eclipse-repository</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <!-- https://github.com/jbosstools/jbosstools-maven-plugins/wiki -->
+ <groupId>org.jboss.tools.tycho-plugins</groupId>
+ <artifactId>repository-utils</artifactId>
+ <version>${jboss.version}</version>
+ <executions>
+ <execution>
+ <id>generate-facade</id>
+ <phase>package</phase>
+ <goals>
+ <goal>generate-repository-facade</goal>
+ </goals>
+ <configuration>
+ <!-- do not generate the pesky web folder and index.html -->
+ <skipWebContentGeneration>true</skipWebContentGeneration>
+ <associateSites>
+ <!-- Py4j Update site -->
+ <site>http://eclipse.py4j.org/</site>
+ <site>http://download.eclipse.org/ease/update/nightly</site>
+ </associateSites>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/releng/platforms/.project b/releng/platforms/.project
new file mode 100644
index 0000000..ba301ba
--- /dev/null
+++ b/releng/platforms/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>targetplatform</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
diff --git a/releng/platforms/org.eclipse.papyrus.ease.targetplatform.2019-03.target b/releng/platforms/org.eclipse.papyrus.ease.targetplatform.2019-03.target
new file mode 100644
index 0000000..53bde0d
--- /dev/null
+++ b/releng/platforms/org.eclipse.papyrus.ease.targetplatform.2019-03.target
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde?>
+<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
+<target name="Papyrus" sequenceNumber="1538126051">
+ <locations>
+ <location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
+ <unit id="org.eclipse.equinox.executable.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.equinox.p2.discovery.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.jdt.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.ocl.uml.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.papyrus.sdk.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.papyrus.views.properties.model.xwt" version="0.0.0"/>
+ <unit id="org.eclipse.platform.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.rcp.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.xtend.sdk.feature.group" version="0.0.0"/>
+ <repository id="eclipse-oxygen" location="http://download.eclipse.org/releases/2019-03/"/>
+ </location>
+ <location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
+ <unit id="org.eclipse.ease.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.ease.lang.javascript.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.ease.lang.python.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.ease.lang.python.py4j.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.ease.lang.unittest.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.ease.modules.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.ease.modules.modeling.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.ease.ui.feature.feature.group" version="0.0.0"/>
+ <repository id="ease" location="http://download.eclipse.org/ease/update/nightly"/>
+ </location>
+ <location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
+ <unit id="org.py4j.feature.feature.group" version="0.0.0"/>
+ <repository id="py4j" location="http://eclipse.py4j.org/"/>
+ </location>
+ </locations>
+</target>
diff --git a/releng/platforms/org.eclipse.papyrus.ease.targetplatform.2019-03.tpd b/releng/platforms/org.eclipse.papyrus.ease.targetplatform.2019-03.tpd
new file mode 100644
index 0000000..5fc2164
--- /dev/null
+++ b/releng/platforms/org.eclipse.papyrus.ease.targetplatform.2019-03.tpd
@@ -0,0 +1,28 @@
+target "Papyrus" with source requirements
+
+location "http://download.eclipse.org/releases/2019-03/" eclipse-oxygen {
+ org.eclipse.equinox.executable.feature.group lazy
+ org.eclipse.equinox.p2.discovery.feature.feature.group lazy
+ org.eclipse.jdt.feature.group lazy
+ org.eclipse.ocl.uml.feature.group lazy
+ org.eclipse.papyrus.sdk.feature.feature.group lazy
+ org.eclipse.papyrus.views.properties.model.xwt lazy
+ org.eclipse.platform.feature.group lazy
+ org.eclipse.rcp.feature.group lazy
+ org.eclipse.xtend.sdk.feature.group lazy
+}
+
+location "http://download.eclipse.org/ease/update/nightly" ease {
+ org.eclipse.ease.feature.feature.group lazy
+ org.eclipse.ease.lang.javascript.feature.feature.group lazy
+ org.eclipse.ease.lang.python.feature.feature.group lazy
+ org.eclipse.ease.lang.python.py4j.feature.feature.group lazy
+ org.eclipse.ease.lang.unittest.feature.feature.group lazy
+ org.eclipse.ease.modules.feature.feature.group lazy
+ org.eclipse.ease.modules.modeling.feature.feature.group lazy
+ org.eclipse.ease.ui.feature.feature.group lazy
+}
+
+location "http://eclipse.py4j.org/" py4j {
+ org.py4j.feature.feature.group lazy
+}
diff --git a/releng/platforms/pom.xml b/releng/platforms/pom.xml
new file mode 100644
index 0000000..b7116b7
--- /dev/null
+++ b/releng/platforms/pom.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.releng.root</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.eclipse.papyrus.ease.targetplatform.2019-03</artifactId>
+ <packaging>eclipse-target-definition</packaging>
+ <name>org.eclipse.papyrus.ease.targetplatform.2019-03</name>
+
+ <groupId>org.eclipse.papyrus.ease</groupId>
+</project>
diff --git a/releng/pom.xml b/releng/pom.xml
new file mode 100644
index 0000000..f366164
--- /dev/null
+++ b/releng/pom.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Parent of this POM -->
+ <parent>
+ <version>0.7.0-SNAPSHOT</version>
+ <groupId>org.eclipse.papyrus.ease</groupId>
+ <artifactId>org.eclipse.papyrus.ease.root</artifactId>
+ </parent>
+
+ <!-- EASE project root POM (aggregator) -->
+ <artifactId>org.eclipse.papyrus.ease.releng.root</artifactId>
+ <name>EASE Releng</name>
+ <packaging>pom</packaging>
+
+ <!-- Children modules to build -->
+ <modules>
+ <module>org.eclipse.papyrus.ease.configuration</module>
+ <module>org.eclipse.papyrus.ease.p2</module>
+ <module>platforms</module>
+ </modules>
+
+</project>