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(&lt;classe name&gt;)"
+            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&amp;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>