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