# HG changeset patch # User Jaroslav Tulach # Date 1402322234 -7200 # Node ID a7bf87c2c1d9cc3db2afc6358580b7c9afcada5d # Parent d51a5533a2e777ef542b635feb17903ee19ddf73# Parent f62b42f0b7517d6c016b9309143d37cfd684f0bc Merging work on closure branch which seems to work relatively well diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Thu May 15 11:38:27 2014 +0200 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Mon Jun 09 15:57:14 2014 +0200 @@ -1329,6 +1329,7 @@ return ret; } + @ExtraJavaScript(processByteCode = false, resource = "") private static class Prprt { private final Element e; private final AnnotationMirror tm; diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Canvas.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Canvas.java Thu May 15 11:38:27 2014 +0200 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Canvas.java Mon Jun 09 15:57:14 2014 +0200 @@ -51,7 +51,7 @@ @JavaScriptBody( args = {"el"}, body = "var e = window.document.getElementById(el._id());\n" - + "return e.getContext('2d');\n") + + "return e['getContext']('2d');\n") private native static Object getContextImpl(Canvas el); public GraphicsContext getContext() { diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Thu May 15 11:38:27 2014 +0200 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Mon Jun 09 15:57:14 2014 +0200 @@ -69,7 +69,7 @@ body="var e = window.document.getElementById(this._id());\n" + "e[ev._id()] = function(ev) {\n" + " var d = ev ? ev : null;\n" - + " r.onEvent__VLjava_lang_Object_2(d);\n" + + " r['onEvent__VLjava_lang_Object_2'](d);\n" + "};\n" ) final void on(OnEvent ev, OnHandler r) { diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator-dynamic/nbactions.xml --- a/javaquery/demo-calculator-dynamic/nbactions.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ - - - - - run - - process-classes - bck2brwsr:brwsr - - - diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator-dynamic/pom.xml --- a/javaquery/demo-calculator-dynamic/pom.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ - - - 4.0.0 - - org.apidesign.bck2brwsr - demo.calculator - 0.9-SNAPSHOT - jar - - JavaQuery Demo - Calculator - http://maven.apache.org - - - UTF-8 - - - - - org.apidesign.bck2brwsr - bck2brwsr-maven-plugin - ${project.version} - - - - brwsr - - - - - org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - true - lib/ - - - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.7 - - true - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9 - - true - - - - maven-assembly-plugin - 2.4 - - - distro-assembly - package - - single - - - - src/main/assembly/bck2brwsr.xml - - - - - - - - - - - org.apidesign.bck2brwsr - emul - ${project.version} - rt - - - org.apidesign.bck2brwsr - javaquery.api - ${project.version} - - - org.testng - testng - 6.5.2 - test - - - org.apidesign.bck2brwsr - vm4brwsr - js - zip - ${project.version} - provided - - - diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator-dynamic/src/main/assembly/bck2brwsr.xml --- a/javaquery/demo-calculator-dynamic/src/main/assembly/bck2brwsr.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ - - - - - bck2brwsr - - zip - dir - - public_html - - - false - runtime - lib - - *:jar - *:rt - - - - false - provided - - *:js - - true - / - - - - - ${project.build.directory}/${project.build.finalName}.jar - / - - - ${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml - / - index.xhtml - - - - \ No newline at end of file diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java --- a/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,146 +0,0 @@ -/** - * Back 2 Browser Bytecode Translator - * Copyright (C) 2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -package org.apidesign.bck2brwsr.demo.calc; - -import java.util.List; -import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; -import org.apidesign.bck2brwsr.htmlpage.api.On; -import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; -import org.apidesign.bck2brwsr.htmlpage.api.OnFunction; -import org.apidesign.bck2brwsr.htmlpage.api.Page; -import org.apidesign.bck2brwsr.htmlpage.api.Property; - -/** HTML5 & Java demo showing the power of - * annotation processors - * as well as other goodies. - * - * @author Jaroslav Tulach - */ -@Page(xhtml="Calculator.xhtml", properties = { - @Property(name = "memory", type = double.class), - @Property(name = "display", type = double.class), - @Property(name = "operation", type = String.class), - @Property(name = "hover", type = boolean.class), - @Property(name = "history", type = HistoryImpl.class, array = true) -}) -public class Calc { - static { - new Calculator().applyBindings().setOperation("plus"); - } - - @On(event = CLICK, id="clear") - static void clear(Calculator c) { - c.setMemory(0); - c.setOperation(null); - c.setDisplay(0); - } - - @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) - static void applyOp(Calculator c, String id) { - c.setMemory(c.getDisplay()); - c.setOperation(id); - c.setDisplay(0); - } - - @On(event = MOUSE_OVER, id= { "result" }) - static void attemptingIn(Calculator c) { - c.setHover(true); - } - @On(event = MOUSE_OUT, id= { "result" }) - static void attemptingOut(Calculator c) { - c.setHover(false); - } - - @On(event = CLICK, id="result") - static void computeTheValue(Calculator c) { - final double newValue = compute( - c.getOperation(), - c.getMemory(), - c.getDisplay() - ); - c.setDisplay(newValue); - if (!containsValue(c.getHistory(), newValue)) { - History h = new History(); - h.setValue(newValue); - h.setOperation(c.getOperation()); - c.getHistory().add(h); - } - c.setMemory(0); - } - - @OnFunction - static void recoverMemory(Calculator c, History data) { - c.setDisplay(data.getValue()); - } - - @OnFunction - static void removeMemory(Calculator c, History data) { - c.getHistory().remove(data); - } - - private static double compute(String op, double memory, double display) { - switch (op) { - case "plus": return memory + display; - case "minus": return memory - display; - case "mul": return memory * display; - case "div": return memory / display; - default: throw new IllegalStateException(op); - } - } - - @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) - static void addDigit(String id, Calculator c) { - id = id.substring(1); - - double v = c.getDisplay(); - if (v == 0.0) { - c.setDisplay(Integer.parseInt(id)); - } else { - String txt = Double.toString(v); - if (txt.endsWith(".0")) { - txt = txt.substring(0, txt.length() - 2); - } - txt = txt + id; - c.setDisplay(Double.parseDouble(txt)); - } - } - - @ComputedProperty - public static String displayPreview( - double display, boolean hover, double memory, String operation - ) { - if (!hover) { - return "Type numbers and perform simple operations! Press '=' to get result."; - } - return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display); - } - - @ComputedProperty - static boolean emptyHistory(List history) { - return history.isEmpty(); - } - - private static boolean containsValue(List arr, final double newValue) { - for (History history : arr) { - if (history.getValue() == newValue) { - return true; - } - } - return false; - } -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/HistoryImpl.java --- a/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/HistoryImpl.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/** - * Back 2 Browser Bytecode Translator - * Copyright (C) 2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -package org.apidesign.bck2brwsr.demo.calc; - -import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; -import org.apidesign.bck2brwsr.htmlpage.api.Model; -import org.apidesign.bck2brwsr.htmlpage.api.OnFunction; -import org.apidesign.bck2brwsr.htmlpage.api.Property; - -/** - * - * @author Jaroslav Tulach - */ -@Model(className = "History", properties = { - @Property(name = "value", type = double.class), - @Property(name = "operation", type = String.class) -}) -public class HistoryImpl { - @ComputedProperty - static String resultOf(String operation) { - return "result of " + operation; - } - - @OnFunction - static void twice(History data) { - data.setValue(2.0 * data.getValue()); - } -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml --- a/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ - - - - - - Simple Calculator in HTML5 and Java - - - - -

Java and HTML5 - Together at Last!

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- -

Previous Results

- -
No results yet.
- - - - - -
- - diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator-dynamic/src/test/java/org/apidesign/bck2brwsr/demo/calc/CalcTest.java --- a/javaquery/demo-calculator-dynamic/src/test/java/org/apidesign/bck2brwsr/demo/calc/CalcTest.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/** - * Back 2 Browser Bytecode Translator - * Copyright (C) 2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -package org.apidesign.bck2brwsr.demo.calc; - -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** Demonstrating POJO testing of HTML page model. - * - * @author Jaroslav Tulach - */ -public class CalcTest { - private Calculator model; - - - @BeforeMethod - public void initModel() { - model = new Calculator().applyBindings(); - } - - @Test - public void testSomeMethod() { - model.setDisplay(10); - Calc.applyOp(model, "plus"); - assertEquals(0.0, model.getDisplay(), "Cleared after pressing +"); - model.setDisplay(5); - Calc.computeTheValue(model); - assertEquals(15.0, model.getDisplay(), "Shows fifteen"); - } -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator/nbactions.xml --- a/javaquery/demo-calculator/nbactions.xml Thu May 15 11:38:27 2014 +0200 +++ b/javaquery/demo-calculator/nbactions.xml Mon Jun 09 15:57:14 2014 +0200 @@ -23,10 +23,11 @@ run package - bck2brwsr:brwsr + bck2brwsr:show true + NONE diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator/pom.xml --- a/javaquery/demo-calculator/pom.xml Thu May 15 11:38:27 2014 +0200 +++ b/javaquery/demo-calculator/pom.xml Mon Jun 09 15:57:14 2014 +0200 @@ -12,7 +12,8 @@ UTF-8 - MINIMAL + FULL + NONE @@ -23,16 +24,19 @@ - j2js - brwsr + aot + show ${project.build.directory}/${project.build.finalName}-bck2brwsr/public_html/ index.xhtml - ${project.build.directory}/bck2brwsr.js + ${project.build.directory}/calculator.js ${bck2brwsr.obfuscationlevel} + + org/apidesign/bck2brwsr/demo/calc/staticcompilation/ + diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml --- a/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Thu May 15 11:38:27 2014 +0200 +++ b/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Mon Jun 09 15:57:14 2014 +0200 @@ -27,27 +27,19 @@ dir public_html - - - false - runtime - lib - - *:jar - *:rt - - - + + + ${project.build.directory} + / + + bck2brwsr.js + calculator.js + lib/*.js + + + - ${project.build.directory}/${project.build.finalName}.jar - / - - - ${project.build.directory}/bck2brwsr.js - / - - ${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml / index.xhtml diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java --- a/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java Thu May 15 11:38:27 2014 +0200 +++ b/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java Mon Jun 09 15:57:14 2014 +0200 @@ -39,7 +39,7 @@ @Property(name = "history", type = double.class, array = true) }) public class Calc { - static { + public static void main(String... args) throws Exception { new Calculator().applyBindings().setOperation("plus"); } diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/package-info.java --- a/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/package-info.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -/** - * Back 2 Browser Bytecode Translator - * Copyright (C) 2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -@Exported -package org.apidesign.bck2brwsr.demo.calc.staticcompilation; - -import org.apidesign.bck2brwsr.core.Exported; diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml --- a/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Thu May 15 11:38:27 2014 +0200 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Mon Jun 09 15:57:14 2014 +0200 @@ -91,8 +91,9 @@
diff -r d51a5533a2e7 -r a7bf87c2c1d9 javaquery/pom.xml --- a/javaquery/pom.xml Thu May 15 11:38:27 2014 +0200 +++ b/javaquery/pom.xml Mon Jun 09 15:57:14 2014 +0200 @@ -14,6 +14,5 @@ api demo-calculator - demo-calculator-dynamic diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype-test/pom.xml --- a/ko/archetype-test/pom.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ - - - 4.0.0 - - org.apidesign.bck2brwsr - ko - 0.9-SNAPSHOT - - org.apidesign.bck2brwsr - ko-archetype-test - 0.9-SNAPSHOT - Knockout Bck2Brwsr Archetype Test - http://maven.apache.org - Verifies the Knockout & net.java.html.json archetype behaves properly. - - UTF-8 - - - - ${project.groupId} - knockout4j-archetype - ${project.version} - - - org.testng - testng - test - - - org.apache.maven.shared - maven-verifier - 1.4 - test - - - ${project.groupId} - ko-fx - ${project.version} - provided - - - ${project.groupId} - ko-bck2brwsr - ${project.version} - provided - - - diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/ArchetypeVersionTest.java --- a/ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/ArchetypeVersionTest.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/** - * Back 2 Browser Bytecode Translator - * Copyright (C) 2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -package org.apidesign.bck2brwsr.ko.archetype.test; - -import java.io.IOException; -import java.net.URL; -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import javax.xml.xpath.XPathFactoryConfigurationException; -import org.testng.annotations.Test; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeClass; -import org.w3c.dom.Document; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -/** - * - * @author Jaroslav Tulach - */ -public class ArchetypeVersionTest { - private String version; - - public ArchetypeVersionTest() { - } - - @BeforeClass public void readCurrentVersion() throws Exception { - version = findCurrentVersion(); - assertFalse(version.isEmpty(), "There should be some version string"); - } - - - @Test public void testComparePomDepsVersions() throws Exception { - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); - URL r = l.getResource("archetype-resources/pom.xml"); - assertNotNull(r, "Archetype pom found"); - - final XPathFactory fact = XPathFactory.newInstance(); - XPathExpression xp2 = fact.newXPath().compile( - "//properties/net.java.html.version/text()" - ); - - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream()); - String arch = (String) xp2.evaluate(dom, XPathConstants.STRING); - - int snapshot = arch.indexOf("-SNAPSHOT"); - if (snapshot >= 0) { - arch = arch.substring(0, snapshot); - } - - assertTrue(arch.matches("[0-9\\.]+"), "net.java.html.json version seems valid: " + arch); - } - - @Test public void testCheckLauncher() throws Exception { - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); - URL r = l.getResource("archetype-resources/pom.xml"); - assertNotNull(r, "Archetype pom found"); - - final XPathFactory fact = XPathFactory.newInstance(); - XPathExpression xp2 = fact.newXPath().compile( - "//properties/bck2brwsr.launcher.version/text()" - ); - - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream()); - String arch = (String) xp2.evaluate(dom, XPathConstants.STRING); - - assertEquals(arch, version, "launcher dependency is on more recent version"); - } - - @Test public void testCheckBck2Brwsr() throws Exception { - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); - URL r = l.getResource("archetype-resources/pom.xml"); - assertNotNull(r, "Archetype pom found"); - - final XPathFactory fact = XPathFactory.newInstance(); - XPathExpression xp2 = fact.newXPath().compile( - "//properties/bck2brwsr.version/text()" - ); - - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream()); - String arch = (String) xp2.evaluate(dom, XPathConstants.STRING); - - assertEquals(arch, version, "bck2brwsr dependency is on more recent version"); - } - - @Test public void testNbActions() throws Exception { - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); - URL r = l.getResource("archetype-resources/nbactions.xml"); - assertNotNull(r, "Archetype nb file found"); - - final XPathFactory fact = XPathFactory.newInstance(); - XPathExpression xp2 = fact.newXPath().compile( - "//goal/text()" - ); - - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream()); - NodeList goals = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET); - - for (int i = 0; i < goals.getLength(); i++) { - String s = goals.item(i).getTextContent(); - if (s.contains("apidesign")) { - assertFalse(s.matches(".*apidesign.*[0-9].*"), "No numbers: " + s); - } - } - } - - static String findCurrentVersion() throws XPathExpressionException, IOException, ParserConfigurationException, SAXException, XPathFactoryConfigurationException { - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); - URL u = l.getResource("META-INF/maven/org.apidesign.bck2brwsr/knockout4j-archetype/pom.xml"); - assertNotNull(u, "Own pom found: " + System.getProperty("java.class.path")); - - final XPathFactory fact = XPathFactory.newInstance(); - fact.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - - XPathExpression xp = fact.newXPath().compile("project/version/text()"); - - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(u.openStream()); - return xp.evaluate(dom); - } -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/VerifyArchetypeTest.java --- a/ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/VerifyArchetypeTest.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/** - * Back 2 Browser Bytecode Translator - * Copyright (C) 2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -package org.apidesign.bck2brwsr.ko.archetype.test; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import org.apache.maven.it.Verifier; -import org.testng.annotations.Test; -import static org.testng.Assert.*; -import org.testng.reporters.Files; - -/** - * - * @author Jaroslav Tulach - */ -public class VerifyArchetypeTest { - @Test public void fxBrwsrCompiles() throws Exception { - final File dir = new File("target/tests/fxcompile/").getAbsoluteFile(); - generateFromArchetype(dir); - - File created = new File(dir, "o-a-test"); - assertTrue(created.isDirectory(), "Project created"); - assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there"); - - Verifier v = new Verifier(created.getAbsolutePath()); - v.executeGoal("verify"); - - v.verifyErrorFreeLog(); - - for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) { - if (l.contains("j2js")) { - fail("No pre-compilaton:\n" + l); - } - } - - v.verifyTextInLog("org.apidesign.bck2brwsr.launcher.FXBrwsrLauncher"); - v.verifyTextInLog("fxcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-fxbrwsr.zip"); - } - - @Test public void bck2BrwsrCompiles() throws Exception { - final File dir = new File("target/tests/b2bcompile/").getAbsoluteFile(); - generateFromArchetype(dir); - - File created = new File(dir, "o-a-test"); - assertTrue(created.isDirectory(), "Project created"); - assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there"); - - Verifier v = new Verifier(created.getAbsolutePath()); - Properties sysProp = v.getSystemProperties(); - if (Boolean.getBoolean("java.awt.headless")) { - sysProp.put("java.awt.headless", "true"); - } - v.addCliOption("-Pbck2brwsr"); - v.executeGoal("verify"); - - v.verifyErrorFreeLog(); - - // no longer does pre-compilation to JavaScript - // v.verifyTextInLog("j2js"); - // uses Bck2BrwsrLauncher - v.verifyTextInLog("BaseHTTPLauncher showBrwsr"); - // building zip: - v.verifyTextInLog("b2bcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-bck2brwsr.zip"); - - for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) { - if (l.contains("fxbrwsr")) { - fail("No fxbrwsr:\n" + l); - } - } - - File zip = new File(new File(created, "target"), "o-a-test-1.0-SNAPSHOT-bck2brwsr.zip"); - assertTrue(zip.isFile(), "Zip file with website was created"); - - ZipFile zf = new ZipFile(zip); - final ZipEntry index = zf.getEntry("public_html/index.html"); - assertNotNull(index, "index.html found"); - - String txt = readText(zf.getInputStream(index)); - final int beg = txt.indexOf("${"); - if (beg >= 0) { - int end = txt.indexOf("}", beg); - if (end < beg) { - end = txt.length(); - } - fail("No substitutions in index.html. Found: " + txt.substring(beg, end)); - } - } - - private Verifier generateFromArchetype(final File dir, String... params) throws Exception { - Verifier v = new Verifier(dir.getAbsolutePath()); - v.setAutoclean(false); - v.setLogFileName("generate.log"); - v.deleteDirectory(""); - dir.mkdirs(); - Properties sysProp = v.getSystemProperties(); - sysProp.put("groupId", "org.apidesign.test"); - sysProp.put("artifactId", "o-a-test"); - sysProp.put("package", "org.apidesign.test.oat"); - sysProp.put("archetypeGroupId", "org.apidesign.bck2brwsr"); - sysProp.put("archetypeArtifactId", "knockout4j-archetype"); - sysProp.put("archetypeVersion", ArchetypeVersionTest.findCurrentVersion()); - - for (String p : params) { - v.addCliOption(p); - } - v.executeGoal("archetype:generate"); - v.verifyErrorFreeLog(); - return v; - } - - private static String readText(InputStream is) throws IOException { - return Files.readFile(is); - } -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/pom.xml --- a/ko/archetype/pom.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ - - - 4.0.0 - - ko - org.apidesign.bck2brwsr - 0.9-SNAPSHOT - - org.apidesign.bck2brwsr - knockout4j-archetype - 0.9-SNAPSHOT - jar - Knockout Bck2Brwsr Maven Archetype - - HTML page with Knockout.js bindings driven by application model - written in Java. Use your favorite language to code. Use - HTML as a lightweight rendering toolkit. Deploy using JavaFX or - bck2brwsr virtual machine. - - - - - src/main/resources - true - - **/pom.xml - - - - src/main/resources - false - - **/pom.xml - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.6 - 1.6 - - - - org.apache.maven.plugins - maven-resources-plugin - 2.6 - - \ - 1.6 - - - - - diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/java/org/apidesign/bck2brwsr/ko/archetype/package-info.java --- a/ko/archetype/src/main/java/org/apidesign/bck2brwsr/ko/archetype/package-info.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -/** - * Back 2 Browser Bytecode Translator - * Copyright (C) 2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -package org.apidesign.bck2brwsr.ko.archetype; diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml --- a/ko/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ - - - - - - src/main/java - - **/*.java - - - - src/main/webapp/pages - - **/*.xhtml - **/*.html - **/*.css - - - - src/test/java - - **/*Test.java - - - - src/main/assembly - - **/*.xml - - - - - - nbactions*.xml - - - - assembly - - fxbrwsr-assembly.xml - bck2brwsr-assembly.xml - - - - \ No newline at end of file diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/nbactions-bck2brwsr.xml --- a/ko/archetype/src/main/resources/archetype-resources/nbactions-bck2brwsr.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ - - - - run - - package - bck2brwsr:brwsr - - - true - NONE - - - diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/nbactions-fxbrwsr.xml --- a/ko/archetype/src/main/resources/archetype-resources/nbactions-fxbrwsr.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ - - - - run - - process-classes - bck2brwsr:brwsr - - - - debug - - process-classes - bck2brwsr:brwsr - - - maven - - - diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/nbactions.xml --- a/ko/archetype/src/main/resources/archetype-resources/nbactions.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ - - - - run - - process-classes - bck2brwsr:brwsr - - - - debug - - process-classes - bck2brwsr:brwsr - - - maven - - - diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/pom.xml --- a/ko/archetype/src/main/resources/archetype-resources/pom.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,283 +0,0 @@ - - - 4.0.0 - - \${groupId} - \${artifactId} - \${version} - jar - - \${artifactId} - - - - java.net - Java.net - https://maven.java.net/content/repositories/releases/ - - true - - - - netbeans - NetBeans - http://bits.netbeans.org/maven2/ - - - - - java.net - Java.net - https://maven.java.net/content/repositories/releases/ - - true - - - - - - UTF-8 - ${net.java.html.version} - ${project.version} - ${project.version} - MINIMAL - pages/index.html - none - - - - - org.apidesign.bck2brwsr - bck2brwsr-maven-plugin - \${bck2brwsr.launcher.version} - - - - brwsr - - - - - \${basedir}/src/main/webapp/ - ${brwsr.startpage} - ${brwsr} - - - - org.netbeans.html - html4j-maven-plugin - ${net.java.html.version} - - - js-classes - - process-js-annotations - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.14.1 - - - \${brwsr} - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - true - lib/ - - - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.7 - - true - - - - - - - - org.testng - testng - 6.7 - test - - - org.apidesign.bck2brwsr - launcher.http - \${bck2brwsr.launcher.version} - test - - - org.apidesign.bck2brwsr - vmtest - \${bck2brwsr.version} - test - - - org.netbeans.html - net.java.html.json - \${net.java.html.version} - jar - - - org.netbeans.html - net.java.html.boot - \${net.java.html.version} - jar - - - - - fxbrwsr - - true - - - fxbrwsr - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - org.apidesign.bck2brwsr.launcher.FXBrwsrLauncher - true - lib/ - - - \${brwsr.startpage} - - - - - - maven-assembly-plugin - 2.4 - - - distro-assembly - package - - single - - - - src/main/assembly/fxbrwsr.xml - - - - - - - - - - org.netbeans.html - ko4j - \${net.java.html.version} - - - org.apidesign.bck2brwsr - launcher.fx - \${bck2brwsr.launcher.version} - runtime - - - - - bck2brwsr - - - brwsr - bck2brwsr - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - netbeans.ignore.jdk.bootclasspath - - - **/JsInteractionTest* - - - - - maven-assembly-plugin - 2.4 - - - distro-assembly - package - - single - - - - src/main/assembly/bck2brwsr.xml - - - - - - - - - - org.apidesign.bck2brwsr - emul - \${bck2brwsr.version} - rt - - - org.apidesign.bck2brwsr - ko-bck2brwsr - \${bck2brwsr.version} - runtime - - - org.apidesign.bck2brwsr - vm4brwsr - js - zip - \${bck2brwsr.version} - provided - - - - - diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/src/main/assembly/bck2brwsr.xml --- a/ko/archetype/src/main/resources/archetype-resources/src/main/assembly/bck2brwsr.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ - - - - bck2brwsr - - zip - - public_html - - - false - runtime - lib - - *:jar - *:rt - - - - false - provided - - *:js - - true - / - - - - - src/main/webapp/pages - / - true - - - - - ${project.build.directory}/${project.build.finalName}.jar - / - - - \ No newline at end of file diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/src/main/assembly/fxbrwsr.xml --- a/ko/archetype/src/main/resources/archetype-resources/src/main/assembly/fxbrwsr.xml Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ - - - - fxbrwsr - - zip - - ${project.build.finalName}-fxbrwsr - - - false - runtime - lib - - - - - ${project.build.directory}/${project.build.finalName}.jar - / - - - - - src/main/webapp/ - / - - pages/** - - true - - - \ No newline at end of file diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java --- a/ko/archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -package ${package}; - -import net.java.html.json.ComputedProperty; -import net.java.html.json.Function; -import net.java.html.json.Model; -import net.java.html.json.Property; - -/** Model annotation generates class Data with - * one message property, boolean property and read only words property - */ -@Model(className = "Data", properties = { - @Property(name = "message", type = String.class), - @Property(name = "on", type = boolean.class) -}) -final class DataModel { - @ComputedProperty static java.util.List words(String message) { - String[] arr = new String[6]; - String[] words = message == null ? new String[0] : message.split(" ", 6); - for (int i = 0; i < 6; i++) { - arr[i] = words.length > i ? words[i] : "!"; - } - return java.util.Arrays.asList(arr); - } - - @Function static void turnOn(Data model) { - model.setOn(true); - } - - @Function static void turnOff(final Data model) { - confirmByUser("Really turn off?", new Runnable() { - @Override - public void run() { - model.setOn(false); - } - }); - } - - /** Shows direct interaction with JavaScript */ - @net.java.html.js.JavaScriptBody( - args = { "msg", "callback" }, - javacall = true, - body = "alert(msg); callback.@java.lang.Runnable::run()();" - ) - static native void confirmByUser(String msg, Runnable callback); -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/src/main/java/Main.java --- a/ko/archetype/src/main/resources/archetype-resources/src/main/java/Main.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -package ${package}; - -public final class Main { - private Main() { - } - - /** - * Called when the page is ready. - */ - static { - Data d = new Data(); - d.setMessage("Hello World from HTML and Java!"); - d.applyBindings(); - } -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/src/main/webapp/pages/index.html --- a/ko/archetype/src/main/resources/archetype-resources/src/main/webapp/pages/index.html Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ - - - - - - - - - - -

Words Demo

- -
- - - -
- - - -
- - - - diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/src/test/java/DataModelTest.java --- a/ko/archetype/src/main/resources/archetype-resources/src/test/java/DataModelTest.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -package ${package}; - -import static org.testng.Assert.*; -import org.testng.annotations.Test; - -public class DataModelTest { - @Test public void areHelloWorldTwoWords() { - Data model = new Data(); - model.setMessage("Hello World!"); - - java.util.List arr = model.getWords(); - assertEquals(arr.size(), 6, "Six words always"); - assertEquals("Hello", arr.get(0), "Hello is the first word"); - assertEquals("World!", arr.get(1), "World is the second word"); - } -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java --- a/ko/archetype/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -package ${package}; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** Bck2brwsr cares about compatibility with real Java. Whatever API is - * supported by bck2brwsr, it needs to behave the same way as when running - * in HotSpot VM. - *

- * There can be bugs, however. To help us fix them, we kindly ask you to - * write an "inconsistency" test. A test that compares behavior of the API - * between real VM and bck2brwsr VM. This class is skeleton of such test. - */ -public class InconsistencyTest { - /** A method to demonstrate inconsistency between bck2brwsr and HotSpot. - * Make calls to an API that behaves strangely, return some result at - * the end. No need to use any assert. - * - * @return value to compare between HotSpot and bck2brwsr - */ - @Compare - public int checkStringHashCode() throws Exception { - return "Is string hashCode the same?".hashCode(); - } - - /** Factory method that creates a three tests for each method annotated with - * {@link org.apidesign.bck2brwsr.vmtest.Compare}. One executes the code in - * HotSpot, one in Rhino and the last one compares the results. - * - * @see org.apidesign.bck2brwsr.vmtest.VMTest - */ - @Factory - public static Object[] create() { - return VMTest.create(InconsistencyTest.class); - } - -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java --- a/ko/archetype/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -package ${package}; - -import org.apidesign.bck2brwsr.vmtest.BrwsrTest; -import org.apidesign.bck2brwsr.vmtest.HtmlFragment; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** Sometimes it is useful to run tests inside of the real browser. - * To do that just annotate your method with {@link org.apidesign.bck2brwsr.vmtest.BrwsrTest} - * and that is it. If your code references elements on the HTML page, - * you can pass in an {@link org.apidesign.bck2brwsr.vmtest.HtmlFragment} which - * will be made available on the page before your test starts. - */ -public class IntegrationTest { - - /** Write to testing code here. Use assert (but not TestNG's - * Assert, as TestNG is not compiled with target 1.6 yet). - */ - @HtmlFragment( - "

Put this snippet on the HTML page

\n" - ) - @BrwsrTest - public void runThisTestInABrowser() { - } - - @Factory - public static Object[] create() { - return VMTest.create(IntegrationTest.class); - } - -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/archetype/src/main/resources/archetype-resources/src/test/java/JsInteractionTest.java --- a/ko/archetype/src/main/resources/archetype-resources/src/test/java/JsInteractionTest.java Thu May 15 11:38:27 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -package ${package}; - -import java.io.Closeable; -import java.io.Reader; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import javax.script.Invocable; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; -import org.apidesign.html.boot.spi.Fn; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** Tests for behavior of @JavaScriptBody methods. Set your JavaScript - * environment up (for example define alert or use some - * emulation library like env.js), register script presenter - * and then you can call methods that deal with JavaScript in your tests. - */ -public class JsInteractionTest { - private Closeable jsEngine; - @BeforeMethod public void initializeJSEngine() throws Exception { - jsEngine = Fn.activate(new ScriptPresenter()); - } - - @AfterMethod public void shutdownJSEngine() throws Exception { - jsEngine.close(); - } - - @Test public void testCallbackFromJavaScript() throws Exception { - class R implements Runnable { - int called; - - @Override - public void run() { - called++; - } - } - R callback = new R(); - - DataModel.confirmByUser("Hello", callback); - - assertEquals(callback.called, 1, "One immediate callback"); - } - - private static class ScriptPresenter implements Fn.Presenter { - private final ScriptEngine eng; - - public ScriptPresenter() throws ScriptException { - eng = new ScriptEngineManager().getEngineByName("javascript"); - eng.eval("function alert(msg) { Packages.java.lang.System.out.println(msg); };"); - } - - @Override - public Fn defineFn(String code, String... names) { - StringBuilder sb = new StringBuilder(); - sb.append("(function() {"); - sb.append(" return function("); - String sep = ""; - 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 Fn(this) { - @Override - public Object invoke(Object thiz, 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++) { - all.add(args[i]); - } - Object ret = ((Invocable)eng).invokeMethod(fn, "call", all.toArray()); // NOI18N - return fn.equals(ret) ? null : thiz; - } - }; - } - - @Override - public void displayPage(URL page, Runnable onPageLoad) { - // not really displaying anything - onPageLoad.run(); - } - - @Override - public void loadScript(Reader code) throws Exception { - eng.eval(code); - } - } -} diff -r d51a5533a2e7 -r a7bf87c2c1d9 ko/pom.xml --- a/ko/pom.xml Thu May 15 11:38:27 2014 +0200 +++ b/ko/pom.xml Mon Jun 09 15:57:14 2014 +0200 @@ -12,8 +12,6 @@ 0.9-SNAPSHOT - archetype - archetype-test bck2brwsr fx diff -r d51a5533a2e7 -r a7bf87c2c1d9 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java Thu May 15 11:38:27 2014 +0200 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java Mon Jun 09 15:57:14 2014 +0200 @@ -131,10 +131,12 @@ if (!startpage.startsWith("/")) { startpage = "/" + startpage; } - String prefix = ""; - int last = startpage.lastIndexOf('/'); - if (last >= 0) { - prefix = startpage.substring(0, last); + String prefix = null; + if (!new File(dir, "bck2brwsr.js").exists()) { + int last = startpage.lastIndexOf('/'); + if (last >= 0) { + prefix = startpage.substring(0, last); + } } HttpServer s = initServer(dir.getPath(), addClasses, prefix); try { @@ -565,7 +567,7 @@ abstract void generateBck2BrwsrJS(StringBuilder sb, Res loader) throws IOException; abstract String harnessResource(); - String compileJar(JarFile jar) throws IOException { + String compileJar(URL jar) throws IOException { return null; } String compileFromClassPath(URL f, Res loader) throws IOException { @@ -585,8 +587,8 @@ final class Res { private final Set ignore = new HashSet(); - String compileJar(JarFile jar, URL jarURL) throws IOException { - String ret = BaseHTTPLauncher.this.compileJar(jar); + String compileJar(URL jarURL) throws IOException { + String ret = BaseHTTPLauncher.this.compileJar(jarURL); ignore.add(jarURL); return ret; } @@ -748,7 +750,7 @@ response.setCharacterEncoding("UTF-8"); if (url.getProtocol().equals("jar")) { JarURLConnection juc = (JarURLConnection) url.openConnection(); - String s = loader.compileJar(juc.getJarFile(), juc.getJarFileURL()); + String s = loader.compileJar(juc.getJarFileURL()); if (s != null) { Writer w = response.getWriter(); w.append(s); @@ -757,6 +759,15 @@ } } if (url.getProtocol().equals("file")) { + final String filePart = url.getFile(); + if (filePart.endsWith(res)) { + url = new URL( + url.getProtocol(), + url.getHost(), + url.getPort(), + filePart.substring(0, filePart.length() - res.length()) + ); + } String s = loader.compileFromClassPath(url); if (s != null) { Writer w = response.getWriter(); diff -r d51a5533a2e7 -r a7bf87c2c1d9 launcher/http/pom.xml --- a/launcher/http/pom.xml Thu May 15 11:38:27 2014 +0200 +++ b/launcher/http/pom.xml Mon Jun 09 15:57:14 2014 +0200 @@ -67,5 +67,11 @@ ${project.version} test + + org.apidesign.bck2brwsr + aot + 0.9-SNAPSHOT + jar + diff -r d51a5533a2e7 -r a7bf87c2c1d9 launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Thu May 15 11:38:27 2014 +0200 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Mon Jun 09 15:57:14 2014 +0200 @@ -18,16 +18,14 @@ package org.apidesign.bck2brwsr.launcher; import java.io.File; -import java.io.FileReader; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; import java.util.HashSet; import java.util.Set; -import java.util.jar.JarFile; import java.util.logging.Level; /** @@ -48,8 +46,14 @@ } @Override - String compileJar(JarFile jar) throws IOException { - return CompileCP.compileJAR(jar, testClasses); + String compileJar(URL jar) throws IOException { + File f; + try { + f = new File(jar.toURI()); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + return CompileCP.compileJAR(f, testClasses); } @Override @@ -122,7 +126,7 @@ + " args.unshift(ldCls);\n" + " return prevvm.apply(null, args);\n" + " };\n" - + " global.bck2brwsr.registerExtension = prevvm.registerExtension;\n" + + " global.bck2brwsr.register = prevvm.register;\n" + "})(this);\n" ); LOG.log(Level.INFO, "Serving bck2brwsr.js", b2b); diff -r d51a5533a2e7 -r a7bf87c2c1d9 launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java Thu May 15 11:38:27 2014 +0200 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java Mon Jun 09 15:57:14 2014 +0200 @@ -17,25 +17,20 @@ */ package org.apidesign.bck2brwsr.launcher; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.StringWriter; import java.net.JarURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; -import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.zip.ZipEntry; +import org.apidesign.bck2brwsr.aot.Bck2BrwsrJars; import org.apidesign.bck2brwsr.launcher.BaseHTTPLauncher.Res; import org.apidesign.vm4brwsr.Bck2Brwsr; @@ -45,42 +40,12 @@ */ class CompileCP { private static final Logger LOG = Logger.getLogger(CompileCP.class.getName()); - static String compileJAR(final JarFile jar, Set testClasses) + static String compileJAR(final File jar, Set testClasses) throws IOException { - List arr = new ArrayList<>(); - List classes = new ArrayList<>(); - Set exported = new HashSet(); - Set keep = new HashSet(testClasses); - listJAR(jar, classes, arr, exported, keep); - List root = new ArrayList<>(); - for (String c : classes) { - if (keep.contains(c)) { - root.add(c); - continue; - } - int slash = c.lastIndexOf('/'); - String pkg = c.substring(0, slash + 1); - if (exported.contains(pkg)) { - root.add(c); - } - } - StringWriter w = new StringWriter(); try { - class JarRes extends EmulationResources implements Bck2Brwsr.Resources { - @Override - public InputStream get(String resource) throws IOException { - InputStream is = jar.getInputStream(new ZipEntry(resource)); - return is == null ? super.get(resource) : is; - } - } - - Bck2Brwsr.newCompiler() - .addClasses(classes.toArray(new String[0])) - .addRootClasses(root.toArray(new String[0])) - .addResources(arr.toArray(new String[0])) - .library(true) - .resources(new JarRes()) + Bck2BrwsrJars.configureFrom(null, jar) + .addExported(testClasses.toArray(new String[0])) .generate(w); w.flush(); return w.toString(); @@ -100,10 +65,17 @@ } catch (URISyntaxException ex) { throw new IOException(ex); } - for (String s : System.getProperty("java.class.path").split(File.pathSeparator)) { - if (!f.getPath().startsWith(s)) { - continue; + String s = f.isDirectory() ? f.getPath() : null; + + for (String candidate : System.getProperty("java.class.path").split(File.pathSeparator)) { + if (s != null) { + break; } + if (f.getPath().startsWith(candidate)) { + s = candidate; + } + } + if (s != null) { File root = new File(s); List arr = new ArrayList<>(); List classes = new ArrayList<>(); @@ -113,7 +85,8 @@ Bck2Brwsr.newCompiler() .addRootClasses(classes.toArray(new String[0])) .addResources(arr.toArray(new String[0])) - .library(true) + .library() + //.obfuscation(ObfuscationLevel.FULL) .resources(new EmulationResources() { @Override public InputStream get(String resource) throws IOException { @@ -136,56 +109,7 @@ return null; } - private static void listJAR( - JarFile j, List classes, - List resources, Set exported, Set keep - ) throws IOException { - Enumeration en = j.entries(); - while (en.hasMoreElements()) { - JarEntry e = en.nextElement(); - final String n = e.getName(); - if (n.endsWith("/")) { - continue; - } - int last = n.lastIndexOf('/'); - String pkg = n.substring(0, last + 1); - if (skipPkg(pkg)) { - continue; - } - if (n.endsWith(".class")) { - classes.add(n.substring(0, n.length() - 6)); - } else { - resources.add(n); - if (n.startsWith("META-INF/services/") && keep != null) { - BufferedReader r = new BufferedReader(new InputStreamReader(j.getInputStream(e))); - for (;;) { - String l = r.readLine(); - if (l == null) { - break; - } - if (l.startsWith("#")) { - continue; - } - keep.add(l.replace('.', '/')); - } - } - } - } - String exp = j.getManifest().getMainAttributes().getValue("Export-Package"); - if (exp != null && exported != null) { - for (String def : exp.split(",")) { - for (String sep : def.split(";")) { - exported.add(sep.replace('.', '/') + "/"); - break; - } - } - } - } - private static boolean skipPkg(String pkg) { - return pkg.equals("org/apidesign/bck2brwsr/launcher/"); - } - private static void listDir(File f, String pref, List classes, List resources) throws IOException { File[] arr = f.listFiles(); if (arr == null) { @@ -203,21 +127,26 @@ } static void compileVM(StringBuilder sb, final Res r) throws IOException { - List arr = new ArrayList<>(); - List classes = new ArrayList<>(); - - { + final Bck2Brwsr rt; + try { URL u = r.get(InterruptedException.class.getName().replace('.', '/') + ".class", 0); JarURLConnection juc = (JarURLConnection)u.openConnection(); - listJAR(juc.getJarFile(), classes, arr, null, null); + rt = Bck2BrwsrJars.configureFrom(null, new File(juc.getJarFileURL().toURI())); + } catch (URISyntaxException ex) { + throw new IOException(ex); } - { + final Bck2Brwsr all; + try { URL u = r.get(Bck2Brwsr.class.getName().replace('.', '/') + ".class", 0); JarURLConnection juc = (JarURLConnection)u.openConnection(); - listJAR(juc.getJarFile(), classes, arr, null, null); + all = Bck2BrwsrJars.configureFrom(rt, new File(juc.getJarFileURL().toURI())); + } catch (URISyntaxException ex) { + throw new IOException(ex); } - Bck2Brwsr.newCompiler().addRootClasses(classes.toArray(new String[0])) + all + .standalone(true) + //.obfuscation(ObfuscationLevel.FULL) .resources(new Bck2Brwsr.Resources() { @Override public InputStream get(String resource) throws IOException { @@ -231,7 +160,7 @@ @Override public InputStream get(String name) throws IOException { - Enumeration en = CompileCP.class.getClassLoader().getResources(name); + Enumeration en = Bck2BrwsrJars.class.getClassLoader().getResources(name); URL u = null; while (en.hasMoreElements()) { u = en.nextElement(); @@ -241,10 +170,11 @@ return null; } if (u.toExternalForm().contains("/rt.jar!")) { - LOG.warning(name + "No bootdelegation for "); + LOG.log(Level.WARNING, "{0}No bootdelegation for ", name); return null; } return u.openStream(); } } + } diff -r d51a5533a2e7 -r a7bf87c2c1d9 pom.xml --- a/pom.xml Thu May 15 11:38:27 2014 +0200 +++ b/pom.xml Mon Jun 09 15:57:14 2014 +0200 @@ -15,7 +15,7 @@ UTF-8 RELEASE80 COPYING - 0.7.6 + 0.8.1 none diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/aot/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/aot/pom.xml Mon Jun 09 15:57:14 2014 +0200 @@ -0,0 +1,20 @@ + + + 4.0.0 + + org.apidesign.bck2brwsr + rt + 0.9-SNAPSHOT + + Ahead of Time Compilation + aot + jar + + + org.apidesign.bck2brwsr + vm4brwsr + ${project.version} + jar + + + \ No newline at end of file diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/Bck2BrwsrJars.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/aot/src/main/java/org/apidesign/bck2brwsr/aot/Bck2BrwsrJars.java Mon Jun 09 15:57:14 2014 +0200 @@ -0,0 +1,163 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.aot; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import org.apidesign.vm4brwsr.Bck2Brwsr; + +/** Utilities to process JAR files and set a compiler + * up. + * + * @since 0.9 + * @author Jaroslav Tulach + */ +public final class Bck2BrwsrJars { + private static final Logger LOG = Logger.getLogger(Bck2BrwsrJars.class.getName()); + + private Bck2BrwsrJars() { + } + + /** Creates new compiler pre-configured from the content of + * provided JAR file. The compiler will compile all classes. + * The system understands OSGi manifest entries and will export + * all packages that are exported in the JAR file. The system + * also recognizes META-INF/services and makes sure the file names + * are not mangled. + * + * @param c the compiler to {@link Bck2Brwsr#addClasses(java.lang.String...) add classes}, + * {@link Bck2Brwsr#addResources(java.lang.String...) add resources} and + * {@link Bck2Brwsr#addExported(java.lang.String...) exported objects} to. + * Can be null - in such case an + * {@link Bck2Brwsr#newCompiler() empty compiler} is constructed. + * @param jar the file to process + * @return newly configured compiler + * @throws IOException if something goes wrong + */ + public static Bck2Brwsr configureFrom(Bck2Brwsr c, File jar) throws IOException { + final JarFile jf = new JarFile(jar); + List classes = new ArrayList<>(); + List resources = new ArrayList<>(); + Set exported = new HashSet<>(); + + listJAR(jf, classes, resources, exported); + + String cp = jf.getManifest().getMainAttributes().getValue("Class-Path"); // NOI18N + String[] classpath = cp == null ? new String[0] : cp.split(" "); + + class JarRes extends EmulationResources implements Bck2Brwsr.Resources { + + @Override + public InputStream get(String resource) throws IOException { + InputStream is = jf.getInputStream(new ZipEntry(resource)); + return is == null ? super.get(resource) : is; + } + } + return Bck2Brwsr.newCompiler() + .library(classpath) + .addClasses(classes.toArray(new String[classes.size()])) + .addExported(exported.toArray(new String[exported.size()])) + .addResources(resources.toArray(new String[resources.size()])) + .resources(new JarRes()); + } + + private static void listJAR( + JarFile j, List classes, + List resources, Set keep + ) throws IOException { + Enumeration en = j.entries(); + while (en.hasMoreElements()) { + JarEntry e = en.nextElement(); + final String n = e.getName(); + if (n.endsWith("/")) { + continue; + } + if (n.startsWith("META-INF/maven/")) { + continue; + } + int last = n.lastIndexOf('/'); + String pkg = n.substring(0, last + 1); + if (pkg.startsWith("java/")) { + keep.add(pkg); + } + if (n.endsWith(".class")) { + classes.add(n.substring(0, n.length() - 6)); + } else { + resources.add(n); + if (n.startsWith("META-INF/services/") && keep != null) { + BufferedReader r = new BufferedReader(new InputStreamReader(j.getInputStream(e))); + for (;;) { + String l = r.readLine(); + if (l == null) { + break; + } + if (l.startsWith("#")) { + continue; + } + keep.add(l.replace('.', '/')); + } + } + } + } + String exp = j.getManifest().getMainAttributes().getValue("Export-Package"); + if (exp != null && keep != null) { + for (String def : exp.split(",")) { + for (String sep : def.split(";")) { + keep.add(sep.replace('.', '/') + "/"); + break; + } + } + } + } + + static class EmulationResources implements Bck2Brwsr.Resources { + + @Override + public InputStream get(String name) throws IOException { + Enumeration en = Bck2BrwsrJars.class.getClassLoader().getResources(name); + URL u = null; + while (en.hasMoreElements()) { + u = en.nextElement(); + } + if (u == null) { + LOG.log(Level.WARNING, "Cannot find {0}", name); + return null; + } + if (u.toExternalForm().contains("/rt.jar!")) { + LOG.log(Level.WARNING, "{0}No bootdelegation for ", name); + return null; + } + return u.openStream(); + } + } + +} diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Mon Jun 09 15:57:14 2014 +0200 @@ -51,7 +51,11 @@ } } assert different : "Not all manifests should look like first one:\n" + first; - return "" + cnt; + if (cnt > 40 && cnt < 50) { + return "OK"; + } else { + return "" + cnt; + } } @Compare public String readResourceAsStream() throws Exception { diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/emul/mini/src/main/java/java/lang/Boolean.java --- a/rt/emul/mini/src/main/java/java/lang/Boolean.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/emul/mini/src/main/java/java/lang/Boolean.java Mon Jun 09 15:57:14 2014 +0200 @@ -289,8 +289,9 @@ initValueOf(); } @JavaScriptBody(args = { }, body = - "vm.java_lang_Boolean(false)" + - ".valueOf = function() { return this._value() ? true : false; };" + "var bc = vm.java_lang_Boolean(false);\n" + + "bc.valueOf = function() { return this._value() ? true : false; };\n" + + "bc.toString = function() { return this.valueOf().toString(); };\n" ) private native static void initValueOf(); } diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/emul/mini/src/main/java/java/lang/Class.java --- a/rt/emul/mini/src/main/java/java/lang/Class.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java Mon Jun 09 15:57:14 2014 +0200 @@ -34,6 +34,7 @@ import java.lang.reflect.Method; import java.lang.reflect.TypeVariable; import java.net.URL; +import org.apidesign.bck2brwsr.core.Exported; import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.bck2brwsr.core.JavaScriptOnly; import org.apidesign.bck2brwsr.emul.reflect.AnnotationImpl; @@ -238,14 +239,18 @@ } @JavaScriptBody(args = {"n", "c" }, body = - "if (!vm[c]) {\n" - + " if (vm.loadClass) {\n" - + " vm.loadClass(n);\n" + "var m = vm[c];\n" + + "if (!m) {\n" + + " var l = vm.loadClass ? vm.loadClass : exports ? exports.loadClass : null;\n" + + " if (l) {\n" + + " l(n);\n" + " }\n" - + " if (!vm[c]) return null;\n" + + " if (vm[c]) m = vm[c];\n" + + " else if (exports[c]) m = exports[c];\n" + "}\n" - + "vm[c](false);" - + "return vm[c].$class;" + + "if (!m) return null;" + + "m(false);" + + "return m.$class;" ) private static native Class loadCls(String n, String c); @@ -300,9 +305,9 @@ @JavaScriptBody(args = { "self", "illegal" }, body = "\nvar c = self.cnstr;" + "\nif (c['cons__V']) {" - + "\n if ((c.cons__V.access & 0x1) != 0) {" + + "\n if ((c['cons__V'].access & 0x1) != 0) {" + "\n var inst = c();" - + "\n c.cons__V.call(inst);" + + "\n c['cons__V'].call(inst);" + "\n return inst;" + "\n }" + "\n return illegal;" @@ -1739,9 +1744,17 @@ native static Class getPrimitiveClass(String type); @JavaScriptBody(args = {}, body = - "return this.desiredAssertionStatus ? this.desiredAssertionStatus : false;" + "return this['desiredAssertionStatus'] ? this['desiredAssertionStatus'] : false;" ) public native boolean desiredAssertionStatus(); + + public boolean equals(Object obj) { + if (isPrimitive() && obj instanceof Class) { + Class c = ((Class)obj); + return c.isPrimitive() && getName().equals(c.getName()); + } + return super.equals(obj); + } static void registerNatives() { boolean assertsOn = false; @@ -1766,10 +1779,11 @@ ) static native Class classFor(Object self); + @Exported @JavaScriptBody(args = { "self" }, body - = "if (self.$hashCode) return self.$hashCode;\n" - + "var h = self.computeHashCode__I ? self.computeHashCode__I() : Math.random() * Math.pow(2, 31);\n" - + "return self.$hashCode = h & h;" + = "if (self['$hashCode']) return self['$hashCode'];\n" + + "var h = self['computeHashCode__I'] ? self['computeHashCode__I']() : Math.random() * Math.pow(2, 31);\n" + + "return self['$hashCode'] = h & h;" ) static native int defaultHashCode(Object self); @@ -1798,6 +1812,7 @@ ) static native int toJS(); + @Exported @JavaScriptOnly(name = "activate__Ljava_io_Closeable_2Lorg_apidesign_html_boot_spi_Fn$Presenter_2", value = "function() {\n" + " return vm.org_apidesign_bck2brwsr_emul_lang_System(false).activate__Ljava_io_Closeable_2();" + "}\n" @@ -1818,6 +1833,7 @@ @JavaScriptBody(args = {"o"}, body = "return o ? o.toString() : null;") private static native String msg(Object o); + @Exported @JavaScriptOnly(name = "bck2BrwsrThrwrbl", value = "c.bck2BrwsrCnvrt__Ljava_lang_Object_2Ljava_lang_Object_2") private static void bck2BrwsrCnvrtVM() { } diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/emul/mini/src/main/java/java/lang/ClassLoader.java --- a/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Mon Jun 09 15:57:14 2014 +0200 @@ -897,7 +897,8 @@ } @JavaScriptBody(args = { "name", "skip" }, body - = "return (vm.loadBytes) ? vm.loadBytes(name, skip) : null;" + = "var lb = vm.loadBytes ? vm.loadBytes : exports.loadBytes;" + + "return lb ? lb(name, skip) : null;" ) static native byte[] getResourceAsStream0(String name, int skip); diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/emul/mini/src/main/java/java/lang/String.java --- a/rt/emul/mini/src/main/java/java/lang/String.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/emul/mini/src/main/java/java/lang/String.java Mon Jun 09 15:57:14 2014 +0200 @@ -30,6 +30,7 @@ import java.lang.reflect.Method; import java.util.Comparator; import java.util.Locale; +import org.apidesign.bck2brwsr.core.Exported; import org.apidesign.bck2brwsr.core.ExtraJavaScript; import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.bck2brwsr.core.JavaScriptOnly; @@ -1457,7 +1458,7 @@ public int hashCode() { return super.hashCode(); } - int computeHashCode() { + @Exported int computeHashCode() { int h = 0; if (h == 0 && length() > 0) { int off = offset(); diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Mon Jun 09 15:57:14 2014 +0200 @@ -21,6 +21,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Enumeration; +import org.apidesign.bck2brwsr.core.Exported; import org.apidesign.bck2brwsr.core.JavaScriptBody; /** Utilities to work on methods. @@ -126,7 +127,7 @@ } return null; } - + public static Method[] findMethods(Class clazz, int mask) { Object[] namesAndData = findMethodData(clazz, "", false); int cnt = 0; @@ -137,6 +138,11 @@ if (middle == -1) { continue; } + if (sig.startsWith("$") && sig.endsWith("$")) { + // produced by Closure compiler in debug mode + // needs to be ignored + continue; + } String name = sig.substring(0, middle); sig = sig.substring(middle + 2); Class cls = (Class) namesAndData[i + 2]; @@ -152,7 +158,8 @@ } return arr; } - static String toSignature(Method m) { + + @Exported static String toSignature(Method m) { StringBuilder sb = new StringBuilder(); sb.append(m.getName()).append("__"); appendType(sb, m.getReturnType()); @@ -222,9 +229,17 @@ public static Enumeration signatureParser(final String sig) { class E implements Enumeration { int pos; + int len; + + E() { + len = sig.length(); + while (sig.charAt(len - 1) == '$') { + len--; + } + } public boolean hasMoreElements() { - return pos < sig.length(); + return pos < len; } public Class nextElement() { diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/mojo/pom.xml --- a/rt/mojo/pom.xml Thu May 15 11:38:27 2014 +0200 +++ b/rt/mojo/pom.xml Mon Jun 09 15:57:14 2014 +0200 @@ -91,5 +91,11 @@ launcher.fx ${project.version} + + org.apidesign.bck2brwsr + aot + 0.9-SNAPSHOT + jar + diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AheadOfTime.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AheadOfTime.java Mon Jun 09 15:57:14 2014 +0200 @@ -0,0 +1,182 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ + +package org.apidesign.bck2brwsr.mojo; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; +import org.apidesign.bck2brwsr.aot.Bck2BrwsrJars; +import org.apidesign.vm4brwsr.Bck2Brwsr; +import org.apidesign.vm4brwsr.ObfuscationLevel; + +/** + * + * @author Jaroslav Tulach + * @since 0.9 + */ +@Mojo(name = "aot", + requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, + defaultPhase = LifecyclePhase.PACKAGE +) +public class AheadOfTime extends AbstractMojo { + @Parameter(defaultValue = "${project}") + private MavenProject prj; + + @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.jar") + private File mainJar; + + @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.js") + private File mainJavaScript; + + @Parameter + private String[] exports; + + /** + * Directory where to generate ahead-of-time JavaScript files for + * required libraries. + */ + @Parameter(defaultValue = "lib") + private String classPathPrefix; + + /** Root JavaScript file to generate */ + @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js") + private File vm; + + /** + * The obfuscation level for the generated JavaScript file. + * + * @since 0.5 + */ + @Parameter(defaultValue = "NONE") + private ObfuscationLevel obfuscation; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + URLClassLoader loader; + try { + loader = buildClassLoader(mainJar, prj.getArtifacts()); + } catch (MalformedURLException ex) { + throw new MojoFailureException("Can't initialize classloader"); + } + for (Artifact a : prj.getArtifacts()) { + if (a.getFile() == null) { + continue; + } + String n = a.getFile().getName(); + if (!n.endsWith(".jar")) { + continue; + } + if ("provided".equals(a.getScope())) { + continue; + } + File aot = new File(prj.getBuild().getDirectory(), classPathPrefix); + aot.mkdirs(); + File js = new File(aot, n.substring(0, n.length() - 4) + ".js"); + if (js.exists()) { + getLog().info("Skipping " + js + " as it already exists."); + continue; + } + try { + getLog().info("Generating " + js); + aotLibrary(a, js , loader); + } catch (IOException ex) { + throw new MojoFailureException("Can't compile" + a.getFile(), ex); + } + } + + try { + if (mainJavaScript.exists()) { + getLog().info("Skipping " + mainJavaScript + " as it already exists."); + } else { + getLog().info("Generating " + mainJavaScript); + Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, mainJar); + if (exports != null) { + for (String e : exports) { + c = c.addExported(e.replace('.', '/')); + } + } + FileWriter w = new FileWriter(mainJavaScript); + c. + obfuscation(obfuscation). + resources(loader). + generate(w); + w.close(); + } + } catch (IOException ex) { + throw new MojoFailureException("Cannot generate script for " + mainJar, ex); + } + + try { + FileWriter w = new FileWriter(vm); + Bck2Brwsr.newCompiler(). + obfuscation(obfuscation). + standalone(false). + resources(new Bck2Brwsr.Resources() { + + @Override + public InputStream get(String resource) throws IOException { + return null; + } + }). + generate(w); + w.close(); + + } catch (IOException ex) { + throw new MojoExecutionException("Can't compile", ex); + } + } + + private void aotLibrary(Artifact a, File js, URLClassLoader loader) throws IOException { + FileWriter w = new FileWriter(js); + Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, a.getFile()); + c. + obfuscation(obfuscation). + resources(loader). + generate(w); + w.close(); + } + private static URLClassLoader buildClassLoader(File root, Collection deps) throws MalformedURLException { + List arr = new ArrayList(); + if (root != null) { + arr.add(root.toURI().toURL()); + } + for (Artifact a : deps) { + if (a.getFile() != null) { + arr.add(a.getFile().toURI().toURL()); + } + } + return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader()); + } +} diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Mon Jun 09 15:57:14 2014 +0200 @@ -108,12 +108,14 @@ try { URLClassLoader url = buildClassLoader(classes, prj.getArtifacts()); FileWriter w = new FileWriter(javascript); - Bck2Brwsr.newCompiler(). + Bck2Brwsr c = Bck2Brwsr.newCompiler(). obfuscation(obfuscation). - library(library). resources(url, ignoreBootClassPath). - addRootClasses(arr.toArray(new String[0])). - generate(w); + addRootClasses(arr.toArray(new String[0])); + if (library) { + c = c.library(); + } + c.generate(w); w.close(); } catch (IOException ex) { throw new MojoExecutionException("Can't compile", ex); diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/ShowMojo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/ShowMojo.java Mon Jun 09 15:57:14 2014 +0200 @@ -0,0 +1,84 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.mojo; + +import java.io.Closeable; +import org.apache.maven.plugin.AbstractMojo; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.model.Resource; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; +import org.apidesign.bck2brwsr.launcher.Launcher; + +/** Executes given HTML page in a browser. */ +@Mojo( + name="show", + requiresDependencyResolution = ResolutionScope.RUNTIME, + defaultPhase=LifecyclePhase.NONE +) +public class ShowMojo extends AbstractMojo { + public ShowMojo() { + } + + /** The identification of a launcher to use. Known values fxbrwsr, + * bck2brwsr, or + * name of an external process to execute. + */ + @Parameter + private String launcher; + + + /** Resource to show as initial page */ + @Parameter + private String startpage; + + /** Root of all pages, and files, etc. */ + @Parameter + private File directory; + + @Override + public void execute() throws MojoExecutionException { + if (startpage == null) { + throw new MojoExecutionException("You have to provide a start page"); + } + if (directory == null) { + throw new MojoExecutionException("You have to provide a root directory"); + } + try { + Closeable httpServer; + httpServer = Launcher.showDir(launcher, directory, null, startpage); + System.in.read(); + httpServer.close(); + } catch (IOException ex) { + throw new MojoExecutionException("Can't show the browser", ex); + } + } +} diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/pom.xml --- a/rt/pom.xml Thu May 15 11:38:27 2014 +0200 +++ b/rt/pom.xml Mon Jun 09 15:57:14 2014 +0200 @@ -17,5 +17,6 @@ mojo vm vmtest + aot diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Mon Jun 09 15:57:14 2014 +0200 @@ -19,7 +19,6 @@ import java.io.IOException; import java.io.InputStream; -import org.apidesign.bck2brwsr.core.Exported; /** Build your own virtual machine! Use methods in this class to generate * a skeleton JVM in JavaScript that contains pre-compiled classes of your @@ -27,7 +26,7 @@ * be used to bootstrap and load the virtual machine:
  * var vm = bck2brwsr();
  * var main = vm.loadClass('org.your.pkg.Main');
- * main.main__V_3Ljava_lang_String_2(null);
+ * main.invoke('main');
  * 
* In case one wants to initialize the virtual machine with ability to * load classes lazily when needed, one can provide a loader function to @@ -40,33 +39,52 @@ * function is asked for its byte code and the system dynamically transforms * it to JavaScript. *

- * Instead of a loader function, one can also provide a URL to a JAR file. + * Instead of a loader function, one can also provide a URL to a JAR file + * or a library JavaScript file generated with {@link #library(java.lang.String...)} + * option on. * The bck2brwsr system will do its best to download the file - * and provide loader function for it automatically. + * and provide loader function for it automatically. In order to use + * the JAR file emul.zip module needs to be available in the system. *

- * One can provide as many loader functions and JAR URL references as necessary. + * One can provide as many loader functions and URL references as necessary. * Then the initialization code would look like:

  * var vm = bck2brwsr(url1, url2, fnctn1, url3, functn2);
  * 
* The provided URLs and loader functions will be consulted one by one. + *

+ * The initialization of the Bck2Brwsr is done asynchronously since + * version 0.9. E.g. call to

+ * var vm = bck2brwsr('myapp.js');
+ * var main = vm.loadClass('org.your.pkg.Main');
+ * main.invoke('main');
+ * 
+ * returns immediately and the call to the static main method will happen + * once the virtual machine is initialized and the class available. * * @author Jaroslav Tulach */ public final class Bck2Brwsr { private final ObfuscationLevel level; - private final StringArray rootcls; + private final StringArray exported; private final StringArray classes; private final StringArray resources; private final Resources res; - private final boolean extension; + private final Boolean extension; + private final StringArray classpath; - private Bck2Brwsr(ObfuscationLevel level, StringArray rootcls, StringArray classes, StringArray resources, Resources res, boolean extension) { + private Bck2Brwsr( + ObfuscationLevel level, + StringArray exported, StringArray classes, StringArray resources, + Resources res, + Boolean extension, StringArray classpath + ) { this.level = level; - this.rootcls = rootcls; + this.exported = exported; this.classes = classes; this.resources = resources; this.res = res; this.extension = extension; + this.classpath = classpath; } /** Helper method to generate virtual machine from bytes served by a resources @@ -103,7 +121,32 @@ * @since 0.5 */ public static Bck2Brwsr newCompiler() { - return new Bck2Brwsr(ObfuscationLevel.NONE, new StringArray(), new StringArray(), new StringArray(), null, false); + return new Bck2Brwsr( + ObfuscationLevel.NONE, + new StringArray(), new StringArray(), new StringArray(), + null, false, null + ); + } + + /** Adds exported classes or packages. If the string ends + * with slash, it is considered a name of package. If it does not, + * it is a name of a class (without .class suffix). + * The exported classes are prevented from being obfuscated. + * All public classes in exported packages are prevented from + * being obfuscated. By listing the packages or classes in this + * method, these classes are not guaranteed to be included in + * the generated script. Use {@link #addClasses} to include + * the classes. + * + * @param exported names of classes and packages to treat as exported + * @return new instances of the Bck2Brwsr compiler which inherits + * all values from this except list of exported classes + */ + public Bck2Brwsr addExported(String... exported) { + return new Bck2Brwsr( + level, this.exported.addAndNew(exported), + classes, resources, res, extension, classpath + ); } /** Adds additional classes @@ -113,7 +156,7 @@ * generated virtual machine code accessible using their fully * qualified name. This brings the same behavior as if the * classes were added by {@link #addClasses(java.lang.String...) } and - * were annotated with {@link Exported} annotation. + * exported via {@link #addExported(java.lang.String...)}. * * @param classes the classes to add to the compilation * @return new instance of the Bck2Brwsr compiler which inherits @@ -122,10 +165,8 @@ public Bck2Brwsr addRootClasses(String... classes) { if (classes.length == 0) { return this; - } else { - return new Bck2Brwsr(level, rootcls.addAndNew(classes), this.classes, resources, res, - extension); - } + } + return addExported(classes).addClasses(classes); } /** Adds additional classes @@ -143,8 +184,9 @@ if (classes.length == 0) { return this; } else { - return new Bck2Brwsr(level, rootcls, this.classes.addAndNew(classes), resources, res, - extension); + return new Bck2Brwsr(level, exported, + this.classes.addAndNew(classes), resources, res, + extension, classpath); } } @@ -163,8 +205,8 @@ if (resources.length == 0) { return this; } else { - return new Bck2Brwsr(level, rootcls, this.classes, - this.resources.addAndNew(resources), res, extension + return new Bck2Brwsr(level, exported, this.classes, + this.resources.addAndNew(resources), res, extension, classpath ); } } @@ -178,7 +220,7 @@ * @since 0.5 */ public Bck2Brwsr obfuscation(ObfuscationLevel level) { - return new Bck2Brwsr(level, rootcls, classes, resources, res, extension); + return new Bck2Brwsr(level, exported, classes, resources, res, extension, classpath); } /** A way to change the provider of additional resources (classes) for the @@ -190,7 +232,10 @@ * @since 0.5 */ public Bck2Brwsr resources(Resources res) { - return new Bck2Brwsr(level, rootcls, classes, resources, res, extension); + return new Bck2Brwsr( + level, exported, classes, resources, + res, extension, classpath + ); } /** Should one generate a library? By default the system generates @@ -199,13 +244,41 @@ * By turning on the library mode, only classes explicitly listed * will be included in the archive. The others will be referenced * as external ones. + *

+ * A library archive may specify its classpath - e.g. link to + * other libraries that should also be included in the application. + * One can specify the list of libraries as vararg to this method. + * These are relative URL with respect to location of this library. + * The runtime system then prefers seek for ".js" suffix of the library + * and only then seeks for the classical ".jar" path. * - * @param library turn on the library mode? + * @param classpath the array of JARs that are referenced by this library - + * by default gets turned into * @return new instance of the compiler with library flag changed * @since 0.9 */ - public Bck2Brwsr library(boolean library) { - return new Bck2Brwsr(level, rootcls, classes, resources, res, library); + public Bck2Brwsr library(String... classpath) { + return new Bck2Brwsr( + level, exported, classes, + resources, res, true, + StringArray.asList(classpath) + ); + } + + /** Turns on the standalone mode. E.g. acts like {@link #library(boolean) library(false)}, + * but also allows to specify whether the Bck2Brwsr VM should + * be included at all. If not, only the skeleton of the launcher is + * generated without any additional VM classes referenced. + * + * @param includeVM should the VM be compiled in, or left out + * @return new instance of the compiler with standalone mode on + * @since 0.9 + */ + public Bck2Brwsr standalone(boolean includeVM) { + return new Bck2Brwsr( + level, exported, classes, resources, + res, includeVM ? false : null, null + ); } /** A way to change the provider of additional resources (classes) for the @@ -264,20 +337,28 @@ return res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader(), false); } - String[] allClasses() { - return classes.addAndNew(rootcls.toArray()).toArray(); - } StringArray allResources() { return resources; } - - StringArray rootClasses() { - return rootcls; + StringArray classes() { + return classes; + } + + StringArray exported() { + return exported; } boolean isExtension() { - return extension; + return Boolean.TRUE.equals(extension); + } + + boolean includeVM() { + return extension != null; + } + + StringArray classpath() { + return classpath; } /** Provider of resources (classes and other files). The diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Jun 09 15:57:14 2014 +0200 @@ -96,10 +96,12 @@ } protected String accessVirtualMethod( - String object, - String mangledName, - String[] fieldInfoName) throws IOException { - return object + "." + mangledName; + String object, + String mangledName, + String[] fieldInfoName, + int params + ) throws IOException { + return object + "." + mangledName + '('; } protected void declaredClass(ClassData classData, String mangledName) @@ -229,17 +231,7 @@ } for (MethodData m : jc.getMethods()) { byte[] onlyArr = m.findAnnotationData(true); - String[] only = findAnnotation(onlyArr, jc, - "org.apidesign.bck2brwsr.core.JavaScriptOnly", - "name", "value" - ); - if (only != null) { - if (only[0] != null && only[1] != null) { - append("\n p.").append(only[0]).append(" = ") - .append(only[1]).append(";"); - } - continue; - } + if (javaScriptOnly(onlyArr)) continue; String destObject; String mn; append("\n "); @@ -301,17 +293,7 @@ append("\n }"); for (FieldData v : jc.getFields()) { byte[] onlyArr = v.findAnnotationData(true); - String[] only = findAnnotation(onlyArr, jc, - "org.apidesign.bck2brwsr.core.JavaScriptOnly", - "name", "value" - ); - if (only != null) { - if (only[0] != null && only[1] != null) { - append("\n p.").append(only[0]).append(" = ") - .append(only[1]).append(";"); - } - continue; - } + if (javaScriptOnly(onlyArr)) continue; if (!v.isStatic()) { append("\n this.fld_"). append(className).append('_'). @@ -331,6 +313,25 @@ // } return ""; } + + private boolean javaScriptOnly(byte[] anno) throws IOException { + String[] only = findAnnotation(anno, jc, + "org.apidesign.bck2brwsr.core.JavaScriptOnly", + "name", "value" + ); + if (only != null) { + if (only[0] != null && only[1] != null) { + append("\n p.").append(only[0]).append(" = ") + .append(only[1]).append(";"); + } + if (ExportedSymbols.isMarkedAsExported(anno, jc)) { + append("\n p['").append(only[0]).append("'] = p.") + .append(only[0]).append(";"); + } + return true; + } + return false; + } private String generateStaticMethod(String destObject, MethodData m, StringArray toInitilize) throws IOException { String jsb = javaScriptBody(destObject, m, true); if (jsb != null) { @@ -1599,6 +1600,7 @@ } if (returnType[0] != 'V') { + mapper.flush(this); append("var ") .append(mapper.pushT(VarType.fromFieldType(returnType[0]))) .append(" = "); @@ -1654,8 +1656,7 @@ .append(" = "); } - append(accessVirtualMethod(vars[0].toString(), mn, mi)); - append('('); + append(accessVirtualMethod(vars[0].toString(), mn, mi, numArguments)); String sep = ""; for (int j = 1; j < numArguments; ++j) { append(sep); diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassPath.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassPath.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClassPath.java Mon Jun 09 15:57:14 2014 +0200 @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import org.apidesign.bck2brwsr.core.Exported; import org.apidesign.bck2brwsr.core.JavaScriptBody; /** Conversion from classpath to load function. @@ -41,42 +42,51 @@ private static native Object set(Object arr, int index, Object value); private static boolean doingToZip; - public static byte[] loadFromCp(Object classpath, String res, int skip) + + static byte[] loadBytes(String resource, Object classpath, int skip) throws IOException, ClassNotFoundException { for (int i = 0; i < length(classpath); i++) { - Object c = at(classpath, i); - if (c instanceof String && !doingToZip) { - try { - doingToZip = true; - String url = (String)c; - final Bck2Brwsr.Resources z = toZip(url); - c = set(classpath, i, z); - final byte[] man = readBytes(z, "META-INF/MANIFEST.MF"); - if (man != null) { - String mainClass = processClassPathAttr(man, url, classpath); + byte[] arr = loadBytes(resource, classpath, i, skip); + if (arr != null) { + return arr; + } + } + return null; + } + @Exported static byte[] loadBytes(String resource, Object classpath, int i, int skip) + throws IOException, ClassNotFoundException { + Object c = at(classpath, i); + if (c instanceof String && !doingToZip) { + try { + doingToZip = true; + String url = (String)c; + final Bck2Brwsr.Resources z = toZip(url); + c = set(classpath, i, z); + final byte[] man = readBytes(z, "META-INF/MANIFEST.MF"); + if (man != null) { + String mainClass = processClassPathAttr(man, url, classpath); // if (mainClass != null) { // Class.forName(mainClass); // } - } - } catch (IOException ex) { - set(classpath, i, ex); - log("Cannot load " + c + " - " + ex.getClass().getName() + ":" + ex.getMessage()); - } finally { - doingToZip = false; } + } catch (IOException ex) { + set(classpath, i, ex); + log("Cannot load " + c + " - " + ex.getClass().getName() + ":" + ex.getMessage()); + } finally { + doingToZip = false; } - if (res != null) { - byte[] checkRes; - if (c instanceof Bck2Brwsr.Resources) { - checkRes = readBytes((Bck2Brwsr.Resources)c, res); - if (checkRes != null && --skip < 0) { - return checkRes; - } - } else { - checkRes = callFunction(c, res, skip); - if (checkRes != null) { - return checkRes; - } + } + if (resource != null) { + byte[] checkRes; + if (c instanceof Bck2Brwsr.Resources) { + checkRes = readBytes((Bck2Brwsr.Resources)c, resource); + if (checkRes != null && --skip < 0) { + return checkRes; + } + } else { + checkRes = callFunction(c, resource, skip); + if (checkRes != null) { + return checkRes; } } } diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Mon Jun 09 15:57:14 2014 +0200 @@ -36,6 +36,7 @@ private static final String[] ARGS = { "--compilation_level", "SIMPLE_OPTIMIZATIONS", + "--output_wrapper", "(function() {%output%})(this);", "--js", "bck2brwsr-raw.js" //, "--debug" //, "--formatting", "PRETTY_PRINT" @@ -157,7 +158,7 @@ private static final String[] FIXED_EXTERNS = { "bck2brwsr", "bck2BrwsrThrwrbl", - "registerExtension", + "register", "$class", "anno", "array", diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/main/java/org/apidesign/vm4brwsr/ExportedSymbols.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ExportedSymbols.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ExportedSymbols.java Mon Jun 09 15:57:14 2014 +0200 @@ -75,6 +75,9 @@ if (pkgName == null) { return false; } + if (pkgName.startsWith("java/")) { + return true; + } final Boolean cachedValue = isMarkedAsExportedCache.get(pkgName); if (cachedValue != null) { @@ -115,6 +118,9 @@ } private boolean resolveIsMarkedAsExportedPackage(String pkgName) { + if (exported.contains(pkgName + '/')) { + return true; + } try { final InputStream is = resources.get(pkgName + "/package-info.class"); @@ -135,7 +141,7 @@ } } - private boolean isMarkedAsExported(byte[] arrData, ClassData cd) + static boolean isMarkedAsExported(byte[] arrData, ClassData cd) throws IOException { if (arrData == null) { return false; diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Mon Jun 09 15:57:14 2014 +0200 @@ -105,11 +105,16 @@ } try (Writer w = new BufferedWriter(new FileWriter(gt))) { - Bck2Brwsr.newCompiler().library(createExtension). + Bck2Brwsr c = Bck2Brwsr.newCompiler(). obfuscation(obfLevel). addRootClasses(classes.toArray()). - resources(new LdrRsrcs(Main.class.getClassLoader(), true)). - generate(w); + resources(new LdrRsrcs(Main.class.getClassLoader(), true)); + + if (createExtension) { + c = c.library(); + } + + c.generate(w); } } diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Mon Jun 09 15:57:14 2014 +0200 @@ -103,6 +103,12 @@ } arr = tmp; } + void remove(String item) { + int f = indexOf(item); + if (f != -1) { + delete(f); + } + } int indexOf(String ic) { if (arr != null) for (int i = 0; i < arr.length; i++) { diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Mon Jun 09 15:57:14 2014 +0200 @@ -34,19 +34,18 @@ private final Bck2Brwsr.Resources resources; private final ExportedSymbols exportedSymbols; private final StringArray invokerMethods; + private final StringArray asBinary; - private static final Class FIXED_DEPENDENCIES[] = { - Class.class, - ArithmeticException.class, - VM.class - }; - - private VM(Appendable out, Bck2Brwsr.Resources resources, StringArray explicitlyExported) { + private VM( + Appendable out, Bck2Brwsr.Resources resources, + StringArray explicitlyExported, StringArray asBinary + ) { super(out); this.resources = resources; this.classDataCache = new ClassDataCache(resources); this.exportedSymbols = new ExportedSymbols(resources, explicitlyExported); this.invokerMethods = new StringArray(); + this.asBinary = asBinary; } static { @@ -67,32 +66,41 @@ static void compile(Appendable out, Bck2Brwsr config ) throws IOException { - String[] both = config.allClasses(); + String[] both = config.classes().toArray(); - VM vm = config.isExtension() ? - new Extension(out, config.getResources(), both, config.rootClasses()) - : - new Standalone(out, config.getResources(), config.rootClasses()); - final StringArray fixedNames = new StringArray(); - - for (final Class fixedClass: FIXED_DEPENDENCIES) { - fixedNames.add(fixedClass.getName().replace('.', '/')); - } - - vm.doCompile(fixedNames.addAndNew(both), config.allResources()); + fixedNames.add(Object.class.getName().replace('.', '/')); + fixedNames.add(Class.class.getName().replace('.', '/')); + fixedNames.add(ArithmeticException.class.getName().replace('.', '/')); + + VM vm; + if (config.isExtension()) { + fixedNames.add(VM.class.getName().replace('.', '/')); + vm = new Extension(out, + config.getResources(), both, config.exported(), + config.allResources(), config.classpath() + ); + } else { + if (config.includeVM()) { + fixedNames.add(VM.class.getName().replace('.', '/')); + } + vm = new Standalone(out, + config.getResources(), config.exported(), + config.allResources() + ); + } + vm.doCompile(fixedNames.addAndNew(both)); } - private void doCompile(StringArray names, StringArray asBinary) throws IOException { + private void doCompile(StringArray names) throws IOException { generatePrologue(); append( "\n var invoker = {};"); generateBody(names); for (String invokerMethod: invokerMethods.toArray()) { - append("\n invoker." + invokerMethod + " = function(target) {" - + "\n return function() {" - + "\n return target['" + invokerMethod + "'].apply(target, arguments);" - + "\n };" + append("\n invoker." + invokerMethod + " = function() {" + + "\n var target = arguments[0];" + + "\n return target['" + invokerMethod + "'].apply(target, Array.prototype.slice.call(arguments, 1));" + "\n };" ); } @@ -232,6 +240,7 @@ throw new IOException("Can't find " + resource); } readResource(emul, this); + asBinary.remove(resource); } scripts = new StringArray(); @@ -249,47 +258,6 @@ } } } -/* - append( - " return vm;\n" - + " };\n" - + " function mangleClass(name) {\n" - + " return name.replace__Ljava_lang_String_2Ljava_lang_CharSequence_2Ljava_lang_CharSequence_2(\n" - + " '_', '_1').replace__Ljava_lang_String_2CC('.','_');\n" - + " };\n" - + " global.bck2brwsr = function() {\n" - + " var args = Array.prototype.slice.apply(arguments);\n" - + " var vm = fillInVMSkeleton({});\n" - + " var loader = {};\n" - + " loader.vm = vm;\n" - + " loader.loadClass = function(name) {\n" - + " var attr = mangleClass(name);\n" - + " var fn = vm[attr];\n" - + " if (fn) return fn(false);\n" - + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n" - + " load__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n" - + " }\n" - + " if (vm.loadClass) {\n" - + " throw 'Cannot initialize the bck2brwsr VM twice!';\n" - + " }\n" - + " vm.loadClass = loader.loadClass;\n" - + " vm._reload = function(name, byteCode) {;\n" - + " var attr = mangleClass(name);\n" - + " delete vm[attr];\n" - + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n" - + " reload__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2_3B(loader, name, args, byteCode);\n" - + " };\n" - + " vm.loadBytes = function(name, skip) {\n" - + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n" - + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, name, args, typeof skip == 'number' ? skip : 0);\n" - + " }\n" - + " vm.java_lang_reflect_Array(false);\n" - + " vm.org_apidesign_vm4brwsr_VMLazy(false).\n" - + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, null, args, 0);\n" - + " return loader;\n" - + " };\n"); - append("}(this));"); -*/ } private static void readResource(InputStream emul, Appendable out) throws IOException { @@ -397,9 +365,11 @@ @Override protected String accessVirtualMethod( - String object, - String mangledName, - String[] fieldInfoName) throws IOException { + String object, + String mangledName, + String[] fieldInfoName, + int params + ) throws IOException { final ClassData referencedClass = classDataCache.getClassData(fieldInfoName[0]); final MethodData method = @@ -413,17 +383,17 @@ || ((referencedClass.getAccessFlags() & ByteCodeParser.ACC_FINAL) != 0) || !isHierarchyExported(method))) { - return object + "." + mangledName; + return object + "." + mangledName + '('; } - return accessThroughInvoker(object, mangledName); + return accessThroughInvoker(object, mangledName, params > 1 ? "," : ""); } - private String accessThroughInvoker(String object, String mangledName) { + private String accessThroughInvoker(String object, String mangledName, String sep) { if (!invokerMethods.contains(mangledName)) { invokerMethods.add(mangledName); } - return "invoker." + mangledName + '(' + object + ')'; + return "invoker." + mangledName + '(' + object + sep; } private boolean isHierarchyExported(final MethodData methodData) @@ -457,7 +427,7 @@ : object + "['" + mangledName + "']"; } - private static final class ExportedMethodFinder + private final class ExportedMethodFinder implements ClassDataCache.TraversalCallback { private final ExportedSymbols exportedSymbols; private MethodData found; @@ -469,7 +439,10 @@ @Override public boolean traverse(final MethodData methodData) { try { - if (exportedSymbols.isExported(methodData)) { + if ( + exportedSymbols.isExported(methodData) || + isExternalClass(methodData.cls.getClassName()) + ) { found = methodData; return false; } @@ -485,8 +458,11 @@ } private static final class Standalone extends VM { - private Standalone(Appendable out, Bck2Brwsr.Resources resources, StringArray explicitlyExported) { - super(out, resources, explicitlyExported); + private Standalone(Appendable out, + Bck2Brwsr.Resources resources, + StringArray explicitlyExported, StringArray asBinary + ) { + super(out, resources, explicitlyExported, asBinary); } @Override @@ -500,10 +476,65 @@ " return vm;\n" + " };\n" + " var extensions = [];\n" + + " function replaceAll(s, target, replacement) {\n" + + " var pos = 0;\n" + + " for (;;) {\n" + + " var indx = s.indexOf(target, pos);\n" + + " if (indx === -1) {\n" + + " return s;\n" + + " }\n" + + " pos = indx + replacement.length;\n" + + " s = s.substring(0, indx) + replacement + s.substring(indx + target.length);\n" + + " }\n" + + " }\n" + " function mangleClass(name) {\n" - + " return name.replace__Ljava_lang_String_2Ljava_lang_CharSequence_2Ljava_lang_CharSequence_2(\n" - + " '_', '_1').replace__Ljava_lang_String_2CC('.','_');\n" + + " name = replaceAll(name, '_', '_1');\n" + + " name = replaceAll(name, '.', '_');\n" + + " return name;\n" + " };\n" + + " var pending = [];\n" + + " var pendingClasses = [];\n" + + " function extensionLoaded(ev) {\n" + + " var at = pending.indexOf(ev.target);\n" + + " pending.splice(at, 1);\n" + + " if (pending.length === 0) {\n" + + " for (var i = 0; i < pendingClasses.length; i += 3) {\n" + + " invokeMethod(pendingClasses[i], pendingClasses[i + 1], pendingClasses[i + 2]);\n" + + " }\n" + + " pendingClasses = [];\n" + + " }\n" + + " }\n" + + " function invokeMethod(vm, n, args) {\n" + + " var clazz = vm.loadClass(n);\n" + + " if (args) {\n" + + " var seek = args[0];\n" + + " var prefix = seek.indexOf('__') == -1 ? seek + '__' : seek;\n" + + " args = Array.prototype.slice.call(args, 1);\n" + + " var found = '';\n" + + " for (var m in clazz) {\n" + + " if (m.indexOf(prefix) === 0) {\n" + + " return clazz[m].apply(null, args);\n" + + " }\n" + + " found += m.toString() + '\\n'\n" + + " }\n" + + " throw 'Cannot find ' + seek + ' in ' + n + ' found:\\n' + found;\n" + + " }\n" + + " }\n" + + " function extensionError(ev) {\n" + + " console.log('error loading ' + ev.target.src);\n" + + " extensionLoaded(ev);\n" + + " }\n" + + " function loadExtension(url) {\n" + + " if (url.substring(url.length - 4) == '.jar')\n" + + " url = url.substring(0, url.length - 4) + '.js';\n" + + " var script = document.createElement('script');\n" + + " script.type = 'text/javascript';\n" + + " script.src = url;\n" + + " script.onload = extensionLoaded;\n" + + " script.onerror = extensionError;\n" + + " document.getElementsByTagName('head')[0].appendChild(script);\n" + + " pending.push(script);\n" + + " }\n" + " global.bck2brwsr = function() {\n" + " var args = Array.prototype.slice.apply(arguments);\n" + " var resources = {};\n" @@ -519,42 +550,17 @@ + " else resources[n].push(arr);\n" + " }\n" + " var vm = fillInVMSkeleton({ 'registerResource' : registerResource });\n" + + " function initVM() {\n" + + " var clsArray = vm['java_lang_reflect_Array'];\n" + + " if (clsArray) clsArray(false);\n" + + " }\n" + " for (var i = 0; i < extensions.length; ++i) {\n" + " extensions[i](vm);\n" + " }\n" + " vm['registerResource'] = null;\n" + " var knownExtensions = extensions.length;\n" + " var loader = {};\n" - + " loader.vm = vm;\n" - + " loader.loadClass = function(name) {\n" - + " var attr = mangleClass(name);\n" - + " var fn = vm[attr];\n" - + " if (fn) return fn(false);\n" - + " try {\n" - + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n" - + " load__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n" - + " } catch (err) {\n" - + " while (knownExtensions < extensions.length) {\n" - + " vm['registerResource'] = registerResource;\n" - + " extensions[knownExtensions++](vm);\n" - + " vm['registerResource'] = null;\n" - + " }\n" - + " fn = vm[attr];\n" - + " if (fn) return fn(false);\n" - + " throw err;\n" - + " }\n" - + " }\n" - + " if (vm.loadClass) {\n" - + " throw 'Cannot initialize the bck2brwsr VM twice!';\n" - + " }\n" - + " vm.loadClass = loader.loadClass;\n" - + " vm._reload = function(name, byteCode) {;\n" - + " var attr = mangleClass(name);\n" - + " delete vm[attr];\n" - + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n" - + " reload__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2_3B(loader, name, args, byteCode);\n" - + " };\n" - + " vm.loadBytes = function(name, skip) {\n" + + " var loadBytes = function(name, skip) {\n" + " skip = typeof skip == 'number' ? skip : 0;\n" + " var arr = resources[name];\n" + " if (arr) {\n" @@ -564,25 +570,103 @@ + " } else {\n" + " var arrSize = 0;\n" + " };\n" - + " var ret = vm.org_apidesign_vm4brwsr_VMLazy(false).\n" - + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, name, args, skip);\n" - + " if (ret !== null) return ret;\n" + + " for (var i = 0; i < args.length; i++) {\n" + + " var at = args[i];\n" + + " if(!at) continue;\n" + + " var ret;\n" + + " if (typeof at === 'string' && at.substring(at.length - 3) === '.js') {\n" + + " loadExtension(at);\n" + + " args[i] = null;\n" + + " } else if (typeof at === 'function') ret = at(name, skip);\n" + + " else {\n" + + " var cp = vm['org_apidesign_vm4brwsr_ClassPath'];\n" + + " if (!cp) throw 'Core Java library not registered. Cannot load from ' + at;\n" + + " ret = cp(false).\n" + + " loadBytes___3BLjava_lang_String_2Ljava_lang_Object_2II(name, args, i, skip);\n" + + " }\n" + + " if (ret) return ret;\n" + + " }\n" + " while (knownExtensions < extensions.length) {\n" + " vm['registerResource'] = registerResource;\n" + " extensions[knownExtensions++](vm);\n" + " vm['registerResource'] = null;\n" + + " initVM();\n" + " }\n" + " var arr = resources[name];\n" + " return (arr && arr.length > arrSize) ? arr[arrSize] : null;\n" + " }\n" - + " vm.java_lang_reflect_Array(false);\n" - + " vm.org_apidesign_vm4brwsr_VMLazy(false).\n" - + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, null, args, 0);\n" + + " var reload = function(name, arr, keep) {\n" + + " if (!arr) throw 'Cannot find ' + name;\n" + + " var lazy = vm['org_apidesign_vm4brwsr_VMLazy'];\n" + + " if (!lazy) throw 'No bck2brwsr VM module to compile ' + name;\n" + + " if (!keep) {\n" + + " var attr = mangleClass(name);\n" + + " delete vm[attr];\n" + + " }\n" + + " return lazy(false)\n" + + " ['load__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2_3B']\n" + + " (vm, name, args, arr);\n" + + " };\n" + + " var loadClass = function(name) {\n" + + " var attr = mangleClass(name);\n" + + " var fn = vm[attr];\n" + + " if (fn) return fn(false);\n" + + " try {\n" + + " var arr = loadBytes(replaceAll(name, '.', '/') + '.class');\n" + + " return reload(name, arr, true);\n" + + " } catch (err) {\n" + + " fn = vm[attr];\n" + + " if (fn) return fn(false);\n" + + " throw err;\n" + + " }\n" + + " }\n" + + " if (vm['loadClass']) {\n" + + " throw 'Cannot initialize the bck2brwsr VM twice!';\n" + + " }\n" + + " vm['loadClass'] = loadClass;\n" + + " vm['_reload'] = reload;\n" + + " vm['loadBytes'] = loadBytes;\n" + + " initVM();\n" + + " loader.loadClass = function(name) {\n" + + " if (pending.length === 0) {\n" + + " try {\n" + + " var c = loadClass(name);\n" + + " c['invoke'] = function() {\n" + + " return invokeMethod(vm, name, arguments);\n" + + " };\n" + + " return c;\n" + + " } catch (err) {\n" + + " if (pending.length === 0) throw err;\n" + + " }\n" + + " }\n" + + " pendingClasses.push(vm);\n" + + " pendingClasses.push(name);\n" + + " pendingClasses.push(null);\n" + + " return {\n" + + " 'invoke' : function() {\n" + + " if (pending.length === 0) {\n" + + " invokeMethod(vm, name, arguments);\n" + + " return;\n" + + " }\n" + + " pendingClasses.push(vm);\n" + + " pendingClasses.push(name);\n" + + " pendingClasses.push(arguments);\n" + + " }\n" + + " };\n" + + " }\n" + " return loader;\n" + " };\n"); append( - " global.bck2brwsr.registerExtension = function(extension) {\n" + " global.bck2brwsr.register = function(config, extension) {\n" + + " if (!config || config['magic'] !== 'kafíčko') {\n" + + " console.log('Will not register: ' + extension);\n" + + " return false;\n" + + " }\n" + " extensions.push(extension);\n" + + " var cp = config['classpath'];\n" + + " if (cp) for (var i = 0; i < cp.length; i++) {\n" + + " loadExtension(cp[i]);\n" + + " }\n" + " return null;\n" + " };\n"); append("}(this));"); @@ -601,17 +685,39 @@ private static final class Extension extends VM { private final StringArray extensionClasses; + private final StringArray classpath; private Extension(Appendable out, Bck2Brwsr.Resources resources, - String[] extClassesArray, StringArray explicitlyExported) { - super(out, resources, explicitlyExported); + String[] extClassesArray, StringArray explicitlyExported, + StringArray asBinary, StringArray classpath + ) { + super(out, resources, explicitlyExported, asBinary); this.extensionClasses = StringArray.asList(extClassesArray); + this.classpath = classpath; } @Override protected void generatePrologue() throws IOException { - append("bck2brwsr.registerExtension(function(exports) {\n" - + " var vm = {};\n"); + append( + "bck2brwsr.register({\n" + + " 'magic' : 'kafíčko'" + ); + if (classpath != null && classpath.toArray().length > 0) { + append( + ",\n 'classpath' : [\n" + ); + String sep = " "; + for (String s : classpath.toArray()) { + append(sep).append("'").append(s).append("'"); + sep = ",\n "; + } + append( + "\n ]" + ); + } + append( + "\n}, function(exports) {\n" + + " var vm = {};\n"); append(" function link(n) {\n" + " return function() {\n" + " var cls = n['replace__Ljava_lang_String_2CC']" diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Mon Jun 09 15:57:14 2014 +0200 @@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import org.apidesign.bck2brwsr.core.Exported; import org.apidesign.bck2brwsr.core.JavaScriptBody; /** @@ -27,35 +28,31 @@ * @author Jaroslav Tulach */ final class VMLazy { - private final Object loader; + private final Object vm; private final Object[] args; - private VMLazy(Object loader, Object[] args) { - this.loader = loader; + private VMLazy(Object vm, Object[] args) { + this.vm = vm; this.args = args; } static void init() { } - static Object load(Object loader, String name, Object[] arguments) + @Exported + static Object load(Object loader, String name, Object[] arguments, byte[] arr) throws IOException, ClassNotFoundException { - return new VMLazy(loader, arguments).load(name, false); + if (arr == null) { + throw new ClassNotFoundException(name); + } + return new VMLazy(loader, arguments).defineClass(arr, name, false); } - static Object reload(Object loader, String name, Object[] arguments, byte[] arr) - throws IOException, ClassNotFoundException { - return new VMLazy(loader, arguments).defineClass(arr, name, false); - } - - static byte[] loadBytes(Object loader, String name, Object[] arguments, int skip) throws Exception { - return ClassPath.loadFromCp(arguments, name, skip); - } - - private Object load(String name, boolean instance) + @Exported + Object load(String name, boolean instance) throws IOException, ClassNotFoundException { String res = name.replace('.', '/') + ".class"; - byte[] arr = ClassPath.loadFromCp(args, res, 0); + byte[] arr = ClassPath.loadBytes(res, args, 0); if (arr == null) { throw new ClassNotFoundException(name); } @@ -65,33 +62,32 @@ private Object defineClass(byte[] arr, String name, boolean instance) throws IOException { StringBuilder out = new StringBuilder(65535); - out.append("var loader = arguments[0];\n"); - out.append("var vm = loader.vm;\n"); + out.append("var vm = arguments[0];\n"); int prelude = out.length(); String initCode = new Gen(this, out).compile(new ByteArrayInputStream(arr)); String code = out.toString().toString(); String under = name.replace('.', '_'); - Object fn = applyCode(loader, under, code, instance); + Object fn = applyCode(vm, under, code, instance); if (!initCode.isEmpty()) { out.setLength(prelude); out.append(initCode); code = out.toString().toString(); - applyCode(loader, null, code, false); + applyCode(vm, null, code, false); } return fn; } - @JavaScriptBody(args = {"loader", "name", "script", "instance" }, body = + @JavaScriptBody(args = {"vm", "name", "script", "instance" }, body = "try {\n" + - " new Function(script)(loader, name);\n" + + " new Function(script)(vm, name);\n" + "} catch (ex) {\n" + " throw 'Cannot compile ' + name + ' ' + ex + ' line: ' + ex.lineNumber + ' script:\\n' + script;\n" + "}\n" + "return name != null ? vm[name](instance) : null;\n" ) - private static native Object applyCode(Object loader, String name, String script, boolean instance); + private static native Object applyCode(Object vm, String name, String script, boolean instance); private static final class Gen extends ByteCodeToJavaScript { @@ -107,8 +103,7 @@ "var cls = n.replace__Ljava_lang_String_2CC('/','_').toString();" + "\nvar dot = n.replace__Ljava_lang_String_2CC('/','.').toString();" + "\nvar lazy = this._lazy();" - + "\nvar loader = lazy._loader();" - + "\nvar vm = loader.vm;" + + "\nvar vm = lazy._vm();" + "\nif (vm[cls]) return false;" + "\nvm[cls] = function() {" + "\n var instance = arguments.length == 0 || arguments[0] === true;" @@ -126,7 +121,7 @@ resourcePath = "/" + resourcePath; } String code = readCode(resourcePath); - applyCode(lazy.loader, null, code, false); + applyCode(lazy.vm, null, code, false); } private String readCode(String resourcePath) throws IOException { diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/test/java/org/apidesign/vm4brwsr/ImplementExternalInterfaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ImplementExternalInterfaceTest.java Mon Jun 09 15:57:14 2014 +0200 @@ -0,0 +1,58 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr; + +import javax.script.ScriptEngine; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** Tests whether private impl can implement public interface method + * from another extension. + * + * @author Jaroslav Tulach + */ +public class ImplementExternalInterfaceTest { + @Test public void checkHello() throws Exception { + String exp = "Hello!"; + + code.assertExec("Can extension implement class from another extension", + ImplementFactory.class, "hello__Ljava_lang_String_2", + exp + ); + } + + private static TestVM code; + + @BeforeClass + public static void compileTheCode() throws Exception { + StringBuilder sb = new StringBuilder(); + ScriptEngine[] eng = { null }; + code = TestVM.compileClassAsExtension(sb, eng, + "org/apidesign/vm4brwsr/extrnl/ImplementInterface", null, null + ); + code = TestVM.compileClassesAsExtension(sb, eng, null, null, + "org/apidesign/vm4brwsr/ImplementFactory", + "org/apidesign/vm4brwsr/ImplementFactory$Impl" + ); + } + @AfterClass + public static void releaseTheCode() { + code = null; + } +} diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/test/java/org/apidesign/vm4brwsr/ImplementFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ImplementFactory.java Mon Jun 09 15:57:14 2014 +0200 @@ -0,0 +1,49 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr; + +import org.apidesign.vm4brwsr.extrnl.ImplementInterface; + +/** + * + * @author Jaroslav Tulach + */ +public class ImplementFactory { + private ImplementFactory() { + } + + private static ImplementInterface create() { + return new Impl(); + } + + public static String hello() { + ImplementInterface i = create(); + return i.sayHello(); + } + + private static class Impl implements ImplementInterface { + + public Impl() { + } + + @Override + public String sayHello() { + return "Hello!"; + } + } +} diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Mon Jun 09 15:57:14 2014 +0200 @@ -216,6 +216,14 @@ false, 30 ); } + + @Test public void computeAround() throws Exception { + double exp = Numbers.around(new Object(), 5, 8); + assertExec("Computes the same value", + Numbers.class, "around__ILjava_lang_Object_2II", + exp, null, 5, 8 + ); + } private static TestVM code; diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Mon Jun 09 15:57:14 2014 +0200 @@ -107,4 +107,19 @@ @JavaScriptBody(args = { "o" }, body = "return o.valueOf();") private static native boolean bvalueOf(Object o); + + public static int around(Object model, int x, int y) { + return minesAt(model, x - 1, y - 1) + + minesAt(model, x - 1, y) + + minesAt(model, x - 1, y + 1) + + minesAt(model, x, y - 1) + + minesAt(model, x, y + 1) + + minesAt(model, x + 1, y - 1) + + minesAt(model, x + 1, y) + + minesAt(model, x + 1, y + 1); + } + + private static int minesAt(Object model, int x, int y) { + return x + y; + } } diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/test/java/org/apidesign/vm4brwsr/Resources.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Resources.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Resources.java Mon Jun 09 15:57:14 2014 +0200 @@ -21,12 +21,27 @@ import java.io.InputStream; import java.net.URL; import java.util.Enumeration; +import net.java.html.js.JavaScriptBody; +import net.java.html.js.JavaScriptResource; /** * * @author Jaroslav Tulach */ +@JavaScriptResource("obj.js") public class Resources { + @JavaScriptBody(args = {}, body = "return obj;") + static Object retObj() { + return null; + } + + public static boolean isObj() { + return retObj() != null; + } + public static boolean isResource() { + return Resources.class.getResource("obj.js") != null; + } + public static String loadKO() throws IOException { InputStream is = Resources.class.getResourceAsStream("ko.js"); return readIS(is, false); diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/test/java/org/apidesign/vm4brwsr/ResourcesWithExtensionsTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ResourcesWithExtensionsTest.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ResourcesWithExtensionsTest.java Mon Jun 09 15:57:14 2014 +0200 @@ -45,6 +45,17 @@ exp ); } + + @Test public void objJSResourceIsNotFound() throws Exception { + assertExec("Objects from @JavaScriptResource resources are available", + Resources.class, "isObj__Z", 1.0 + ); + } + @Test public void objJSIsFound() throws Exception { + assertExec("The resources used as @JavaScriptResource aren't available", + Resources.class, "isResource__Z", 0.0 + ); + } private static TestVM code; diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Thu May 15 11:38:27 2014 +0200 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Mon Jun 09 15:57:14 2014 +0200 @@ -23,7 +23,12 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import javax.script.Invocable; import javax.script.ScriptContext; import javax.script.ScriptEngine; @@ -60,7 +65,10 @@ Object ret = null; try { ret = code.invokeMethod(bck2brwsr, "loadClass", clazz.getName()); - ret = code.invokeMethod(ret, method, args); + List ma = new ArrayList<>(); + ma.add(method); + ma.addAll(Arrays.asList(args)); + ret = code.invokeMethod(ret, "invoke", ma.toArray()); } catch (ScriptException ex) { fail("Execution failed in " + dumpJS(codeSeq) + ": " + ex.getMessage(), ex); } catch (NoSuchMethodException ex) { @@ -141,6 +149,12 @@ StringBuilder sb, ScriptEngine[] eng, String name, final String resourceName, final String resourceContent ) throws ScriptException, IOException { + return compileClassesAsExtension(sb, eng, resourceName, resourceContent, name); + } + static TestVM compileClassesAsExtension( + StringBuilder sb, ScriptEngine[] eng, + final String resourceName, final String resourceContent, String... names + ) throws ScriptException, IOException { if (sb == null) { sb = new StringBuilder(); } @@ -150,6 +164,11 @@ eng[0] = js; Bck2Brwsr.generate(sb, new EmulationResources()); } + Set exp = new HashSet(); + for (String n : names) { + int last = n.lastIndexOf('/'); + exp.add(n.substring(0, last + 1)); + } Bck2Brwsr b2b = Bck2Brwsr.newCompiler(). resources(new EmulationResources() { @Override @@ -160,9 +179,11 @@ return super.get(name); } }). - addRootClasses(name). + addClasses(names). + addResources("org/apidesign/vm4brwsr/obj.js"). + addExported(exp.toArray(new String[0])). obfuscation(ObfuscationLevel.FULL). - library(true); + library(); if (resourceName != null) { b2b = b2b.addResources(resourceName); } @@ -188,8 +209,7 @@ Bck2Brwsr b2b = Bck2Brwsr.newCompiler(). resources(new EmulationResources()). addRootClasses(name). - addResources(resources). - library(false); + addResources(resources); b2b.generate(sb); ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine js = sem.getEngineByExtension("js"); diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/test/java/org/apidesign/vm4brwsr/extrnl/ImplementInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/extrnl/ImplementInterface.java Mon Jun 09 15:57:14 2014 +0200 @@ -0,0 +1,26 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr.extrnl; + +/** + * + * @author Jaroslav Tulach + */ +public interface ImplementInterface { + public String sayHello(); +} diff -r d51a5533a2e7 -r a7bf87c2c1d9 rt/vm/src/test/resources/org/apidesign/vm4brwsr/obj.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/test/resources/org/apidesign/vm4brwsr/obj.js Mon Jun 09 15:57:14 2014 +0200 @@ -0,0 +1,20 @@ +/* + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +var obj = {}; + +