launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Console.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 22 Jan 2013 11:14:00 +0100
changeset 517 70c062dbd783
parent 413 c91483c86597
child 519 aeb076729a8a
permissions -rw-r--r--
Tests should run with assertions on
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 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.bck2brwsr.launcher;
    19 
    20 import java.io.IOException;
    21 import java.io.InputStream;
    22 import java.lang.reflect.InvocationTargetException;
    23 import java.lang.reflect.Method;
    24 import java.lang.reflect.Modifier;
    25 import java.net.URL;
    26 import java.util.Enumeration;
    27 import org.apidesign.bck2brwsr.core.JavaScriptBody;
    28 
    29 /**
    30  *
    31  * @author Jaroslav Tulach <jtulach@netbeans.org>
    32  */
    33 public class Console {
    34     static {
    35         turnAssetionStatusOn();
    36     }
    37     public static String welcome() {
    38         return "HellofromBck2Brwsr";
    39     }
    40     public static String multiply() {
    41         return String.valueOf(Integer.MAX_VALUE / 2 + Integer.MAX_VALUE);
    42     }
    43     
    44     @JavaScriptBody(args = {"id", "attr"}, body = 
    45         "return window.document.getElementById(id)[attr].toString();")
    46     private static native Object getAttr(String id, String attr);
    47 
    48     @JavaScriptBody(args = {"id", "attr", "value"}, body = 
    49         "window.document.getElementById(id)[attr] = value;")
    50     private static native void setAttr(String id, String attr, Object value);
    51     
    52     @JavaScriptBody(args = {}, body = "return; window.close();")
    53     private static native void closeWindow();
    54 
    55     private static void log(String newText) {
    56         String id = "result";
    57         String attr = "value";
    58         setAttr(id, attr, getAttr(id, attr) + "\n" + newText);
    59         setAttr(id, "scrollTop", getAttr(id, "scrollHeight"));
    60     }
    61     
    62     public static void execute() throws Exception {
    63         String clazz = (String) getAttr("clazz", "value");
    64         String method = (String) getAttr("method", "value");
    65         Object res = invokeMethod(clazz, method);
    66         setAttr("result", "value", res);
    67     }
    68     
    69     public static void harness(String url) {
    70         log("Connecting to " + url);
    71         try {
    72             URL u = new URL(url);
    73             for (;;) {
    74                 String data = (String) u.getContent(new Class[] { String.class });
    75                 log("\nGot \"" + data + "\"");
    76                 if (data.isEmpty()) {
    77                     log("No data, exiting");
    78                     closeWindow();
    79                     break;
    80                 }
    81                 
    82                 Case c = Case.parseData(data);
    83                 log("Invoking " + c.getClassName() + '.' + c.getMethodName() + " as request: " + c.getRequestId());
    84 
    85                 Object result = invokeMethod(c.getClassName(), c.getMethodName());
    86                 
    87                 log("Result: " + result);
    88                 
    89                 result = encodeURL("" + result);
    90                 
    91                 log("Sending back: " + url + "?request=" + c.getRequestId() + "&result=" + result);
    92                 u = new URL(url + "?request=" + c.getRequestId() + "&result=" + result);
    93             }
    94             
    95             
    96         } catch (Exception ex) {
    97             log(ex.getMessage());
    98         }
    99     }
   100     
   101     private static String encodeURL(String r) {
   102         StringBuilder sb = new StringBuilder();
   103         for (int i = 0; i < r.length(); i++) {
   104             int ch = r.charAt(i);
   105             if (ch < 32 || ch == '%' || ch == '+') {
   106                 sb.append("%").append(("0" + Integer.toHexString(ch)).substring(0, 2));
   107             } else {
   108                 if (ch == 32) {
   109                     sb.append("+");
   110                 } else {
   111                     sb.append((char)ch);
   112                 }
   113             }
   114         }
   115         return sb.toString();
   116     }
   117     
   118     static String invoke(String clazz, String method) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException {
   119         final Object r = invokeMethod(clazz, method);
   120         return r == null ? "null" : r.toString().toString();
   121     }
   122 
   123     /** Helper method that inspects the classpath and loads given resource
   124      * (usually a class file). Used while running tests in Rhino.
   125      * 
   126      * @param name resource name to find
   127      * @return the array of bytes in the given resource
   128      * @throws IOException I/O in case something goes wrong
   129      */
   130     public static byte[] read(String name) throws IOException {
   131         URL u = null;
   132         Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
   133         while (en.hasMoreElements()) {
   134             u = en.nextElement();
   135         }
   136         if (u == null) {
   137             throw new IOException("Can't find " + name);
   138         }
   139         try (InputStream is = u.openStream()) {
   140             byte[] arr;
   141             arr = new byte[is.available()];
   142             int offset = 0;
   143             while (offset < arr.length) {
   144                 int len = is.read(arr, offset, arr.length - offset);
   145                 if (len == -1) {
   146                     throw new IOException("Can't read " + name);
   147                 }
   148                 offset += len;
   149             }
   150             return arr;
   151         }
   152     }
   153    
   154     private static Object invokeMethod(String clazz, String method) 
   155     throws ClassNotFoundException, InvocationTargetException, 
   156     SecurityException, IllegalAccessException, IllegalArgumentException,
   157     InstantiationException {
   158         Method found = null;
   159         Class<?> c = Class.forName(clazz);
   160         for (Method m : c.getMethods()) {
   161             if (m.getName().equals(method)) {
   162                 found = m;
   163             }
   164         }
   165         Object res;
   166         if (found != null) {
   167             try {
   168                 if ((found.getModifiers() & Modifier.STATIC) != 0) {
   169                     res = found.invoke(null);
   170                 } else {
   171                     res = found.invoke(c.newInstance());
   172                 }
   173             } catch (Exception | Error ex) {
   174                 res = ex.getClass().getName() + ":" + ex.getMessage();
   175             }
   176         } else {
   177             res = "Can't find method " + method + " in " + clazz;
   178         }
   179         return res;
   180     }
   181 
   182     @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
   183     private static void turnAssetionStatusOn() {
   184     }
   185     
   186     private static final class Case {
   187         private final Object data;
   188 
   189         private Case(Object data) {
   190             this.data = data;
   191         }
   192         
   193         public static Case parseData(String s) {
   194             return new Case(toJSON(s));
   195         }
   196         
   197         public String getMethodName() {
   198             return value("methodName", data);
   199         }
   200 
   201         public String getClassName() {
   202             return value("className", data);
   203         }
   204         
   205         public String getRequestId() {
   206             return value("request", data);
   207         }
   208         
   209         @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');")
   210         private static native Object toJSON(String s);
   211         
   212         @JavaScriptBody(args = {"p", "d"}, body = "return d[p].toString();")
   213         private static native String value(String p, Object d);
   214     }
   215 }