r9657 - in helma-ng/trunk: modules src/org/helma/javascript

[email protected] Wed, 22 Apr 2009 15:10:09 +0200 (CEST)
Newsgroups gmane.comp.java.helma.cvs
Message-ID <20090422131009.C891F3D0D6@mia>
Author: hannes
Date: 2009-04-22 15:10:09 +0200 (Wed, 22 Apr 2009)
New Revision: 9657

Modified:
   helma-ng/trunk/modules/helmaglobal.js
   helma-ng/trunk/src/org/helma/javascript/ModuleScope.java
   helma-ng/trunk/src/org/helma/javascript/ReloadableScript.java
   helma-ng/trunk/src/org/helma/javascript/RhinoEngine.java
Log:
Implement __exports__ support in Java instead of JavaScript. Add serialization proxy for exports object.

Details at http://dev.helma.org/trac/helma/changeset/9657

Modified: helma-ng/trunk/modules/helmaglobal.js
===================================================================
--- helma-ng/trunk/modules/helmaglobal.js	2009-04-22 13:10:07 UTC (rev 9656)
+++ helma-ng/trunk/modules/helmaglobal.js	2009-04-22 13:10:09 UTC (rev 9657)
@@ -19,17 +19,6 @@
                 exports = {};
                 Object.defineProperty(module, "exports", { value: exports });
             }
-            // the __exports__ array is an alternative way for a module to export properties.
-            // it contains a list of property names that will be copied to the exports object.
-            if (module.__exports__) {
-                for each (var key in module.__exports__) {
-                    // print("Exporting", moduleName, key, "->", typeof(module[key]));
-                    Object.defineProperty(exports, key, {
-                        value: module[key],
-                        enumerable: true
-                    });
-                }
-            }
             return exports; 
         }
     });

Modified: helma-ng/trunk/src/org/helma/javascript/ModuleScope.java
===================================================================
--- helma-ng/trunk/src/org/helma/javascript/ModuleScope.java	2009-04-22 13:10:07 UTC (rev 9656)
+++ helma-ng/trunk/src/org/helma/javascript/ModuleScope.java	2009-04-22 13:10:09 UTC (rev 9657)
@@ -18,10 +18,7 @@
 
 import org.helma.repository.Repository;
 import org.helma.repository.Trackable;
-import org.mozilla.javascript.Context;
-import org.mozilla.javascript.NativeObject;
-import org.mozilla.javascript.Scriptable;
-import org.mozilla.javascript.NativeArray;
+import org.mozilla.javascript.*;
 
 /**
  * A scriptable object that keeps track of the resource it has been loaded from
@@ -43,7 +40,7 @@
         this.repository = source instanceof Repository ?
                 (Repository) source : source.getParentRepository();
         this.name = moduleName;
-        this.exports = cx.newObject(this);
+        this.exports = new ExportsObject();
         defineProperty("exports", exports,  DONTENUM);
         defineProperty("__exports__", cx.newArray(this, 0), DONTENUM);
         defineProperty("__name__", moduleName, DONTENUM);
@@ -55,7 +52,7 @@
     }
 
     public void reset(Context cx) {
-        this.exports = cx.newObject(this);
+        this.exports = new ExportsObject();
         defineProperty("exports", exports,  DONTENUM);
         delete("__shared__");     
         defineProperty("__exports__", cx.newArray(this, 0), DONTENUM);
@@ -69,7 +66,7 @@
         this.checksum = checksum;
     }
 
-    public String getName() {
+    public String getModuleName() {
         return name;
     }
 
@@ -77,6 +74,26 @@
         return exports;
     }
 
+    protected void processExports() {
+        // the __exports__ array is an alternative way for a module to export properties.
+        // it contains a list of property names that will be copied to the exports object.
+        Object e = get("__exports__", this);
+        if (e instanceof NativeArray) {
+            NativeArray array = (NativeArray) e;
+            long length = array.getLength();
+            int flags = READONLY | PERMANENT;
+            for (int i = 0; i < length; i++) {
+                // print("Exporting", moduleName, key, "->", typeof(module[key]));
+                Object key = array.get(i, array);
+                if (key instanceof String) {
+                    Object value = get((String) key, this);
+                    ScriptableObject.defineProperty(exports, (String) key, value, flags);
+                }
+            }
+        }
+
+    }
+
     @Override
     public String toString() {
         return "[ModuleScope " + source + "]";
@@ -89,4 +106,15 @@
         }
         return super.getDefaultValue(hint);
     }
+
+    class ExportsObject extends NativeObject {
+        ExportsObject() {
+            setParentScope(ModuleScope.this);
+            setPrototype(getObjectPrototype(ModuleScope.this));
+        }
+
+        public String getModuleName() {
+            return name;
+        }
+    }
 }

Modified: helma-ng/trunk/src/org/helma/javascript/ReloadableScript.java
===================================================================
--- helma-ng/trunk/src/org/helma/javascript/ReloadableScript.java	2009-04-22 13:10:07 UTC (rev 9656)
+++ helma-ng/trunk/src/org/helma/javascript/ReloadableScript.java	2009-04-22 13:10:09 UTC (rev 9657)
@@ -187,11 +187,11 @@
      * @throws JavaScriptException if an error occurred evaluating the script file
      * @throws IOException if an error occurred reading the script file
      */
-    protected synchronized Scriptable load(Scriptable prototype, Context cx)
+    protected synchronized ModuleScope load(Scriptable prototype, Context cx)
             throws JavaScriptException, IOException {
         // check if we already came across the module in the current context/request
-        Map<Trackable,Scriptable> modules =
-                (Map<Trackable,Scriptable>) cx.getThreadLocal("modules");
+        Map<Trackable,ModuleScope> modules =
+                (Map<Trackable,ModuleScope>) cx.getThreadLocal("modules");
         if (modules.containsKey(source)) {
             return modules.get(source);
         }
@@ -209,6 +209,7 @@
         }
         modules.put(source, module);
         script.exec(cx, module);
+        module.processExports();
         checkShared(module);
         module.setChecksum(getChecksum());
         return module;

Modified: helma-ng/trunk/src/org/helma/javascript/RhinoEngine.java
===================================================================
--- helma-ng/trunk/src/org/helma/javascript/RhinoEngine.java	2009-04-22 13:10:07 UTC (rev 9656)
+++ helma-ng/trunk/src/org/helma/javascript/RhinoEngine.java	2009-04-22 13:10:09 UTC (rev 9657)
@@ -415,11 +415,11 @@
      * @return the loaded module scope
      * @throws IOException indicates that in input/output related error occurred
      */
-    public Scriptable loadModule(Context cx, String moduleName, Scriptable loadingScope)
+    public ModuleScope loadModule(Context cx, String moduleName, Scriptable loadingScope)
             throws IOException {
         Repository local = getParentRepository(loadingScope);
         ReloadableScript script = getScript(moduleName, local);
-        Scriptable module;
+        ModuleScope module;
         ReloadableScript parent = getCurrentScript(cx);
         try {
             setCurrentScript(cx, script);
@@ -587,8 +587,8 @@
                 protected Object replaceObject(Object obj) throws IOException {
                     if (obj == topLevelScope) {
                         return new SerializedScopeProxy(null);
-                    } else if (obj instanceof ModuleScope) {
-                        return new SerializedScopeProxy(((ModuleScope) obj).getName());
+                    } else if (obj instanceof ModuleScope || obj instanceof ModuleScope.ExportsObject) {
+                        return new SerializedScopeProxy(obj);
                     }
                     return super.replaceObject(obj);
                 }
@@ -629,11 +629,21 @@
 
     private static class SerializedScopeProxy implements Serializable {
         String moduleName;
-        SerializedScopeProxy(String moduleName) {
-            this.moduleName = moduleName;
+        boolean isExports;
+        SerializedScopeProxy(Object obj) {
+            if (obj instanceof ModuleScope) {
+                moduleName = ((ModuleScope) obj).getModuleName();
+                isExports = false;
+            } else if (obj instanceof ModuleScope.ExportsObject) {
+                moduleName = ((ModuleScope.ExportsObject) obj).getModuleName();
+                isExports = true;
+            }
         }
 
         Object getObject(Context cx, RhinoEngine engine) throws IOException {
+            if (isExports) {
+                return engine.loadModule(cx, moduleName, null).getExports();
+            }
             return moduleName == null ? engine.topLevelScope : engine.loadModule(cx, moduleName, null);
         }
     }