2012-11-26 85 views
1

好吧,所以r.js可以運行在Rhino。這很棒。如何爲r.js提供僞文件系統?

做它需要做的事情。

在犀牛上,它基本上使用java.io.File,java.io.FileOutputStreamjava.io.FileInputStream來實現它需要做的文件系統修改。 (背景:我正致力於爲基於Maven的Java/Javascript開發人員提供更好的開發經驗,作爲Maven,有約定的力量和有見地的權力,你可以在jszip.org看到進展。)

所以我想要做的就是將磁盤上的結構作爲虛擬文件系統顯示爲魔術。

所以在磁盤上,我們將有一個結構,像這樣:

/ 
/module1/src/main/js/controllers/controller.js 
/module2/src/main/js/models/model.js 
/module3/src/main/js/views/view.js 
/webapp/src/build/js/profile.js 
/webapp/src/main/js/main.js 
/webapp/src/main/webapp/index.html 

/webapp/src/build/js/profile.js應該是這個樣子:

({ 
    appDir: "src", 
    baseUrl:".", 
    dir: "target", 
    optimize: "closure", 
    modules:[ 
     { 
      name:"main" 
     } 
    ] 
}) 

這樣

  • 時r.js要求new File("src/main.js")我實際上會給它new File("/webapp/src/main/js/main.js")

  • 時,它要求new File("profile.js")我會給它new File("/webapp/src/build/js/profile.js")

  • 時,它要求new File("controllers/controller.js")我會給它new File("/module1/src/main/js/controllers/controller.js")

  • 時,它要求new File("target")我會給它new File("/webapp/target/webapp-1.0-SNAPSHOT")

我有沒有問題寫所需的三個模擬類,即那些在地方java.io.Filejava.io.FileInputStreamjava.io.FileOutputStream使用,

一些問題,比如this有指向之類的東西ClassShutter答案,我可以看到我可以像這樣使用:

 context.setClassShutter(new ClassShutter() { 
      public boolean visibleToScripts(String fullClassName) { 
       if (File.class.getName().equals(fullClassName)) return false; 
       if (FileOutputStream.class.getName().equals(fullClassName)) return false; 
       if (FileInputStream.class.getName().equals(fullClassName)) return false; 
       return true; 
      } 
     }); 

隱藏原始實現。

這個問題就越來越犀牛解決沙盒等價的...我不斷獲取

TypeError: [JavaPackage java.io.File] is not a function, it is object. 

即使我前綴的java.io.File = org.jszip.rhino.SandboxFile地圖我在現在缺java.io.File沙盒實現將優先執行呼叫

我甚至可以考慮在編譯之前使用搜索並替換已加載的r.js文件......但我覺得必須有更好的方法。

有沒有人有任何提示?

回答

2

好,多次試驗後,這似乎是這樣做的方法:

Scriptable scope = context.newObject(global); 
scope.setPrototype(global); 
scope.setParentScope(null); 

NativeJavaTopPackage $packages = (NativeJavaTopPackage) global.get("Packages"); 
NativeJavaPackage $java = (NativeJavaPackage) $packages.get("java"); 
NativeJavaPackage $java_io = (NativeJavaPackage) $java.get("io"); 

ProxyNativeJavaPackage proxy$java = new ProxyNativeJavaPackage($java); 
ProxyNativeJavaPackage proxy$java_io = new ProxyNativeJavaPackage($java_io); 
proxy$java_io.put("File", scope, get(scope, "Packages." + PseudoFile.class.getName())); 
proxy$java_io.put("FileInputStream", scope, 
     get(scope, "Packages." + PseudoFileInputStream.class.getName())); 
proxy$java_io.put("FileOutputStream", scope, 
     get(scope, "Packages." + PseudoFileOutputStream.class.getName())); 
proxy$java.put("io", scope, proxy$java_io); 
scope.put("java", scope, proxy$java); 

有一個輔助方法:

private static Object get(Scriptable scope, String name) { 
    Scriptable cur = scope; 
    for (String part : StringUtils.split(name, ".")) { 
     Object next = cur.get(part, scope); 
     if (next instanceof Scriptable) { 
      cur = (Scriptable) next; 
     } else { 
      return null; 
     } 
    } 
    return cur; 
} 

在哪裏ProxyNativeJavaPackage是一樣的東西

public class ProxyNativeJavaPackage extends ScriptableObject implements Serializable { 
    static final long serialVersionUID = 1L; 

    protected final NativeJavaPackage delegate; 
    private final Map<String, Object> mutations = new HashMap<String, Object>(); 

    public ProxyNativeJavaPackage(NativeJavaPackage delegate) { 
     delegate.getClass(); 
     this.delegate = delegate; 
    } 

    @Override 
    public String getClassName() { 
     return delegate.getClassName(); 
    } 

    @Override 
    public boolean has(String id, Scriptable start) { 
     return mutations.containsKey(id) ? mutations.get(id) != null : delegate.has(id, start); 
    } 

    @Override 
    public boolean has(int index, Scriptable start) { 
     return delegate.has(index, start); 
    } 

    @Override 
    public void put(String id, Scriptable start, Object value) { 
     mutations.put(id, value); 
    } 

    @Override 
    public void put(int index, Scriptable start, Object value) { 
     delegate.put(index, start, value); 
    } 

    @Override 
    public Object get(String id, Scriptable start) { 
     if (mutations.containsKey(id)) { 
      return mutations.get(id); 
     } 
     return delegate.get(id, start); 
    } 

    @Override 
    public Object get(int index, Scriptable start) { 
     return delegate.get(index, start); 
    } 

    @Override 
    public Object getDefaultValue(Class<?> ignored) { 
     return toString(); 
    } 

    @Override 
    public String toString() { 
     return delegate.toString(); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof ProxyNativeJavaPackage) { 
      ProxyNativeJavaPackage that = (ProxyNativeJavaPackage) obj; 
      return delegate.equals(that.delegate) && mutations.equals(that.mutations); 
     } 
     return false; 
    } 

    @Override 
    public int hashCode() { 
     return delegate.hashCode(); 
    } 
} 

這仍然保留在Packages.java.io.File等原始類,但爲r.js這個要求就足夠了,其他人應該可以把這個技巧擴展到一般情況。

相關問題