Flexible composition of classpath. One can either specify a URL or a load function emul
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 12 Feb 2013 23:30:01 +0100
branchemul
changeset 7291ee59fe94653
parent 715 7572022945a0
child 738 68e321728e22
Flexible composition of classpath. One can either specify a URL or a load function
javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml
vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java
vm/src/main/java/org/apidesign/vm4brwsr/VM.java
vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java
vm/src/main/java/org/apidesign/vm4brwsr/Zips.java
vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java
     1.1 --- a/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml	Tue Feb 12 16:46:13 2013 +0100
     1.2 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml	Tue Feb 12 23:30:01 2013 +0100
     1.3 @@ -79,9 +79,7 @@
     1.4          <div data-bind="text: displayPreview"></div>
     1.5          <script src="bck2brwsr.js"/>
     1.6          <script>
     1.7 -            var vm = bck2brwsr(
     1.8 -                [ 'demo.static.calculator-0.3-SNAPSHOT.jar' ]
     1.9 -            );
    1.10 +            var vm = bck2brwsr('demo.static.calculator-0.3-SNAPSHOT.jar');
    1.11          </script>
    1.12      </body>
    1.13  </html>
     2.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Tue Feb 12 16:46:13 2013 +0100
     2.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Tue Feb 12 23:30:01 2013 +0100
     2.3 @@ -40,6 +40,16 @@
     2.4   * In this scenario, when a request for an unknown class is made, the loader
     2.5   * function is asked for its byte code and the system dynamically transforms
     2.6   * it to JavaScript.
     2.7 + * <p>
     2.8 + * Instead of a loader function, one can also provide a URL to a JAR file.
     2.9 + * The <code>bck2brwsr</code> system will do its best to download the file
    2.10 + * and provide loader function for it automatically.
    2.11 + * <p>
    2.12 + * One can provide as many loader functions and JAR URL references as necessary.
    2.13 + * Then the initialization code would look like:<pre>
    2.14 + * var vm = bck2brwsr(url1, url2, fnctn1, url3, functn2);
    2.15 + * </pre>
    2.16 + * The provided URLs and loader functions will be consulted one by one.
    2.17   *
    2.18   * @author Jaroslav Tulach <jtulach@netbeans.org>
    2.19   */
     3.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Tue Feb 12 16:46:13 2013 +0100
     3.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Tue Feb 12 23:30:01 2013 +0100
     3.3 @@ -119,36 +119,28 @@
     3.4                "  return vm;\n"
     3.5              + "  };\n"
     3.6              + "  global.bck2brwsr = function() {\n"
     3.7 -            + "    var args = arguments;\n"
     3.8 +            + "    var args = Array.prototype.slice.apply(arguments);\n"
     3.9              + "    var vm = fillInVMSkeleton({});\n"
    3.10              + "    var loader = {};\n"
    3.11 -            + "    var init = null;\n"
    3.12              + "    loader.vm = vm;\n"
    3.13 -            + "    if (args.length == 1 && typeof args[0] !== 'function') {;\n"
    3.14 -            + "      var classpath = args[0];\n"
    3.15 -            + "      init = args[0] = function(name) {\n"
    3.16 -            + "        return vm.org_apidesign_vm4brwsr_Zips(false).loadFromCp___3B_3Ljava_lang_Object_2Ljava_lang_String_2(classpath, name);\n"
    3.17 -            + "      };\n"
    3.18 -            + "    };\n"
    3.19              + "    loader.loadClass = function(name) {\n"
    3.20              + "      var attr = name.replace__Ljava_lang_String_2CC('.','_');\n"
    3.21              + "      var fn = vm[attr];\n"
    3.22              + "      if (fn) return fn(false);\n"
    3.23 -            + "      if (!args[0]) throw 'bck2brwsr initialized without loader function, cannot load ' + name;\n"
    3.24              + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
    3.25              + "        load__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
    3.26              + "    }\n"
    3.27 -            + "    if (args[0]) {\n"
    3.28 -            + "      if (vm.loadClass) {\n"
    3.29 -            + "        throw 'Cannot initialize the bck2brwsr VM twice!';\n"
    3.30 -            + "      }\n"
    3.31 -            + "      vm.loadClass = loader.loadClass;\n"
    3.32 -            + "      vm.loadBytes = function(name) {\n"
    3.33 -            + "        if (!args[0]) throw 'bck2brwsr initialized without loader function, cannot load ' + name;\n"
    3.34 -            + "        return args[0](name);\n"
    3.35 -            + "      }\n"
    3.36 +            + "    if (vm.loadClass) {\n"
    3.37 +            + "      throw 'Cannot initialize the bck2brwsr VM twice!';\n"
    3.38              + "    }\n"
    3.39 -            + "    if (init) init(null);\n"
    3.40 +            + "    vm.loadClass = loader.loadClass;\n"
    3.41 +            + "    vm.loadBytes = function(name) {\n"
    3.42 +            + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
    3.43 +            + "        loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
    3.44 +            + "    }\n"
    3.45 +            + "    vm.java_lang_reflect_Array(false);\n"
    3.46 +            + "    vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
    3.47 +            + "      loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, null, args);\n"
    3.48              + "    return loader;\n"
    3.49              + "  };\n");
    3.50          out.append("}(this));");
     4.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Tue Feb 12 16:46:13 2013 +0100
     4.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Tue Feb 12 23:30:01 2013 +0100
     4.3 @@ -20,6 +20,7 @@
     4.4  import java.io.ByteArrayInputStream;
     4.5  import java.io.IOException;
     4.6  import java.io.InputStream;
     4.7 +import java.lang.reflect.Array;
     4.8  import org.apidesign.bck2brwsr.core.JavaScriptBody;
     4.9  
    4.10  /**
    4.11 @@ -38,23 +39,19 @@
    4.12      static void init() {
    4.13      }
    4.14      
    4.15 -    @JavaScriptBody(args={"l", "res", "args" }, body = ""
    4.16 -        + "\ntry {"
    4.17 -        + "\n  return args[0](res.toString());"
    4.18 -        + "\n} catch (x) {"
    4.19 -        + "\n  throw Object.getOwnPropertyNames(l.vm).toString() + x.toString();"
    4.20 -        + "\n}")
    4.21 -    private static native byte[] read(Object l, String res, Object[] args);
    4.22 -    
    4.23      static Object load(Object loader, String name, Object[] arguments) 
    4.24      throws IOException, ClassNotFoundException {
    4.25          return new VMLazy(loader, arguments).load(name, false);
    4.26      }
    4.27      
    4.28 +    static byte[] loadBytes(Object loader, String name, Object[] arguments) throws Exception {
    4.29 +        return Zips.loadFromCp(arguments, name);
    4.30 +    }
    4.31 +    
    4.32      private Object load(String name, boolean instance)
    4.33      throws IOException, ClassNotFoundException {
    4.34          String res = name.replace('.', '/') + ".class";
    4.35 -        byte[] arr = read(loader, res, args);
    4.36 +        byte[] arr = Zips.loadFromCp(args, res);
    4.37          if (arr == null) {
    4.38              throw new ClassNotFoundException(name);
    4.39          }
     5.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/Zips.java	Tue Feb 12 16:46:13 2013 +0100
     5.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Zips.java	Tue Feb 12 23:30:01 2013 +0100
     5.3 @@ -42,15 +42,22 @@
     5.4      
     5.5      public static void init() {
     5.6      }
     5.7 +    @JavaScriptBody(args = { "arr" }, body = "return arr.length;")
     5.8 +    private static native int length(Object arr);
     5.9 +    @JavaScriptBody(args = { "arr", "index" }, body = "return arr[index];")
    5.10 +    private static native Object at(Object arr, int index);
    5.11 +    @JavaScriptBody(args = { "arr", "index", "value" }, body = "arr[index] = value; return value;")
    5.12 +    private static native Object set(Object arr, int index, Object value);
    5.13      
    5.14 -    public static byte[] loadFromCp(Object[] classpath, String res) throws Exception {
    5.15 -        for (int i = 0; i < classpath.length; i++) {
    5.16 -            Object c = classpath[i];
    5.17 +    public static byte[] loadFromCp(Object classpath, String res) 
    5.18 +    throws IOException, ClassNotFoundException {
    5.19 +        for (int i = 0; i < length(classpath); i++) {
    5.20 +            Object c = at(classpath, i);
    5.21              if (c instanceof String) {
    5.22                  try {
    5.23                      String url = (String)c;
    5.24                      final Zips z = toZip(url);
    5.25 -                    c = classpath[i] = z;
    5.26 +                    c = set(classpath, i, z);
    5.27                      final byte[] man = z.findRes("META-INF/MANIFEST.MF");
    5.28                      if (man != null) {
    5.29                          String mainClass = processClassPathAttr(man, url, classpath);
    5.30 @@ -58,21 +65,32 @@
    5.31                              Class.forName(mainClass);
    5.32                          }
    5.33                      }
    5.34 -                } catch (Exception ex) {
    5.35 -                    classpath[i] = ex;
    5.36 +                } catch (IOException | ClassNotFoundException ex) {
    5.37 +                    set(classpath, i, ex);
    5.38                      throw ex;
    5.39                  }
    5.40              }
    5.41 -            if (res != null && c instanceof Zips) {
    5.42 -                Object checkRes = ((Zips)c).findRes(res);
    5.43 -                if (checkRes instanceof byte[]) {
    5.44 -                    return (byte[])checkRes;
    5.45 +            if (res != null) {
    5.46 +                byte[] checkRes;
    5.47 +                if (c instanceof Zips) {
    5.48 +                    checkRes = ((Zips)c).findRes(res);
    5.49 +                } else {
    5.50 +                    checkRes = callFunction(c, res);
    5.51 +                }
    5.52 +                if (checkRes != null) {
    5.53 +                    return checkRes;
    5.54                  }
    5.55              }
    5.56          }
    5.57          return null;
    5.58      }
    5.59      
    5.60 +    @JavaScriptBody(args = { "fn", "res" }, body = 
    5.61 +        "if (typeof fn === 'function') return fn(res);\n"
    5.62 +      + "return null;"
    5.63 +    )
    5.64 +    private static native byte[] callFunction(Object fn, String res);
    5.65 +    
    5.66      @JavaScriptBody(args = { "msg" }, body = "console.log(msg.toString());")
    5.67      private static native void log(String msg);
    5.68  
    5.69 @@ -100,7 +118,7 @@
    5.70          return new Zips(path, zipData);
    5.71      }
    5.72  
    5.73 -    private static String processClassPathAttr(final byte[] man, String url, Object[] classpath) throws IOException {
    5.74 +    private static String processClassPathAttr(final byte[] man, String url, Object classpath) throws IOException {
    5.75          try (ParseMan is = new ParseMan(new ByteArrayInputStream(man))) {
    5.76              String cp = is.toString();
    5.77              if (cp != null) {
    5.78 @@ -120,17 +138,17 @@
    5.79          }
    5.80      }
    5.81  
    5.82 -    private static Object[] addToArray(Object[] arr, String value) {
    5.83 -        final int last = arr.length;
    5.84 -        Object[] ret = enlargeArray(arr, last + 1);
    5.85 -        ret[last] = value;
    5.86 +    private static Object addToArray(Object arr, String value) {
    5.87 +        final int last = length(arr);
    5.88 +        Object ret = enlargeArray(arr, last + 1);
    5.89 +        set(ret, last, value);
    5.90          return ret;
    5.91      }
    5.92  
    5.93 -    @JavaScriptBody(args = { "arr", "len" }, body = "while (arr.length < len) arr.push(null); return arr;throw('Arr: ' + arr);")
    5.94 -    private static native Object[] enlargeArray(Object[] arr, int len);
    5.95 +    @JavaScriptBody(args = { "arr", "len" }, body = "while (arr.length < len) arr.push(null); return arr;")
    5.96 +    private static native Object enlargeArray(Object arr, int len);
    5.97      @JavaScriptBody(args = { "arr", "len" }, body = "while (arr.length < len) arr.push(0);")
    5.98 -    private static native void enlargeArray(byte[] arr, int len);
    5.99 +    private static native void enlargeBytes(byte[] arr, int len);
   5.100  
   5.101      @JavaScriptBody(args = { "arr", "len" }, body = "arr.splice(len, arr.length - len);")
   5.102      private static native void sliceArray(byte[] arr, int len);
   5.103 @@ -144,7 +162,7 @@
   5.104              }
   5.105              offset += len;
   5.106              if (offset == arr.length) {
   5.107 -                enlargeArray(arr, arr.length + 4096);
   5.108 +                enlargeBytes(arr, arr.length + 4096);
   5.109              }
   5.110          }
   5.111          sliceArray(arr, offset);
     6.1 --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java	Tue Feb 12 16:46:13 2013 +0100
     6.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java	Tue Feb 12 23:30:01 2013 +0100
     6.3 @@ -54,7 +54,7 @@
     6.4      }
     6.5      
     6.6      @JavaScriptBody(args = { "res", "path" }, body = 
     6.7 -          "var myvm = bck2brwsr(path);\n"
     6.8 +          "var myvm = bck2brwsr.apply(null, path);\n"
     6.9          + "var cls = myvm.loadClass('java.lang.String');\n"
    6.10          + "return cls.getClass__Ljava_lang_Class_2().getResourceAsStream__Ljava_io_InputStream_2Ljava_lang_String_2(res);\n"
    6.11      )