rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassPath.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 14 Jun 2016 05:44:20 +0200
branchLibraries
changeset 1976 9d33c9507806
parent 1787 ea12a3bb4b33
permissions -rw-r--r--
Hardcoding that Array.push is using varargs
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012-2015 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.vm4brwsr;
    19 
    20 import java.io.ByteArrayInputStream;
    21 import java.io.IOException;
    22 import java.io.InputStream;
    23 import java.net.URL;
    24 import org.apidesign.bck2brwsr.core.Exported;
    25 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    26 
    27 /** Conversion from classpath to load function.
    28  *
    29  * @author Jaroslav Tulach <jtulach@netbeans.org>
    30  */
    31 @Exported
    32 final class ClassPath {
    33     private ClassPath() {
    34     }
    35     
    36     public static void init() {
    37     }
    38     @JavaScriptBody(args = { "arr" }, body = "return arr.length;")
    39     private static native int length(Object arr);
    40     @JavaScriptBody(args = { "arr", "index" }, body = "return arr[index];")
    41     private static native Object at(Object arr, int index);
    42     @JavaScriptBody(args = { "arr", "index", "value" }, body = "arr[index] = value; return value;")
    43     private static native Object set(Object arr, int index, Object value);
    44     
    45     private static boolean doingToZip;
    46     
    47     static byte[] loadBytes(String resource, Object classpath, int skip)
    48     throws IOException, ClassNotFoundException {
    49         for (int i = 0; i < length(classpath); i++) {
    50             byte[] arr = loadBytes(resource, classpath, i, skip);
    51             if (arr != null) {
    52                 return arr;
    53             }
    54         }
    55         return null;
    56     }
    57     @Exported static byte[] loadBytes(String resource, Object classpath, int i, int skip) 
    58     throws IOException, ClassNotFoundException {
    59         Object c = at(classpath, i);
    60         if (c instanceof String && !doingToZip) {
    61             try {
    62                 doingToZip = true;
    63                 String url = (String)c;
    64                 final Bck2Brwsr.Resources z = toZip(url);
    65                 c = set(classpath, i, z);
    66                 final byte[] man = readBytes(z, "META-INF/MANIFEST.MF");
    67                 if (man != null) {
    68                     String mainClass = processClassPathAttr(man, url, classpath);
    69 //                        if (mainClass != null) {
    70 //                            Class.forName(mainClass);
    71 //                        }
    72                 }
    73             } catch (IOException ex) {
    74                 set(classpath, i, ex);
    75                 log("Cannot load " + c + " - " + ex.getClass().getName() + ":" + ex.getMessage());
    76             } finally {
    77                 doingToZip = false;
    78             }
    79         }
    80         if (resource != null) {
    81             byte[] checkRes;
    82             if (c instanceof Bck2Brwsr.Resources) {
    83                 checkRes = readBytes((Bck2Brwsr.Resources)c, resource);
    84                 if (checkRes != null && --skip < 0) {
    85                     return checkRes;
    86                 }
    87             } else {
    88                 checkRes = callFunction(c, resource, skip);
    89                 if (checkRes != null) {
    90                     return checkRes;
    91                 }
    92             }
    93         }
    94         return null;
    95     }
    96     
    97     @JavaScriptBody(args = { "fn", "res", "skip" }, body = 
    98         "if (typeof fn === 'function') return fn(res, skip);\n"
    99       + "return null;"
   100     )
   101     private static native byte[] callFunction(Object fn, String res, int skip);
   102     
   103     @JavaScriptBody(args = { "msg" }, body = "if (typeof console !== 'undefined') console.log(msg.toString());")
   104     private static native void log(String msg);
   105 
   106     private static String processClassPathAttr(final byte[] man, String url, Object classpath) throws IOException {
   107         try (ParseMan is = new ParseMan(new ByteArrayInputStream(man))) {
   108             String cp = is.toString();
   109             if (cp != null) {
   110                 cp = cp.trim();
   111                 for (int p = 0; p < cp.length();) {
   112                     int n = cp.indexOf(' ', p);
   113                     if (n == -1) {
   114                         n = cp.length();
   115                     }
   116                     String el = cp.substring(p, n);
   117                     URL u = new URL(new URL(url), el);
   118                     classpath = addToArray(classpath, u.toString());
   119                     p = n + 1;
   120                 }
   121             }
   122             return is.getMainClass();
   123         }
   124     }
   125 
   126     private static Object addToArray(Object arr, String value) {
   127         final int last = length(arr);
   128         Object ret = enlargeArray(arr, last + 1);
   129         set(ret, last, value);
   130         return ret;
   131     }
   132 
   133     @JavaScriptBody(args = { "arr", "len" }, body = "while (arr.length < len) arr.push(null); return arr;")
   134     private static native Object enlargeArray(Object arr, int len);
   135 
   136     private static Bck2Brwsr.Resources toZip(String path) throws IOException {
   137         URL u = new URL(path);
   138         byte[] zipData = (byte[]) u.getContent(new Class[]{byte[].class});
   139         Bck2Brwsr.Resources r;
   140         try {
   141             Class<?> fastJar = Class.forName("org.apidesign.bck2brwsr.vmzip.ZipResources");
   142             return (Bck2Brwsr.Resources) fastJar.getConstructor(byte[].class).newInstance(zipData);
   143         } catch (Exception ex) {
   144             log("Reading JARs is only possible with enum.zip module included: " + ex.getMessage());
   145             ex.printStackTrace();
   146             throw new IOException(ex);
   147         }
   148     }
   149     
   150     private static byte[] readBytes(Bck2Brwsr.Resources r, String res) throws IOException {
   151         InputStream is = r.get(res);
   152         if (is == null) {
   153             return null;
   154         }
   155         byte[] arr = new byte[is.available()];
   156         int off = 0;
   157         for (;;) {
   158             int len = is.read(arr, off, arr.length - off);
   159             if (len == -1) {
   160                 break;
   161             }
   162             off += len;
   163         }
   164         is.close();
   165         return arr;
   166     }
   167 }