1.1 --- a/launcher/pom.xml Thu Jan 31 16:13:04 2013 +0100
1.2 +++ b/launcher/pom.xml Thu Jan 31 16:58:27 2013 +0100
1.3 @@ -23,6 +23,14 @@
1.4 <target>1.7</target>
1.5 </configuration>
1.6 </plugin>
1.7 + <plugin>
1.8 + <groupId>org.apache.maven.plugins</groupId>
1.9 + <artifactId>maven-javadoc-plugin</artifactId>
1.10 + <version>2.8.1</version>
1.11 + <configuration>
1.12 + <excludePackageNames>org.apidesign.bck2brwsr.launcher.impl</excludePackageNames>
1.13 + </configuration>
1.14 + </plugin>
1.15 </plugins>
1.16 </build>
1.17 <properties>
2.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Thu Jan 31 16:13:04 2013 +0100
2.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Thu Jan 31 16:58:27 2013 +0100
2.3 @@ -55,9 +55,9 @@
2.4 */
2.5 final class Bck2BrwsrLauncher extends Launcher implements Closeable {
2.6 private static final Logger LOG = Logger.getLogger(Bck2BrwsrLauncher.class.getName());
2.7 - private static final MethodInvocation END = new MethodInvocation(null, null, null);
2.8 - private Set<ClassLoader> loaders = new LinkedHashSet<>();
2.9 - private BlockingQueue<MethodInvocation> methods = new LinkedBlockingQueue<>();
2.10 + private static final InvocationContext END = new InvocationContext(null, null, null);
2.11 + private final Set<ClassLoader> loaders = new LinkedHashSet<>();
2.12 + private final BlockingQueue<InvocationContext> methods = new LinkedBlockingQueue<>();
2.13 private long timeOut;
2.14 private final Res resources = new Res();
2.15 private final String cmd;
2.16 @@ -70,9 +70,8 @@
2.17 }
2.18
2.19 @Override
2.20 - MethodInvocation addMethod(Class<?> clazz, String method, String html) throws IOException {
2.21 - loaders.add(clazz.getClassLoader());
2.22 - MethodInvocation c = new MethodInvocation(clazz.getName(), method, html);
2.23 + InvocationContext runMethod(InvocationContext c) throws IOException {
2.24 + loaders.add(c.clazz.getClassLoader());
2.25 methods.add(c);
2.26 try {
2.27 c.await(timeOut);
2.28 @@ -154,7 +153,7 @@
2.29 ), "/execute");
2.30 conf.addHttpHandler(new HttpHandler() {
2.31 int cnt;
2.32 - List<MethodInvocation> cases = new ArrayList<>();
2.33 + List<InvocationContext> cases = new ArrayList<>();
2.34 @Override
2.35 public void service(Request request, Response response) throws Exception {
2.36 String id = request.getParameter("request");
2.37 @@ -166,7 +165,7 @@
2.38 cases.get(Integer.parseInt(id)).result(value, null);
2.39 }
2.40
2.41 - MethodInvocation mi = methods.take();
2.42 + InvocationContext mi = methods.take();
2.43 if (mi == END) {
2.44 response.getWriter().write("");
2.45 wait.countDown();
2.46 @@ -176,7 +175,7 @@
2.47 }
2.48
2.49 cases.add(mi);
2.50 - final String cn = mi.className;
2.51 + final String cn = mi.clazz.getName();
2.52 final String mn = mi.methodName;
2.53 LOG.log(Level.INFO, "Request for {0} case. Sending {1}.{2}", new Object[]{cnt, cn, mn});
2.54 response.getWriter().write("{"
3.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Console.java Thu Jan 31 16:13:04 2013 +0100
3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
3.3 @@ -1,253 +0,0 @@
3.4 -/**
3.5 - * Back 2 Browser Bytecode Translator
3.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
3.7 - *
3.8 - * This program is free software: you can redistribute it and/or modify
3.9 - * it under the terms of the GNU General Public License as published by
3.10 - * the Free Software Foundation, version 2 of the License.
3.11 - *
3.12 - * This program is distributed in the hope that it will be useful,
3.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.15 - * GNU General Public License for more details.
3.16 - *
3.17 - * You should have received a copy of the GNU General Public License
3.18 - * along with this program. Look for COPYING file in the top folder.
3.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
3.20 - */
3.21 -package org.apidesign.bck2brwsr.launcher;
3.22 -
3.23 -import java.io.IOException;
3.24 -import java.io.InputStream;
3.25 -import java.lang.reflect.InvocationTargetException;
3.26 -import java.lang.reflect.Method;
3.27 -import java.lang.reflect.Modifier;
3.28 -import java.net.URL;
3.29 -import java.util.Enumeration;
3.30 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
3.31 -
3.32 -/**
3.33 - *
3.34 - * @author Jaroslav Tulach <jtulach@netbeans.org>
3.35 - */
3.36 -public class Console {
3.37 - static {
3.38 - turnAssetionStatusOn();
3.39 - }
3.40 -
3.41 - @JavaScriptBody(args = {"id", "attr"}, body =
3.42 - "return window.document.getElementById(id)[attr].toString();")
3.43 - private static native Object getAttr(String id, String attr);
3.44 -
3.45 - @JavaScriptBody(args = {"id", "attr", "value"}, body =
3.46 - "window.document.getElementById(id)[attr] = value;")
3.47 - private static native void setAttr(String id, String attr, Object value);
3.48 -
3.49 - @JavaScriptBody(args = {}, body = "return; window.close();")
3.50 - private static native void closeWindow();
3.51 -
3.52 - private static void log(String newText) {
3.53 - String id = "bck2brwsr.result";
3.54 - String attr = "value";
3.55 - setAttr(id, attr, getAttr(id, attr) + "\n" + newText);
3.56 - setAttr(id, "scrollTop", getAttr(id, "scrollHeight"));
3.57 - }
3.58 -
3.59 - public static void execute() throws Exception {
3.60 - String clazz = (String) getAttr("clazz", "value");
3.61 - String method = (String) getAttr("method", "value");
3.62 - Object res = invokeMethod(clazz, method);
3.63 - setAttr("bck2brwsr.result", "value", res);
3.64 - }
3.65 -
3.66 - @JavaScriptBody(args = { "url", "callback", "arr" }, body = ""
3.67 - + "var request = new XMLHttpRequest();\n"
3.68 - + "request.open('GET', url, true);\n"
3.69 - + "request.onreadystatechange = function() {\n"
3.70 - + " if (this.readyState!==4) return;\n"
3.71 - + " arr[0] = this.responseText;\n"
3.72 - + " callback.run__V();\n"
3.73 - + "};"
3.74 - + "request.send();"
3.75 - )
3.76 - private static native void loadText(String url, Runnable callback, String[] arr) throws IOException;
3.77 -
3.78 - public static void harness(String url) throws IOException {
3.79 - log("Connecting to " + url);
3.80 - Request r = new Request(url);
3.81 - }
3.82 -
3.83 - private static class Request implements Runnable {
3.84 - private final String[] arr = { null };
3.85 - private final String url;
3.86 -
3.87 - private Request(String url) throws IOException {
3.88 - this.url = url;
3.89 - loadText(url, this, arr);
3.90 - }
3.91 -
3.92 - @Override
3.93 - public void run() {
3.94 - try {
3.95 - String data = arr[0];
3.96 - log("\nGot \"" + data + "\"");
3.97 -
3.98 - if (data == null) {
3.99 - log("Some error exiting");
3.100 - closeWindow();
3.101 - return;
3.102 - }
3.103 -
3.104 - if (data.isEmpty()) {
3.105 - log("No data, exiting");
3.106 - closeWindow();
3.107 - return;
3.108 - }
3.109 -
3.110 - Case c = Case.parseData(data);
3.111 - if (c.getHtmlFragment() != null) {
3.112 - setAttr("bck2brwsr.fragment", "innerHTML", c.getHtmlFragment());
3.113 - }
3.114 - log("Invoking " + c.getClassName() + '.' + c.getMethodName() + " as request: " + c.getRequestId());
3.115 -
3.116 - Object result = invokeMethod(c.getClassName(), c.getMethodName());
3.117 -
3.118 - setAttr("bck2brwsr.fragment", "innerHTML", "");
3.119 - log("Result: " + result);
3.120 -
3.121 - result = encodeURL("" + result);
3.122 -
3.123 - log("Sending back: " + url + "?request=" + c.getRequestId() + "&result=" + result);
3.124 - String u = url + "?request=" + c.getRequestId() + "&result=" + result;
3.125 -
3.126 - loadText(u, this, arr);
3.127 -
3.128 - } catch (Exception ex) {
3.129 - log(ex.getMessage());
3.130 - }
3.131 - }
3.132 - }
3.133 -
3.134 - private static String encodeURL(String r) {
3.135 - StringBuilder sb = new StringBuilder();
3.136 - for (int i = 0; i < r.length(); i++) {
3.137 - int ch = r.charAt(i);
3.138 - if (ch < 32 || ch == '%' || ch == '+') {
3.139 - sb.append("%").append(("0" + Integer.toHexString(ch)).substring(0, 2));
3.140 - } else {
3.141 - if (ch == 32) {
3.142 - sb.append("+");
3.143 - } else {
3.144 - sb.append((char)ch);
3.145 - }
3.146 - }
3.147 - }
3.148 - return sb.toString();
3.149 - }
3.150 -
3.151 - static String invoke(String clazz, String method) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException {
3.152 - final Object r = invokeMethod(clazz, method);
3.153 - return r == null ? "null" : r.toString().toString();
3.154 - }
3.155 -
3.156 - /** Helper method that inspects the classpath and loads given resource
3.157 - * (usually a class file). Used while running tests in Rhino.
3.158 - *
3.159 - * @param name resource name to find
3.160 - * @return the array of bytes in the given resource
3.161 - * @throws IOException I/O in case something goes wrong
3.162 - */
3.163 - public static byte[] read(String name) throws IOException {
3.164 - URL u = null;
3.165 - Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
3.166 - while (en.hasMoreElements()) {
3.167 - u = en.nextElement();
3.168 - }
3.169 - if (u == null) {
3.170 - throw new IOException("Can't find " + name);
3.171 - }
3.172 - try (InputStream is = u.openStream()) {
3.173 - byte[] arr;
3.174 - arr = new byte[is.available()];
3.175 - int offset = 0;
3.176 - while (offset < arr.length) {
3.177 - int len = is.read(arr, offset, arr.length - offset);
3.178 - if (len == -1) {
3.179 - throw new IOException("Can't read " + name);
3.180 - }
3.181 - offset += len;
3.182 - }
3.183 - return arr;
3.184 - }
3.185 - }
3.186 -
3.187 - private static Object invokeMethod(String clazz, String method)
3.188 - throws ClassNotFoundException, InvocationTargetException,
3.189 - SecurityException, IllegalAccessException, IllegalArgumentException,
3.190 - InstantiationException {
3.191 - Method found = null;
3.192 - Class<?> c = Class.forName(clazz);
3.193 - for (Method m : c.getMethods()) {
3.194 - if (m.getName().equals(method)) {
3.195 - found = m;
3.196 - }
3.197 - }
3.198 - Object res;
3.199 - if (found != null) {
3.200 - try {
3.201 - if ((found.getModifiers() & Modifier.STATIC) != 0) {
3.202 - res = found.invoke(null);
3.203 - } else {
3.204 - res = found.invoke(c.newInstance());
3.205 - }
3.206 - } catch (Throwable ex) {
3.207 - res = ex.getClass().getName() + ":" + ex.getMessage();
3.208 - }
3.209 - } else {
3.210 - res = "Can't find method " + method + " in " + clazz;
3.211 - }
3.212 - return res;
3.213 - }
3.214 -
3.215 - @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
3.216 - private static void turnAssetionStatusOn() {
3.217 - }
3.218 -
3.219 - private static final class Case {
3.220 - private final Object data;
3.221 -
3.222 - private Case(Object data) {
3.223 - this.data = data;
3.224 - }
3.225 -
3.226 - public static Case parseData(String s) {
3.227 - return new Case(toJSON(s));
3.228 - }
3.229 -
3.230 - public String getMethodName() {
3.231 - return value("methodName", data);
3.232 - }
3.233 -
3.234 - public String getClassName() {
3.235 - return value("className", data);
3.236 - }
3.237 -
3.238 - public String getRequestId() {
3.239 - return value("request", data);
3.240 - }
3.241 -
3.242 - public String getHtmlFragment() {
3.243 - return value("html", data);
3.244 - }
3.245 -
3.246 - @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');")
3.247 - private static native Object toJSON(String s);
3.248 -
3.249 - @JavaScriptBody(args = {"p", "d"}, body =
3.250 - "var v = d[p];\n"
3.251 - + "if (typeof v === 'undefined') return null;\n"
3.252 - + "return v.toString();"
3.253 - )
3.254 - private static native String value(String p, Object d);
3.255 - }
3.256 -}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java Thu Jan 31 16:58:27 2013 +0100
4.3 @@ -0,0 +1,97 @@
4.4 +/**
4.5 + * Back 2 Browser Bytecode Translator
4.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
4.7 + *
4.8 + * This program is free software: you can redistribute it and/or modify
4.9 + * it under the terms of the GNU General Public License as published by
4.10 + * the Free Software Foundation, version 2 of the License.
4.11 + *
4.12 + * This program is distributed in the hope that it will be useful,
4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.15 + * GNU General Public License for more details.
4.16 + *
4.17 + * You should have received a copy of the GNU General Public License
4.18 + * along with this program. Look for COPYING file in the top folder.
4.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
4.20 + */
4.21 +package org.apidesign.bck2brwsr.launcher;
4.22 +
4.23 +import java.io.IOException;
4.24 +import java.util.concurrent.CountDownLatch;
4.25 +import java.util.concurrent.TimeUnit;
4.26 +
4.27 +/** Represents individual method invocation, its context and its result.
4.28 + *
4.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
4.30 + */
4.31 +public final class InvocationContext {
4.32 + final CountDownLatch wait = new CountDownLatch(1);
4.33 + final Class<?> clazz;
4.34 + final String methodName;
4.35 + private final Launcher launcher;
4.36 + private String result;
4.37 + private Throwable exception;
4.38 + String html;
4.39 + String httpContent;
4.40 + String httpType;
4.41 + String httpPath;
4.42 +
4.43 + InvocationContext(Launcher launcher, Class<?> clazz, String methodName) {
4.44 + this.launcher = launcher;
4.45 + this.clazz = clazz;
4.46 + this.methodName = methodName;
4.47 + }
4.48 +
4.49 + /** An HTML fragment to be available for the execution. Useful primarily when
4.50 + * executing in a browser via {@link Launcher#createBrowser(java.lang.String)}.
4.51 + * @param html the html fragment
4.52 + */
4.53 + public void setHtmlFragment(String html) {
4.54 + this.html = html;
4.55 + }
4.56 +
4.57 + /** HTTP resource to be available during execution. An invocation may
4.58 + * perform an HTTP query and obtain a resource relative to the page.
4.59 + */
4.60 + public void setHttpResource(String relativePath, String mimeType, String content) {
4.61 + this.httpPath = relativePath;
4.62 + this.httpType = mimeType;
4.63 + this.httpContent = content;
4.64 + }
4.65 +
4.66 + /** Invokes the associated method.
4.67 + * @return the textual result of the invocation
4.68 + */
4.69 + public String invoke() throws IOException {
4.70 + launcher.runMethod(this);
4.71 + return toString();
4.72 + }
4.73 +
4.74 + /** Obtains textual result of the invocation.
4.75 + * @return text representing the exception or result value
4.76 + */
4.77 + @Override
4.78 + public String toString() {
4.79 + if (exception != null) {
4.80 + return exception.toString();
4.81 + }
4.82 + return result;
4.83 + }
4.84 +
4.85 + /**
4.86 + * @param timeOut
4.87 + * @throws InterruptedException
4.88 + */
4.89 + void await(long timeOut) throws InterruptedException {
4.90 + wait.await(timeOut, TimeUnit.MILLISECONDS);
4.91 + }
4.92 +
4.93 + void result(String r, Throwable e) {
4.94 + this.result = r;
4.95 + this.exception = e;
4.96 + wait.countDown();
4.97 + }
4.98 +
4.99 +
4.100 +}
5.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Thu Jan 31 16:13:04 2013 +0100
5.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Thu Jan 31 16:58:27 2013 +0100
5.3 @@ -17,6 +17,7 @@
5.4 */
5.5 package org.apidesign.bck2brwsr.launcher;
5.6
5.7 +import org.apidesign.bck2brwsr.launcher.impl.Console;
5.8 import java.io.IOException;
5.9 import java.io.InputStream;
5.10 import java.net.URL;
5.11 @@ -43,18 +44,17 @@
5.12 private Object console;
5.13
5.14
5.15 - @Override MethodInvocation addMethod(Class<?> clazz, String method, String html) {
5.16 - loaders.add(clazz.getClassLoader());
5.17 - MethodInvocation mi = new MethodInvocation(clazz.getName(), method, html);
5.18 + @Override InvocationContext runMethod(InvocationContext mi) {
5.19 + loaders.add(mi.clazz.getClassLoader());
5.20 try {
5.21 long time = System.currentTimeMillis();
5.22 - LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.className, mi.methodName});
5.23 + LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.clazz.getName(), mi.methodName});
5.24 String res = code.invokeMethod(
5.25 console,
5.26 "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2",
5.27 - mi.className, mi.methodName).toString();
5.28 + mi.clazz.getName(), mi.methodName).toString();
5.29 time = System.currentTimeMillis() - time;
5.30 - LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.className, mi.methodName, res, time});
5.31 + LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.clazz.getName(), mi.methodName, res, time});
5.32 mi.result(res, null);
5.33 } catch (ScriptException | NoSuchMethodException ex) {
5.34 mi.result(null, ex);
5.35 @@ -89,7 +89,7 @@
5.36 ScriptEngine mach = sem.getEngineByExtension("js");
5.37
5.38 sb.append(
5.39 - "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.Console.read);"
5.40 + "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.impl.Console.read);"
5.41 + "\nfunction initVM() { return vm; };"
5.42 + "\n");
5.43
6.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Thu Jan 31 16:13:04 2013 +0100
6.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Thu Jan 31 16:58:27 2013 +0100
6.3 @@ -24,7 +24,8 @@
6.4 import org.apidesign.vm4brwsr.Bck2Brwsr;
6.5
6.6 /** An abstraction for executing tests in a Bck2Brwsr virtual machine.
6.7 - * Either in JavaScript engine, or in external browser.
6.8 + * Either in {@linkm Launcher#createJavaScript JavaScript engine},
6.9 + * or in {@linkm Launcher#createBrowser external browser}.
6.10 *
6.11 * @author Jaroslav Tulach <jtulach@netbeans.org>
6.12 */
6.13 @@ -32,39 +33,83 @@
6.14
6.15 Launcher() {
6.16 }
6.17 +
6.18 + /** Initializes the launcher. This may mean starting a web browser or
6.19 + * initializing execution engine.
6.20 + * @throws IOException if something goes wrong
6.21 + */
6.22 + public abstract void initialize() throws IOException;
6.23
6.24 - abstract MethodInvocation addMethod(Class<?> clazz, String method, String html) throws IOException;
6.25 -
6.26 - public abstract void initialize() throws IOException;
6.27 + /** Shuts down the launcher.
6.28 + * @throws IOException if something goes wrong
6.29 + */
6.30 public abstract void shutdown() throws IOException;
6.31 - public MethodInvocation invokeMethod(Class<?> clazz, String method, String html) throws IOException {
6.32 - return addMethod(clazz, method, html);
6.33 +
6.34 +
6.35 + /** Builds an invocation context. The context can later be customized
6.36 + * and {@link InvocationContext#invoke() invoked}.
6.37 + *
6.38 + * @param clazz the class to execute method from
6.39 + * @param method the method to execute
6.40 + * @return the context pointing to the selected method
6.41 + */
6.42 + public InvocationContext createInvocation(Class<?> clazz, String method) {
6.43 + return new InvocationContext(this, clazz, method);
6.44 }
6.45
6.46 -
6.47
6.48 + /** Creates launcher that uses internal JavaScript engine (Rhino).
6.49 + * @return the launcher
6.50 + */
6.51 public static Launcher createJavaScript() {
6.52 final JSLauncher l = new JSLauncher();
6.53 l.addClassLoader(Bck2Brwsr.class.getClassLoader());
6.54 return l;
6.55 }
6.56
6.57 + /** Creates launcher that is using external browser.
6.58 + *
6.59 + * @param cmd <code>null</code> to use <code>java.awt.Desktop</code> to show the launcher
6.60 + * or a string to execute in an external process (with a parameter to the URL)
6.61 + * @return launcher executing in external browser.
6.62 + */
6.63 public static Launcher createBrowser(String cmd) {
6.64 final Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(cmd);
6.65 l.addClassLoader(Bck2Brwsr.class.getClassLoader());
6.66 l.setTimeout(180000);
6.67 return l;
6.68 }
6.69 +
6.70 + /** Starts an HTTP server which provides access to classes and resources
6.71 + * available in the <code>classes</code> URL and shows a start page
6.72 + * available as {@link ClassLoader#getResource(java.lang.String)} from the
6.73 + * provide classloader. Opens a browser with URL showing the start page.
6.74 + *
6.75 + * @param classes classloader offering access to classes and resources
6.76 + * @param startpage page to show in the browser
6.77 + * @return interface that allows one to stop the server
6.78 + * @throws IOException if something goes wrong
6.79 + */
6.80 public static Closeable showURL(URLClassLoader classes, String startpage) throws IOException {
6.81 Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(null);
6.82 l.addClassLoader(classes);
6.83 l.showURL(startpage);
6.84 return l;
6.85 }
6.86 + /** Starts an HTTP server which provides access to certain directory.
6.87 + * The <code>startpage</code> should be relative location inside the root
6.88 + * driecotry
6.89 + * Opens a browser with URL showing the start page.
6.90 + *
6.91 + * @param directory the root directory on disk
6.92 + * @praam startpage relative path from the root to the page
6.93 + * @exception IOException if something goes wrong.
6.94 + */
6.95 public static Closeable showDir(File directory, String startpage) throws IOException {
6.96 Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(null);
6.97 l.showDirectory(directory, startpage);
6.98 return l;
6.99 }
6.100
6.101 + abstract InvocationContext runMethod(InvocationContext c) throws IOException;
6.102 }
7.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/MethodInvocation.java Thu Jan 31 16:13:04 2013 +0100
7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
7.3 @@ -1,59 +0,0 @@
7.4 -/**
7.5 - * Back 2 Browser Bytecode Translator
7.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
7.7 - *
7.8 - * This program is free software: you can redistribute it and/or modify
7.9 - * it under the terms of the GNU General Public License as published by
7.10 - * the Free Software Foundation, version 2 of the License.
7.11 - *
7.12 - * This program is distributed in the hope that it will be useful,
7.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.15 - * GNU General Public License for more details.
7.16 - *
7.17 - * You should have received a copy of the GNU General Public License
7.18 - * along with this program. Look for COPYING file in the top folder.
7.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
7.20 - */
7.21 -package org.apidesign.bck2brwsr.launcher;
7.22 -
7.23 -import java.util.concurrent.CountDownLatch;
7.24 -import java.util.concurrent.TimeUnit;
7.25 -
7.26 -/**
7.27 - *
7.28 - * @author Jaroslav Tulach <jtulach@netbeans.org>
7.29 - */
7.30 -public final class MethodInvocation {
7.31 - final CountDownLatch wait = new CountDownLatch(1);
7.32 - final String className;
7.33 - final String methodName;
7.34 - final String html;
7.35 - private String result;
7.36 - private Throwable exception;
7.37 -
7.38 - MethodInvocation(String className, String methodName, String html) {
7.39 - this.className = className;
7.40 - this.methodName = methodName;
7.41 - this.html = html;
7.42 - }
7.43 -
7.44 - void await(long timeOut) throws InterruptedException {
7.45 - wait.await(timeOut, TimeUnit.MILLISECONDS);
7.46 - }
7.47 -
7.48 - void result(String r, Throwable e) {
7.49 - this.result = r;
7.50 - this.exception = e;
7.51 - wait.countDown();
7.52 - }
7.53 -
7.54 - @Override
7.55 - public String toString() {
7.56 - if (exception != null) {
7.57 - return exception.toString();
7.58 - }
7.59 - return result;
7.60 - }
7.61 -
7.62 -}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java Thu Jan 31 16:58:27 2013 +0100
8.3 @@ -0,0 +1,255 @@
8.4 +/**
8.5 + * Back 2 Browser Bytecode Translator
8.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
8.7 + *
8.8 + * This program is free software: you can redistribute it and/or modify
8.9 + * it under the terms of the GNU General Public License as published by
8.10 + * the Free Software Foundation, version 2 of the License.
8.11 + *
8.12 + * This program is distributed in the hope that it will be useful,
8.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8.15 + * GNU General Public License for more details.
8.16 + *
8.17 + * You should have received a copy of the GNU General Public License
8.18 + * along with this program. Look for COPYING file in the top folder.
8.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
8.20 + */
8.21 +package org.apidesign.bck2brwsr.launcher.impl;
8.22 +
8.23 +import java.io.IOException;
8.24 +import java.io.InputStream;
8.25 +import java.lang.reflect.InvocationTargetException;
8.26 +import java.lang.reflect.Method;
8.27 +import java.lang.reflect.Modifier;
8.28 +import java.net.URL;
8.29 +import java.util.Enumeration;
8.30 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
8.31 +
8.32 +/**
8.33 + *
8.34 + * @author Jaroslav Tulach <jtulach@netbeans.org>
8.35 + */
8.36 +public class Console {
8.37 + private Console() {
8.38 + }
8.39 + static {
8.40 + turnAssetionStatusOn();
8.41 + }
8.42 +
8.43 + @JavaScriptBody(args = {"id", "attr"}, body =
8.44 + "return window.document.getElementById(id)[attr].toString();")
8.45 + private static native Object getAttr(String id, String attr);
8.46 +
8.47 + @JavaScriptBody(args = {"id", "attr", "value"}, body =
8.48 + "window.document.getElementById(id)[attr] = value;")
8.49 + private static native void setAttr(String id, String attr, Object value);
8.50 +
8.51 + @JavaScriptBody(args = {}, body = "return; window.close();")
8.52 + private static native void closeWindow();
8.53 +
8.54 + private static void log(String newText) {
8.55 + String id = "bck2brwsr.result";
8.56 + String attr = "value";
8.57 + setAttr(id, attr, getAttr(id, attr) + "\n" + newText);
8.58 + setAttr(id, "scrollTop", getAttr(id, "scrollHeight"));
8.59 + }
8.60 +
8.61 + public static void execute() throws Exception {
8.62 + String clazz = (String) getAttr("clazz", "value");
8.63 + String method = (String) getAttr("method", "value");
8.64 + Object res = invokeMethod(clazz, method);
8.65 + setAttr("bck2brwsr.result", "value", res);
8.66 + }
8.67 +
8.68 + @JavaScriptBody(args = { "url", "callback", "arr" }, body = ""
8.69 + + "var request = new XMLHttpRequest();\n"
8.70 + + "request.open('GET', url, true);\n"
8.71 + + "request.onreadystatechange = function() {\n"
8.72 + + " if (this.readyState!==4) return;\n"
8.73 + + " arr[0] = this.responseText;\n"
8.74 + + " callback.run__V();\n"
8.75 + + "};"
8.76 + + "request.send();"
8.77 + )
8.78 + private static native void loadText(String url, Runnable callback, String[] arr) throws IOException;
8.79 +
8.80 + public static void harness(String url) throws IOException {
8.81 + log("Connecting to " + url);
8.82 + Request r = new Request(url);
8.83 + }
8.84 +
8.85 + private static class Request implements Runnable {
8.86 + private final String[] arr = { null };
8.87 + private final String url;
8.88 +
8.89 + private Request(String url) throws IOException {
8.90 + this.url = url;
8.91 + loadText(url, this, arr);
8.92 + }
8.93 +
8.94 + @Override
8.95 + public void run() {
8.96 + try {
8.97 + String data = arr[0];
8.98 + log("\nGot \"" + data + "\"");
8.99 +
8.100 + if (data == null) {
8.101 + log("Some error exiting");
8.102 + closeWindow();
8.103 + return;
8.104 + }
8.105 +
8.106 + if (data.isEmpty()) {
8.107 + log("No data, exiting");
8.108 + closeWindow();
8.109 + return;
8.110 + }
8.111 +
8.112 + Case c = Case.parseData(data);
8.113 + if (c.getHtmlFragment() != null) {
8.114 + setAttr("bck2brwsr.fragment", "innerHTML", c.getHtmlFragment());
8.115 + }
8.116 + log("Invoking " + c.getClassName() + '.' + c.getMethodName() + " as request: " + c.getRequestId());
8.117 +
8.118 + Object result = invokeMethod(c.getClassName(), c.getMethodName());
8.119 +
8.120 + setAttr("bck2brwsr.fragment", "innerHTML", "");
8.121 + log("Result: " + result);
8.122 +
8.123 + result = encodeURL("" + result);
8.124 +
8.125 + log("Sending back: " + url + "?request=" + c.getRequestId() + "&result=" + result);
8.126 + String u = url + "?request=" + c.getRequestId() + "&result=" + result;
8.127 +
8.128 + loadText(u, this, arr);
8.129 +
8.130 + } catch (Exception ex) {
8.131 + log(ex.getMessage());
8.132 + }
8.133 + }
8.134 + }
8.135 +
8.136 + private static String encodeURL(String r) {
8.137 + StringBuilder sb = new StringBuilder();
8.138 + for (int i = 0; i < r.length(); i++) {
8.139 + int ch = r.charAt(i);
8.140 + if (ch < 32 || ch == '%' || ch == '+') {
8.141 + sb.append("%").append(("0" + Integer.toHexString(ch)).substring(0, 2));
8.142 + } else {
8.143 + if (ch == 32) {
8.144 + sb.append("+");
8.145 + } else {
8.146 + sb.append((char)ch);
8.147 + }
8.148 + }
8.149 + }
8.150 + return sb.toString();
8.151 + }
8.152 +
8.153 + static String invoke(String clazz, String method) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException {
8.154 + final Object r = invokeMethod(clazz, method);
8.155 + return r == null ? "null" : r.toString().toString();
8.156 + }
8.157 +
8.158 + /** Helper method that inspects the classpath and loads given resource
8.159 + * (usually a class file). Used while running tests in Rhino.
8.160 + *
8.161 + * @param name resource name to find
8.162 + * @return the array of bytes in the given resource
8.163 + * @throws IOException I/O in case something goes wrong
8.164 + */
8.165 + public static byte[] read(String name) throws IOException {
8.166 + URL u = null;
8.167 + Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
8.168 + while (en.hasMoreElements()) {
8.169 + u = en.nextElement();
8.170 + }
8.171 + if (u == null) {
8.172 + throw new IOException("Can't find " + name);
8.173 + }
8.174 + try (InputStream is = u.openStream()) {
8.175 + byte[] arr;
8.176 + arr = new byte[is.available()];
8.177 + int offset = 0;
8.178 + while (offset < arr.length) {
8.179 + int len = is.read(arr, offset, arr.length - offset);
8.180 + if (len == -1) {
8.181 + throw new IOException("Can't read " + name);
8.182 + }
8.183 + offset += len;
8.184 + }
8.185 + return arr;
8.186 + }
8.187 + }
8.188 +
8.189 + private static Object invokeMethod(String clazz, String method)
8.190 + throws ClassNotFoundException, InvocationTargetException,
8.191 + SecurityException, IllegalAccessException, IllegalArgumentException,
8.192 + InstantiationException {
8.193 + Method found = null;
8.194 + Class<?> c = Class.forName(clazz);
8.195 + for (Method m : c.getMethods()) {
8.196 + if (m.getName().equals(method)) {
8.197 + found = m;
8.198 + }
8.199 + }
8.200 + Object res;
8.201 + if (found != null) {
8.202 + try {
8.203 + if ((found.getModifiers() & Modifier.STATIC) != 0) {
8.204 + res = found.invoke(null);
8.205 + } else {
8.206 + res = found.invoke(c.newInstance());
8.207 + }
8.208 + } catch (Throwable ex) {
8.209 + res = ex.getClass().getName() + ":" + ex.getMessage();
8.210 + }
8.211 + } else {
8.212 + res = "Can't find method " + method + " in " + clazz;
8.213 + }
8.214 + return res;
8.215 + }
8.216 +
8.217 + @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
8.218 + private static void turnAssetionStatusOn() {
8.219 + }
8.220 +
8.221 + private static final class Case {
8.222 + private final Object data;
8.223 +
8.224 + private Case(Object data) {
8.225 + this.data = data;
8.226 + }
8.227 +
8.228 + public static Case parseData(String s) {
8.229 + return new Case(toJSON(s));
8.230 + }
8.231 +
8.232 + public String getMethodName() {
8.233 + return value("methodName", data);
8.234 + }
8.235 +
8.236 + public String getClassName() {
8.237 + return value("className", data);
8.238 + }
8.239 +
8.240 + public String getRequestId() {
8.241 + return value("request", data);
8.242 + }
8.243 +
8.244 + public String getHtmlFragment() {
8.245 + return value("html", data);
8.246 + }
8.247 +
8.248 + @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');")
8.249 + private static native Object toJSON(String s);
8.250 +
8.251 + @JavaScriptBody(args = {"p", "d"}, body =
8.252 + "var v = d[p];\n"
8.253 + + "if (typeof v === 'undefined') return null;\n"
8.254 + + "return v.toString();"
8.255 + )
8.256 + private static native String value(String p, Object d);
8.257 + }
8.258 +}
9.1 --- a/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Thu Jan 31 16:13:04 2013 +0100
9.2 +++ b/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Thu Jan 31 16:58:27 2013 +0100
9.3 @@ -34,7 +34,7 @@
9.4 <div id="bck2brwsr.fragment"/>
9.5
9.6 <script type="text/javascript">
9.7 - vm.loadClass('org.apidesign.bck2brwsr.launcher.Console').harness__VLjava_lang_String_2('$U/../data');
9.8 + vm.loadClass('org.apidesign.bck2brwsr.launcher.impl.Console').harness__VLjava_lang_String_2('$U/../data');
9.9 </script>
9.10 </body>
9.11 </html>
10.1 --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Thu Jan 31 16:13:04 2013 +0100
10.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Thu Jan 31 16:58:27 2013 +0100
10.3 @@ -24,7 +24,7 @@
10.4 import java.lang.reflect.InvocationTargetException;
10.5 import java.lang.reflect.Method;
10.6 import org.apidesign.bck2brwsr.launcher.Launcher;
10.7 -import org.apidesign.bck2brwsr.launcher.MethodInvocation;
10.8 +import org.apidesign.bck2brwsr.launcher.InvocationContext;
10.9 import org.testng.ITest;
10.10 import org.testng.annotations.Test;
10.11
10.12 @@ -51,8 +51,11 @@
10.13 @Test(groups = "run")
10.14 public void executeCode() throws Throwable {
10.15 if (l != null) {
10.16 - MethodInvocation c = l.invokeMethod(m.getDeclaringClass(), m.getName(), html);
10.17 - String res = c.toString();
10.18 + InvocationContext c = l.createInvocation(m.getDeclaringClass(), m.getName());
10.19 + if (html != null) {
10.20 + c.setHtmlFragment(html);
10.21 + }
10.22 + String res = c.invoke();
10.23 value = res;
10.24 if (fail) {
10.25 int idx = res.indexOf(':');