1.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Tue Jan 22 18:07:23 2013 +0100
1.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Tue Jan 22 19:16:38 2013 +0100
1.3 @@ -55,7 +55,7 @@
1.4 */
1.5 final class Bck2BrwsrLauncher extends Launcher implements Closeable {
1.6 private static final Logger LOG = Logger.getLogger(Bck2BrwsrLauncher.class.getName());
1.7 - private static final MethodInvocation END = new MethodInvocation(null, null);
1.8 + private static final MethodInvocation END = new MethodInvocation(null, null, null);
1.9 private Set<ClassLoader> loaders = new LinkedHashSet<>();
1.10 private BlockingQueue<MethodInvocation> methods = new LinkedBlockingQueue<>();
1.11 private long timeOut;
1.12 @@ -70,9 +70,9 @@
1.13 }
1.14
1.15 @Override
1.16 - public MethodInvocation addMethod(Class<?> clazz, String method) throws IOException {
1.17 + MethodInvocation addMethod(Class<?> clazz, String method, String html) throws IOException {
1.18 loaders.add(clazz.getClassLoader());
1.19 - MethodInvocation c = new MethodInvocation(clazz.getName(), method);
1.20 + MethodInvocation c = new MethodInvocation(clazz.getName(), method, html);
1.21 methods.add(c);
1.22 try {
1.23 c.await(timeOut);
1.24 @@ -174,7 +174,13 @@
1.25 + "className: '" + cn + "', "
1.26 + "methodName: '" + mn + "', "
1.27 + "request: " + cnt
1.28 - + "}");
1.29 + );
1.30 + if (mi.html != null) {
1.31 + response.getWriter().write(", html: '");
1.32 + response.getWriter().write(encodeJSON(mi.html));
1.33 + response.getWriter().write("'");
1.34 + }
1.35 + response.getWriter().write("}");
1.36 cnt++;
1.37 }
1.38 }, "/data");
1.39 @@ -182,6 +188,22 @@
1.40 this.brwsr = launchServerAndBrwsr(server, "/execute");
1.41 }
1.42
1.43 + private static String encodeJSON(String in) {
1.44 + StringBuilder sb = new StringBuilder();
1.45 + for (int i = 0; i < in.length(); i++) {
1.46 + char ch = in.charAt(i);
1.47 + if (ch < 32 || ch == '\'' || ch == '"') {
1.48 + sb.append("\\u");
1.49 + String hs = "0000" + Integer.toHexString(ch);
1.50 + hs = hs.substring(hs.length() - 4);
1.51 + sb.append(hs);
1.52 + } else {
1.53 + sb.append(ch);
1.54 + }
1.55 + }
1.56 + return sb.toString();
1.57 + }
1.58 +
1.59 @Override
1.60 public void shutdown() throws IOException {
1.61 methods.offer(END);
1.62 @@ -348,7 +370,7 @@
1.63 public Page(Res res, String resource, String... args) {
1.64 this.res = res;
1.65 this.resource = resource;
1.66 - this.args = args;
1.67 + this.args = args.length == 0 ? new String[] { "$0" } : args;
1.68 }
1.69
1.70 @Override
2.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Console.java Tue Jan 22 18:07:23 2013 +0100
2.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Console.java Tue Jan 22 19:16:38 2013 +0100
2.3 @@ -53,7 +53,7 @@
2.4 private static native void closeWindow();
2.5
2.6 private static void log(String newText) {
2.7 - String id = "result";
2.8 + String id = "bck2brwsr.result";
2.9 String attr = "value";
2.10 setAttr(id, attr, getAttr(id, attr) + "\n" + newText);
2.11 setAttr(id, "scrollTop", getAttr(id, "scrollHeight"));
2.12 @@ -63,7 +63,7 @@
2.13 String clazz = (String) getAttr("clazz", "value");
2.14 String method = (String) getAttr("method", "value");
2.15 Object res = invokeMethod(clazz, method);
2.16 - setAttr("result", "value", res);
2.17 + setAttr("bck2brwsr.result", "value", res);
2.18 }
2.19
2.20 @JavaScriptBody(args = { "url", "callback", "arr" }, body = ""
2.21 @@ -111,10 +111,14 @@
2.22 }
2.23
2.24 Case c = Case.parseData(data);
2.25 + if (c.getHtmlFragment() != null) {
2.26 + setAttr("bck2brwsr.fragment", "innerHTML", c.getHtmlFragment());
2.27 + }
2.28 log("Invoking " + c.getClassName() + '.' + c.getMethodName() + " as request: " + c.getRequestId());
2.29
2.30 Object result = invokeMethod(c.getClassName(), c.getMethodName());
2.31
2.32 + setAttr("bck2brwsr.fragment", "innerHTML", "");
2.33 log("Result: " + result);
2.34
2.35 result = encodeURL("" + result);
2.36 @@ -237,11 +241,19 @@
2.37 public String getRequestId() {
2.38 return value("request", data);
2.39 }
2.40 +
2.41 + public String getHtmlFragment() {
2.42 + return value("html", data);
2.43 + }
2.44
2.45 @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');")
2.46 private static native Object toJSON(String s);
2.47
2.48 - @JavaScriptBody(args = {"p", "d"}, body = "return d[p].toString();")
2.49 + @JavaScriptBody(args = {"p", "d"}, body =
2.50 + "var v = d[p];\n"
2.51 + + "if (typeof v === 'undefined') return null;\n"
2.52 + + "return v.toString();"
2.53 + )
2.54 private static native String value(String p, Object d);
2.55 }
2.56 }
3.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Tue Jan 22 18:07:23 2013 +0100
3.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Tue Jan 22 19:16:38 2013 +0100
3.3 @@ -42,10 +42,9 @@
3.4 private Object console;
3.5
3.6
3.7 - @Override
3.8 - public MethodInvocation addMethod(Class<?> clazz, String method) {
3.9 + @Override MethodInvocation addMethod(Class<?> clazz, String method, String html) {
3.10 loaders.add(clazz.getClassLoader());
3.11 - MethodInvocation mi = new MethodInvocation(clazz.getName(), method);
3.12 + MethodInvocation mi = new MethodInvocation(clazz.getName(), method, html);
3.13 try {
3.14 mi.result(code.invokeMethod(
3.15 console,
4.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Tue Jan 22 18:07:23 2013 +0100
4.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Tue Jan 22 19:16:38 2013 +0100
4.3 @@ -32,12 +32,12 @@
4.4 Launcher() {
4.5 }
4.6
4.7 - abstract MethodInvocation addMethod(Class<?> clazz, String method) throws IOException;
4.8 + abstract MethodInvocation addMethod(Class<?> clazz, String method, String html) throws IOException;
4.9
4.10 public abstract void initialize() throws IOException;
4.11 public abstract void shutdown() throws IOException;
4.12 - public MethodInvocation invokeMethod(Class<?> clazz, String method) throws IOException {
4.13 - return addMethod(clazz, method);
4.14 + public MethodInvocation invokeMethod(Class<?> clazz, String method, String html) throws IOException {
4.15 + return addMethod(clazz, method, html);
4.16 }
4.17
4.18
5.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/MethodInvocation.java Tue Jan 22 18:07:23 2013 +0100
5.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/MethodInvocation.java Tue Jan 22 19:16:38 2013 +0100
5.3 @@ -28,12 +28,14 @@
5.4 final CountDownLatch wait = new CountDownLatch(1);
5.5 final String className;
5.6 final String methodName;
5.7 + final String html;
5.8 private String result;
5.9 private Throwable exception;
5.10
5.11 - MethodInvocation(String className, String methodName) {
5.12 + MethodInvocation(String className, String methodName, String html) {
5.13 this.className = className;
5.14 this.methodName = methodName;
5.15 + this.html = html;
5.16 }
5.17
5.18 void await(long timeOut) throws InterruptedException {
6.1 --- a/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Tue Jan 22 18:07:23 2013 +0100
6.2 +++ b/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Tue Jan 22 19:16:38 2013 +0100
6.3 @@ -27,10 +27,12 @@
6.4 <script src="/bck2brwsr.js"></script>
6.5 <script src="/vm.js"></script>
6.6
6.7 - <h1>Bck2Browser Execution Harness</h1>
6.8 + <h1>Bck2Brwsr Execution Harness</h1>
6.9
6.10 - <textarea id="result" rows="25" style="width: 100%;" disabled="">
6.11 + <textarea id="bck2brwsr.result" rows="25" style="width: 100%;" disabled="">
6.12 </textarea>
6.13 +
6.14 + <div id="bck2brwsr.fragment"/>
6.15
6.16 <script type="text/javascript">
6.17 vm.loadClass('org.apidesign.bck2brwsr.launcher.Console').harness__VLjava_lang_String_2('$U/../data');
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/HtmlFragment.java Tue Jan 22 19:16:38 2013 +0100
7.3 @@ -0,0 +1,38 @@
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.vmtest;
7.22 +
7.23 +import java.lang.annotation.ElementType;
7.24 +import java.lang.annotation.Retention;
7.25 +import java.lang.annotation.RetentionPolicy;
7.26 +import java.lang.annotation.Target;
7.27 +
7.28 +/** Allows to specify an HTML fragment for a given {@link BrwsrTest}.
7.29 + * Apply either to the method or to enclosing class. The fragment will be
7.30 + * made available in the page that executes given test. Its elements shall
7.31 + * be regularly accessible from the test.
7.32 + *
7.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
7.34 + */
7.35 +@Retention(RetentionPolicy.RUNTIME)
7.36 +@Target({ ElementType.METHOD, ElementType.TYPE})
7.37 +public @interface HtmlFragment {
7.38 + /** HTML code fragment to be exposed on the testing page.
7.39 + */
7.40 + String value();
7.41 +}
8.1 --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Tue Jan 22 18:07:23 2013 +0100
8.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Tue Jan 22 19:16:38 2013 +0100
8.3 @@ -40,20 +40,20 @@
8.4 private final String type;
8.5 private final boolean fail;
8.6 Object value;
8.7 - private static final Map<Class, Object[]> compiled = new WeakHashMap<>();
8.8 - private Object inst;
8.9 + private final String html;
8.10
8.11 - Bck2BrwsrCase(Method m, String type, Launcher l, boolean fail) {
8.12 + Bck2BrwsrCase(Method m, String type, Launcher l, boolean fail, String html) {
8.13 this.l = l;
8.14 this.m = m;
8.15 this.type = type;
8.16 this.fail = fail;
8.17 + this.html = html;
8.18 }
8.19
8.20 @Test(groups = "run")
8.21 public void executeCode() throws Throwable {
8.22 if (l != null) {
8.23 - MethodInvocation c = l.invokeMethod(m.getDeclaringClass(), m.getName());
8.24 + MethodInvocation c = l.invokeMethod(m.getDeclaringClass(), m.getName(), html);
8.25 String res = c.toString();
8.26 value = res;
8.27 if (fail) {
9.1 --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Tue Jan 22 18:07:23 2013 +0100
9.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Tue Jan 22 19:16:38 2013 +0100
9.3 @@ -111,15 +111,15 @@
9.4 if (c == null) {
9.5 return;
9.6 }
9.7 - final Bck2BrwsrCase real = new Bck2BrwsrCase(m, "Java", null, false);
9.8 - final Bck2BrwsrCase js = new Bck2BrwsrCase(m, "JavaScript", l.javaScript(), false);
9.9 + final Bck2BrwsrCase real = new Bck2BrwsrCase(m, "Java", null, false, null);
9.10 + final Bck2BrwsrCase js = new Bck2BrwsrCase(m, "JavaScript", l.javaScript(), false, null);
9.11 ret.add(real);
9.12 ret.add(js);
9.13 ret.add(new CompareCase(m, real, js));
9.14 for (String b : brwsr) {
9.15 final Launcher s = l.brwsr(b);
9.16 ret.add(s);
9.17 - final Bck2BrwsrCase cse = new Bck2BrwsrCase(m, b, s, false);
9.18 + final Bck2BrwsrCase cse = new Bck2BrwsrCase(m, b, s, false, null);
9.19 ret.add(cse);
9.20 ret.add(new CompareCase(m, real, cse));
9.21 }
9.22 @@ -129,15 +129,20 @@
9.23 if (c == null) {
9.24 return;
9.25 }
9.26 + HtmlFragment f = m.getAnnotation(HtmlFragment.class);
9.27 + if (f == null) {
9.28 + f = m.getDeclaringClass().getAnnotation(HtmlFragment.class);
9.29 + }
9.30 + String html = f == null ? null : f.value();
9.31 if (brwsr.length == 0) {
9.32 final Launcher s = l.brwsr(null);
9.33 ret.add(s);
9.34 - ret.add(new Bck2BrwsrCase(m, "Brwsr", s, true));
9.35 + ret.add(new Bck2BrwsrCase(m, "Brwsr", s, true, html));
9.36 } else {
9.37 for (String b : brwsr) {
9.38 final Launcher s = l.brwsr(b);
9.39 ret.add(s);
9.40 - ret.add(new Bck2BrwsrCase(m, b, s, true));
9.41 + ret.add(new Bck2BrwsrCase(m, b, s, true, html));
9.42 }
9.43 }
9.44 }
10.1 --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java Tue Jan 22 18:07:23 2013 +0100
10.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java Tue Jan 22 19:16:38 2013 +0100
10.3 @@ -19,6 +19,7 @@
10.4
10.5 import org.apidesign.bck2brwsr.core.JavaScriptBody;
10.6 import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
10.7 +import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
10.8 import org.apidesign.bck2brwsr.vmtest.VMTest;
10.9 import org.testng.annotations.Factory;
10.10
10.11 @@ -27,17 +28,30 @@
10.12 * @author Jaroslav Tulach <jtulach@netbeans.org>
10.13 */
10.14 public class BrwsrCheckTest {
10.15 -
10.16 +
10.17 @BrwsrTest public void assertWindowObjectIsDefined() {
10.18 assert window() != null : "No window object found!";
10.19 }
10.20 +
10.21 +
10.22 +
10.23 +
10.24 + @HtmlFragment("<h1 id='hello'>\n"
10.25 + + "Hello!\n"
10.26 + + "</h1>\n")
10.27 + @BrwsrTest public void accessProvidedFragment() {
10.28 + assert getElementById("hello") != null : "Element with 'hello' ID found";
10.29 + }
10.30
10.31 @Factory
10.32 public static Object[] create() {
10.33 return VMTest.create(BrwsrCheckTest.class);
10.34 }
10.35 +
10.36
10.37 @JavaScriptBody(args = {}, body = "return window;")
10.38 private static native Object window();
10.39 -
10.40 +
10.41 + @JavaScriptBody(args = { "id" }, body = "return window.document.getElementById(id);")
10.42 + private static native Object getElementById(String id);
10.43 }