Bug 534634: [Python] support import statements for EASE modules

  fixed globals to allow modules to access java classes

Change-Id: I22e744a2bcf22edc4340899c0e6070f7ac5cdcc0
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/plugin.xml b/plugins/org.eclipse.ease.lang.python.jython.debugger/plugin.xml
index 1fba5f4..d924aa3 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/plugin.xml
+++ b/plugins/org.eclipse.ease.lang.python.jython.debugger/plugin.xml
@@ -21,9 +21,5 @@
             class="org.eclipse.ease.lang.python.jython.PythonEnvironementBootStrapper"
             engineID="org.eclipse.ease.python.jythonDebugger">
       </launchExtension>
-      <launchExtension
-            class="org.eclipse.ease.lang.python.Pep302ModuleImporter"
-            engineID="org.eclipse.ease.python.jythonDebugger">
-      </launchExtension>
    </extension>
 </plugin>
diff --git a/plugins/org.eclipse.ease.lang.python.jython/plugin.xml b/plugins/org.eclipse.ease.lang.python.jython/plugin.xml
index 0dd32f9..1454f92 100644
--- a/plugins/org.eclipse.ease.lang.python.jython/plugin.xml
+++ b/plugins/org.eclipse.ease.lang.python.jython/plugin.xml
@@ -16,10 +16,6 @@
             class="org.eclipse.ease.lang.python.jython.PythonEnvironementBootStrapper"

             engineID="org.eclipse.ease.python.jython">

       </launchExtension>

-            <launchExtension

-                  class="org.eclipse.ease.lang.python.Pep302ModuleImporter"

-                  engineID="org.eclipse.ease.python.jython">

-            </launchExtension>

    </extension>

  <extension

        point="org.eclipse.ui.preferencePages">

diff --git a/plugins/org.eclipse.ease.lang.python.jython/src/org/eclipse/ease/lang/python/jython/JythonScriptEngine.java b/plugins/org.eclipse.ease.lang.python.jython/src/org/eclipse/ease/lang/python/jython/JythonScriptEngine.java
index 88213c7..d99f20a 100644
--- a/plugins/org.eclipse.ease.lang.python.jython/src/org/eclipse/ease/lang/python/jython/JythonScriptEngine.java
+++ b/plugins/org.eclipse.ease.lang.python.jython/src/org/eclipse/ease/lang/python/jython/JythonScriptEngine.java
@@ -55,6 +55,8 @@
 
 public class JythonScriptEngine extends AbstractReplScriptEngine {
 
+	public static final String ENGINE_ID = "org.eclipse.ease.python.jython";
+
 	protected InteractiveInterpreter mEngine;
 
 	private PyObject mResult;
diff --git a/plugins/org.eclipse.ease.lang.python.py4j/pysrc/ease_py4j_main.py b/plugins/org.eclipse.ease.lang.python.py4j/pysrc/ease_py4j_main.py
index b909393..3aae1b2 100644
--- a/plugins/org.eclipse.ease.lang.python.py4j/pysrc/ease_py4j_main.py
+++ b/plugins/org.eclipse.ease.lang.python.py4j/pysrc/ease_py4j_main.py
@@ -41,6 +41,13 @@
         integer_types = (int,)
         string_types = (str,)
 
+# builtins used to set global variables
+try:
+    # Python 3.*
+    import builtins
+except ImportError:
+    # Python 2.*
+    builtins = __builtins__
 
 # To ease some debugging of the py4j engine itself it is useful to turn logging on,
 # uncomment the following lines for one way to do that
@@ -228,11 +235,19 @@
         # so that code like "java.lang.String()" can work.
         # for other names, jvm.<package name> should be used
         self.locals['java'] = gateway.jvm.java
+        builtins.__dict__['java'] = gateway.jvm.java
+
         self.locals['javax'] = gateway.jvm.javax
+        builtins.__dict__['javax'] = gateway.jvm.javax  # @IndentOk
         self.locals['org'] = gateway.jvm.org
+        builtins.__dict__['org'] = gateway.jvm.org
         self.locals['com'] = gateway.jvm.com
+        builtins.__dict__['com'] = gateway.jvm.com
         self.locals['net'] = gateway.jvm.net
+        builtins.__dict__['net'] = gateway.jvm.net
         self.locals['jvm'] = gateway.jvm
+        builtins.__dict__['jvm'] = gateway.jvm.jvm
+
         self.locals['gateway'] = gateway
         self.locals['py4j'] = py4j
         sys.displayhook = self.displayhook
@@ -293,7 +308,7 @@
 
     def internalSetVariable(self, name, content):
         self.locals[name] = content
-        __builtins__.__dict__[name] = content 
+        builtins.__dict__.update({name: content}) 
 
     def teardownEngine(self):
         self.shutdown_event.set()
diff --git a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCodeFactory.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCodeFactory.java
index ddf61c9..990b59f 100644
--- a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCodeFactory.java
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCodeFactory.java
@@ -296,17 +296,15 @@
 	/**
 	 * Create wrapper code for Pep302 import statements.
 	 *
+	 * @param environment
+	 *            script environment instance
 	 * @param instance
 	 *            instance to wrap
 	 * @param identifier
-	 * @param instance2
+	 *            instance identifier to be used
 	 * @return wrapper code to be loaded by python
 	 */
 	public String createPep302WrapperCode(EnvironmentModule environment, Object instance, String identifier) {
-
-		String code = "import __main__\n" + createWrapper(environment, instance, "__main__." + identifier, false, environment.getScriptEngine());
-		code = code.replaceAll(EnvironmentModule.getWrappedVariableName(environment), "__main__." + EnvironmentModule.getWrappedVariableName(environment));
-
-		return code;
+		return createWrapper(environment, instance, identifier, false, environment.getScriptEngine());
 	}
 }
diff --git a/tests/org.eclipse.ease.lang.python.py4j.test/src/org/eclipse/ease/lang/python/py4j/Py4JPep302ModuleLoadingTest.java b/tests/org.eclipse.ease.lang.python.py4j.test/src/org/eclipse/ease/lang/python/py4j/Py4JPep302ModuleLoadingTest.java
new file mode 100644
index 0000000..574ba22
--- /dev/null
+++ b/tests/org.eclipse.ease.lang.python.py4j.test/src/org/eclipse/ease/lang/python/py4j/Py4JPep302ModuleLoadingTest.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.lang.python.py4j;
+
+import org.eclipse.ease.IReplEngine;
+import org.eclipse.ease.lang.python.py4j.internal.Py4jScriptEngine;
+import org.eclipse.ease.service.EngineDescription;
+import org.eclipse.ease.service.IScriptService;
+import org.eclipse.ease.service.ScriptService;
+import org.eclipse.ease.testhelper.python.AbstractPep302ModuleLoadingTest;
+
+public class Py4JPep302ModuleLoadingTest extends AbstractPep302ModuleLoadingTest {
+
+	protected IReplEngine createEngine() {
+		final IScriptService scriptService = ScriptService.getService();
+		final EngineDescription description = scriptService.getEngineByID(Py4jScriptEngine.ENGINE_ID);
+		return (IReplEngine) description.createEngine();
+	}
+}
diff --git a/tests/org.eclipse.ease.testhelper/META-INF/MANIFEST.MF b/tests/org.eclipse.ease.testhelper/META-INF/MANIFEST.MF
index 833fb5d..ed93c8b 100644
--- a/tests/org.eclipse.ease.testhelper/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.ease.testhelper/META-INF/MANIFEST.MF
@@ -10,4 +10,5 @@
  org.eclipse.debug.core,
  org.eclipse.ease.ui,
  org.eclipse.ui.ide
-Export-Package: org.eclipse.ease.testhelper
+Export-Package: org.eclipse.ease.testhelper,
+ org.eclipse.ease.testhelper.python
diff --git a/tests/org.eclipse.ease.testhelper/plugin.xml b/tests/org.eclipse.ease.testhelper/plugin.xml
index 5730fd0..d5cfa2b 100644
--- a/tests/org.eclipse.ease.testhelper/plugin.xml
+++ b/tests/org.eclipse.ease.testhelper/plugin.xml
@@ -17,7 +17,7 @@
       <module
             category="org.eclipse.ease.testhelper.category"
             class="org.eclipse.ease.testhelper.AdvancedModule"
-            id="org.eclipse.ease.testhelper.basicModule"
+            id="org.eclipse.ease.testhelper.advancedModule"
             name="Advanced"
             visible="true">
          <dependency
diff --git a/tests/org.eclipse.ease.testhelper/src/org/eclipse/ease/testhelper/python/AbstractPep302ModuleLoadingTest.java b/tests/org.eclipse.ease.testhelper/src/org/eclipse/ease/testhelper/python/AbstractPep302ModuleLoadingTest.java
new file mode 100644
index 0000000..f5bbb7e
--- /dev/null
+++ b/tests/org.eclipse.ease.testhelper/src/org/eclipse/ease/testhelper/python/AbstractPep302ModuleLoadingTest.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.testhelper.python;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.ease.IReplEngine;
+import org.eclipse.ease.ScriptResult;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public abstract class AbstractPep302ModuleLoadingTest {
+
+	private IReplEngine fEngine;
+
+	abstract protected IReplEngine createEngine();
+
+	@Before
+	public void setup() {
+		fEngine = createEngine();
+		fEngine.setTerminateOnIdle(false);
+	}
+
+	@After
+	public void teardown() {
+		fEngine.terminate();
+	}
+
+	@Test
+	public void loadSimpleModule() throws InterruptedException {
+		final ScriptResult result = fEngine.executeSync("import eclipse.test.basic");
+
+		// make sure the import does not throw
+		assertFalse(result.hasException());
+	}
+
+	@Test
+	public void loadModuleWithDependencies() throws InterruptedException {
+		final ScriptResult result = fEngine.executeSync("import eclipse.test.advanced");
+
+		// make sure the import does not throw
+		assertFalse(result.hasException());
+	}
+
+	@Test
+	public void loadNotExistingModule() throws InterruptedException {
+		final ScriptResult result = fEngine.executeSync("import eclipse.test.notthere");
+
+		assertTrue(result.hasException());
+	}
+
+	@Test
+	public void accessModule() throws InterruptedException {
+		fEngine.executeSync("import eclipse.test.basic");
+		final ScriptResult result = fEngine.executeSync("eclipse.test.basic.add(2, 4)");
+
+		assertFalse(result.hasException());
+		assertEquals(6, result.getResult());
+	}
+
+	@Test
+	public void accessAdvancedModule() throws InterruptedException {
+		fEngine.executeSync("import eclipse.test.advanced");
+		final ScriptResult result = fEngine.executeSync("eclipse.test.advanced.area(2, 4)");
+
+		assertFalse(result.hasException());
+		assertEquals(8, result.getResult());
+	}
+
+	@Test
+	public void importAs() throws InterruptedException {
+		fEngine.executeSync("import eclipse.test.basic as basic");
+		final ScriptResult result = fEngine.executeSync("basic.add(2, 4)");
+
+		assertFalse(result.hasException());
+		assertEquals(6, result.getResult());
+	}
+
+	@Test
+	public void fromBasicImportAll() throws InterruptedException {
+		fEngine.executeSync("from eclipse.test.basic import *");
+		final ScriptResult result = fEngine.executeSync("add(2, 4)");
+
+		assertFalse(result.hasException());
+		assertEquals(6, result.getResult());
+	}
+
+	@Test
+	public void fromBasicImportMethod() throws InterruptedException {
+		fEngine.executeSync("from eclipse.test.basic import add");
+		final ScriptResult result = fEngine.executeSync("add(2, 4)");
+
+		assertFalse(result.hasException());
+		assertEquals(6, result.getResult());
+	}
+}