2012-11-26 40 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这个要求就足够了,其他人应该可以把这个技巧扩展到一般情况。

相关问题