jaroslav@323: /** jaroslav@323: * Back 2 Browser Bytecode Translator jaroslav@323: * Copyright (C) 2012 Jaroslav Tulach jaroslav@323: * jaroslav@323: * This program is free software: you can redistribute it and/or modify jaroslav@323: * it under the terms of the GNU General Public License as published by jaroslav@323: * the Free Software Foundation, version 2 of the License. jaroslav@323: * jaroslav@323: * This program is distributed in the hope that it will be useful, jaroslav@323: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@323: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@323: * GNU General Public License for more details. jaroslav@323: * jaroslav@323: * You should have received a copy of the GNU General Public License jaroslav@323: * along with this program. Look for COPYING file in the top folder. jaroslav@323: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@323: */ jaroslav@323: package org.apidesign.bck2brwsr.launcher; jaroslav@323: jaroslav@360: import java.io.IOException; jaroslav@360: import java.io.InputStream; jaroslav@332: import java.lang.reflect.InvocationTargetException; jaroslav@323: import java.lang.reflect.Method; jaroslav@332: import java.net.URL; jaroslav@360: import java.util.Enumeration; jaroslav@323: import org.apidesign.bck2brwsr.core.JavaScriptBody; jaroslav@323: jaroslav@323: /** jaroslav@323: * jaroslav@323: * @author Jaroslav Tulach jaroslav@323: */ jaroslav@323: public class Console { jaroslav@323: public static String welcome() { jaroslav@342: return "HellofromBck2Brwsr"; jaroslav@323: } jaroslav@342: public static String multiply() { jaroslav@342: return String.valueOf(Integer.MAX_VALUE / 2 + Integer.MAX_VALUE); jaroslav@342: } jaroslav@323: jaroslav@323: @JavaScriptBody(args = {"id", "attr"}, body = jaroslav@323: "return window.document.getElementById(id)[attr].toString();") jaroslav@323: private static native Object getAttr(String id, String attr); jaroslav@323: jaroslav@323: @JavaScriptBody(args = {"id", "attr", "value"}, body = jaroslav@323: "window.document.getElementById(id)[attr] = value;") jaroslav@323: private static native void setAttr(String id, String attr, Object value); jaroslav@342: jaroslav@343: private static void log(String newText) { jaroslav@343: String id = "result"; jaroslav@343: String attr = "value"; jaroslav@342: setAttr(id, attr, getAttr(id, attr) + "\n" + newText); jaroslav@343: setAttr(id, "scrollTop", getAttr(id, "scrollHeight")); jaroslav@342: } jaroslav@323: jaroslav@323: public static void execute() throws Exception { jaroslav@323: String clazz = (String) getAttr("clazz", "value"); jaroslav@323: String method = (String) getAttr("method", "value"); jaroslav@332: Object res = invokeMethod(clazz, method); jaroslav@332: setAttr("result", "value", res); jaroslav@332: } jaroslav@332: jaroslav@342: public static void harness(String url) { jaroslav@343: log("Connecting to " + url); jaroslav@332: try { jaroslav@342: URL u = new URL(url); jaroslav@342: for (;;) { jaroslav@342: String data = (String) u.getContent(new Class[] { String.class }); jaroslav@344: log("\nGot \"" + data + "\""); jaroslav@342: if (data.isEmpty()) { jaroslav@343: log("No data, exiting"); jaroslav@342: break; jaroslav@342: } jaroslav@342: jaroslav@342: Case c = Case.parseData(data); jaroslav@344: log("Invoking " + c.getClassName() + '.' + c.getMethodName() + " as request: " + c.getRequestId()); jaroslav@342: jaroslav@342: Object result = invokeMethod(c.getClassName(), c.getMethodName()); jaroslav@355: jaroslav@344: log("Result: " + result); jaroslav@355: log("Sending back: " + url + "?request=" + c.getRequestId() + "&result=" + result); jaroslav@355: u = new URL(url + "?request=" + c.getRequestId() + "&result=" + result); jaroslav@342: } jaroslav@342: jaroslav@342: jaroslav@332: } catch (Exception ex) { jaroslav@343: log(ex.getMessage()); jaroslav@332: } jaroslav@332: } jaroslav@356: jaroslav@356: static String invoke(String clazz, String method) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException { jaroslav@356: final Object r = invokeMethod(clazz, method); jaroslav@356: return r == null ? "null" : r.toString().toString(); jaroslav@356: } jaroslav@323: jaroslav@360: /** Helper method that inspects the classpath and loads given resource jaroslav@360: * (usually a class file). Used while running tests in Rhino. jaroslav@360: * jaroslav@360: * @param name resource name to find jaroslav@360: * @return the array of bytes in the given resource jaroslav@360: * @throws IOException I/O in case something goes wrong jaroslav@360: */ jaroslav@360: public static byte[] read(String name) throws IOException { jaroslav@360: URL u = null; jaroslav@360: Enumeration en = Console.class.getClassLoader().getResources(name); jaroslav@360: while (en.hasMoreElements()) { jaroslav@360: u = en.nextElement(); jaroslav@360: } jaroslav@360: if (u == null) { jaroslav@360: throw new IOException("Can't find " + name); jaroslav@360: } jaroslav@360: try (InputStream is = u.openStream()) { jaroslav@360: byte[] arr; jaroslav@360: arr = new byte[is.available()]; jaroslav@360: int offset = 0; jaroslav@360: while (offset < arr.length) { jaroslav@360: int len = is.read(arr, offset, arr.length - offset); jaroslav@360: if (len == -1) { jaroslav@360: throw new IOException("Can't read " + name); jaroslav@360: } jaroslav@360: offset += len; jaroslav@360: } jaroslav@360: return arr; jaroslav@360: } jaroslav@360: } jaroslav@360: jaroslav@332: private static Object invokeMethod(String clazz, String method) jaroslav@332: throws ClassNotFoundException, InvocationTargetException, jaroslav@332: SecurityException, IllegalAccessException, IllegalArgumentException { jaroslav@323: Method found = null; jaroslav@323: Class c = Class.forName(clazz); jaroslav@323: for (Method m : c.getMethods()) { jaroslav@323: if (m.getName().equals(method)) { jaroslav@323: found = m; jaroslav@323: } jaroslav@323: } jaroslav@323: Object res; jaroslav@323: if (found != null) { jaroslav@323: res = found.invoke(null); jaroslav@323: } else { jaroslav@323: res = "Can't find method " + method + " in " + clazz; jaroslav@323: } jaroslav@332: return res; jaroslav@323: } jaroslav@342: jaroslav@342: private static final class Case { jaroslav@342: private final Object data; jaroslav@342: jaroslav@342: private Case(Object data) { jaroslav@342: this.data = data; jaroslav@342: } jaroslav@342: jaroslav@342: public static Case parseData(String s) { jaroslav@342: return new Case(toJSON(s)); jaroslav@342: } jaroslav@342: jaroslav@342: public String getMethodName() { jaroslav@342: return value("methodName", data); jaroslav@342: } jaroslav@342: jaroslav@342: public String getClassName() { jaroslav@342: return value("className", data); jaroslav@342: } jaroslav@342: jaroslav@342: public String getRequestId() { jaroslav@342: return value("request", data); jaroslav@342: } jaroslav@342: jaroslav@342: @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');") jaroslav@342: private static native Object toJSON(String s); jaroslav@342: jaroslav@342: @JavaScriptBody(args = {"p", "d"}, body = "return d[p].toString();") jaroslav@342: private static native String value(String p, Object d); jaroslav@342: } jaroslav@323: }