# HG changeset patch # User Jaroslav Tulach # Date 1401821796 -7200 # Node ID a61fd3f48997cf0dc7be67593bcf2dd3fc077084 # Parent 8ba1935e4b0803e6c0d643029ba5a1bf30c163fc Proper presenter that is using javax.script API JavaScript engine diff -r 8ba1935e4b08 -r a61fd3f48997 boot-script/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-script/pom.xml Tue Jun 03 20:56:36 2014 +0200 @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.netbeans.html + pom + 1.0-SNAPSHOT + + Presenter via javax.script + net.java.html.boot.script + 1.0-SNAPSHOT + jar + + NONE + + + + org.netbeans.html + net.java.html.boot + ${project.version} + jar + + + org.testng + testng + test + + + org.webjars + envjs + 1.2 + test + + + ${project.groupId} + net.java.html.json.tck + ${project.version} + test + + + \ No newline at end of file diff -r 8ba1935e4b08 -r a61fd3f48997 boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java Tue Jun 03 20:56:36 2014 +0200 @@ -0,0 +1,244 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package net.java.html.boot.script; + +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import org.apidesign.html.boot.spi.Fn; +import org.apidesign.html.boot.spi.Fn.Presenter; + +/** Implementation of {@link Presenter} that delegates + * to Java {@link ScriptEngine scripting} API. The presenter runs headless + * without appropriate simulation of browser APIs. Its primary usefulness + * is inside testing environments. + *

+ * One can load in browser simulation for example from + * env.js. The best way to achieve so, + * is to add dependency on XXX + * + * + * @author Jaroslav Tulach + */ +public final class ScriptPresenter implements Presenter, Fn.FromJavaScript, Fn.ToJavaScript { + private final ScriptEngine eng; + + public ScriptPresenter() { + try { + eng = new ScriptEngineManager().getEngineByName("javascript"); + eng.eval("function alert(msg) { Packages.java.lang.System.out.println(msg); };"); + } catch (ScriptException ex) { + throw new IllegalStateException(ex); + } + } + + @Override + public Fn defineFn(String code, String... names) { + return defineImpl(code, names); + } + private FnImpl defineImpl(String code, String... names) { + StringBuilder sb = new StringBuilder(); + sb.append("(function() {"); + sb.append(" return function("); + String sep = ""; + if (names != null) for (String n : names) { + sb.append(sep).append(n); + sep = ","; + } + sb.append(") {\n"); + sb.append(code); + sb.append("};"); + sb.append("})()"); + + final Object fn; + try { + fn = eng.eval(sb.toString()); + } catch (ScriptException ex) { + throw new IllegalStateException(ex); + } + return new FnImpl(this, fn); + } + + @Override + public void displayPage(URL page, Runnable onPageLoad) { + // not really displaying anything + if (onPageLoad != null) { + onPageLoad.run(); + } + } + + @Override + public void loadScript(Reader code) throws Exception { + eng.eval(code); + } + + // + // array conversions + // + + final Object convertArrays(Object[] arr) throws Exception { + for (int i = 0; i < arr.length; i++) { + if (arr[i] instanceof Object[]) { + arr[i] = convertArrays((Object[]) arr[i]); + } + } + final Object wrapArr = wrapArrFn().invokeImpl(null, false, arr); // NOI18N + return wrapArr; + } + + private FnImpl wrapArrImpl; + private FnImpl wrapArrFn() { + if (wrapArrImpl == null) { + try { + wrapArrImpl = defineImpl("return Array.prototype.slice.call(arguments);"); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + return wrapArrImpl; + } + + final Object checkArray(Object val) throws Exception { + final FnImpl fn = arraySizeFn(); + final Object fnRes = fn.invokeImpl(null, false, val, null); + int length = ((Number) fnRes).intValue(); + if (length == -1) { + return val; + } + Object[] arr = new Object[length]; + fn.invokeImpl(null, false, val, arr); + return arr; + } + private FnImpl arraySize; + private FnImpl arraySizeFn() { + if (arraySize == null) { + try { + arraySize = defineImpl("\n" + + "if (to === null) {\n" + + " if (Object.prototype.toString.call(arr) === '[object Array]') return arr.length;\n" + + " else return -1;\n" + + "} else {\n" + + " var l = arr.length;\n" + + " for (var i = 0; i < l; i++) to[i] = arr[i];\n" + + " return l;\n" + + "}", "arr", "to" + ); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + return arraySize; + } + + @Override + public Object toJava(Object jsArray) { + try { + return checkArray(jsArray); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + + @Override + public Object toJavaScript(Object toReturn) { + if (toReturn instanceof Object[]) { + try { + return convertArrays((Object[])toReturn); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } else { + return toReturn; + } + } + + private class FnImpl extends Fn { + + private final Object fn; + + public FnImpl(Presenter presenter, Object fn) { + super(presenter); + this.fn = fn; + } + + @Override + public Object invoke(Object thiz, Object... args) throws Exception { + return invokeImpl(thiz, true, args); + } + + final Object invokeImpl(Object thiz, boolean arrayChecks, Object... args) throws Exception { + List all = new ArrayList(args.length + 1); + all.add(thiz == null ? fn : thiz); + for (int i = 0; i < args.length; i++) { + if (arrayChecks) { + if (args[i] instanceof Object[]) { + Object[] arr = (Object[]) args[i]; + Object conv = ((ScriptPresenter)presenter()).convertArrays(arr); + args[i] = conv; + } + if (args[i] instanceof Character) { + args[i] = (int)((Character)args[i]); + } + } + all.add(args[i]); + } + Object ret = ((Invocable)eng).invokeMethod(fn, "call", all.toArray()); // NOI18N + if (ret == fn) { + return null; + } + if (!arrayChecks) { + return ret; + } + return ((ScriptPresenter)presenter()).checkArray(ret); + } + } + +} diff -r 8ba1935e4b08 -r a61fd3f48997 boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java Tue Jun 03 20:56:36 2014 +0200 @@ -0,0 +1,117 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package net.java.html.boot.script; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import net.java.html.boot.BrowserBuilder; +import org.apidesign.html.boot.spi.Fn; +import org.apidesign.html.json.tck.KOTest; +import org.testng.Assert; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class Jsr223JavaScriptTest { + private static Class browserClass; + private static Fn.Presenter browserPresenter; + + public Jsr223JavaScriptTest() { + } + + @Factory public static Object[] compatibilityTests() throws Exception { + final BrowserBuilder bb = BrowserBuilder.newBrowser(new ScriptPresenter()). + loadClass(Jsr223JavaScriptTest.class). + loadPage("empty.html"). + invoke("initialized"); + + Executors.newSingleThreadExecutor().submit(new Runnable() { + @Override + public void run() { + bb.showAndWait(); + } + }); + + List res = new ArrayList(); + Class test = + loadClass().getClassLoader().loadClass(KOTest.class.getName()). + asSubclass(Annotation.class); + + Class[] arr = (Class[]) loadClass().getDeclaredMethod("tests").invoke(null); + for (Class c : arr) { + for (Method m : c.getMethods()) { + if (m.getAnnotation(test) != null) { + res.add(new SingleCase(browserPresenter, m)); + } + } + } + return res.toArray(); + } + + static synchronized Class loadClass() throws InterruptedException { + while (browserClass == null) { + Jsr223JavaScriptTest.class.wait(); + } + return browserClass; + } + + public static synchronized void ready(Class browserCls) throws Exception { + browserClass = browserCls; + browserPresenter = Fn.activePresenter(); + Jsr223JavaScriptTest.class.notifyAll(); + } + + public static void initialized() throws Exception { + Assert.assertSame( + Jsr223JavaScriptTest.class.getClassLoader(), + ClassLoader.getSystemClassLoader(), + "No special classloaders" + ); + Jsr223JavaScriptTest.ready(Jsr223JavaScriptTst.class); + } +} diff -r 8ba1935e4b08 -r a61fd3f48997 boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTst.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTst.java Tue Jun 03 20:56:36 2014 +0200 @@ -0,0 +1,55 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package net.java.html.boot.script; + +import org.apidesign.html.json.tck.JavaScriptTCK; + +/** + * + * @author Jaroslav Tulach + */ +public final class Jsr223JavaScriptTst extends JavaScriptTCK { + public static Class[] tests() { + return testClasses(); + } +} diff -r 8ba1935e4b08 -r a61fd3f48997 boot-script/src/test/java/net/java/html/boot/script/SingleCase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-script/src/test/java/net/java/html/boot/script/SingleCase.java Tue Jun 03 20:56:36 2014 +0200 @@ -0,0 +1,127 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package net.java.html.boot.script; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import org.apidesign.html.boot.spi.Fn; +import org.netbeans.html.boot.impl.FnContext; +import org.testng.IHookCallBack; +import org.testng.IHookable; +import org.testng.ITest; +import org.testng.ITestResult; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public final class SingleCase implements ITest, IHookable, Runnable { + private static final Executor JS = Executors.newSingleThreadExecutor(); + private final Fn.Presenter p; + private final Method m; + private Object result; + private Object inst; + + SingleCase(Fn.Presenter p, Method m) { + this.p = p; + this.m = m; + } + + @Override + public String getTestName() { + return m.getName(); + } + + @Test + public synchronized void executeTest() throws Exception { + if (result == null) { + JS.execute(this); + wait(); + } + if (result instanceof Exception) { + throw (Exception)result; + } + if (result instanceof Error) { + throw (Error)result; + } + } + + @Override + public synchronized void run() { + boolean notify = true; + try { + FnContext.currentPresenter(p); + if (inst == null) { + inst = m.getDeclaringClass().newInstance(); + } + result = m.invoke(inst); + if (result == null) { + result = this; + } + } catch (InvocationTargetException ex) { + Throwable r = ex.getTargetException(); + if (r instanceof InterruptedException) { + notify = false; + JS.execute(this); + return; + } + result = r; + } catch (Exception ex) { + result = ex; + } finally { + if (notify) { + notifyAll(); + } + FnContext.currentPresenter(null); + } + } + + @Override + public void run(IHookCallBack ihcb, ITestResult itr) { + ihcb.runTestMethod(itr); + } + +} diff -r 8ba1935e4b08 -r a61fd3f48997 pom.xml --- a/pom.xml Wed May 28 14:50:18 2014 +0200 +++ b/pom.xml Tue Jun 03 20:56:36 2014 +0200 @@ -32,6 +32,7 @@ html4j-maven-plugin ko-osgi-test equinox-agentclass-hook + boot-script