# HG changeset patch # User toni.epple@eppleton.de # Date 1368779261 -7200 # Node ID ae3f2aa509703f20184c6c2593b05e6ca30a3e3c # Parent d127d41768bdab9af6ebfc9412e97887141281b8# Parent 8ee3112f5647f6180cc1a12ab9146ff7c1cc7644 Merging latest changes from main line diff -r d127d41768bd -r ae3f2aa50970 .hgtags --- a/.hgtags Tue Mar 05 07:57:16 2013 +0100 +++ b/.hgtags Fri May 17 10:27:41 2013 +0200 @@ -1,2 +1,12 @@ 0a115f1c6f3c70458fc479ae82b4d7fcdeb7e95a jdk7-b147_base 7367a296a9ec4a88e0292a41244c96283818e563 bck2brwsr-0.3 +caf1e66268fd4100d57922d973ae09a6bf3be847 release-${releaseVersion} +30e9ac29654fba6f67d0921e7e3aa21133442592 release-0.5 +caf1e66268fd4100d57922d973ae09a6bf3be847 release-0.4 +caf1e66268fd4100d57922d973ae09a6bf3be847 release-${releaseVersion} +0000000000000000000000000000000000000000 release-${releaseVersion} +52a4a5f868bccc67d50ad17f793b9ebabdf75d88 release-0.6 +6792dc0bafb9c76a099e45bfc9e967d6a2823827 release-0.7 +623816269b75e53fffb4b19960df7040a3c20056 release-0.7 +23572dc719bd630817d11eaabdee4565f63ef8e1 release-0.7.1 +56abd247f421febd8b2c5e59d666968692e11555 release-0.7.2 diff -r d127d41768bd -r ae3f2aa50970 benchmarks/matrix-multiplication/pom.xml --- a/benchmarks/matrix-multiplication/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/benchmarks/matrix-multiplication/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,12 +4,12 @@ org.apidesign.bck2brwsr matrix.multiplication - 0.4-SNAPSHOT + 0.8-SNAPSHOT jar benchmarks org.apidesign.bck2brwsr - 0.4-SNAPSHOT + 0.8-SNAPSHOT Matrix multiplication @@ -37,6 +37,36 @@ true + + org.codehaus.mojo + xml-maven-plugin + 1.0 + + + + transform + + install + + + + + + target/surefire-reports + target/surefire-reports + + TEST*.xml + + src/main/select-time.xsl + + + .csv + + + + + + @@ -44,7 +74,7 @@ org.apidesign.bck2brwsr emul.mini - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.testng @@ -61,7 +91,13 @@ org.apidesign.bck2brwsr vmtest - 0.4-SNAPSHOT + 0.8-SNAPSHOT + test + + + org.apidesign.bck2brwsr + launcher.http + 0.8-SNAPSHOT test diff -r d127d41768bd -r ae3f2aa50970 benchmarks/matrix-multiplication/src/main/select-time.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/benchmarks/matrix-multiplication/src/main/select-time.xsl Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,55 @@ + + + + + + + + End + + NaN + + + + + + + + + + , + + + + + + + + + + + , + + + + + + diff -r d127d41768bd -r ae3f2aa50970 benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java --- a/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java Fri May 17 10:27:41 2013 +0200 @@ -31,6 +31,22 @@ } @Compare(scripting = false) + public String oneIteration() throws IOException { + + Matrix m1 = new Matrix(5); + Matrix m2 = new Matrix(5); + + m1.generateData(); + m2.generateData(); + + Matrix res = m1.multiply(m2); + + StringBuilder sb = new StringBuilder(); + res.printOn(sb); + return sb.toString(); + } + + @Compare(scripting = false) public String tenThousandIterations() throws IOException { Matrix m1 = new Matrix(5); @@ -50,6 +66,27 @@ return sb.toString(); } + @Compare(scripting = false) + public String tenUselessIterations() throws IOException { + + Matrix m1 = new Matrix(5); + Matrix m2 = new Matrix(5); + + m1.generateData(); + m2.generateData(); + + Matrix res = null; + for (int i = 0; i < 10; i++) { + res = m1.multiply(m2); + m1 = res; + } + + StringBuilder sb = new StringBuilder(); + res.printOn(sb); + return sb.toString(); + } + + @Factory public static Object[] create() { return VMTest.create(MatrixTest.class); diff -r d127d41768bd -r ae3f2aa50970 benchmarks/pom.xml --- a/benchmarks/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/benchmarks/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,11 +4,11 @@ bck2brwsr org.apidesign - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr benchmarks - 0.4-SNAPSHOT + 0.8-SNAPSHOT pom Performance benchmarks diff -r d127d41768bd -r ae3f2aa50970 dew/pom.xml --- a/dew/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/dew/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,11 +4,11 @@ org.apidesign bck2brwsr - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr dew - 0.4-SNAPSHOT + 0.8-SNAPSHOT Development Environment for Web http://maven.apache.org @@ -42,6 +42,14 @@ + + org.apache.maven.plugins + maven-deploy-plugin + 2.7 + + true + + diff -r d127d41768bd -r ae3f2aa50970 ide/editor/pom.xml --- a/ide/editor/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/ide/editor/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,19 +4,18 @@ ide org.apidesign.bck2brwsr - 0.4-SNAPSHOT + 0.8-SNAPSHOT - org.apidesign.bck2brwsr.ide.editor + org.apidesign.bck2brwsr.ide editor - 0.4-SNAPSHOT + 0.8-SNAPSHOT nbm Editor Support for Bck2Brwsr UTF-8 - RELEASE72 ${project.build.directory}/endorsed @@ -40,71 +39,59 @@ org.netbeans.api org-netbeans-api-annotations-common - ${netbeans.version} org.netbeans.api org-netbeans-modules-java-source - ${netbeans.version} org.netbeans.api org-netbeans-libs-javacapi - ${netbeans.version} org.netbeans.api org-netbeans-spi-java-hints - ${netbeans.version} org.netbeans.api org-netbeans-modules-parsing-api - ${netbeans.version} org.netbeans.api org-netbeans-spi-editor-hints - ${netbeans.version} org.netbeans.api org-openide-util - ${netbeans.version} org.netbeans.api org-netbeans-modules-java-lexer - ${netbeans.version} org.netbeans.api org-netbeans-modules-lexer - ${netbeans.version} org.apidesign.bck2brwsr core - 0.4-SNAPSHOT + 0.8-SNAPSHOT jar test org.netbeans.api org-netbeans-modules-java-hints-test - ${netbeans.version} test org.netbeans.api org-netbeans-libs-junit4 - ${netbeans.version} test org.netbeans.modules org-netbeans-lib-nbjavac - ${netbeans.version} test diff -r d127d41768bd -r ae3f2aa50970 ide/pom.xml --- a/ide/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/ide/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,14 +4,26 @@ bck2brwsr org.apidesign - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr ide - 0.4-SNAPSHOT + 0.8-SNAPSHOT pom IDE Support editor + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.7 + + true + + + + diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/pom.xml --- a/javaquery/api/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,11 +4,11 @@ org.apidesign.bck2brwsr javaquery - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr javaquery.api - 0.4-SNAPSHOT + 0.8-SNAPSHOT JavaQuery API http://maven.apache.org @@ -18,8 +18,8 @@ maven-compiler-plugin 2.3.2 - 1.6 - 1.6 + 1.7 + 1.7 @@ -73,5 +73,11 @@ ${project.version} test + + ${project.groupId} + launcher.http + ${project.version} + test + diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,155 @@ +/** + * 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.htmlpage; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Jaroslav Tulach + */ +public final class ConvertTypes { + ConvertTypes() { + } + + public static String toString(Object object, String property) { + Object ret = getProperty(object, property); + return ret == null ? null : ret.toString(); + } + + public static double toDouble(Object object, String property) { + Object ret = getProperty(object, property); + return ret instanceof Number ? ((Number)ret).doubleValue() : Double.NaN; + } + + public static int toInt(Object object, String property) { + Object ret = getProperty(object, property); + return ret instanceof Number ? ((Number)ret).intValue() : Integer.MIN_VALUE; + } + + public static T toModel(Class modelClass, Object object, String property) { + Object ret = getProperty(object, property); + if (ret == null || modelClass.isInstance(ret)) { + return modelClass.cast(ret); + } + throw new IllegalStateException("Value " + ret + " is not of type " + modelClass); + } + + public static String toJSON(Object value) { + if (value == null) { + return "null"; + } + if (value instanceof Enum) { + value = value.toString(); + } + if (value instanceof String) { + return '"' + + ((String)value). + replace("\"", "\\\""). + replace("\n", "\\n"). + replace("\r", "\\r"). + replace("\t", "\\t") + + '"'; + } + return value.toString(); + } + + @JavaScriptBody(args = { "object", "property" }, + body = "if (property === null) return object;\n" + + "var p = object[property]; return p ? p : null;" + ) + private static Object getProperty(Object object, String property) { + return null; + } + + public static String createJSONP(Object[] jsonResult, Runnable whenDone) { + int h = whenDone.hashCode(); + String name; + for (;;) { + name = "jsonp" + Integer.toHexString(h); + if (defineIfUnused(name, jsonResult, whenDone)) { + return name; + } + h++; + } + } + + @JavaScriptBody(args = { "name", "arr", "run" }, body = + "if (window[name]) return false;\n " + + "window[name] = function(data) {\n " + + " delete window[name];\n" + + " var el = window.document.getElementById(name);\n" + + " el.parentNode.removeChild(el);\n" + + " arr[0] = data;\n" + + " run.run__V();\n" + + "};\n" + + "return true;\n" + ) + private static boolean defineIfUnused(String name, Object[] arr, Runnable run) { + return true; + } + + @JavaScriptBody(args = { "url", "arr", "callback" }, body = "" + + "var request = new XMLHttpRequest();\n" + + "request.open('GET', url, true);\n" + + "request.setRequestHeader('Content-Type', 'application/json; charset=utf-8');\n" + + "request.onreadystatechange = function() {\n" + + " if (this.readyState!==4) return;\n" + + " try {\n" + + " arr[0] = eval('(' + this.response + ')');\n" + + " } catch (error) {;\n" + + " throw 'Cannot parse' + error + ':' + this.response;\n" + + " };\n" + + " callback.run__V();\n" + + "};" + + "request.send();" + ) + private static void loadJSON( + String url, Object[] jsonResult, Runnable whenDone + ) { + } + + public static void loadJSON( + String url, Object[] jsonResult, Runnable whenDone, String jsonp + ) { + if (jsonp == null) { + loadJSON(url, jsonResult, whenDone); + } else { + loadJSONP(url, jsonp); + } + } + + @JavaScriptBody(args = { "url", "jsonp" }, body = + "var scrpt = window.document.createElement('script');\n " + + "scrpt.setAttribute('src', url);\n " + + "scrpt.setAttribute('id', jsonp);\n " + + "scrpt.setAttribute('type', 'text/javascript');\n " + + "var body = document.getElementsByTagName('body')[0];\n " + + "body.appendChild(scrpt);\n" + ) + private static void loadJSONP(String url, String jsonp) { + + } + + public static void extractJSON(Object jsonObject, String[] props, Object[] values) { + for (int i = 0; i < props.length; i++) { + values[i] = getProperty(jsonObject, props[i]); + } + } + +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/KOList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/KOList.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,167 @@ +/** + * 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.htmlpage; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import org.apidesign.bck2brwsr.core.JavaScriptOnly; + +/** + * + * @author Jaroslav Tulach + */ +public final class KOList extends ArrayList { + private final String name; + private final String[] deps; + private Knockout model; + private Runnable onchange; + + public KOList(String name, String... deps) { + this.name = name; + this.deps = deps; + } + + public void assign(Knockout model) { + if (this.model != model) { + this.model = model; + notifyChange(); + } + } + + public KOList onChange(Runnable r) { + if (this.onchange != null) { + throw new IllegalStateException(); + } + this.onchange = r; + return this; + } + + @Override + public boolean add(T e) { + boolean ret = super.add(e); + notifyChange(); + return ret; + } + + @Override + public boolean addAll(Collection c) { + boolean ret = super.addAll(c); + notifyChange(); + return ret; + } + + @Override + public boolean addAll(int index, Collection c) { + boolean ret = super.addAll(index, c); + notifyChange(); + return ret; + } + + @Override + public boolean remove(Object o) { + boolean ret = super.remove(o); + notifyChange(); + return ret; + } + + @Override + public void clear() { + super.clear(); + notifyChange(); + } + + @Override + public boolean removeAll(Collection c) { + boolean ret = super.removeAll(c); + notifyChange(); + return ret; + } + + @Override + public boolean retainAll(Collection c) { + boolean ret = super.retainAll(c); + notifyChange(); + return ret; + } + + @Override + public T set(int index, T element) { + T ret = super.set(index, element); + notifyChange(); + return ret; + } + + @Override + public void add(int index, T element) { + super.add(index, element); + notifyChange(); + } + + @Override + public T remove(int index) { + T ret = super.remove(index); + notifyChange(); + return ret; + } + + @Override + public String toString() { + Iterator it = iterator(); + if (!it.hasNext()) { + return "[]"; + } + String sep = ""; + StringBuilder sb = new StringBuilder(); + sb.append('['); + while (it.hasNext()) { + T t = it.next(); + sb.append(sep); + sb.append(ConvertTypes.toJSON(t)); + sep = ","; + } + sb.append(']'); + return sb.toString(); + } + + + @JavaScriptOnly(name = "koArray", value = "function() { return this.toArray___3Ljava_lang_Object_2(); }") + private static native int koArray(); + + private void notifyChange() { + Knockout m = model; + if (m != null) { + m.valueHasMutated(name); + for (String dependant : deps) { + m.valueHasMutated(dependant); + } + } + Runnable r = onchange; + if (r != null) { + r.run(); + } + } + + @Override + public KOList clone() { + KOList ko = (KOList)super.clone(); + ko.model = null; + return ko; + } + +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Fri May 17 10:27:41 2013 +0200 @@ -18,6 +18,7 @@ package org.apidesign.bck2brwsr.htmlpage; import java.lang.reflect.Method; +import java.util.List; import org.apidesign.bck2brwsr.core.ExtraJavaScript; import org.apidesign.bck2brwsr.core.JavaScriptBody; @@ -29,38 +30,40 @@ public class Knockout { /** used by tests */ static Knockout next; - - Knockout() { + private final Object model; + + Knockout(Object model) { + this.model = model == null ? this : model; } public static Knockout applyBindings( - Class modelClass, M model, String[] propsGettersAndSetters + Object model, String[] propsGettersAndSetters, + String[] methodsAndSignatures + ) { + applyImpl(propsGettersAndSetters, model.getClass(), model, model, methodsAndSignatures); + return new Knockout(model); + } + public static Knockout applyBindings( + Class modelClass, M model, String[] propsGettersAndSetters, + String[] methodsAndSignatures ) { Knockout bindings = next; next = null; if (bindings == null) { - bindings = new Knockout(); + bindings = new Knockout(null); } - for (int i = 0; i < propsGettersAndSetters.length; i += 4) { - try { - Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]); - bind(bindings, model, propsGettersAndSetters[i], - propsGettersAndSetters[i + 1], - propsGettersAndSetters[i + 2], - getter.getReturnType().isPrimitive() - ); - } catch (NoSuchMethodException ex) { - throw new IllegalStateException(ex.getMessage()); - } - } + applyImpl(propsGettersAndSetters, modelClass, bindings, model, methodsAndSignatures); applyBindings(bindings); return bindings; } - @JavaScriptBody(args = { "prop" }, body = - "this[prop].valueHasMutated();" + public void valueHasMutated(String prop) { + valueHasMutated(model, prop); + } + @JavaScriptBody(args = { "self", "prop" }, body = + "self[prop].valueHasMutated();" ) - public void valueHasMutated(String prop) { + public void valueHasMutated(Object self, String prop) { } @@ -68,26 +71,60 @@ public static void triggerEvent(String id, String ev) { } - @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive" }, body = + @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive", "array" }, body = "var bnd = {\n" - + " read: function() {\n" + + " 'read': function() {\n" + " var v = model[getter]();\n" + + " if (array) v = v.koArray();\n" + " return v;\n" + " },\n" - + " owner: bindings\n" + + " 'owner': bindings\n" + "};\n" + "if (setter != null) {\n" - + " bnd.write = function(val) {\n" + + " bnd['write'] = function(val) {\n" + " model[setter](primitive ? new Number(val) : val);\n" + " };\n" + "}\n" - + "bindings[prop] = ko.computed(bnd);" + + "bindings[prop] = ko['computed'](bnd);" ) private static void bind( - Object bindings, Object model, String prop, String getter, String setter, boolean primitive + Object bindings, Object model, String prop, String getter, String setter, boolean primitive, boolean array + ) { + } + + @JavaScriptBody(args = { "bindings", "model", "prop", "sig" }, body = + "bindings[prop] = function(data, ev) { model[sig](data, ev); };" + ) + private static void expose( + Object bindings, Object model, String prop, String sig ) { } @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);") private static void applyBindings(Object bindings) {} + + private static void applyImpl( + String[] propsGettersAndSetters, + Class modelClass, + Object bindings, + Object model, + String[] methodsAndSignatures + ) throws IllegalStateException, SecurityException { + for (int i = 0; i < propsGettersAndSetters.length; i += 4) { + try { + Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]); + bind(bindings, model, propsGettersAndSetters[i], + propsGettersAndSetters[i + 1], + propsGettersAndSetters[i + 2], + getter.getReturnType().isPrimitive(), + List.class.isAssignableFrom(getter.getReturnType())); + } catch (NoSuchMethodException ex) { + throw new IllegalStateException(ex.getMessage()); + } + } + for (int i = 0; i < methodsAndSignatures.length; i += 2) { + expose( + bindings, model, methodsAndSignatures[i], methodsAndSignatures[i + 1]); + } + } } diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Fri May 17 10:27:41 2013 +0200 @@ -20,23 +20,30 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; +import java.io.StringWriter; import java.io.Writer; +import java.lang.annotation.AnnotationTypeMismatchException; +import java.lang.annotation.IncompleteAnnotationException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.WeakHashMap; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Completion; import javax.annotation.processing.Completions; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; @@ -44,13 +51,21 @@ import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; import javax.lang.model.type.MirroredTypeException; +import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; import javax.tools.Diagnostic; import javax.tools.FileObject; import javax.tools.StandardLocation; import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; +import org.apidesign.bck2brwsr.htmlpage.api.Model; import org.apidesign.bck2brwsr.htmlpage.api.On; +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction; +import org.apidesign.bck2brwsr.htmlpage.api.OnPropertyChange; +import org.apidesign.bck2brwsr.htmlpage.api.OnReceive; import org.apidesign.bck2brwsr.htmlpage.api.Page; import org.apidesign.bck2brwsr.htmlpage.api.Property; import org.openide.util.lookup.ServiceProvider; @@ -62,89 +77,70 @@ */ @ServiceProvider(service=Processor.class) @SupportedAnnotationTypes({ + "org.apidesign.bck2brwsr.htmlpage.api.Model", "org.apidesign.bck2brwsr.htmlpage.api.Page", + "org.apidesign.bck2brwsr.htmlpage.api.OnFunction", + "org.apidesign.bck2brwsr.htmlpage.api.OnReceive", + "org.apidesign.bck2brwsr.htmlpage.api.OnPropertyChange", + "org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty", "org.apidesign.bck2brwsr.htmlpage.api.On" }) public final class PageProcessor extends AbstractProcessor { + private final Map models = new WeakHashMap<>(); + private final Map verify = new WeakHashMap<>(); @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { - for (Element e : roundEnv.getElementsAnnotatedWith(Page.class)) { - Page p = e.getAnnotation(Page.class); - if (p == null) { - continue; - } - PackageElement pe = (PackageElement)e.getEnclosingElement(); - String pkg = pe.getQualifiedName().toString(); - - ProcessPage pp; - try { - InputStream is = openStream(pkg, p.xhtml()); - pp = ProcessPage.readPage(is); - is.close(); - } catch (IOException iOException) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't read " + p.xhtml(), e); - return false; - } - Writer w; - String className = p.className(); - if (className.isEmpty()) { - int indx = p.xhtml().indexOf('.'); - className = p.xhtml().substring(0, indx); - } - try { - FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e); - w = new OutputStreamWriter(java.openOutputStream()); - try { - w.append("package " + pkg + ";\n"); - w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n"); - w.append("final class ").append(className).append(" {\n"); - w.append(" private boolean locked;\n"); - if (!initializeOnClick(className, (TypeElement) e, w, pp)) { - return false; - } - for (String id : pp.ids()) { - String tag = pp.tagNameForId(id); - String type = type(tag); - w.append(" ").append("public final "). - append(type).append(' ').append(cnstnt(id)).append(" = new "). - append(type).append("(\"").append(id).append("\");\n"); - } - List propsGetSet = new ArrayList(); - Map> propsDeps = new HashMap>(); - generateComputedProperties(w, e.getEnclosedElements(), propsGetSet, propsDeps); - generateProperties(w, p.properties(), propsGetSet, propsDeps); - w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n"); - if (!propsGetSet.isEmpty()) { - w.write("public " + className + " applyBindings() {\n"); - w.write(" ko = org.apidesign.bck2brwsr.htmlpage.Knockout.applyBindings("); - w.write(className + ".class, this, "); - w.write("new String[] {\n"); - String sep = ""; - for (String n : propsGetSet) { - w.write(sep); - if (n == null) { - w.write(" null"); - } else { - w.write(" \"" + n + "\""); - } - sep = ",\n"; - } - w.write("\n });\n return this;\n}\n"); - - w.write("public void triggerEvent(Element e, OnEvent ev) {\n"); - w.write(" org.apidesign.bck2brwsr.htmlpage.Knockout.triggerEvent(e.getId(), ev.getElementPropertyName());\n"); - w.write("}\n"); - } - w.append("}\n"); - } finally { - w.close(); - } - } catch (IOException ex) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't create " + className + ".java", e); - return false; + boolean ok = true; + for (Element e : roundEnv.getElementsAnnotatedWith(Model.class)) { + if (!processModel(e)) { + ok = false; } } - return true; + for (Element e : roundEnv.getElementsAnnotatedWith(Page.class)) { + if (!processPage(e)) { + ok = false; + } + } + if (roundEnv.processingOver()) { + models.clear(); + for (Map.Entry entry : verify.entrySet()) { + TypeElement te = (TypeElement)entry.getKey(); + String fqn = processingEnv.getElementUtils().getBinaryName(te).toString(); + Element finalElem = processingEnv.getElementUtils().getTypeElement(fqn); + if (finalElem == null) { + continue; + } + Prprt[] props; + Model m = finalElem.getAnnotation(Model.class); + if (m != null) { + props = Prprt.wrap(processingEnv, finalElem, m.properties()); + } else { + Page p = finalElem.getAnnotation(Page.class); + props = Prprt.wrap(processingEnv, finalElem, p.properties()); + } + for (Prprt p : props) { + boolean[] isModel = { false }; + boolean[] isEnum = { false }; + boolean[] isPrimitive = { false }; + String t = checkType(p, isModel, isEnum, isPrimitive); + if (isEnum[0]) { + continue; + } + if (isPrimitive[0]) { + continue; + } + if (isModel[0]) { + continue; + } + if ("java.lang.String".equals(t)) { + continue; + } + error("The type " + t + " should be defined by @Model annotation", entry.getKey()); + } + } + verify.clear(); + } + return ok; } private InputStream openStream(String pkg, String name) throws IOException { @@ -157,6 +153,236 @@ } } + private void error(String msg, Element e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e); + } + + private boolean processModel(Element e) { + boolean ok = true; + Model m = e.getAnnotation(Model.class); + if (m == null) { + return true; + } + String pkg = findPkgName(e); + Writer w; + String className = m.className(); + models.put(e, className); + try { + StringWriter body = new StringWriter(); + List propsGetSet = new ArrayList<>(); + List functions = new ArrayList<>(); + Map> propsDeps = new HashMap<>(); + Map> functionDeps = new HashMap<>(); + Prprt[] props = createProps(e, m.properties()); + + if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) { + ok = false; + } + if (!generateOnChange(e, propsDeps, props, className, functionDeps)) { + ok = false; + } + if (!generateProperties(e, body, props, propsGetSet, propsDeps, functionDeps)) { + ok = false; + } + if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) { + ok = false; + } + FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e); + w = new OutputStreamWriter(java.openOutputStream()); + try { + w.append("package " + pkg + ";\n"); + w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n"); + w.append("import org.apidesign.bck2brwsr.htmlpage.KOList;\n"); + w.append("import org.apidesign.bck2brwsr.core.JavaScriptOnly;\n"); + w.append("final class ").append(className).append(" implements Cloneable {\n"); + w.append(" private boolean locked;\n"); + w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n"); + w.append(body.toString()); + w.append(" private static Class<" + inPckName(e) + "> modelFor() { return null; }\n"); + w.append(" public ").append(className).append("() {\n"); + w.append(" intKnckt();\n"); + w.append(" };\n"); + w.append(" private void intKnckt() {\n"); + w.append(" ko = org.apidesign.bck2brwsr.htmlpage.Knockout.applyBindings(this, "); + writeStringArray(propsGetSet, w); + w.append(", "); + writeStringArray(functions, w); + w.append(" );\n"); + w.append(" };\n"); + w.append(" ").append(className).append("(Object json) {\n"); + int values = 0; + for (int i = 0; i < propsGetSet.size(); i += 4) { + Prprt p = findPrprt(props, propsGetSet.get(i)); + if (p == null) { + continue; + } + values++; + } + w.append(" Object[] ret = new Object[" + values + "];\n"); + w.append(" org.apidesign.bck2brwsr.htmlpage.ConvertTypes.extractJSON(json, new String[] {\n"); + for (int i = 0; i < propsGetSet.size(); i += 4) { + Prprt p = findPrprt(props, propsGetSet.get(i)); + if (p == null) { + continue; + } + w.append(" \"").append(propsGetSet.get(i)).append("\",\n"); + } + w.append(" }, ret);\n"); + for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 4) { + final String pn = propsGetSet.get(i); + Prprt p = findPrprt(props, pn); + if (p == null) { + continue; + } + boolean[] isModel = { false }; + boolean[] isEnum = { false }; + boolean isPrimitive[] = { false }; + String type = checkType(props[prop++], isModel, isEnum, isPrimitive); + if (p.array()) { + w.append("if (ret[" + cnt + "] instanceof Object[]) {\n"); + w.append(" for (Object e : ((Object[])ret[" + cnt + "])) {\n"); + if (isModel[0]) { + w.append(" this.prop_").append(pn).append(".add(new "); + w.append(type).append("(e));\n"); + } else if (isEnum[0]) { + w.append(" this.prop_").append(pn); + w.append(".add(e == null ? null : "); + w.append(type).append(".valueOf((String)e));\n"); + } else { + if (isPrimitive(type)) { + w.append(" this.prop_").append(pn).append(".add(((Number)e)."); + w.append(type).append("Value());\n"); + } else { + w.append(" this.prop_").append(pn).append(".add(("); + w.append(type).append(")e);\n"); + } + } + w.append(" }\n"); + w.append("}\n"); + } else { + if (isEnum[0]) { + w.append(" this.prop_").append(pn); + w.append(" = ret[" + cnt + "] == null ? null : "); + w.append(type).append(".valueOf((String)ret[" + cnt + "]);\n"); + } else if (isPrimitive(type)) { + w.append(" this.prop_").append(pn); + w.append(" = ((Number)").append("ret[" + cnt + "])."); + w.append(type).append("Value();\n"); + } else { + w.append(" this.prop_").append(pn); + w.append(" = (").append(type).append(')'); + w.append("ret[" + cnt + "];\n"); + } + } + cnt++; + } + w.append(" intKnckt();\n"); + w.append(" };\n"); + writeToString(props, w); + writeClone(className, props, w); + w.append("}\n"); + } finally { + w.close(); + } + } catch (IOException ex) { + error("Can't create " + className + ".java", e); + return false; + } + return ok; + } + + private boolean processPage(Element e) { + boolean ok = true; + Page p = e.getAnnotation(Page.class); + if (p == null) { + return true; + } + String pkg = findPkgName(e); + + ProcessPage pp; + try (InputStream is = openStream(pkg, p.xhtml())) { + pp = ProcessPage.readPage(is); + is.close(); + } catch (IOException iOException) { + error("Can't read " + p.xhtml() + " as " + iOException.getMessage(), e); + ok = false; + pp = null; + } + Writer w; + String className = p.className(); + if (className.isEmpty()) { + int indx = p.xhtml().indexOf('.'); + className = p.xhtml().substring(0, indx); + } + try { + StringWriter body = new StringWriter(); + List propsGetSet = new ArrayList<>(); + List functions = new ArrayList<>(); + Map> propsDeps = new HashMap<>(); + Map> functionDeps = new HashMap<>(); + + Prprt[] props = createProps(e, p.properties()); + if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) { + ok = false; + } + if (!generateOnChange(e, propsDeps, props, className, functionDeps)) { + ok = false; + } + if (!generateProperties(e, body, props, propsGetSet, propsDeps, functionDeps)) { + ok = false; + } + if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) { + ok = false; + } + if (!generateReceive(e, body, className, e.getEnclosedElements(), functions)) { + ok = false; + } + + FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e); + w = new OutputStreamWriter(java.openOutputStream()); + try { + w.append("package " + pkg + ";\n"); + w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n"); + w.append("import org.apidesign.bck2brwsr.htmlpage.KOList;\n"); + w.append("final class ").append(className).append(" {\n"); + w.append(" private boolean locked;\n"); + if (!initializeOnClick(className, (TypeElement) e, w, pp)) { + ok = false; + } else { + if (pp != null) for (String id : pp.ids()) { + String tag = pp.tagNameForId(id); + String type = type(tag); + w.append(" ").append("public final "). + append(type).append(' ').append(cnstnt(id)).append(" = new "). + append(type).append("(\"").append(id).append("\");\n"); + } + } + w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n"); + w.append(body.toString()); + if (!propsGetSet.isEmpty()) { + w.write("public " + className + " applyBindings() {\n"); + w.write(" ko = org.apidesign.bck2brwsr.htmlpage.Knockout.applyBindings("); + w.write(className + ".class, this, "); + writeStringArray(propsGetSet, w); + w.append(", "); + writeStringArray(functions, w); + w.write(");\n return this;\n}\n"); + + w.write("public void triggerEvent(Element e, OnEvent ev) {\n"); + w.write(" org.apidesign.bck2brwsr.htmlpage.Knockout.triggerEvent(e.getId(), ev.getElementPropertyName());\n"); + w.write("}\n"); + } + w.append("}\n"); + } finally { + w.close(); + } + } catch (IOException ex) { + error("Can't create " + className + ".java", e); + return false; + } + return ok; + } + private static String type(String tag) { if (tag.equals("title")) { return "Title"; @@ -177,12 +403,13 @@ } private static String cnstnt(String id) { - return id.toUpperCase(Locale.ENGLISH).replace('.', '_').replace('-', '_'); + return id.replace('.', '_').replace('-', '_'); } private boolean initializeOnClick( String className, TypeElement type, Writer w, ProcessPage pp ) throws IOException { + boolean ok = true; TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); { //for (Element clazz : pe.getEnclosedElements()) { // if (clazz.getKind() != ElementKind.CLASS) { @@ -195,46 +422,27 @@ On oc = method.getAnnotation(On.class); if (oc != null) { for (String id : oc.id()) { + if (pp == null) { + error("id = " + id + " not found in HTML page.", method); + ok = false; + continue; + } if (pp.tagNameForId(id) == null) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "id = " + id + " does not exist in the HTML page. Found only " + pp.ids(), method); - return false; + error("id = " + id + " does not exist in the HTML page. Found only " + pp.ids(), method); + ok = false; + continue; } ExecutableElement ee = (ExecutableElement)method; - StringBuilder params = new StringBuilder(); - { - boolean first = true; - for (VariableElement ve : ee.getParameters()) { - if (!first) { - params.append(", "); - } - first = false; - if (ve.asType() == stringType) { - params.append('"').append(id).append('"'); - continue; - } - String rn = ve.asType().toString(); - int last = rn.lastIndexOf('.'); - if (last >= 0) { - rn = rn.substring(last + 1); - } - if (rn.equals(className)) { - params.append(className).append(".this"); - continue; - } - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "@On method can only accept String or " + className + " arguments", - ee - ); - return false; - } - } + CharSequence params = wrapParams(ee, id, className, "ev", null); if (!ee.getModifiers().contains(Modifier.STATIC)) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method has to be static", ee); - return false; + error("@On method has to be static", ee); + ok = false; + continue; } if (ee.getModifiers().contains(Modifier.PRIVATE)) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method can't be private", ee); - return false; + error("@On method can't be private", ee); + ok = false; + continue; } w.append(" OnEvent." + oc.event()).append(".of(").append(cnstnt(id)). append(").perform(new OnDispatch(" + dispatchCnt + "));\n"); @@ -252,10 +460,10 @@ } w.append(" }\n"); if (dispatchCnt > 0) { - w.append("class OnDispatch implements Runnable {\n"); + w.append("class OnDispatch implements OnHandler {\n"); w.append(" private final int dispatch;\n"); w.append(" OnDispatch(int d) { dispatch = d; }\n"); - w.append(" public void run() {\n"); + w.append(" public void onEvent(Object ev) {\n"); w.append(" switch (dispatch) {\n"); w.append(dispatch); w.append(" }\n"); @@ -265,7 +473,7 @@ } - return true; + return ok; } @Override @@ -279,8 +487,7 @@ Element cls = findClass(element); Page p = cls.getAnnotation(Page.class); - PackageElement pe = (PackageElement) cls.getEnclosingElement(); - String pkg = pe.getQualifiedName().toString(); + String pkg = findPkgName(cls); ProcessPage pp; try { InputStream is = openStream(pkg, p.xhtml()); @@ -290,7 +497,7 @@ return Collections.emptyList(); } - List cc = new ArrayList(); + List cc = new ArrayList<>(); userText = userText.substring(1); for (String id : pp.ids()) { if (id.startsWith(userText)) { @@ -311,44 +518,89 @@ return e.getEnclosingElement(); } - private static void generateProperties( - Writer w, Property[] properties, Collection props, - Map> deps + private boolean generateProperties( + Element where, + Writer w, Prprt[] properties, + Collection props, + Map> deps, + Map> functionDeps ) throws IOException { - for (Property p : properties) { - final String tn = typeName(p); - String[] gs = toGetSet(p.name(), tn); + boolean ok = true; + for (Prprt p : properties) { + final String tn; + tn = typeName(where, p); + String[] gs = toGetSet(p.name(), tn, p.array()); - w.write("private " + tn + " prop_" + p.name() + ";\n"); - w.write("public " + tn + " " + gs[0] + "() {\n"); - w.write(" if (locked) throw new IllegalStateException();\n"); - w.write(" return prop_" + p.name() + ";\n"); - w.write("}\n"); - w.write("public void " + gs[1] + "(" + tn + " v) {\n"); - w.write(" if (locked) throw new IllegalStateException();\n"); - w.write(" prop_" + p.name() + " = v;\n"); - w.write(" if (ko != null) {\n"); - w.write(" ko.valueHasMutated(\"" + p.name() + "\");\n"); - final Collection dependants = deps.get(p.name()); - if (dependants != null) { - for (String depProp : dependants) { - w.write(" ko.valueHasMutated(\"" + depProp + "\");\n"); + if (p.array()) { + w.write("private KOList<" + tn + "> prop_" + p.name() + " = new KOList<" + tn + ">(\"" + + p.name() + "\""); + Collection dependants = deps.get(p.name()); + if (dependants != null) { + for (String depProp : dependants) { + w.write(", "); + w.write('\"'); + w.write(depProp); + w.write('\"'); + } } + w.write(")"); + + dependants = functionDeps.get(p.name()); + if (dependants != null) { + w.write(".onChange(new Runnable() { public void run() {\n"); + for (String call : dependants) { + w.append(call); + } + w.write("}})"); + } + w.write(";\n"); + + w.write("public java.util.List<" + tn + "> " + gs[0] + "() {\n"); + w.write(" if (locked) throw new IllegalStateException();\n"); + w.write(" prop_" + p.name() + ".assign(ko);\n"); + w.write(" return prop_" + p.name() + ";\n"); + w.write("}\n"); + } else { + w.write("private " + tn + " prop_" + p.name() + ";\n"); + w.write("public " + tn + " " + gs[0] + "() {\n"); + w.write(" if (locked) throw new IllegalStateException();\n"); + w.write(" return prop_" + p.name() + ";\n"); + w.write("}\n"); + w.write("public void " + gs[1] + "(" + tn + " v) {\n"); + w.write(" if (locked) throw new IllegalStateException();\n"); + w.write(" prop_" + p.name() + " = v;\n"); + w.write(" if (ko != null) {\n"); + w.write(" ko.valueHasMutated(\"" + p.name() + "\");\n"); + Collection dependants = deps.get(p.name()); + if (dependants != null) { + for (String depProp : dependants) { + w.write(" ko.valueHasMutated(\"" + depProp + "\");\n"); + } + } + w.write(" }\n"); + dependants = functionDeps.get(p.name()); + if (dependants != null) { + for (String call : dependants) { + w.append(call); + } + } + w.write("}\n"); } - w.write(" }\n"); - w.write("}\n"); props.add(p.name()); props.add(gs[2]); props.add(gs[3]); props.add(gs[0]); } + return ok; } private boolean generateComputedProperties( - Writer w, Collection arr, Collection props, + Writer w, Prprt[] fixedProps, + Collection arr, Collection props, Map> deps ) throws IOException { + boolean ok = true; for (Element e : arr) { if (e.getKind() != ElementKind.METHOD) { continue; @@ -357,30 +609,43 @@ continue; } ExecutableElement ee = (ExecutableElement)e; - final String tn = ee.getReturnType().toString(); + final TypeMirror rt = ee.getReturnType(); + final Types tu = processingEnv.getTypeUtils(); + TypeMirror ert = tu.erasure(rt); + String tn = fqn(ert, ee); + boolean array = false; + if (tn.equals("java.util.List")) { + array = true; + } + final String sn = ee.getSimpleName().toString(); - String[] gs = toGetSet(sn, tn); + String[] gs = toGetSet(sn, tn, array); w.write("public " + tn + " " + gs[0] + "() {\n"); w.write(" if (locked) throw new IllegalStateException();\n"); int arg = 0; for (VariableElement pe : ee.getParameters()) { final String dn = pe.getSimpleName().toString(); - final String dt = pe.asType().toString(); - String[] call = toGetSet(dn, dt); + + if (!verifyPropName(pe, dn, fixedProps)) { + ok = false; + } + + final String dt = fqn(pe.asType(), ee); + String[] call = toGetSet(dn, dt, false); w.write(" " + dt + " arg" + (++arg) + " = "); w.write(call[0] + "();\n"); Collection depends = deps.get(dn); if (depends == null) { - depends = new LinkedHashSet(); + depends = new LinkedHashSet<>(); deps.put(dn, depends); } depends.add(sn); } w.write(" try {\n"); w.write(" locked = true;\n"); - w.write(" return " + e.getEnclosingElement().getSimpleName() + '.' + e.getSimpleName() + "("); + w.write(" return " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + e.getSimpleName() + "("); String sep = ""; for (int i = 1; i <= arg; i++) { w.write(sep); @@ -392,17 +657,17 @@ w.write(" locked = false;\n"); w.write(" }\n"); w.write("}\n"); - + props.add(e.getSimpleName().toString()); props.add(gs[2]); props.add(null); props.add(gs[0]); } - return true; + return ok; } - private static String[] toGetSet(String name, String type) { + private static String[] toGetSet(String name, String type, boolean array) { String n = Character.toUpperCase(name.charAt(0)) + name.substring(1); String bck2brwsrType = "L" + type.replace('.', '_') + "_2"; if ("int".equals(type)) { @@ -417,6 +682,14 @@ bck2brwsrType = "Z"; } final String nu = n.replace('.', '_'); + if (array) { + return new String[] { + "get" + n, + null, + "get" + nu + "__Ljava_util_List_2", + null + }; + } return new String[]{ pref + n, "set" + n, @@ -425,11 +698,702 @@ }; } - private static String typeName(Property p) { - try { - return p.type().getName(); - } catch (MirroredTypeException ex) { - return ex.getTypeMirror().toString(); + private String typeName(Element where, Prprt p) { + String ret; + boolean[] isModel = { false }; + boolean[] isEnum = { false }; + boolean isPrimitive[] = { false }; + ret = checkType(p, isModel, isEnum, isPrimitive); + if (p.array()) { + String bt = findBoxedType(ret); + if (bt != null) { + return bt; + } + } + return ret; + } + + private static String findBoxedType(String ret) { + if (ret.equals("boolean")) { + return Boolean.class.getName(); + } + if (ret.equals("byte")) { + return Byte.class.getName(); + } + if (ret.equals("short")) { + return Short.class.getName(); + } + if (ret.equals("char")) { + return Character.class.getName(); + } + if (ret.equals("int")) { + return Integer.class.getName(); + } + if (ret.equals("long")) { + return Long.class.getName(); + } + if (ret.equals("float")) { + return Float.class.getName(); + } + if (ret.equals("double")) { + return Double.class.getName(); + } + return null; + } + + private boolean verifyPropName(Element e, String propName, Prprt[] existingProps) { + StringBuilder sb = new StringBuilder(); + String sep = ""; + for (Prprt Prprt : existingProps) { + if (Prprt.name().equals(propName)) { + return true; + } + sb.append(sep); + sb.append('"'); + sb.append(Prprt.name()); + sb.append('"'); + sep = ", "; + } + error( + propName + " is not one of known properties: " + sb + , e + ); + return false; + } + + private static String findPkgName(Element e) { + for (;;) { + if (e.getKind() == ElementKind.PACKAGE) { + return ((PackageElement)e).getQualifiedName().toString(); + } + e = e.getEnclosingElement(); } } + + private boolean generateFunctions( + Element clazz, StringWriter body, String className, + List enclosedElements, List functions + ) { + for (Element m : enclosedElements) { + if (m.getKind() != ElementKind.METHOD) { + continue; + } + ExecutableElement e = (ExecutableElement)m; + OnFunction onF = e.getAnnotation(OnFunction.class); + if (onF == null) { + continue; + } + if (!e.getModifiers().contains(Modifier.STATIC)) { + error("@OnFunction method needs to be static", e); + return false; + } + if (e.getModifiers().contains(Modifier.PRIVATE)) { + error("@OnFunction method cannot be private", e); + return false; + } + if (e.getReturnType().getKind() != TypeKind.VOID) { + error("@OnFunction method should return void", e); + return false; + } + String n = e.getSimpleName().toString(); + body.append("private void ").append(n).append("(Object data, Object ev) {\n"); + body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); + body.append(wrapParams(e, null, className, "ev", "data")); + body.append(");\n"); + body.append("}\n"); + + functions.add(n); + functions.add(n + "__VLjava_lang_Object_2Ljava_lang_Object_2"); + } + return true; + } + + private boolean generateOnChange(Element clazz, Map> propDeps, + Prprt[] properties, String className, + Map> functionDeps + ) { + for (Element m : clazz.getEnclosedElements()) { + if (m.getKind() != ElementKind.METHOD) { + continue; + } + ExecutableElement e = (ExecutableElement) m; + OnPropertyChange onPC = e.getAnnotation(OnPropertyChange.class); + if (onPC == null) { + continue; + } + for (String pn : onPC.value()) { + if (findPrprt(properties, pn) == null && findDerivedFrom(propDeps, pn).isEmpty()) { + error("No Prprt named '" + pn + "' in the model", clazz); + return false; + } + } + if (!e.getModifiers().contains(Modifier.STATIC)) { + error("@OnPrprtChange method needs to be static", e); + return false; + } + if (e.getModifiers().contains(Modifier.PRIVATE)) { + error("@OnPrprtChange method cannot be private", e); + return false; + } + if (e.getReturnType().getKind() != TypeKind.VOID) { + error("@OnPrprtChange method should return void", e); + return false; + } + String n = e.getSimpleName().toString(); + + + for (String pn : onPC.value()) { + StringBuilder call = new StringBuilder(); + call.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); + call.append(wrapPropName(e, className, "name", pn)); + call.append(");\n"); + + Collection change = functionDeps.get(pn); + if (change == null) { + change = new ArrayList<>(); + functionDeps.put(pn, change); + } + change.add(call.toString()); + for (String dpn : findDerivedFrom(propDeps, pn)) { + change = functionDeps.get(dpn); + if (change == null) { + change = new ArrayList<>(); + functionDeps.put(dpn, change); + } + change.add(call.toString()); + } + } + } + return true; + } + + private boolean generateReceive( + Element clazz, StringWriter body, String className, + List enclosedElements, List functions + ) { + for (Element m : enclosedElements) { + if (m.getKind() != ElementKind.METHOD) { + continue; + } + ExecutableElement e = (ExecutableElement)m; + OnReceive onR = e.getAnnotation(OnReceive.class); + if (onR == null) { + continue; + } + if (!e.getModifiers().contains(Modifier.STATIC)) { + error("@OnReceive method needs to be static", e); + return false; + } + if (e.getModifiers().contains(Modifier.PRIVATE)) { + error("@OnReceive method cannot be private", e); + return false; + } + if (e.getReturnType().getKind() != TypeKind.VOID) { + error("@OnReceive method should return void", e); + return false; + } + String modelClass = null; + boolean expectsList = false; + List args = new ArrayList<>(); + { + for (VariableElement ve : e.getParameters()) { + TypeMirror modelType = null; + if (ve.asType().toString().equals(className)) { + args.add(className + ".this"); + } else if (isModel(ve.asType())) { + modelType = ve.asType(); + } else if (ve.asType().getKind() == TypeKind.ARRAY) { + modelType = ((ArrayType)ve.asType()).getComponentType(); + expectsList = true; + } + if (modelType != null) { + if (modelClass != null) { + error("There can be only one model class among arguments", e); + } else { + modelClass = modelType.toString(); + if (expectsList) { + args.add("arr"); + } else { + args.add("arr[0]"); + } + } + } + } + } + if (modelClass == null) { + error("The method needs to have one @Model class as parameter", e); + } + String n = e.getSimpleName().toString(); + body.append("public void ").append(n).append("("); + StringBuilder assembleURL = new StringBuilder(); + String jsonpVarName = null; + { + String sep = ""; + boolean skipJSONP = onR.jsonp().isEmpty(); + for (String p : findParamNames(e, onR.url(), assembleURL)) { + if (!skipJSONP && p.equals(onR.jsonp())) { + skipJSONP = true; + jsonpVarName = p; + continue; + } + body.append(sep); + body.append("String ").append(p); + sep = ", "; + } + if (!skipJSONP) { + error( + "Name of jsonp attribute ('" + onR.jsonp() + + "') is not used in url attribute '" + onR.url() + "'", e + ); + } + } + body.append(") {\n"); + body.append(" final Object[] result = { null };\n"); + body.append( + " class ProcessResult implements Runnable {\n" + + " @Override\n" + + " public void run() {\n" + + " Object value = result[0];\n"); + body.append( + " " + modelClass + "[] arr;\n"); + body.append( + " if (value instanceof Object[]) {\n" + + " Object[] data = ((Object[])value);\n" + + " arr = new " + modelClass + "[data.length];\n" + + " for (int i = 0; i < data.length; i++) {\n" + + " arr[i] = new " + modelClass + "(data[i]);\n" + + " }\n" + + " } else {\n" + + " arr = new " + modelClass + "[1];\n" + + " arr[0] = new " + modelClass + "(value);\n" + + " }\n" + ); + { + body.append(clazz.getSimpleName()).append(".").append(n).append("("); + String sep = ""; + for (String arg : args) { + body.append(sep); + body.append(arg); + sep = ", "; + } + body.append(");\n"); + } + body.append( + " }\n" + + " }\n" + ); + body.append(" ProcessResult pr = new ProcessResult();\n"); + if (jsonpVarName != null) { + body.append(" String ").append(jsonpVarName). + append(" = org.apidesign.bck2brwsr.htmlpage.ConvertTypes.createJSONP(result, pr);\n"); + } + body.append(" org.apidesign.bck2brwsr.htmlpage.ConvertTypes.loadJSON(\n "); + body.append(assembleURL); + body.append(", result, pr, ").append(jsonpVarName).append("\n );\n"); +// body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); +// body.append(wrapParams(e, null, className, "ev", "data")); +// body.append(");\n"); + body.append("}\n"); + } + return true; + } + + private CharSequence wrapParams( + ExecutableElement ee, String id, String className, String evName, String dataName + ) { + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); + StringBuilder params = new StringBuilder(); + boolean first = true; + for (VariableElement ve : ee.getParameters()) { + if (!first) { + params.append(", "); + } + first = false; + String toCall = null; + if (ve.asType() == stringType) { + if (ve.getSimpleName().contentEquals("id")) { + params.append('"').append(id).append('"'); + continue; + } + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toString("; + } + if (ve.asType().getKind() == TypeKind.DOUBLE) { + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toDouble("; + } + if (ve.asType().getKind() == TypeKind.INT) { + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toInt("; + } + if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) { + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toModel(" + ve.asType() + ".class, "; + } + + if (toCall != null) { + params.append(toCall); + if (dataName != null && ve.getSimpleName().contentEquals(dataName)) { + params.append(dataName); + params.append(", null"); + } else { + if (evName == null) { + final StringBuilder sb = new StringBuilder(); + sb.append("Unexpected string parameter name."); + if (dataName != null) { + sb.append(" Try \"").append(dataName).append("\""); + } + error(sb.toString(), ee); + } + params.append(evName); + params.append(", \""); + params.append(ve.getSimpleName().toString()); + params.append("\""); + } + params.append(")"); + continue; + } + String rn = fqn(ve.asType(), ee); + int last = rn.lastIndexOf('.'); + if (last >= 0) { + rn = rn.substring(last + 1); + } + if (rn.equals(className)) { + params.append(className).append(".this"); + continue; + } + error( + "@On method can only accept String named 'id' or " + className + " arguments", + ee + ); + } + return params; + } + + + private CharSequence wrapPropName( + ExecutableElement ee, String className, String propName, String propValue + ) { + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); + StringBuilder params = new StringBuilder(); + boolean first = true; + for (VariableElement ve : ee.getParameters()) { + if (!first) { + params.append(", "); + } + first = false; + if (ve.asType() == stringType) { + if (propName != null && ve.getSimpleName().contentEquals(propName)) { + params.append('"').append(propValue).append('"'); + } else { + error("Unexpected string parameter name. Try \"" + propName + "\".", ee); + } + continue; + } + String rn = fqn(ve.asType(), ee); + int last = rn.lastIndexOf('.'); + if (last >= 0) { + rn = rn.substring(last + 1); + } + if (rn.equals(className)) { + params.append(className).append(".this"); + continue; + } + error( + "@OnPrprtChange method can only accept String or " + className + " arguments", + ee); + } + return params; + } + + private boolean isModel(TypeMirror tm) { + final Element e = processingEnv.getTypeUtils().asElement(tm); + if (e == null) { + return false; + } + for (Element ch : e.getEnclosedElements()) { + if (ch.getKind() == ElementKind.METHOD) { + ExecutableElement ee = (ExecutableElement)ch; + if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) { + return true; + } + } + } + return models.values().contains(e.getSimpleName().toString()); + } + + private void writeStringArray(List strings, Writer w) throws IOException { + w.write("new String[] {\n"); + String sep = ""; + for (String n : strings) { + w.write(sep); + if (n == null) { + w.write(" null"); + } else { + w.write(" \"" + n + "\""); + } + sep = ",\n"; + } + w.write("\n }"); + } + + private void writeToString(Prprt[] props, Writer w) throws IOException { + w.write(" public String toString() {\n"); + w.write(" StringBuilder sb = new StringBuilder();\n"); + w.write(" sb.append('{');\n"); + String sep = ""; + for (Prprt p : props) { + w.write(sep); + w.append(" sb.append('\"').append(\"" + p.name() + "\")"); + w.append(".append('\"').append(\":\");\n"); + w.append(" sb.append(org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toJSON(prop_"); + w.append(p.name()).append("));\n"); + sep = " sb.append(',');\n"; + } + w.write(" sb.append('}');\n"); + w.write(" return sb.toString();\n"); + w.write(" }\n"); + } + private void writeClone(String className, Prprt[] props, Writer w) throws IOException { + w.write(" public " + className + " clone() {\n"); + w.write(" " + className + " ret = new " + className + "();\n"); + for (Prprt p : props) { + if (!p.array()) { + boolean isModel[] = { false }; + boolean isEnum[] = { false }; + boolean isPrimitive[] = { false }; + checkType(p, isModel, isEnum, isPrimitive); + if (!isModel[0]) { + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + ";\n"); + continue; + } + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + ".clone();\n"); + } else { + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + ".clone();\n"); + } + } + + w.write(" return ret;\n"); + w.write(" }\n"); + } + + private String inPckName(Element e) { + StringBuilder sb = new StringBuilder(); + while (e.getKind() != ElementKind.PACKAGE) { + if (sb.length() == 0) { + sb.append(e.getSimpleName()); + } else { + sb.insert(0, '.'); + sb.insert(0, e.getSimpleName()); + } + e = e.getEnclosingElement(); + } + return sb.toString(); + } + + private String fqn(TypeMirror pt, Element relative) { + if (pt.getKind() == TypeKind.ERROR) { + final Elements eu = processingEnv.getElementUtils(); + PackageElement pckg = eu.getPackageOf(relative); + return pckg.getQualifiedName() + "." + pt.toString(); + } + return pt.toString(); + } + + private String checkType(Prprt p, boolean[] isModel, boolean[] isEnum, boolean[] isPrimitive) { + TypeMirror tm; + try { + String ret = p.typeName(processingEnv); + TypeElement e = processingEnv.getElementUtils().getTypeElement(ret); + if (e == null) { + isModel[0] = true; + isEnum[0] = false; + isPrimitive[0] = false; + return ret; + } + tm = e.asType(); + } catch (MirroredTypeException ex) { + tm = ex.getTypeMirror(); + } + tm = processingEnv.getTypeUtils().erasure(tm); + isPrimitive[0] = tm.getKind().isPrimitive(); + final Element e = processingEnv.getTypeUtils().asElement(tm); + final Model m = e == null ? null : e.getAnnotation(Model.class); + + String ret; + if (m != null) { + ret = findPkgName(e) + '.' + m.className(); + isModel[0] = true; + models.put(e, m.className()); + } else if (findModelForMthd(e)) { + ret = ((TypeElement)e).getQualifiedName().toString(); + isModel[0] = true; + } else { + ret = tm.toString(); + } + TypeMirror enm = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType(); + enm = processingEnv.getTypeUtils().erasure(enm); + isEnum[0] = processingEnv.getTypeUtils().isSubtype(tm, enm); + return ret; + } + + private static boolean findModelForMthd(Element clazz) { + if (clazz == null) { + return false; + } + for (Element e : clazz.getEnclosedElements()) { + if (e.getKind() == ElementKind.METHOD) { + ExecutableElement ee = (ExecutableElement)e; + if ( + ee.getSimpleName().contentEquals("modelFor") && + ee.getParameters().isEmpty() + ) { + return true; + } + } + } + return false; + } + + private Iterable findParamNames(Element e, String url, StringBuilder assembleURL) { + List params = new ArrayList<>(); + + for (int pos = 0; ;) { + int next = url.indexOf('{', pos); + if (next == -1) { + assembleURL.append('"') + .append(url.substring(pos)) + .append('"'); + return params; + } + int close = url.indexOf('}', next); + if (close == -1) { + error("Unbalanced '{' and '}' in " + url, e); + return params; + } + final String paramName = url.substring(next + 1, close); + params.add(paramName); + assembleURL.append('"') + .append(url.substring(pos, next)) + .append("\" + ").append(paramName).append(" + "); + pos = close + 1; + } + } + + private static Prprt findPrprt(Prprt[] properties, String propName) { + for (Prprt p : properties) { + if (propName.equals(p.name())) { + return p; + } + } + return null; + } + + private boolean isPrimitive(String type) { + return + "int".equals(type) || + "double".equals(type) || + "long".equals(type) || + "short".equals(type) || + "byte".equals(type) || + "float".equals(type); + } + + private static Collection findDerivedFrom(Map> propsDeps, String derivedProp) { + Set names = new HashSet<>(); + for (Map.Entry> e : propsDeps.entrySet()) { + if (e.getValue().contains(derivedProp)) { + names.add(e.getKey()); + } + } + return names; + } + + private Prprt[] createProps(Element e, Property[] arr) { + Prprt[] ret = Prprt.wrap(processingEnv, e, arr); + Prprt[] prev = verify.put(e, ret); + if (prev != null) { + error("Two sets of properties for ", e); + } + return ret; + } + + private static class Prprt { + private final Element e; + private final AnnotationMirror tm; + private final Property p; + + public Prprt(Element e, AnnotationMirror tm, Property p) { + this.e = e; + this.tm = tm; + this.p = p; + } + + String name() { + return p.name(); + } + + boolean array() { + return p.array(); + } + + String typeName(ProcessingEnvironment env) { + try { + return p.type().getName(); + } catch (IncompleteAnnotationException | AnnotationTypeMismatchException ex) { + for (Object v : getAnnoValues(env)) { + String s = v.toString().replace(" ", ""); + if (s.startsWith("type=") && s.endsWith(".class")) { + return s.substring(5, s.length() - 6); + } + } + throw ex; + } + } + + + static Prprt[] wrap(ProcessingEnvironment pe, Element e, Property[] arr) { + if (arr.length == 0) { + return new Prprt[0]; + } + + if (e.getKind() != ElementKind.CLASS) { + throw new IllegalStateException("" + e.getKind()); + } + TypeElement te = (TypeElement)e; + List val = null; + for (AnnotationMirror an : te.getAnnotationMirrors()) { + for (Map.Entry entry : an.getElementValues().entrySet()) { + if (entry.getKey().getSimpleName().contentEquals("properties")) { + val = (List)entry.getValue().getValue(); + break; + } + } + } + if (val == null || val.size() != arr.length) { + pe.getMessager().printMessage(Diagnostic.Kind.ERROR, "" + val, e); + return new Prprt[0]; + } + Prprt[] ret = new Prprt[arr.length]; + BIG: for (int i = 0; i < ret.length; i++) { + AnnotationMirror am = (AnnotationMirror)val.get(i).getValue(); + ret[i] = new Prprt(e, am, arr[i]); + + } + return ret; + } + + private List getAnnoValues(ProcessingEnvironment pe) { + try { + Class trees = Class.forName("com.sun.tools.javac.api.JavacTrees"); + Method m = trees.getMethod("instance", ProcessingEnvironment.class); + Object instance = m.invoke(null, pe); + m = instance.getClass().getMethod("getPath", Element.class, AnnotationMirror.class); + Object path = m.invoke(instance, e, tm); + m = path.getClass().getMethod("getLeaf"); + Object leaf = m.invoke(path); + m = leaf.getClass().getMethod("getArguments"); + return (List)m.invoke(leaf); + } catch (Exception ex) { + return Collections.emptyList(); + } + } + } + } diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ComputedProperty.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ComputedProperty.java Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ComputedProperty.java Fri May 17 10:27:41 2013 +0200 @@ -22,16 +22,11 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** Can be used in classes annotated with {@link Page} annotation to - * define a derived property. Value of derived property is based on values - * of {@link Property} as enumerated by {@link Page#properties()}. - *

- * The name of the derived property is the name of the method. The arguments - * of the method define the property names (from {@link Page#properties()} list) - * the value of property depends on. - * +/** + * @deprecated Replaced by new {@link net.java.html.json.ComputedProperty net.java.html.json} API. * @author Jaroslav Tulach */ +@Deprecated @Retention(RetentionPolicy.SOURCE) @Target(ElementType.METHOD) public @interface ComputedProperty { diff -r d127d41768bd -r ae3f2aa50970 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 Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Fri May 17 10:27:41 2013 +0200 @@ -61,14 +61,18 @@ /** Executes given runnable when user performs a "click" on the given * element. + * @param data an array of one element to fill with event parameter (if any) * @param r the runnable to execute, never null */ @JavaScriptBody( args={ "ev", "r" }, body="var e = window.document.getElementById(this._id());\n" - + "e[ev._id()] = function() { r.run__V(); };\n" + + "e[ev._id()] = function(ev) {\n" + + " var d = ev ? ev : null;\n" + + " r.onEvent__VLjava_lang_Object_2(d);\n" + + "};\n" ) - final void on(OnEvent ev, Runnable r) { + final void on(OnEvent ev, OnHandler r) { } /** Shows alert message dialog in a browser. diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Model.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Model.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,38 @@ +/** + * 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.htmlpage.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @deprecated Replaced by new {@link net.java.html.json.Model net.java.html.json} API. + * @author Jaroslav Tulach + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +@Deprecated +public @interface Model { + /** Name of the model class */ + String className(); + /** List of properties in the model. + */ + Property[] properties(); +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java Fri May 17 10:27:41 2013 +0200 @@ -30,14 +30,33 @@ this.arr = arr; } + /** Registers an event handler on associated {@link OnEvent} + * and {@link Element} + * + * @param handler the handler to be called when the event occurs + */ + public void perform(final OnHandler handler) { + for (Element e : arr) { + e.on(event, handler); + } + } + /** Registers a runnable to be performed on associated {@link OnEvent} * and {@link Element}. * * @see OnEvent#of */ - public void perform(Runnable r) { + public void perform(final Runnable r) { + class W implements OnHandler { + @Override + public void onEvent(Object event) throws Exception { + r.run(); + } + } + perform(new W()); + OnHandler w = new W(); for (Element e : arr) { - e.on(event, r); + e.on(event, w); } } } diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnFunction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnFunction.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,33 @@ +/** + * 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.htmlpage.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @deprecated Replaced by new {@link net.java.html.json.Function net.java.html.json} API. + * @author Jaroslav Tulach + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.SOURCE) +@Deprecated +public @interface OnFunction { +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnHandler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnHandler.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,33 @@ +/** + * 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.htmlpage.api; + +/** Handler to be called when an event in an HTML {@link Page} appears. + * @see OnEvent + * @see OnController + * + * @author Jaroslav Tulach + */ +public interface OnHandler { + /** Called when a DOM event appears + * + * @param event the event as produced by the browser + * @throws Exception execution can throw exception + */ + public void onEvent(Object event) throws Exception; +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnPropertyChange.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnPropertyChange.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,38 @@ +/** + * 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.htmlpage.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @deprecated Replaced by new {@link net.java.html.json.OnPropertyChange net.java.html.json} API. + * @author Jaroslav Tulach + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.METHOD) +@Deprecated +public @interface OnPropertyChange { + /** Name(s) of the properties. One wishes to observe. + * + * @return valid java identifier + */ + String[] value(); +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnReceive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnReceive.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,53 @@ +/** + * 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.htmlpage.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @deprecated Replaced by new {@link net.java.html.json.OnReceive net.java.html.json} API. + * @author Jaroslav Tulach + * @since 0.6 + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.METHOD) +@Deprecated +public @interface OnReceive { + /** The URL to connect to. Can contain variable names surrounded by '{' and '}'. + * Those parameters will then become variables of the associated method. + * + * @return the (possibly parametrized) url to connect to + */ + String url(); + + /** Support for JSONP requires + * a callback from the server generated page to a function defined in the + * system. The name of such function is usually specified as a property + * (of possibly different names). By defining the jsonp attribute + * one turns on the JSONP + * transmission and specifies the name of the property. The property should + * also be used in the {@link #url()} attribute on appropriate place. + * + * @return name of a property to carry the name of JSONP + * callback function. + */ + String jsonp() default ""; +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Property.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Property.java Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Property.java Fri May 17 10:27:41 2013 +0200 @@ -20,15 +20,36 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.List; -/** Represents a property in a generated model of an HTML - * {@link Page}. - * +/** + * @deprecated Replaced by new {@link net.java.html.json.Property net.java.html.json} API. * @author Jaroslav Tulach */ @Retention(RetentionPolicy.SOURCE) @Target({}) +@Deprecated public @interface Property { + /** Name of the property. Will be used to define proper getter and setter + * in the associated class. + * + * @return valid java identifier + */ String name(); + + /** Type of the property. Can either be primitive type (like int.class, + * double.class, etc.), {@link String} or complex model + * class (defined by {@link Model} property). + * + * @return the class of the property + */ Class type(); + + /** Is this property an array of the {@link #type()} or a single value? + * If the property is an array, only its getter (returning mutable {@link List} of + * the boxed {@link #type()}). + * + * @return true, if this is supposed to be an array of values. + */ + boolean array() default false; } diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js --- a/javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js Fri May 17 10:27:41 2013 +0200 @@ -2193,7 +2193,14 @@ else element[attrName] = attrValue; } else if (!toRemove) { - element.setAttribute(attrName, attrValue.toString()); + try { + element.setAttribute(attrName, attrValue.toString()); + } catch (err) { + // ignore for now + if (console) { + console.log("Can't set attribute " + attrName + " to " + attrValue + " error: " + err); + } + } } // Treat "name" specially - although you can think of it as an attribute, it also needs diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Compile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Compile.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,203 @@ +/** + * 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.htmlpage; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +/** + * + * @author Jaroslav Tulach + */ +final class Compile implements DiagnosticListener { + private final List> errors = new ArrayList<>(); + private final Map classes; + private final String pkg; + private final String cls; + private final String html; + + private Compile(String html, String code) throws IOException { + this.pkg = findPkg(code); + this.cls = findCls(code); + this.html = html; + classes = compile(html, code); + } + + /** Performs compilation of given HTML page and associated Java code + */ + public static Compile create(String html, String code) throws IOException { + return new Compile(html, code); + } + + /** Checks for given class among compiled resources */ + public byte[] get(String res) { + return classes.get(res); + } + + /** Obtains errors created during compilation. + */ + public List> getErrors() { + List> err = new ArrayList<>(); + for (Diagnostic diagnostic : errors) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + err.add(diagnostic); + } + } + return err; + } + + private Map compile(final String html, final String code) throws IOException { + StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null); + + final Map class2BAOS = new HashMap<>(); + + JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return code; + } + }; + final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return html; + } + + @Override + public InputStream openInputStream() throws IOException { + return new ByteArrayInputStream(html.getBytes()); + } + }; + + final URI scratch; + try { + scratch = new URI("mem://mem3"); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + + JavaFileManager jfm = new ForwardingJavaFileManager(sjfm) { + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { + if (kind == Kind.CLASS) { + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + class2BAOS.put(className.replace('.', '/') + ".class", buffer); + return new SimpleJavaFileObject(sibling.toUri(), kind) { + @Override + public OutputStream openOutputStream() throws IOException { + return buffer; + } + }; + } + + if (kind == Kind.SOURCE) { + return new SimpleJavaFileObject(scratch/*sibling.toUri()*/, kind) { + private final ByteArrayOutputStream data = new ByteArrayOutputStream(); + @Override + public OutputStream openOutputStream() throws IOException { + return data; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + data.close(); + return new String(data.toByteArray()); + } + }; + } + + throw new IllegalStateException(); + } + + @Override + public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { + if (location == StandardLocation.SOURCE_PATH) { + if (packageName.equals(pkg)) { + return htmlFile; + } + } + + return null; + } + + }; + + ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call(); + + Map result = new HashMap<>(); + + for (Map.Entry e : class2BAOS.entrySet()) { + result.put(e.getKey(), e.getValue().toByteArray()); + } + + return result; + } + + + @Override + public void report(Diagnostic diagnostic) { + errors.add(diagnostic); + } + private static String findPkg(String java) throws IOException { + Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE); + Matcher m = p.matcher(java); + if (!m.find()) { + throw new IOException("Can't find package declaration in the java file"); + } + String pkg = m.group(1); + return pkg; + } + private static String findCls(String java) throws IOException { + Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE); + Matcher m = p.matcher(java); + if (!m.find()) { + throw new IOException("Can't find package declaration in the java file"); + } + String cls = m.group(1); + return cls; + } + + String getHtml() { + String fqn = "'" + pkg + '.' + cls + "'"; + return html.replace("'${fqn}'", fqn); + } +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypesTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,63 @@ +/** + * 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.htmlpage; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class ConvertTypesTest { + @JavaScriptBody(args = { "includeSex" }, body = "var json = new Object();" + + "json.firstName = 'son';\n" + + "json.lastName = 'dj';\n" + + "if (includeSex) json.sex = 'MALE';\n" + + "return json;" + ) + private static native Object createJSON(boolean includeSex); + + @BrwsrTest + public void testConvertToPeople() throws Exception { + final Object o = createJSON(true); + + Person p = new Person(o); + + assert "son".equals(p.getFirstName()) : "First name: " + p.getFirstName(); + assert "dj".equals(p.getLastName()) : "Last name: " + p.getLastName(); + assert Sex.MALE.equals(p.getSex()) : "Sex: " + p.getSex(); + } + + @BrwsrTest + public void testConvertToPeopleWithoutSex() throws Exception { + final Object o = createJSON(false); + + Person p = new Person(o); + + assert "son".equals(p.getFirstName()) : "First name: " + p.getFirstName(); + assert "dj".equals(p.getLastName()) : "Last name: " + p.getLastName(); + assert p.getSex() == null : "No sex: " + p.getSex(); + } + + @Factory public static Object[] create() { + return VMTest.create(ConvertTypesTest.class); + } +} \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/JSONTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/JSONTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,392 @@ +/** + * 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.htmlpage; + +import java.util.Arrays; +import java.util.Iterator; +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.htmlpage.api.OnReceive; +import org.apidesign.bck2brwsr.htmlpage.api.Page; +import org.apidesign.bck2brwsr.htmlpage.api.Property; +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; +import org.apidesign.bck2brwsr.vmtest.Http; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.testng.annotations.Test; +import static org.testng.Assert.*; +import org.testng.annotations.Factory; + +/** Need to verify that models produce reasonable JSON objects. + * + * @author Jaroslav Tulach + */ +@Page(xhtml = "Empty.html", className = "JSONik", properties = { + @Property(name = "fetched", type = PersonImpl.class), + @Property(name = "fetchedCount", type = int.class), + @Property(name = "fetchedSex", type = Sex.class, array = true) +}) +public class JSONTest { + private JSONik js; + private Integer orig; + + @Test public void personToString() throws JSONException { + Person p = new Person(); + p.setSex(Sex.MALE); + p.setFirstName("Jarda"); + p.setLastName("Tulach"); + + JSONTokener t = new JSONTokener(p.toString()); + JSONObject o; + try { + o = new JSONObject(t); + } catch (JSONException ex) { + throw new AssertionError("Can't parse " + p.toString(), ex); + } + + Iterator it = o.sortedKeys(); + assertEquals(it.next(), "firstName"); + assertEquals(it.next(), "lastName"); + assertEquals(it.next(), "sex"); + + assertEquals(o.getString("firstName"), "Jarda"); + assertEquals(o.getString("lastName"), "Tulach"); + assertEquals(o.getString("sex"), "MALE"); + } + + @BrwsrTest public void toJSONInABrowser() throws Throwable { + Person p = new Person(); + p.setSex(Sex.MALE); + p.setFirstName("Jarda"); + p.setLastName("Tulach"); + + Object json; + try { + json = parseJSON(p.toString()); + } catch (Throwable ex) { + throw new IllegalStateException("Can't parse " + p).initCause(ex); + } + + Person p2 = new Person(json); + + assert p2.getFirstName().equals(p.getFirstName()) : + "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName(); + } + + @Test public void personWithWildCharactersAndNulls() throws JSONException { + Person p = new Person(); + p.setFirstName("'\"\n"); + p.setLastName("\t\r\u0002"); + + JSONTokener t = new JSONTokener(p.toString()); + JSONObject o; + try { + o = new JSONObject(t); + } catch (JSONException ex) { + throw new AssertionError("Can't parse " + p.toString(), ex); + } + + Iterator it = o.sortedKeys(); + assertEquals(it.next(), "firstName"); + assertEquals(it.next(), "lastName"); + assertEquals(it.next(), "sex"); + + assertEquals(o.getString("firstName"), p.getFirstName()); + assertEquals(o.getString("lastName"), p.getLastName()); + assertEquals(o.get("sex"), JSONObject.NULL); + } + + @Test public void personsInArray() throws JSONException { + Person p1 = new Person(); + p1.setFirstName("One"); + + Person p2 = new Person(); + p2.setFirstName("Two"); + + People arr = new People(); + arr.getInfo().add(p1); + arr.getInfo().add(p2); + arr.getNicknames().add("Prvn\u00ed k\u016f\u0148"); + final String n2 = "Druh\u00fd hlem\u00fd\u017e\u010f, star\u0161\u00ed"; + arr.getNicknames().add(n2); + arr.getAge().add(33); + arr.getAge().add(73); + + + final String json = arr.toString(); + + JSONTokener t = new JSONTokener(json); + JSONObject o; + try { + o = new JSONObject(t); + } catch (JSONException ex) { + throw new AssertionError("Can't parse " + json, ex); + } + + assertEquals(o.getJSONArray("info").getJSONObject(0).getString("firstName"), "One"); + assertEquals(o.getJSONArray("nicknames").getString(1), n2); + assertEquals(o.getJSONArray("age").getInt(1), 73); + } + + + @OnReceive(url="/{url}") + static void fetch(Person p, JSONik model) { + model.setFetched(p); + } + + @OnReceive(url="/{url}") + static void fetchArray(Person[] p, JSONik model) { + model.setFetchedCount(p.length); + model.setFetched(p[0]); + } + + @OnReceive(url="/{url}") + static void fetchPeople(People p, JSONik model) { + model.setFetchedCount(p.getInfo().size()); + model.setFetched(p.getInfo().get(0)); + } + + @OnReceive(url="/{url}") + static void fetchPeopleAge(People p, JSONik model) { + int sum = 0; + for (int a : p.getAge()) { + sum += a; + } + model.setFetchedCount(sum); + } + + @Http(@Http.Resource( + content = "{'firstName': 'Sitar', 'sex': 'MALE'}", + path="/person.json", + mimeType = "application/json" + )) + @BrwsrTest public void loadAndParseJSON() throws InterruptedException { + if (js == null) { + js = new JSONik(); + js.applyBindings(); + + js.fetch("person.json"); + } + + Person p = js.getFetched(); + if (p == null) { + throw new InterruptedException(); + } + + assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName(); + assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex(); + } + + @OnReceive(url="/{url}?callme={me}", jsonp = "me") + static void fetchViaJSONP(Person p, JSONik model) { + model.setFetched(p); + } + + @Http(@Http.Resource( + content = "$0({'firstName': 'Mitar', 'sex': 'MALE'})", + path="/person.json", + mimeType = "application/javascript", + parameters = { "callme" } + )) + @BrwsrTest public void loadAndParseJSONP() throws InterruptedException { + + if (js == null) { + orig = scriptElements(); + assert orig > 0 : "There should be some scripts on the page"; + + js = new JSONik(); + js.applyBindings(); + + js.fetchViaJSONP("person.json"); + } + + Person p = js.getFetched(); + if (p == null) { + throw new InterruptedException(); + } + + assert "Mitar".equals(p.getFirstName()) : "Unexpected: " + p.getFirstName(); + assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex(); + + int now = scriptElements(); + + assert orig == now : "The set of elements is unchanged. Delta: " + (now - orig); + } + + @JavaScriptBody(args = { }, body = "return window.document.getElementsByTagName('script').length;") + private static native int scriptElements(); + + @JavaScriptBody(args = { "s" }, body = "return window.JSON.parse(s);") + private static native Object parseJSON(String s); + + @Http(@Http.Resource( + content = "{'firstName': 'Sitar', 'sex': 'MALE'}", + path="/person.json", + mimeType = "application/json" + )) + @BrwsrTest public void loadAndParseJSONSentToArray() throws InterruptedException { + if (js == null) { + js = new JSONik(); + js.applyBindings(); + + js.fetchArray("person.json"); + } + + Person p = js.getFetched(); + if (p == null) { + throw new InterruptedException(); + } + + assert p != null : "We should get our person back: " + p; + assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName(); + assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex(); + } + + @Http(@Http.Resource( + content = "[{'firstName': 'Gitar', 'sex': 'FEMALE'}]", + path="/person.json", + mimeType = "application/json" + )) + @BrwsrTest public void loadAndParseJSONArraySingle() throws InterruptedException { + if (js == null) { + js = new JSONik(); + js.applyBindings(); + + js.fetch("person.json"); + } + + Person p = js.getFetched(); + if (p == null) { + throw new InterruptedException(); + } + + assert p != null : "We should get our person back: " + p; + assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName(); + assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex(); + } + + @Http(@Http.Resource( + content = "{'info':[{'firstName': 'Gitar', 'sex': 'FEMALE'}]}", + path="/people.json", + mimeType = "application/json" + )) + @BrwsrTest public void loadAndParseArrayInPeople() throws InterruptedException { + if (js == null) { + js = new JSONik(); + js.applyBindings(); + + js.fetchPeople("people.json"); + } + + if (0 == js.getFetchedCount()) { + throw new InterruptedException(); + } + + assert js.getFetchedCount() == 1 : "One person loaded: " + js.getFetchedCount(); + + Person p = js.getFetched(); + + assert p != null : "We should get our person back: " + p; + assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName(); + assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex(); + } + + @Http(@Http.Resource( + content = "{'age':[1, 2, 3]}", + path="/people.json", + mimeType = "application/json" + )) + @BrwsrTest public void loadAndParseArrayOfIntegers() throws InterruptedException { + if (js == null) { + js = new JSONik(); + js.applyBindings(); + + js.fetchPeopleAge("people.json"); + } + + if (0 == js.getFetchedCount()) { + throw new InterruptedException(); + } + + assert js.getFetchedCount() == 6 : "1 + 2 + 3 is " + js.getFetchedCount(); + } + + @OnReceive(url="/{url}") + static void fetchPeopleSex(People p, JSONik model) { + model.setFetchedCount(1); + model.getFetchedSex().addAll(p.getSex()); + } + + + @Http(@Http.Resource( + content = "{'sex':['FEMALE', 'MALE', 'MALE']}", + path="/people.json", + mimeType = "application/json" + )) + @BrwsrTest public void loadAndParseArrayOfEnums() throws InterruptedException { + if (js == null) { + js = new JSONik(); + js.applyBindings(); + + js.fetchPeopleSex("people.json"); + } + + if (0 == js.getFetchedCount()) { + throw new InterruptedException(); + } + + assert js.getFetchedCount() == 1 : "Loaded"; + + assert js.getFetchedSex().size() == 3 : "Three values " + js.getFetchedSex(); + assert js.getFetchedSex().get(0) == Sex.FEMALE : "Female first " + js.getFetchedSex(); + assert js.getFetchedSex().get(1) == Sex.MALE : "male 2nd " + js.getFetchedSex(); + assert js.getFetchedSex().get(2) == Sex.MALE : "male 3rd " + js.getFetchedSex(); + } + + @Http(@Http.Resource( + content = "[{'firstName': 'Gitar', 'sex': 'FEMALE'}," + + "{'firstName': 'Peter', 'sex': 'MALE'}" + + "]", + path="/person.json", + mimeType = "application/json" + )) + @BrwsrTest public void loadAndParseJSONArray() throws InterruptedException { + if (js == null) { + js = new JSONik(); + js.applyBindings(); + js.fetchArray("person.json"); + } + + + Person p = js.getFetched(); + if (p == null) { + throw new InterruptedException(); + } + + assert js.getFetchedCount() == 2 : "We got two values: " + js.getFetchedCount(); + assert p != null : "We should get our person back: " + p; + assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName(); + assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex(); + } + + @Factory public static Object[] create() { + return VMTest.create(JSONTest.class); + } + +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java Fri May 17 10:27:41 2013 +0200 @@ -17,21 +17,29 @@ */ package org.apidesign.bck2brwsr.htmlpage; +import java.util.List; +import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; import 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; import org.apidesign.bck2brwsr.vmtest.BrwsrTest; import org.apidesign.bck2brwsr.vmtest.HtmlFragment; import org.apidesign.bck2brwsr.vmtest.VMTest; +import static org.testng.Assert.assertEquals; import org.testng.annotations.Factory; +import org.testng.annotations.Test; /** * * @author Jaroslav Tulach */ @Page(xhtml="Knockout.xhtml", className="KnockoutModel", properties={ - @Property(name="name", type=String.class) + @Property(name="name", type=String.class), + @Property(name="results", type=String.class, array = true), + @Property(name="callbackCount", type=int.class), + @Property(name="people", type=PersonImpl.class, array = true) }) public class KnockoutTest { @@ -44,19 +52,207 @@ KnockoutModel m = new KnockoutModel(); m.setName("Kukuc"); m.applyBindings(); - assert "Kukuc".equals(m.INPUT.getValue()) : "Value is really kukuc: " + m.INPUT.getValue(); - m.INPUT.setValue("Jardo"); - m.triggerEvent(m.INPUT, OnEvent.CHANGE); + assert "Kukuc".equals(m.input.getValue()) : "Value is really kukuc: " + m.input.getValue(); + m.input.setValue("Jardo"); + m.triggerEvent(m.input, OnEvent.CHANGE); assert "Jardo".equals(m.getName()) : "Name property updated: " + m.getName(); } + @HtmlFragment( + "

    \n" + + "
  • \n" + + "
\n" + ) + @BrwsrTest public void displayContentOfArray() { + KnockoutModel m = new KnockoutModel(); + m.getResults().add("Ahoj"); + m.applyBindings(); + + int cnt = countChildren("ul"); + assert cnt == 1 : "One child, but was " + cnt; + + m.getResults().add("Hi"); + + cnt = countChildren("ul"); + assert cnt == 2 : "Two children now, but was " + cnt; + + triggerChildClick("ul", 1); + + assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount(); + assert "Hi".equals(m.getName()) : "We got callback from 2nd child " + m.getName(); + } + + @HtmlFragment( + "
    \n" + + "
  • \n" + + "
\n" + ) + @BrwsrTest public void displayContentOfDerivedArray() { + KnockoutModel m = new KnockoutModel(); + m.getResults().add("Ahoj"); + m.applyBindings(); + + int cnt = countChildren("ul"); + assert cnt == 1 : "One child, but was " + cnt; + + m.getResults().add("hello"); + + cnt = countChildren("ul"); + assert cnt == 2 : "Two children now, but was " + cnt; + } + + @HtmlFragment( + "
    \n" + + "
  • \n" + + "
\n" + ) + @BrwsrTest public void displayContentOfArrayOfPeople() { + KnockoutModel m = new KnockoutModel(); + + final Person first = new Person(); + first.setFirstName("first"); + m.getPeople().add(first); + + m.applyBindings(); + + int cnt = countChildren("ul"); + assert cnt == 1 : "One child, but was " + cnt; + + final Person second = new Person(); + second.setFirstName("second"); + m.getPeople().add(second); + + cnt = countChildren("ul"); + assert cnt == 2 : "Two children now, but was " + cnt; + + triggerChildClick("ul", 1); + + assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount(); + + cnt = countChildren("ul"); + assert cnt == 1 : "Again one child, but was " + cnt; + + String txt = childText("ul", 0); + assert "first".equals(txt) : "Expecting 'first': " + txt; + + first.setFirstName("changed"); + + txt = childText("ul", 0); + assert "changed".equals(txt) : "Expecting 'changed': " + txt; + } + + @ComputedProperty + static Person firstPerson(List people) { + return people.isEmpty() ? null : people.get(0); + } + + @HtmlFragment( + "

\n" + + " \n" + + "

\n" + ) + @BrwsrTest public void accessFirstPersonWithOnFunction() { + trasfertToFemale(); + } + + @HtmlFragment( + "
    \n" + + "
  • \n" + + "
\n" + ) + @BrwsrTest public void onPersonFunction() { + trasfertToFemale(); + } + + private void trasfertToFemale() { + KnockoutModel m = new KnockoutModel(); + + final Person first = new Person(); + first.setFirstName("first"); + first.setSex(Sex.MALE); + m.getPeople().add(first); + + + m.applyBindings(); + + int cnt = countChildren("ul"); + assert cnt == 1 : "One child, but was " + cnt; + + + triggerChildClick("ul", 0); + + assert first.getSex() == Sex.FEMALE : "Transverted to female: " + first.getSex(); + } + + @Test public void cloneModel() { + Person model = new Person(); + + model.setFirstName("first"); + Person snd = model.clone(); + snd.setFirstName("clone"); + assertEquals("first", model.getFirstName(), "Value has not changed"); + assertEquals("clone", snd.getFirstName(), "Value has changed in clone"); + } + + + @Test public void deepCopyOnClone() { + People model = new People(); + model.getNicknames().add("Jarda"); + assertEquals(model.getNicknames().size(), 1, "One element"); + People snd = model.clone(); + snd.getNicknames().clear(); + assertEquals(snd.getNicknames().size(), 0, "Clone is empty"); + assertEquals(model.getNicknames().size(), 1, "Still one element"); + } + + + @OnFunction + static void call(KnockoutModel m, String data) { + m.setName(data); + m.setCallbackCount(m.getCallbackCount() + 1); + } + + @OnFunction + static void removePerson(KnockoutModel model, Person data) { + model.setCallbackCount(model.getCallbackCount() + 1); + model.getPeople().remove(data); + } + + @ComputedProperty static String helloMessage(String name) { return "Hello " + name + "!"; } + @ComputedProperty + static List cmpResults(List results) { + return results; + } + @Factory public static Object[] create() { return VMTest.create(KnockoutTest.class); } + + @JavaScriptBody(args = { "id" }, body = + "var e = window.document.getElementById(id);\n " + + "if (typeof e === 'undefined') return -2;\n " + + "return e.children.length;\n " + ) + private static native int countChildren(String id); + + @JavaScriptBody(args = { "id", "pos" }, body = + "var e = window.document.getElementById(id);\n " + + "var ev = window.document.createEvent('MouseEvents');\n " + + "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n " + + "e.children[pos].dispatchEvent(ev);\n " + ) + private static native void triggerChildClick(String id, int pos); + + @JavaScriptBody(args = { "id", "pos" }, body = + "var e = window.document.getElementById(id);\n " + + "var t = e.children[pos].innerHTML;\n " + + "return t ? t : null;" + ) + private static native String childText(String id, int pos); } diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Fri May 17 10:27:41 2013 +0200 @@ -18,8 +18,13 @@ package org.apidesign.bck2brwsr.htmlpage; import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; +import org.apidesign.bck2brwsr.htmlpage.api.OnFunction; +import org.apidesign.bck2brwsr.htmlpage.api.OnPropertyChange; import org.apidesign.bck2brwsr.htmlpage.api.Page; import org.apidesign.bck2brwsr.htmlpage.api.Property; import static org.testng.Assert.*; @@ -30,17 +35,22 @@ * * @author Jaroslav Tulach */ -@Page(xhtml = "Empty.html", className = "Model", properties = { +@Page(xhtml = "Empty.html", className = "Modelik", properties = { @Property(name = "value", type = int.class), - @Property(name = "unrelated", type = long.class) + @Property(name = "count", type = int.class), + @Property(name = "unrelated", type = long.class), + @Property(name = "names", type = String.class, array = true), + @Property(name = "values", type = int.class, array = true), + @Property(name = "people", type = PersonImpl.class, array = true), + @Property(name = "changedProperty", type=String.class) }) public class ModelTest { - private Model model; - private static Model leakedModel; + private Modelik model; + private static Modelik leakedModel; @BeforeMethod public void createModel() { - model = new Model(); + model = new Modelik(); } @Test public void classGeneratedWithSetterGetter() { @@ -53,6 +63,75 @@ assertEquals(16, model.getPowerValue()); } + @Test public void arrayIsMutable() { + assertEquals(model.getNames().size(), 0, "Is empty"); + model.getNames().add("Jarda"); + assertEquals(model.getNames().size(), 1, "One element"); + } + + @Test public void arrayChangesNotified() { + MockKnockout my = new MockKnockout(); + MockKnockout.next = my; + + model.applyBindings(); + + model.getNames().add("Hello"); + + assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated); + assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated); + + my.mutated.clear(); + + Iterator it = model.getNames().iterator(); + assertEquals(it.next(), "Hello"); + it.remove(); + + assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated); + assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated); + + my.mutated.clear(); + + ListIterator lit = model.getNames().listIterator(); + lit.add("Jarda"); + + assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated); + assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated); + } + + @Test public void autoboxedArray() { + MockKnockout my = new MockKnockout(); + MockKnockout.next = my; + + model.applyBindings(); + + model.getValues().add(10); + + assertEquals(model.getValues().get(0), Integer.valueOf(10), "Really ten"); + } + + @Test public void derivedArrayProp() { + MockKnockout my = new MockKnockout(); + MockKnockout.next = my; + + model.applyBindings(); + + model.setCount(10); + + List arr = model.getRepeat(); + assertEquals(arr.size(), 10, "Ten items: " + arr); + + my.mutated.clear(); + + model.setCount(5); + + arr = model.getRepeat(); + assertEquals(arr.size(), 5, "Five items: " + arr); + + assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated); + assertTrue(my.mutated.contains("repeat"), "Array is in there: " + my.mutated); + assertTrue(my.mutated.contains("count"), "Count is in there: " + my.mutated); + } + @Test public void derivedPropertiesAreNotified() { MockKnockout my = new MockKnockout(); MockKnockout.next = my; @@ -61,6 +140,9 @@ model.setValue(33); + // not interested in change of this property + my.mutated.remove("changedProperty"); + assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated); assertTrue(my.mutated.contains("powerValue"), "Power value is in there: " + my.mutated); assertTrue(my.mutated.contains("value"), "Simple value is in there: " + my.mutated); @@ -68,7 +150,11 @@ my.mutated.clear(); model.setUnrelated(44); - assertEquals(my.mutated.size(), 1, "One property changed"); + + + // not interested in change of this property + my.mutated.remove("changedProperty"); + assertEquals(my.mutated.size(), 1, "One property changed: " + my.mutated); assertTrue(my.mutated.contains("unrelated"), "Its name is unrelated"); } @@ -92,11 +178,43 @@ } } + @OnFunction + static void doSomething() { + } + @ComputedProperty static int powerValue(int value) { return value * value; } + @OnPropertyChange({ "powerValue", "unrelated" }) + static void aPropertyChanged(Modelik m, String name) { + m.setChangedProperty(name); + } + + @OnPropertyChange({ "values" }) + static void anArrayPropertyChanged(String name, Modelik m) { + m.setChangedProperty(name); + } + + @Test public void changeAnything() { + model.setCount(44); + assertNull(model.getChangedProperty(), "No observed value change"); + } + @Test public void changeValue() { + model.setValue(33); + assertEquals(model.getChangedProperty(), "powerValue", "power property changed"); + } + @Test public void changeUnrelated() { + model.setUnrelated(333); + assertEquals(model.getChangedProperty(), "unrelated", "unrelated changed"); + } + + @Test public void changeInArray() { + model.getValues().add(10); + assertEquals(model.getChangedProperty(), "values", "Something added into the array"); + } + @ComputedProperty static String notAllowedRead() { return "Not allowed callback: " + leakedModel.getUnrelated(); @@ -108,12 +226,31 @@ return "Not allowed callback!"; } + @ComputedProperty + static List repeat(int count) { + return Collections.nCopies(count, "Hello"); + } + static class MockKnockout extends Knockout { - List mutated = new ArrayList(); + List mutated = new ArrayList<>(); + + MockKnockout() { + super(null); + } @Override public void valueHasMutated(String prop) { mutated.add(prop); } } + + public @Test void hasPersonPropertyAndComputedFullName() { + List arr = model.getPeople(); + assertEquals(arr.size(), 0, "By default empty"); + Person p = null; + if (p != null) { + String fullNameGenerated = p.getFullName(); + assertNotNull(fullNameGenerated); + } + } } diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Fri May 17 10:27:41 2013 +0200 @@ -50,7 +50,7 @@ if (PAGE != ref) { throw new IllegalStateException("Both references should be the same. " + ref + " != " + PAGE); } - ref.PG_TITLE.setText("You want this window to be named " + ref.PG_TEXT.getValue()); + ref.pg_title.setText("You want this window to be named " + ref.pg_text.getValue()); } @On(event = CLICK, id={ "pg.title", "pg.text" }) @@ -58,6 +58,11 @@ if (!id.equals("pg.title")) { throw new IllegalStateException(); } - PAGE.PG_TITLE.setText(id); + PAGE.pg_title.setText(id); + } + + @On(event = CLICK, id={ "pg.canvas" }) + static void clickCanvas(String id, double layerX) { + PAGE.pg_canvas.setWidth((int) layerX); } } diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,53 @@ +/** + * 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.htmlpage; + +import java.io.IOException; +import java.util.Locale; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** Verify errors emitted by the processor. + * + * @author Jaroslav Tulach + */ +public class PageTest { + @Test public void verifyWrongType() throws IOException { + String html = "" + + ""; + String code = "package x.y.z;\n" + + "import org.apidesign.bck2brwsr.htmlpage.api.*;\n" + + "@Page(xhtml=\"index.xhtml\", className=\"Model\", properties={\n" + + " @Property(name=\"prop\", type=Runnable.class)\n" + + "})\n" + + "class X {\n" + + "}\n"; + + Compile c = Compile.create(html, code); + assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors()); + for (Diagnostic e : c.getErrors()) { + String msg = e.getMessage(Locale.ENGLISH); + if (!msg.contains("Runnable")) { + fail("Should contain warning about Runnable: " + msg); + } + } + } + +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PersonImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PersonImpl.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,62 @@ +/** + * 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.htmlpage; + +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 = "Person", properties = { + @Property(name = "firstName", type = String.class), + @Property(name = "lastName", type = String.class), + @Property(name = "sex", type = Sex.class) +}) +final class PersonImpl { + @ComputedProperty + public static String fullName(String firstName, String lastName) { + return firstName + " " + lastName; + } + + @ComputedProperty + public static String sexType(Sex sex) { + return sex == null ? "unknown" : sex.toString(); + } + + @OnFunction + static void changeSex(Person p) { + if (p.getSex() == Sex.MALE) { + p.setSex(Sex.FEMALE); + } else { + p.setSex(Sex.MALE); + } + } + + @Model(className = "People", properties = { + @Property(array = true, name = "info", type = Person.class), + @Property(array = true, name = "nicknames", type = String.class), + @Property(array = true, name = "age", type = int.class), + @Property(array = true, name = "sex", type = Sex.class) + }) + public class PeopleImpl { + } +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Fri May 17 10:27:41 2013 +0200 @@ -36,11 +36,12 @@ assertNotNull(is, "Sample HTML page found"); ProcessPage res = ProcessPage.readPage(is); final Set ids = res.ids(); - assertEquals(ids.size(), 3, "Three ids found: " + ids); + assertEquals(ids.size(), 4, "Four ids found: " + ids); assertEquals(res.tagNameForId("pg.title"), "title"); assertEquals(res.tagNameForId("pg.button"), "button"); assertEquals(res.tagNameForId("pg.text"), "input"); + assertEquals(res.tagNameForId("pg.canvas"), "canvas"); } @Test public void testCompileAndRunPageController() throws Exception { @@ -53,11 +54,13 @@ + "doc.title.innerHTML = 'nothing';\n" + "doc.text = new Object();\n" + "doc.text.value = 'something';\n" + + "doc.canvas = new Object();\n" + "doc.getElementById = function(id) {\n" + " switch(id) {\n" + " case 'pg.button': return doc.button;\n" + " case 'pg.title': return doc.title;\n" + " case 'pg.text': return doc.text;\n" + + " case 'pg.canvas': return doc.canvas;\n" + " }\n" + " throw id;\n" + " }\n" @@ -92,11 +95,13 @@ + "doc.title.innerHTML = 'nothing';\n" + "doc.text = new Object();\n" + "doc.text.value = 'something';\n" + + "doc.canvas = new Object();\n" + "doc.getElementById = function(id) {\n" + " switch(id) {\n" + " case 'pg.button': return doc.button;\n" + " case 'pg.title': return doc.title;\n" + " case 'pg.text': return doc.text;\n" + + " case 'pg.canvas': return doc.canvas;\n" + " }\n" + " throw id;\n" + " }\n" @@ -123,12 +128,61 @@ assertEquals(ret, "pg.title", "Title has been passed to the method argument"); } + @Test public void clickWithArgumentAndParameterCalled() throws Exception { + StringBuilder sb = new StringBuilder(); + sb.append( + "var window = new Object();\n" + + "var doc = new Object();\n" + + "var eventObject = new Object();\n" + + "eventObject.layerX = 100;\n" + + "doc.button = new Object();\n" + + "doc.title = new Object();\n" + + "doc.title.innerHTML = 'nothing';\n" + + "doc.text = new Object();\n" + + "doc.text.value = 'something';\n" + + "doc.canvas = new Object();\n" + + "doc.canvas.width = 200;\n" + + "doc.getElementById = function(id) {\n" + + " switch(id) {\n" + + " case 'pg.button': return doc.button;\n" + + " case 'pg.title': return doc.title;\n" + + " case 'pg.text': return doc.text;\n" + + " case 'pg.canvas': return doc.canvas;\n" + + " }\n" + + " throw id;\n" + + " }\n" + + "\n" + + "function clickAndCheck() {\n" + + " doc.canvas.onclick(eventObject);\n" + + " return doc.canvas.width.toString();\n" + + "};\n" + + "\n" + + "window.document = doc;\n" + ); + Invocable i = compileClass(sb, + "org/apidesign/bck2brwsr/htmlpage/PageController" + ); + + Object ret = null; + try { + ret = i.invokeFunction("clickAndCheck"); + } catch (ScriptException ex) { + fail("Execution failed in " + sb, ex); + } catch (NoSuchMethodException ex) { + fail("Cannot find method in " + sb, ex); + } + assertEquals(ret, "100", "layerX has been passed to the method argument"); + } + static Invocable compileClass(StringBuilder sb, String... names) throws ScriptException, IOException { if (sb == null) { sb = new StringBuilder(); } Bck2Brwsr.generate(sb, ProcessPageTest.class.getClassLoader(), names); sb.append("var vm = this.bck2brwsr();\n"); + for (String c : names) { + sb.append("vm.loadClass('").append(c.replace('/', '.')).append("');\n"); + } ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine js = sem.getEngineByExtension("js"); diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Sex.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Sex.java Fri May 17 10:27:41 2013 +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.bck2brwsr.htmlpage; + +/** + * + * @author Jaroslav Tulach + */ +public enum Sex { + MALE, FEMALE; +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html --- a/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html Fri May 17 10:27:41 2013 +0200 @@ -26,5 +26,6 @@ New title: + diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-calculator-dynamic/nbactions.xml --- a/javaquery/demo-calculator-dynamic/nbactions.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/nbactions.xml Fri May 17 10:27:41 2013 +0200 @@ -23,7 +23,7 @@ run process-classes - org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr + bck2brwsr:brwsr diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-calculator-dynamic/pom.xml --- a/javaquery/demo-calculator-dynamic/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,7 +4,7 @@ org.apidesign.bck2brwsr demo.calculator - 0.4-SNAPSHOT + 0.8-SNAPSHOT jar JavaQuery Demo - Calculator @@ -17,8 +17,8 @@ org.apidesign.bck2brwsr - mojo - 0.4-SNAPSHOT + bck2brwsr-maven-plugin + ${project.version} @@ -93,13 +93,13 @@ org.apidesign.bck2brwsr emul - 0.4-SNAPSHOT + ${project.version} rt org.apidesign.bck2brwsr javaquery.api - 0.4-SNAPSHOT + ${project.version} org.testng @@ -112,7 +112,7 @@ vm4brwsr js zip - 0.4-SNAPSHOT + ${project.version} provided diff -r d127d41768bd -r ae3f2aa50970 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 Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java Fri May 17 10:27:41 2013 +0200 @@ -17,9 +17,11 @@ */ 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; @@ -33,11 +35,12 @@ @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 = "hover", type = boolean.class), + @Property(name = "history", type = HistoryImpl.class, array = true) }) public class Calc { static { - new Calculator().applyBindings(); + new Calculator().applyBindings().setOperation("plus"); } @On(event = CLICK, id="clear") @@ -48,31 +51,48 @@ } @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) - static void applyOp(Calculator c, String op) { + static void applyOp(Calculator c, String id) { c.setMemory(c.getDisplay()); - c.setOperation(op); + c.setOperation(id); c.setDisplay(0); } @On(event = MOUSE_OVER, id= { "result" }) - static void attemptingIn(Calculator c, String op) { + static void attemptingIn(Calculator c) { c.setHover(true); } @On(event = MOUSE_OUT, id= { "result" }) - static void attemptingOut(Calculator c, String op) { + static void attemptingOut(Calculator c) { c.setHover(false); } @On(event = CLICK, id="result") static void computeTheValue(Calculator c) { - c.setDisplay(compute( + 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; @@ -84,18 +104,18 @@ } @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) - static void addDigit(String digit, Calculator c) { - digit = digit.substring(1); + static void addDigit(String id, Calculator c) { + id = id.substring(1); double v = c.getDisplay(); if (v == 0.0) { - c.setDisplay(Integer.parseInt(digit)); + c.setDisplay(Integer.parseInt(id)); } else { String txt = Double.toString(v); if (txt.endsWith(".0")) { txt = txt.substring(0, txt.length() - 2); } - txt = txt + digit; + txt = txt + id; c.setDisplay(Double.parseDouble(txt)); } } @@ -109,4 +129,18 @@ } 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 d127d41768bd -r ae3f2aa50970 javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/HistoryImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/HistoryImpl.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,43 @@ +/** + * 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 d127d41768bd -r ae3f2aa50970 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 Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml Fri May 17 10:27:41 2013 +0200 @@ -78,82 +78,25 @@
+

Previous Results

+ +
No results yet.
+ +
-
-    package org.apidesign.bck2brwsr.mavenhtml;
-
-    import org.apidesign.bck2brwsr.htmlpage.api.OnClick;
-    import org.apidesign.bck2brwsr.htmlpage.api.Page;
-
-    /** HTML5 & Java demo showing the power of annotation processors
-     * as well as other goodies, including type-safe association between
-     * an XHTML page and Java.
-     * 
-     * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
-     */
-    @Page(xhtml="Calculator.xhtml")
-    public class App {
-        private static double memory;
-        private static String operation;
-
-        @OnClick(id="clear")
-        static void clear() {
-            memory = 0;
-            operation = null;
-            Calculator.DISPLAY.setValue("0");
-        }
-
-        @OnClick(id= { "plus", "minus", "mul", "div" })
-        static void applyOp(String op) {
-            memory = getValue();
-            operation = op;
-            Calculator.DISPLAY.setValue("0");
-        }
-
-        @OnClick(id="result")
-        static void computeTheValue() {
-            switch (operation) {
-                case "plus": setValue(memory + getValue()); break;
-                case "minus": setValue(memory - getValue()); break;
-                case "mul": setValue(memory * getValue()); break;
-                case "div": setValue(memory / getValue()); break;
-                default: throw new IllegalStateException(operation);
-            }
-        }
-
-        @OnClick(id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) 
-        static void addDigit(String digit) {
-            digit = digit.substring(1);
-            String v = Calculator.DISPLAY.getValue();
-            if (getValue() == 0.0) {
-                Calculator.DISPLAY.setValue(digit);
-            } else {
-                Calculator.DISPLAY.setValue(v + digit);
-            }
-        }
-
-        private static void setValue(double v) {
-            StringBuilder sb = new StringBuilder();
-            sb.append(v);
-            Calculator.DISPLAY.setValue(sb.toString());
-        }
-
-        private static double getValue() {
-            try {
-                return Double.parseDouble(Calculator.DISPLAY.getValue());
-            } catch (NumberFormatException ex) {
-                Calculator.DISPLAY.setValue("err");
-                return 0.0;
-            }
-        }
-    }
-
-    
diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-calculator/nbactions.xml --- a/javaquery/demo-calculator/nbactions.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/demo-calculator/nbactions.xml Fri May 17 10:27:41 2013 +0200 @@ -23,7 +23,7 @@ run package - org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr + bck2brwsr:brwsr true diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-calculator/pom.xml --- a/javaquery/demo-calculator/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/demo-calculator/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,7 +4,7 @@ org.apidesign.bck2brwsr demo.static.calculator - 0.4-SNAPSHOT + 0.8-SNAPSHOT jar JavaQuery Demo - Calculator - Static Compilation @@ -12,16 +12,18 @@ UTF-8 + MINIMAL org.apidesign.bck2brwsr - mojo - 0.4-SNAPSHOT + bck2brwsr-maven-plugin + ${project.version} + j2js brwsr @@ -29,6 +31,8 @@ ${project.build.directory}/${project.build.finalName}-bck2brwsr/public_html/ index.xhtml + ${project.build.directory}/bck2brwsr.js + ${bck2brwsr.obfuscationlevel} @@ -94,21 +98,13 @@ org.apidesign.bck2brwsr emul - 0.4-SNAPSHOT + ${project.version} rt org.apidesign.bck2brwsr javaquery.api - 0.4-SNAPSHOT - - - org.apidesign.bck2brwsr - vm4brwsr - js - zip - 0.4-SNAPSHOT - provided + ${project.version} diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml --- a/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Fri May 17 10:27:41 2013 +0200 @@ -37,15 +37,6 @@ *:rt - - false - provided - - *:js - - true - / - @@ -53,6 +44,10 @@ / + ${project.build.directory}/bck2brwsr.js + / + + ${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml / index.xhtml diff -r d127d41768bd -r ae3f2aa50970 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 Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java Fri May 17 10:27:41 2013 +0200 @@ -17,9 +17,11 @@ */ package org.apidesign.bck2brwsr.demo.calc.staticcompilation; +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; @@ -33,11 +35,12 @@ @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 = "hover", type = boolean.class), + @Property(name = "history", type = double.class, array = true) }) public class Calc { static { - new Calculator().applyBindings(); + new Calculator().applyBindings().setOperation("plus"); } @On(event = CLICK, id="clear") @@ -48,31 +51,45 @@ } @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) - static void applyOp(Calculator c, String op) { + static void applyOp(Calculator c, String id) { c.setMemory(c.getDisplay()); - c.setOperation(op); + c.setOperation(id); c.setDisplay(0); } @On(event = MOUSE_OVER, id= { "result" }) - static void attemptingIn(Calculator c, String op) { + static void attemptingIn(Calculator c) { c.setHover(true); } @On(event = MOUSE_OUT, id= { "result" }) - static void attemptingOut(Calculator c, String op) { + static void attemptingOut(Calculator c) { c.setHover(false); } @On(event = CLICK, id="result") static void computeTheValue(Calculator c) { - c.setDisplay(compute( + final double newValue = compute( c.getOperation(), c.getMemory(), c.getDisplay() - )); + ); + c.setDisplay(newValue); + if (!c.getHistory().contains(newValue)) { + c.getHistory().add(newValue); + } c.setMemory(0); } + @OnFunction + static void recoverMemory(Calculator c, double data) { + c.setDisplay(data); + } + + @OnFunction + static void removeMemory(Calculator c, double data) { + c.getHistory().remove(data); + } + private static double compute(String op, double memory, double display) { switch (op) { case "plus": return memory + display; @@ -84,18 +101,18 @@ } @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) - static void addDigit(String digit, Calculator c) { - digit = digit.substring(1); + static void addDigit(String id, Calculator c) { + id = id.substring(1); double v = c.getDisplay(); if (v == 0.0) { - c.setDisplay(Integer.parseInt(digit)); + c.setDisplay(Integer.parseInt(id)); } else { String txt = Double.toString(v); if (txt.endsWith(".0")) { txt = txt.substring(0, txt.length() - 2); } - txt = txt + digit; + txt = txt + id; c.setDisplay(Double.parseDouble(txt)); } } @@ -109,4 +126,9 @@ } return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display); } + + @ComputedProperty + static boolean emptyHistory(List history) { + return history.isEmpty(); + } } diff -r d127d41768bd -r ae3f2aa50970 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 Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Fri May 17 10:27:41 2013 +0200 @@ -76,10 +76,22 @@ + +

Previous Results

+ +
No results yet.
+ +
- diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-twitter/bck2brwsr-assembly.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-twitter/bck2brwsr-assembly.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,62 @@ + + + + + bck2brwsr + + zip + + public_html + + + false + runtime + lib + + *:jar + *:rt + + + + + + ${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/twitter/ + + **/* + + + **/*.class + + / + + + + + ${project.build.directory}/${project.build.finalName}.jar + / + + + ${project.build.directory}/bck2brwsr.js + / + + + \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-twitter/nb-configuration.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-twitter/nb-configuration.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,37 @@ + + + + + + + none + + diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-twitter/nbactions.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-twitter/nbactions.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,29 @@ + + + + + run + + process-classes + bck2brwsr:brwsr + + + diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-twitter/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-twitter/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,151 @@ + + + 4.0.0 + + javaquery + org.apidesign.bck2brwsr + 0.8-SNAPSHOT + + + org.apidesign.bck2brwsr + demo-twitter + 0.8-SNAPSHOT + jar + + Bck2Brwsr's Twttr + + Rewrite of knockoutjs example to use model written in Java and + execute using Bck2Brwsr virtual machine. + + + + + java.net + Java.net + https://maven.java.net/content/repositories/releases/ + + + + + netbeans + NetBeans + http://bits.netbeans.org/maven2/ + + + + + java.net + Java.net + https://maven.java.net/content/repositories/releases/ + + + + + + + UTF-8 + MINIMAL + + + + + org.apidesign.bck2brwsr + bck2brwsr-maven-plugin + ${project.version} + + + + brwsr + j2js + + + + + org/apidesign/bck2brwsr/demo/twitter/index.html + ${project.build.directory}/bck2brwsr.js + ${bck2brwsr.obfuscationlevel} + + + + 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 + + + + maven-assembly-plugin + 2.4 + + + distro-assembly + package + + single + + + + bck2brwsr-assembly.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 + vmtest + ${project.version} + test + + + org.apidesign.bck2brwsr + launcher.http + ${project.version} + runtime + + + diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,194 @@ +/** + * 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.twitter; + +import java.util.Arrays; +import java.util.List; +import org.apidesign.bck2brwsr.htmlpage.api.*; +import org.apidesign.bck2brwsr.htmlpage.api.Page; +import org.apidesign.bck2brwsr.htmlpage.api.Property; +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; + +/** Controller class for access to Twitter. + * + * @author Jaroslav Tulach + */ +@Page(xhtml="index.html", className="TwitterModel", properties={ + @Property(name="savedLists", type=Tweeters.class, array = true), + @Property(name="activeTweetersName", type=String.class), + @Property(name="activeTweeters", type=String.class, array = true), + @Property(name="userNameToAdd", type=String.class), + @Property(name="currentTweets", type=Tweet.class, array = true) +}) +public class TwitterClient { + @Model(className = "Tweeters", properties = { + @Property(name="name", type = String.class), + @Property(name="userNames", type = String.class, array = true) + }) + static class Twttrs { + } + @Model(className = "Tweet", properties = { + @Property(name = "from_user", type = String.class), + @Property(name = "from_user_id", type = int.class), + @Property(name = "profile_image_url", type = String.class), + @Property(name = "text", type = String.class), + @Property(name = "created_at", type = String.class), + }) + static final class Twt { + @ComputedProperty static String html(String text) { + StringBuilder sb = new StringBuilder(320); + for (int pos = 0;;) { + int http = text.indexOf("http", pos); + if (http == -1) { + sb.append(text.substring(pos)); + return sb.toString(); + } + int spc = text.indexOf(' ', http); + if (spc == -1) { + spc = text.length(); + } + sb.append(text.substring(pos, http)); + String url = text.substring(http, spc); + sb.append("").append(url).append(""); + pos = spc; + } + } + + @ComputedProperty static String userUrl(String from_user) { + return "http://twitter.com/" + from_user; + } + } + @Model(className = "TwitterQuery", properties = { + @Property(array = true, name = "results", type = Twt.class) + }) + public static final class TwttrQr { + } + + @OnReceive(url="{root}/search.json?{query}&callback={me}", jsonp="me") + static void queryTweets(TwitterModel page, TwitterQuery q) { + page.getCurrentTweets().clear(); + page.getCurrentTweets().addAll(q.getResults()); + } + + @OnPropertyChange("activeTweetersName") + static void changeTweetersList(TwitterModel model) { + Tweeters people = findByName(model.getSavedLists(), model.getActiveTweetersName()); + model.getActiveTweeters().clear(); + model.getActiveTweeters().addAll(people.getUserNames()); + } + + @OnPropertyChange({ "activeTweeters", "activeTweetersCount" }) + static void refreshTweets(TwitterModel model) { + StringBuilder sb = new StringBuilder(); + sb.append("rpp=25&q="); + String sep = ""; + for (String p : model.getActiveTweeters()) { + sb.append(sep); + sb.append("from:"); + sb.append(p); + sep = " OR "; + } + model.queryTweets("http://search.twitter.com", sb.toString()); + } + + static { + final TwitterModel model = new TwitterModel(); + final List svdLst = model.getSavedLists(); + svdLst.add(newTweeters("API Design", "JaroslavTulach")); + svdLst.add(newTweeters("Celebrities", "JohnCleese", "MCHammer", "StephenFry", "algore", "StevenSanderson")); + svdLst.add(newTweeters("Microsoft people", "BillGates", "shanselman", "ScottGu")); + svdLst.add(newTweeters("NetBeans", "GeertjanW","monacotoni", "NetBeans", "petrjiricka")); + svdLst.add(newTweeters("Tech pundits", "Scobleizer", "LeoLaporte", "techcrunch", "BoingBoing", "timoreilly", "codinghorror")); + + model.setActiveTweetersName("NetBeans"); + + model.applyBindings(); + } + + @ComputedProperty + static boolean hasUnsavedChanges(List activeTweeters, List savedLists, String activeTweetersName) { + Tweeters tw = findByName(savedLists, activeTweetersName); + if (activeTweeters == null) { + return false; + } + return !tw.getUserNames().equals(activeTweeters); + } + + @ComputedProperty + static int activeTweetersCount(List activeTweeters) { + return activeTweeters.size(); + } + + @ComputedProperty + static boolean userNameToAddIsValid( + String userNameToAdd, String activeTweetersName, List savedLists, List activeTweeters + ) { + return userNameToAdd != null && + userNameToAdd.matches("[a-zA-Z0-9_]{1,15}") && + !activeTweeters.contains(userNameToAdd); + } + + @OnFunction + static void deleteList(TwitterModel model) { + final List sl = model.getSavedLists(); + sl.remove(findByName(sl, model.getActiveTweetersName())); + if (sl.isEmpty()) { + final Tweeters t = new Tweeters(); + t.setName("New"); + sl.add(t); + } + model.setActiveTweetersName(sl.get(0).getName()); + } + + @OnFunction + static void saveChanges(TwitterModel model) { + Tweeters t = findByName(model.getSavedLists(), model.getActiveTweetersName()); + int indx = model.getSavedLists().indexOf(t); + if (indx != -1) { + t.setName(model.getActiveTweetersName()); + t.getUserNames().clear(); + t.getUserNames().addAll(model.getActiveTweeters()); + } + } + + @OnFunction + static void addUser(TwitterModel model) { + String n = model.getUserNameToAdd(); + model.getActiveTweeters().add(n); + } + @OnFunction + static void removeUser(String data, TwitterModel model) { + model.getActiveTweeters().remove(data); + } + + private static Tweeters findByName(List list, String name) { + for (Tweeters l : list) { + if (l.getName() != null && l.getName().equals(name)) { + return l; + } + } + return list.isEmpty() ? new Tweeters() : list.get(0); + } + + private static Tweeters newTweeters(String listName, String... userNames) { + Tweeters t = new Tweeters(); + t.setName(listName); + t.getUserNames().addAll(Arrays.asList(userNames)); + return t; + } +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/index.html Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,99 @@ + + + + + + + + + Bck2Brwsr's Twitter + + + + + + + +

Bck2Brwsr's Twitter

+ +

+ This code based on original knockout.js Twitter example and + uses almost unmodified HTML code. It just changes the model. It + is written in Java language and it is executed using Bck2Brwsr + virtual machine. The Java source code has about 190 lines and is available + here + - in fact it may even be more dense than the original JavaScript model. +

+ +
+
+
+ + + +
+ +

Currently viewing user(s):

+
+
    +
  • + +
    +
  • +
+
+ +
+ + + +
+
+
+
Loading...
+ + + + + +
+ + +
+
+
+
+ + + + + + + diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/twitterExample.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/twitterExample.css Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,50 @@ +/** + * 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. + */ + +/* + Copied from knockout.js Twitter example: + http://knockoutjs.com/examples/twitter.html +*/ + +.configuration, .tweets, .tweets td { font-family: Verdana; font-size: 13px; } +.configuration { background-color: #DEDEDE; border: 2px solid gray; float:left; height: 40em; width: 40%; padding: 0.5em; border-right-width:0; } +.tweets { width: 55%; border: 2px solid gray; height: 40em; overflow: scroll; overflow-x: hidden; background-color: Black; color: White; padding: 0.5em; position: relative; } +.tweets table { border-width: 0;} +.tweets tr { vertical-align: top; } +.tweets td { padding: 0.4em 0.3em 1em 0.4em; border-width: 0; } +.tweets img { width: 4em; } +.tweetInfo { color: Gray; font-size: 0.9em; } +.twitterUser { color: #77AAFF; text-decoration: none; font-size: 1.1em; font-weight: bold; } +input.invalid { border: 1px solid red !important; background-color: #FFAAAA !important; } + +.listChooser select, .listChooser button { vertical-align:top; } +.listChooser select { width: 60%; font-size:1.2em; height:1.4em; } +.listChooser button { width: 19%; height:1.68em; float:right; } + +.currentUsers { height: 28em; overflow-y: auto; overflow-x: hidden; } +.currentUsers button { float: right; height: 2.5em; margin: 0.1em; padding-left: 1em; padding-right: 1em; } +.currentUsers ul, .configuration li { list-style: none; margin: 0; padding: 0 } +.currentUsers li { height: 2.4em; font-size: 1.2em; background-color: #A7D0E3; border: 1px solid gray; margin-bottom: 0.3em; -webkit-border-radius: 5px; -moz-border-radius: 5px; -webkit-box-shadow: 0 0.2em 0.5em gray; -moz-box-shadow: 0 0.2em 0.5em gray; } +.currentUsers li div { padding: 0.6em; } +.currentUsers li:hover { background-color: #EEC; } + +.configuration form label { width: 25%; display: inline-block; text-align:right; overflow: hidden; } +.configuration form input { width:40%; font-size: 1.3em; border:1px solid silver; background-color: White; padding: 0.1em; } +.configuration form button { width: 20%; margin-left: 0.3em; height: 2em; } + +.loadingIndicator { position: absolute; top: 0.1em; left: 0.1em; font: 0.8em Arial; background-color: #229; color: White; padding: 0.2em 0.5em 0.2em 0.5em; display: none; } diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClientTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClientTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,67 @@ +/** + * 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.twitter; + +import java.util.List; +import static org.testng.Assert.*; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** We can unit test the TwitterModel smoothly. + * + * @author Jaroslav Tulach + */ +public class TwitterClientTest { + private TwitterModel model; + + + @BeforeMethod + public void initModel() { + model = new TwitterModel().applyBindings(); + } + + @Test public void testIsValidToAdd() { + model.setUserNameToAdd("Joe"); + Tweeters t = new Tweeters(); + t.setName("test"); + model.getSavedLists().add(t); + model.setActiveTweetersName("test"); + + assertTrue(model.isUserNameToAddIsValid(), "Joe is OK"); + TwitterClient.addUser(model); + assertFalse(model.isUserNameToAddIsValid(), "Can't add Joe for the 2nd time"); + assertEquals(t.getUserNames().size(), 0, "Original tweeters list remains empty"); + + List mod = model.getActiveTweeters(); + assertTrue(model.isHasUnsavedChanges(), "We have modifications"); + assertEquals(mod.size(), 1, "One element in the list"); + assertEquals(mod.get(0), "Joe", "Its name is Joe"); + + assertSame(model.getActiveTweeters(), mod, "Editing list is the modified one"); + + TwitterClient.saveChanges(model); + assertFalse(model.isHasUnsavedChanges(), "Does not have anything to save"); + + assertSame(model.getActiveTweeters(), mod, "Still editing the old modified one"); + } + + @Test public void httpAtTheEnd() { + String res = TwitterClient.Twt.html("Ahoj http://kuk"); + assertEquals(res, "Ahoj http://kuk"); + } +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterProtocolTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterProtocolTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,94 @@ +/** + * 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.twitter; + +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; +import org.apidesign.bck2brwsr.vmtest.Http; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class TwitterProtocolTest { + private TwitterModel page; + @Http(@Http.Resource( + path = "/search.json", + mimeType = "application/json", + parameters = {"callback"}, + content = "$0({\"completed_in\":0.04,\"max_id\":320055706885689344,\"max_id_str\"" + + ":\"320055706885689344\",\"page\":1,\"query\":\"from%3AJaroslavTulach\",\"refresh_url\":" + + "\"?since_id=320055706885689344&q=from%3AJaroslavTulach\"," + + "\"results\":[{\"created_at\":\"Fri, 05 Apr 2013 06:10:01 +0000\"," + + "\"from_user\":\"JaroslavTulach\",\"from_user_id\":420944648,\"from_user_id_str\":" + + "\"420944648\",\"from_user_name\":\"Jaroslav Tulach\",\"geo\":null,\"id\":320055706885689344," + + "\"id_str\":\"320055706885689344\",\"iso_language_code\":\"en\",\"metadata\":{\"result_type\":" + + "\"recent\"},\"profile_image_url\":\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\"," + + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\"," + + "\"source\":\"<a href="http:\\/\\/twitter.com\\/">web<\\/a>\",\"text\":" + + "\"@tom_enebo Amzng! Not that I would like #ruby, but I am really glad you guys stabilized the plugin + " + + "made it work in #netbeans 7.3! Gd wrk.\",\"to_user\":\"tom_enebo\",\"to_user_id\":14498747," + + "\"to_user_id_str\":\"14498747\",\"to_user_name\":\"tom_enebo\",\"in_reply_to_status_id\":319832359509839872," + + "\"in_reply_to_status_id_str\":\"319832359509839872\"},{\"created_at\":\"Thu, 04 Apr 2013 07:33:06 +0000\"," + + "\"from_user\":\"JaroslavTulach\",\"from_user_id\":420944648,\"from_user_id_str\":" + + "\"420944648\",\"from_user_name\":\"Jaroslav Tulach\",\"geo\":null,\"id\":319714227088678913," + + "\"id_str\":\"319714227088678913\",\"iso_language_code\":\"en\",\"metadata\":{\"result_type\":" + + "\"recent\"},\"profile_image_url\":\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\"," + + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\"," + + "\"source\":\"<a href="http:\\/\\/twitter.com\\/">web<\\/a>\",\"text\":" + + "\"RT @drkrab: At #erlangfactory @joerl: Frameworks grow in complexity until nobody can use them.\"}," + + "{\"created_at\":\"Tue, 02 Apr 2013 07:44:34 +0000\",\"from_user\":\"JaroslavTulach\"," + + "\"from_user_id\":420944648,\"from_user_id_str\":\"420944648\",\"from_user_name\":\"Jaroslav Tulach\"," + + "\"geo\":null,\"id\":318992336145248256,\"id_str\":\"318992336145248256\",\"iso_language_code\":\"en\"," + + "\"metadata\":{\"result_type\":\"recent\"},\"profile_image_url\":" + + "\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\"," + + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\"," + + "\"source\":\"<a href="http:\\/\\/twitter.com\\/">web<\\/a>\",\"text\":" + + "\"Twitter renamed to twttr http:\\/\\/t.co\\/tqaN4T1xlZ - good, I don't have to rename #bck2brwsr!\"}," + + "{\"created_at\":\"Sun, 31 Mar 2013 03:52:04 +0000\",\"from_user\":\"JaroslavTulach\",\"from_user_id\":420944648," + + "\"from_user_id_str\":\"420944648\",\"from_user_name\":\"Jaroslav Tulach\",\"geo\":null," + + "\"id\":318209051223789568,\"id_str\":\"318209051223789568\",\"iso_language_code\":\"en\",\"metadata\":" + + "{\"result_type\":\"recent\"},\"profile_image_url\":" + + "\"http:\\/\\/a0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\"," + + "\"profile_image_url_https\":\"https:\\/\\/si0.twimg.com\\/profile_images\\/1656828312\\/jst_normal.gif\"," + + "\"source\":\"<a href="http:\\/\\/twitter.com\\/">web<\\/a>\",\"text\":" + + "\"Math proofs without words. Ingenious: http:\\/\\/t.co\\/sz7yVbfpGw\"}],\"results_per_page\":100," + + "\"since_id\":0,\"since_id_str\":\"0\"})" + )) + @BrwsrTest public void readFromTwttr() throws InterruptedException { + if (page == null) { + page = new TwitterModel(); + page.applyBindings(); + page.queryTweets("", "q=xyz"); + } + + if (page.getCurrentTweets().isEmpty()) { + throw new InterruptedException(); + } + + assert 4 == page.getCurrentTweets().size() : "Four tweets: " + page.getCurrentTweets(); + + String firstDate = page.getCurrentTweets().get(0).getCreated_at(); + assert "Fri, 05 Apr 2013 06:10:01 +0000".equals(firstDate) : "Date is OK: " + firstDate; + } + + @Factory public static Object[] create() { + return VMTest.create(TwitterProtocolTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 javaquery/pom.xml --- a/javaquery/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/javaquery/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,16 +4,17 @@ bck2brwsr org.apidesign - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr javaquery - 0.4-SNAPSHOT + 0.8-SNAPSHOT pom JavaQuery API and Demo api demo-calculator demo-calculator-dynamic - - + demo-twitter +
+ \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 launcher/api/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/api/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,31 @@ + + + 4.0.0 + + org.apidesign.bck2brwsr + launcher-pom + 0.8-SNAPSHOT + + org.apidesign.bck2brwsr + launcher + 0.8-SNAPSHOT + Launcher API + http://maven.apache.org + + UTF-8 + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + org.apidesign.bck2brwsr.launcher + false + + + + + + + diff -r d127d41768bd -r ae3f2aa50970 launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,115 @@ +/** + * 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.launcher; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** Represents individual method invocation, its context and its result. + * + * @author Jaroslav Tulach + */ +public final class InvocationContext { + final CountDownLatch wait = new CountDownLatch(1); + final Class clazz; + final String methodName; + private final Launcher launcher; + private String result; + private Throwable exception; + String html; + final List resources = new ArrayList<>(); + + InvocationContext(Launcher launcher, Class clazz, String methodName) { + this.launcher = launcher; + this.clazz = clazz; + this.methodName = methodName; + } + + /** An HTML fragment to be available for the execution. Useful primarily when + * executing in a browser via {@link Launcher#createBrowser(java.lang.String)}. + * @param html the html fragment + */ + public void setHtmlFragment(String html) { + this.html = html; + } + + /** HTTP resource to be available during execution. An invocation may + * perform an HTTP query and obtain a resource relative to the page. + */ + public void addHttpResource(String relativePath, String mimeType, String[] parameters, InputStream content) { + if (relativePath == null || mimeType == null || content == null || parameters == null) { + throw new NullPointerException(); + } + resources.add(new Resource(content, mimeType, relativePath, parameters)); + } + + /** Invokes the associated method. + * @return the textual result of the invocation + */ + public String invoke() throws IOException { + launcher.runMethod(this); + return toString(); + } + + /** Obtains textual result of the invocation. + * @return text representing the exception or result value + */ + @Override + public String toString() { + if (exception != null) { + return exception.toString(); + } + return result; + } + + /** + * @param timeOut + * @throws InterruptedException + */ + void await(long timeOut) throws InterruptedException { + wait.await(timeOut, TimeUnit.MILLISECONDS); + } + + void result(String r, Throwable e) { + this.result = r; + this.exception = e; + wait.countDown(); + } + + + static final class Resource { + final InputStream httpContent; + final String httpType; + final String httpPath; + final String[] parameters; + + Resource(InputStream httpContent, String httpType, String httpPath, + String[] parameters + ) { + httpContent.mark(Integer.MAX_VALUE); + this.httpContent = httpContent; + this.httpType = httpType; + this.httpPath = httpPath; + this.parameters = parameters; + } + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,166 @@ +/** + * 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.launcher; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; + +/** An abstraction for executing tests in a Bck2Brwsr virtual machine. + * Either in {@link Launcher#createJavaScript JavaScript engine}, + * or in {@link Launcher#createBrowser external browser}. + *

+ * There also are methods to {@link #showDir(java.io.File, java.lang.String) display pages} + * in an external browser served by internal HTTP server. + * + * @author Jaroslav Tulach + */ +public abstract class Launcher { + + Launcher() { + } + + /** Initializes the launcher. This may mean starting a web browser or + * initializing execution engine. + * @throws IOException if something goes wrong + */ + public abstract void initialize() throws IOException; + + /** Shuts down the launcher. + * @throws IOException if something goes wrong + */ + public abstract void shutdown() throws IOException; + + + /** Builds an invocation context. The context can later be customized + * and {@link InvocationContext#invoke() invoked}. + * + * @param clazz the class to execute method from + * @param method the method to execute + * @return the context pointing to the selected method + */ + public InvocationContext createInvocation(Class clazz, String method) { + return new InvocationContext(this, clazz, method); + } + + + /** Creates launcher that uses internal JavaScript engine (Rhino). + * @return the launcher + */ + public static Launcher createJavaScript() { + try { + Class c = loadClass("org.apidesign.bck2brwsr.launcher.JSLauncher"); + return (Launcher) c.newInstance(); + } catch (Exception ex) { + throw new IllegalStateException("Please include org.apidesign.bck2brwsr:launcher.html dependency!", ex); + } + } + + /** Creates launcher that is using external browser. + * + * @param cmd null to use java.awt.Desktop to show the launcher + * or a string to execute in an external process (with a parameter to the URL) + * @return launcher executing in external browser. + */ + public static Launcher createBrowser(String cmd) { + String msg = "Trying to create browser '" + cmd + "'"; + try { + Class c; + if ("fxbrwsr".equals(cmd)) { // NOI18N + msg = "Please include org.apidesign.bck2brwsr:launcher.fx dependency!"; + c = loadClass("org.apidesign.bck2brwsr.launcher.FXBrwsrLauncher"); // NOI18N + } else { + msg = "Please include org.apidesign.bck2brwsr:launcher.html dependency!"; + c = loadClass("org.apidesign.bck2brwsr.launcher.Bck2BrwsrLauncher"); // NOI18N + if ("bck2brwsr".equals(cmd)) { // NOI18N + // use default executable + cmd = null; + } + } + Constructor cnstr = c.getConstructor(String.class); + return (Launcher) cnstr.newInstance(cmd); + } catch (Exception ex) { + throw new IllegalStateException(msg, ex); + } + } + + /** Starts an HTTP server which provides access to classes and resources + * available in the classes URL and shows a start page + * available as {@link ClassLoader#getResource(java.lang.String)} from the + * provide classloader. Opens a browser with URL showing the start page. + * + * @param classes classloader offering access to classes and resources + * @param startpage page to show in the browser + * @return interface that allows one to stop the server + * @throws IOException if something goes wrong + */ + public static Closeable showURL(ClassLoader classes, String startpage) throws IOException { + return showURL(null, classes, startpage); + } + /** Starts an HTTP server which provides access to classes and resources + * available in the classes URL and shows a start page + * available as {@link ClassLoader#getResource(java.lang.String)} from the + * provide classloader. Opens a browser with URL showing the start page. + * + * @param brwsr name of browser to use or null + * @param classes classloader offering access to classes and resources + * @param startpage page to show in the browser + * @return interface that allows one to stop the server + * @throws IOException if something goes wrong + * @since 0.7 + */ + public static Closeable showURL(String brwsr, ClassLoader classes, String startpage) throws IOException { + Launcher l = createBrowser(brwsr); + l.addClassLoader(classes); + l.showURL(startpage); + return (Closeable) l; + } + /** Starts an HTTP server which provides access to certain directory. + * The startpage should be relative location inside the root + * directory. Opens a browser with URL showing the start page. + * + * @param directory the root directory on disk + * @param startpage relative path from the root to the page + * @exception IOException if something goes wrong. + */ + public static Closeable showDir(File directory, String startpage) throws IOException { + Launcher l = createBrowser(null); + l.showDirectory(directory, startpage); + return (Closeable) l; + } + + abstract InvocationContext runMethod(InvocationContext c) throws IOException; + + + private static Class loadClass(String cn) throws ClassNotFoundException { + return Launcher.class.getClassLoader().loadClass(cn); + } + + void showDirectory(File directory, String startpage) throws IOException { + throw new UnsupportedOperationException(); + } + + void showURL(String startpage) throws IOException { + throw new UnsupportedOperationException(); + } + + void addClassLoader(ClassLoader classes) { + throw new UnsupportedOperationException(); + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/fx/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/fx/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,58 @@ + + + 4.0.0 + + org.apidesign.bck2brwsr + launcher-pom + 0.8-SNAPSHOT + + org.apidesign.bck2brwsr + launcher.fx + 0.8-SNAPSHOT + FXBrwsr Launcher + http://maven.apache.org + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-javadoc-plugin + + org.apidesign.bck2brwsr.launcher.fx + false + + + + + + ${java.home}/lib/jfxrt.jar + UTF-8 + + + + ${project.groupId} + launcher + ${project.version} + + + org.glassfish.grizzly + grizzly-http-server + ${grizzly.version} + + + com.oracle + javafx + 2.2 + system + ${jfxrt.jar} + + + diff -r d127d41768bd -r ae3f2aa50970 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,634 @@ +/** + * 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.launcher; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apidesign.bck2brwsr.launcher.InvocationContext.Resource; +import org.glassfish.grizzly.PortRange; +import org.glassfish.grizzly.http.server.HttpHandler; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.http.server.NetworkListener; +import org.glassfish.grizzly.http.server.Request; +import org.glassfish.grizzly.http.server.Response; +import org.glassfish.grizzly.http.server.ServerConfiguration; +import org.glassfish.grizzly.http.util.HttpStatus; +import org.glassfish.grizzly.threadpool.ThreadPoolConfig; + +/** + * Lightweight server to launch Bck2Brwsr applications and tests. + * Supports execution in native browser as well as Java's internal + * execution engine. + */ +abstract class BaseHTTPLauncher extends Launcher implements Closeable, Callable { + static final Logger LOG = Logger.getLogger(BaseHTTPLauncher.class.getName()); + private static final InvocationContext END = new InvocationContext(null, null, null); + private final Set loaders = new LinkedHashSet<>(); + private final BlockingQueue methods = new LinkedBlockingQueue<>(); + private long timeOut; + private final Res resources = new Res(); + private final String cmd; + private Object[] brwsr; + private HttpServer server; + private CountDownLatch wait; + + public BaseHTTPLauncher(String cmd) { + this.cmd = cmd; + addClassLoader(BaseHTTPLauncher.class.getClassLoader()); + setTimeout(180000); + } + + @Override + InvocationContext runMethod(InvocationContext c) throws IOException { + loaders.add(c.clazz.getClassLoader()); + methods.add(c); + try { + c.await(timeOut); + } catch (InterruptedException ex) { + throw new IOException(ex); + } + return c; + } + + public void setTimeout(long ms) { + timeOut = ms; + } + + public void addClassLoader(ClassLoader url) { + this.loaders.add(url); + } + + ClassLoader[] loaders() { + return loaders.toArray(new ClassLoader[loaders.size()]); + } + + public void showURL(String startpage) throws IOException { + if (!startpage.startsWith("/")) { + startpage = "/" + startpage; + } + HttpServer s = initServer(".", true); + int last = startpage.lastIndexOf('/'); + String prefix = startpage.substring(0, last); + String simpleName = startpage.substring(last); + s.getServerConfiguration().addHttpHandler(new SubTree(resources, prefix), "/"); + server = s; + try { + launchServerAndBrwsr(s, simpleName); + } catch (URISyntaxException | InterruptedException ex) { + throw new IOException(ex); + } + } + + void showDirectory(File dir, String startpage) throws IOException { + if (!startpage.startsWith("/")) { + startpage = "/" + startpage; + } + HttpServer s = initServer(dir.getPath(), false); + try { + launchServerAndBrwsr(s, startpage); + } catch (URISyntaxException | InterruptedException ex) { + throw new IOException(ex); + } + } + + @Override + public void initialize() throws IOException { + try { + executeInBrowser(); + } catch (InterruptedException ex) { + final InterruptedIOException iio = new InterruptedIOException(ex.getMessage()); + iio.initCause(ex); + throw iio; + } catch (Exception ex) { + if (ex instanceof IOException) { + throw (IOException)ex; + } + if (ex instanceof RuntimeException) { + throw (RuntimeException)ex; + } + throw new IOException(ex); + } + } + + private HttpServer initServer(String path, boolean addClasses) throws IOException { + HttpServer s = HttpServer.createSimpleServer(path, new PortRange(8080, 65535)); + + ThreadPoolConfig fewThreads = ThreadPoolConfig.defaultConfig().copy(). + setPoolName("Fx/Bck2 Brwsr"). + setCorePoolSize(1). + setMaxPoolSize(5); + ThreadPoolConfig oneKernel = ThreadPoolConfig.defaultConfig().copy(). + setPoolName("Kernel Fx/Bck2"). + setCorePoolSize(1). + setMaxPoolSize(3); + for (NetworkListener nl : s.getListeners()) { + nl.getTransport().setWorkerThreadPoolConfig(fewThreads); + nl.getTransport().setKernelThreadPoolConfig(oneKernel); + } + + final ServerConfiguration conf = s.getServerConfiguration(); + if (addClasses) { + conf.addHttpHandler(new VM(), "/bck2brwsr.js"); + conf.addHttpHandler(new Classes(resources), "/classes/"); + } + return s; + } + + private void executeInBrowser() throws InterruptedException, URISyntaxException, IOException { + wait = new CountDownLatch(1); + server = initServer(".", true); + final ServerConfiguration conf = server.getServerConfiguration(); + + class DynamicResourceHandler extends HttpHandler { + private final InvocationContext ic; + public DynamicResourceHandler(InvocationContext ic) { + if (ic == null || ic.resources.isEmpty()) { + throw new NullPointerException(); + } + this.ic = ic; + for (Resource r : ic.resources) { + conf.addHttpHandler(this, r.httpPath); + } + } + + public void close() { + conf.removeHttpHandler(this); + } + + @Override + public void service(Request request, Response response) throws Exception { + for (Resource r : ic.resources) { + if (r.httpPath.equals(request.getRequestURI())) { + LOG.log(Level.INFO, "Serving HttpResource for {0}", request.getRequestURI()); + response.setContentType(r.httpType); + r.httpContent.reset(); + String[] params = null; + if (r.parameters.length != 0) { + params = new String[r.parameters.length]; + for (int i = 0; i < r.parameters.length; i++) { + params[i] = request.getParameter(r.parameters[i]); + if (params[i] == null) { + if ("http.method".equals(r.parameters[i])) { + params[i] = request.getMethod().toString(); + } else if ("http.requestBody".equals(r.parameters[i])) { + Reader rdr = request.getReader(); + StringBuilder sb = new StringBuilder(); + for (;;) { + int ch = rdr.read(); + if (ch == -1) { + break; + } + sb.append((char)ch); + } + params[i] = sb.toString(); + } + } + if (params[i] == null) { + params[i] = "null"; + } + } + } + + copyStream(r.httpContent, response.getOutputStream(), null, params); + } + } + } + } + + conf.addHttpHandler(new Page(resources, harnessResource()), "/execute"); + + conf.addHttpHandler(new HttpHandler() { + int cnt; + List cases = new ArrayList<>(); + DynamicResourceHandler prev; + @Override + public void service(Request request, Response response) throws Exception { + String id = request.getParameter("request"); + String value = request.getParameter("result"); + if (value != null && value.indexOf((char)0xC5) != -1) { + value = toUTF8(value); + } + + + InvocationContext mi = null; + int caseNmbr = -1; + + if (id != null && value != null) { + LOG.log(Level.INFO, "Received result for case {0} = {1}", new Object[]{id, value}); + value = decodeURL(value); + int indx = Integer.parseInt(id); + cases.get(indx).result(value, null); + if (++indx < cases.size()) { + mi = cases.get(indx); + LOG.log(Level.INFO, "Re-executing case {0}", indx); + caseNmbr = indx; + } + } else { + if (!cases.isEmpty()) { + LOG.info("Re-executing test cases"); + mi = cases.get(0); + caseNmbr = 0; + } + } + + if (prev != null) { + prev.close(); + prev = null; + } + + if (mi == null) { + mi = methods.take(); + caseNmbr = cnt++; + } + if (mi == END) { + response.getWriter().write(""); + wait.countDown(); + cnt = 0; + LOG.log(Level.INFO, "End of data reached. Exiting."); + return; + } + + if (!mi.resources.isEmpty()) { + prev = new DynamicResourceHandler(mi); + } + + cases.add(mi); + final String cn = mi.clazz.getName(); + final String mn = mi.methodName; + LOG.log(Level.INFO, "Request for {0} case. Sending {1}.{2}", new Object[]{caseNmbr, cn, mn}); + response.getWriter().write("{" + + "className: '" + cn + "', " + + "methodName: '" + mn + "', " + + "request: " + caseNmbr + ); + if (mi.html != null) { + response.getWriter().write(", html: '"); + response.getWriter().write(encodeJSON(mi.html)); + response.getWriter().write("'"); + } + response.getWriter().write("}"); + } + }, "/data"); + + this.brwsr = launchServerAndBrwsr(server, "/execute"); + } + + private static String encodeJSON(String in) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < in.length(); i++) { + char ch = in.charAt(i); + if (ch < 32 || ch == '\'' || ch == '"') { + sb.append("\\u"); + String hs = "0000" + Integer.toHexString(ch); + hs = hs.substring(hs.length() - 4); + sb.append(hs); + } else { + sb.append(ch); + } + } + return sb.toString(); + } + + @Override + public void shutdown() throws IOException { + methods.offer(END); + for (;;) { + int prev = methods.size(); + try { + if (wait != null && wait.await(timeOut, TimeUnit.MILLISECONDS)) { + break; + } + } catch (InterruptedException ex) { + throw new IOException(ex); + } + if (prev == methods.size()) { + LOG.log( + Level.WARNING, + "Timeout and no test has been executed meanwhile (at {0}). Giving up.", + methods.size() + ); + break; + } + LOG.log(Level.INFO, + "Timeout, but tests got from {0} to {1}. Trying again.", + new Object[]{prev, methods.size()} + ); + } + stopServerAndBrwsr(server, brwsr); + } + + static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException { + for (;;) { + int ch = is.read(); + if (ch == -1) { + break; + } + if (ch == '$' && params.length > 0) { + int cnt = is.read() - '0'; + if (baseURL != null && cnt == 'U' - '0') { + os.write(baseURL.getBytes("UTF-8")); + } else { + if (cnt >= 0 && cnt < params.length) { + os.write(params[cnt].getBytes("UTF-8")); + } else { + os.write('$'); + os.write(cnt + '0'); + } + } + } else { + os.write(ch); + } + } + } + + private Object[] launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException { + server.start(); + NetworkListener listener = server.getListeners().iterator().next(); + int port = listener.getPort(); + + URI uri = new URI("http://localhost:" + port + page); + return showBrwsr(uri); + } + private static String toUTF8(String value) throws UnsupportedEncodingException { + byte[] arr = new byte[value.length()]; + for (int i = 0; i < arr.length; i++) { + arr[i] = (byte)value.charAt(i); + } + return new String(arr, "UTF-8"); + } + + private static String decodeURL(String s) { + for (;;) { + int pos = s.indexOf('%'); + if (pos == -1) { + return s; + } + int i = Integer.parseInt(s.substring(pos + 1, pos + 2), 16); + s = s.substring(0, pos) + (char)i + s.substring(pos + 2); + } + } + + private void stopServerAndBrwsr(HttpServer server, Object[] brwsr) throws IOException { + if (brwsr == null) { + return; + } + Process process = (Process)brwsr[0]; + + server.stop(); + InputStream stdout = process.getInputStream(); + InputStream stderr = process.getErrorStream(); + drain("StdOut", stdout); + drain("StdErr", stderr); + process.destroy(); + int res; + try { + res = process.waitFor(); + } catch (InterruptedException ex) { + throw new IOException(ex); + } + LOG.log(Level.INFO, "Exit code: {0}", res); + + deleteTree((File)brwsr[1]); + } + + private static void drain(String name, InputStream is) throws IOException { + int av = is.available(); + if (av > 0) { + StringBuilder sb = new StringBuilder(); + sb.append("v== ").append(name).append(" ==v\n"); + while (av-- > 0) { + sb.append((char)is.read()); + } + sb.append("\n^== ").append(name).append(" ==^"); + LOG.log(Level.INFO, sb.toString()); + } + } + + private void deleteTree(File file) { + if (file == null) { + return; + } + File[] arr = file.listFiles(); + if (arr != null) { + for (File s : arr) { + deleteTree(s); + } + } + file.delete(); + } + + @Override + public HttpServer call() throws Exception { + return server; + } + + @Override + public void close() throws IOException { + shutdown(); + } + + protected Object[] showBrwsr(URI uri) throws IOException { + LOG.log(Level.INFO, "Showing {0}", uri); + if (cmd == null) { + try { + LOG.log(Level.INFO, "Trying Desktop.browse on {0} {2} by {1}", new Object[] { + System.getProperty("java.vm.name"), + System.getProperty("java.vm.vendor"), + System.getProperty("java.vm.version"), + }); + java.awt.Desktop.getDesktop().browse(uri); + LOG.log(Level.INFO, "Desktop.browse successfully finished"); + return null; + } catch (UnsupportedOperationException ex) { + LOG.log(Level.INFO, "Desktop.browse not supported: {0}", ex.getMessage()); + LOG.log(Level.FINE, null, ex); + } + } + { + String cmdName = cmd == null ? "xdg-open" : cmd; + String[] cmdArr = { + cmdName, uri.toString() + }; + LOG.log(Level.INFO, "Launching {0}", Arrays.toString(cmdArr)); + final Process process = Runtime.getRuntime().exec(cmdArr); + return new Object[] { process, null }; + } + } + + abstract void generateBck2BrwsrJS(StringBuilder sb, Res loader) throws IOException; + abstract String harnessResource(); + + class Res { + public InputStream get(String resource) throws IOException { + URL u = null; + for (ClassLoader l : loaders) { + Enumeration en = l.getResources(resource); + while (en.hasMoreElements()) { + u = en.nextElement(); + if (u.toExternalForm().matches("^.*emul.*rt\\.jar.*$")) { + return u.openStream(); + } + } + } + if (u != null) { + if (u.toExternalForm().contains("rt.jar")) { + LOG.log(Level.WARNING, "Fallback to bootclasspath for {0}", u); + } + return u.openStream(); + } + throw new IOException("Can't find " + resource); + } + } + + private static class Page extends HttpHandler { + final String resource; + private final String[] args; + private final Res res; + + public Page(Res res, String resource, String... args) { + this.res = res; + this.resource = resource; + this.args = args.length == 0 ? new String[] { "$0" } : args; + } + + @Override + public void service(Request request, Response response) throws Exception { + String r = computePage(request); + if (r.startsWith("/")) { + r = r.substring(1); + } + String[] replace = {}; + if (r.endsWith(".html")) { + response.setContentType("text/html"); + LOG.info("Content type text/html"); + replace = args; + } + if (r.endsWith(".xhtml")) { + response.setContentType("application/xhtml+xml"); + LOG.info("Content type application/xhtml+xml"); + replace = args; + } + OutputStream os = response.getOutputStream(); + try (InputStream is = res.get(r)) { + copyStream(is, os, request.getRequestURL().toString(), replace); + } catch (IOException ex) { + response.setDetailMessage(ex.getLocalizedMessage()); + response.setError(); + response.setStatus(404); + } + } + + protected String computePage(Request request) { + String r = resource; + if (r == null) { + r = request.getHttpHandlerPath(); + } + return r; + } + } + + private static class SubTree extends Page { + + public SubTree(Res res, String resource, String... args) { + super(res, resource, args); + } + + @Override + protected String computePage(Request request) { + return resource + request.getHttpHandlerPath(); + } + + + } + + private class VM extends HttpHandler { + @Override + public void service(Request request, Response response) throws Exception { + response.setCharacterEncoding("UTF-8"); + response.setContentType("text/javascript"); + StringBuilder sb = new StringBuilder(); + generateBck2BrwsrJS(sb, BaseHTTPLauncher.this.resources); + response.getWriter().write(sb.toString()); + } + } + + private static class Classes extends HttpHandler { + private final Res loader; + + public Classes(Res loader) { + this.loader = loader; + } + + @Override + public void service(Request request, Response response) throws Exception { + String res = request.getHttpHandlerPath(); + if (res.startsWith("/")) { + res = res.substring(1); + } + try (InputStream is = loader.get(res)) { + response.setContentType("text/javascript"); + Writer w = response.getWriter(); + w.append("["); + for (int i = 0;; i++) { + int b = is.read(); + if (b == -1) { + break; + } + if (i > 0) { + w.append(", "); + } + if (i % 20 == 0) { + w.write("\n"); + } + if (b > 127) { + b = b - 256; + } + w.append(Integer.toString(b)); + } + w.append("\n]"); + } catch (IOException ex) { + response.setStatus(HttpStatus.NOT_FOUND_404); + response.setError(); + response.setDetailMessage(ex.getMessage()); + } + } + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/FXBrwsrLauncher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/FXBrwsrLauncher.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,161 @@ +/** + * 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.launcher; + +import org.apidesign.bck2brwsr.launcher.fximpl.FXBrwsr; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Enumeration; +import java.util.List; + +import java.util.concurrent.Executors; +import java.util.jar.Manifest; +import java.util.logging.Level; +import java.util.logging.Logger; +import javafx.application.Platform; +import org.apidesign.bck2brwsr.launcher.fximpl.JVMBridge; + +/** + * + * @author Jaroslav Tulach + */ +final class FXBrwsrLauncher extends BaseHTTPLauncher { + private static final Logger LOG = Logger.getLogger(FXBrwsrLauncher.class.getName()); + static { + try { + Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + m.setAccessible(true); + URL l = new URL("file://" + System.getProperty("java.home") + "/lib/jfxrt.jar"); + LOG.log(Level.INFO, "url : {0}", l); + m.invoke(ClassLoader.getSystemClassLoader(), l); + } catch (Exception ex) { + throw new LinkageError("Can't add jfxrt.jar on the classpath", ex); + } + } + + public FXBrwsrLauncher(String ignore) { + super(null); + } + + @Override + protected Object[] showBrwsr(final URI url) throws IOException { + try { + LOG.log(Level.INFO, "showBrwsr for {0}", url); + JVMBridge.registerClassLoaders(loaders()); + LOG.info("About to launch WebView"); + Executors.newSingleThreadExecutor().submit(new Runnable() { + @Override + public void run() { + LOG.log(Level.INFO, "In FX thread. Launching!"); + try { + FXBrwsr.launch(FXBrwsr.class, url.toString()); + LOG.log(Level.INFO, "Launcher is back. Closing"); + close(); + System.exit(0); + } catch (Throwable ex) { + LOG.log(Level.WARNING, "Error launching Web View", ex); + } + } + }); + } catch (Throwable ex) { + LOG.log(Level.WARNING, "Can't open WebView", ex); + } + return null; + } + + @Override + void generateBck2BrwsrJS(StringBuilder sb, Res loader) throws IOException { + sb.append("(function() {\n" + + " var impl = this.bck2brwsr;\n" + + " this.bck2brwsr = function() { return impl; };\n"); + if (isDebugged()) { + sb.append("var scr = window.document.createElement('script');\n"); + sb.append("scr.type = 'text/javascript';\n"); + sb.append("scr.src = 'https://getfirebug.com/firebug-lite.js';\n"); + sb.append("scr.text = '{ startOpened: true }';\n"); + sb.append("var head = window.document.getElementsByTagName('head')[0];"); + sb.append("head.appendChild(scr);\n"); + sb.append("var html = window.document.getElementsByTagName('html')[0];"); + sb.append("html.debug = true;\n"); + } + + sb.append("})(window);\n"); + JVMBridge.onBck2BrwsrLoad(); + } + + @Override + public void close() throws IOException { + super.close(); + Platform.exit(); + } + + String harnessResource() { + return "org/apidesign/bck2brwsr/launcher/fximpl/harness.xhtml"; + } + + public static void main(String... args) throws IOException { + String startPage = null; + + final ClassLoader cl = FXBrwsrLauncher.class.getClassLoader(); + startPage = findStartPage(cl, startPage); + if (startPage == null) { + throw new NullPointerException("Can't find StartPage tag in manifests!"); + } + + Launcher.showURL("fxbrwsr", cl, startPage); + } + + private static String findStartPage(final ClassLoader cl, String startPage) throws IOException { + Enumeration en = cl.getResources("META-INF/MANIFEST.MF"); + while (en.hasMoreElements()) { + URL url = en.nextElement(); + Manifest mf; + try (InputStream is = url.openStream()) { + mf = new Manifest(is); + } + String sp = mf.getMainAttributes().getValue("StartPage"); + if (sp != null) { + startPage = sp; + break; + } + } + return startPage; + } + + private static boolean isDebugged() { + try { + return isDebuggedImpl(); + } catch (LinkageError e) { + return false; + } + } + + private static boolean isDebuggedImpl() { + java.lang.management.RuntimeMXBean runtime; + runtime = java.lang.management.ManagementFactory.getRuntimeMXBean(); + List args = runtime.getInputArguments(); + if (args.contains("-Xdebug")) { // NOI18N + return true; + } + return false; + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fx/LauncherFX.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fx/LauncherFX.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,32 @@ +/** + * 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.launcher.fx; + +import org.apidesign.bck2brwsr.launcher.Launcher; + +/** This is a launcher for the Bck2Brwsr + * project that is using JavaFX's WebView to display the browser inside + * real Java virtual machine. Use {@link Launcher} methods to access this + * functionality via public, supported methods. + * + * @author Jaroslav Tulach + */ +public final class LauncherFX { + private LauncherFX() { + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Console.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Console.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,395 @@ +/** + * 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.launcher.fximpl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.Enumeration; +import javafx.scene.web.WebEngine; +import netscape.javascript.JSObject; + +/** + * + * @author Jaroslav Tulach + */ +public final class Console { + public Console() { + } + + private static Object getAttr(Object elem, String attr) { + return InvokeJS.CObject.call("getAttr", elem, attr); + } + + private static void setAttr(String id, String attr, Object value) { + InvokeJS.CObject.call("setAttrId", id, attr, value); + } + private static void setAttr(Object id, String attr, Object value) { + InvokeJS.CObject.call("setAttr", id, attr, value); + } + + private static void closeWindow() {} + + private static Object textArea; + private static Object statusArea; + + private static void log(String newText) { + if (textArea == null) { + return; + } + String attr = "value"; + setAttr(textArea, attr, getAttr(textArea, attr) + "\n" + newText); + setAttr(textArea, "scrollTop", getAttr(textArea, "scrollHeight")); + } + + private static void beginTest(Case c) { + Object[] arr = new Object[2]; + beginTest(c.getClassName() + "." + c.getMethodName(), c, arr); + textArea = arr[0]; + statusArea = arr[1]; + } + + private static void finishTest(Case c, Object res) { + if ("null".equals(res)) { + setAttr(statusArea, "innerHTML", "Success"); + } else { + setAttr(statusArea, "innerHTML", "Result " + res); + } + statusArea = null; + textArea = null; + } + + private static final String BEGIN_TEST = + "var ul = window.document.getElementById('bck2brwsr.result');\n" + + "var li = window.document.createElement('li');\n" + + "var span = window.document.createElement('span');" + + "span.innerHTML = test + ' - ';\n" + + "var details = window.document.createElement('a');\n" + + "details.innerHTML = 'Details';\n" + + "details.href = '#';\n" + + "var p = window.document.createElement('p');\n" + + "var status = window.document.createElement('a');\n" + + "status.innerHTML = 'running';" + + "details.onclick = function() { li.appendChild(p); li.removeChild(details); status.innerHTML = 'Run Again'; status.href = '#'; };\n" + + "status.onclick = function() { c.again(arr); }\n" + + "var pre = window.document.createElement('textarea');\n" + + "pre.cols = 100;" + + "pre.rows = 10;" + + "li.appendChild(span);\n" + + "li.appendChild(status);\n" + + "var span = window.document.createElement('span');" + + "span.innerHTML = ' ';\n" + + "li.appendChild(span);\n" + + "li.appendChild(details);\n" + + "p.appendChild(pre);\n" + + "ul.appendChild(li);\n" + + "arr[0] = pre;\n" + + "arr[1] = status;\n"; + + private static void beginTest(String test, Case c, Object[] arr) { + InvokeJS.CObject.call("beginTest", test, c, arr); + } + + private static final String LOAD_TEXT = + "var request = new XMLHttpRequest();\n" + + "request.open('GET', url, true);\n" + + "request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n" + + "request.onreadystatechange = function() {\n" + + " if (this.readyState!==4) return;\n" + + " try {" + + " arr[0] = this.responseText;\n" + + " callback.run__V();\n" + + " } catch (e) { alert(e); }" + + "};" + + "request.send();"; + private static void loadText(String url, Runnable callback, String[] arr) throws IOException { + InvokeJS.CObject.call("loadText", url, new Run(callback), arr); + } + + public static void runHarness(String url) throws IOException { + new Console().harness(url); + } + + public void harness(String url) throws IOException { + log("Connecting to " + url); + Request r = new Request(url); + } + + private static class Request implements Runnable { + private final String[] arr = { null }; + private final String url; + private Case c; + private int retries; + + private Request(String url) throws IOException { + this.url = url; + loadText(url, this, arr); + } + private Request(String url, String u) throws IOException { + this.url = url; + loadText(u, this, arr); + } + + @Override + public void run() { + try { + if (c == null) { + String data = arr[0]; + + if (data == null) { + log("Some error exiting"); + closeWindow(); + return; + } + + if (data.isEmpty()) { + log("No data, exiting"); + closeWindow(); + return; + } + + c = Case.parseData(data); + beginTest(c); + log("Got \"" + data + "\""); + } else { + log("Processing \"" + arr[0] + "\" for " + retries + " time"); + } + Object result = retries++ >= 10 ? "java.lang.InterruptedException:timeout" : c.runTest(); + finishTest(c, result); + + String u = url + "?request=" + c.getRequestId() + "&result=" + result; + new Request(url, u); + } catch (Exception ex) { + if (ex instanceof InterruptedException) { + log("Re-scheduling in 100ms"); + schedule(this, 100); + return; + } + log(ex.getClass().getName() + ":" + ex.getMessage()); + } + } + } + + private static String encodeURL(String r) throws UnsupportedEncodingException { + final String SPECIAL = "%$&+,/:;=?@"; + StringBuilder sb = new StringBuilder(); + byte[] utf8 = r.getBytes("UTF-8"); + for (int i = 0; i < utf8.length; i++) { + int ch = utf8[i] & 0xff; + if (ch < 32 || ch > 127 || SPECIAL.indexOf(ch) >= 0) { + final String numbers = "0" + Integer.toHexString(ch); + sb.append("%").append(numbers.substring(numbers.length() - 2)); + } else { + if (ch == 32) { + sb.append("+"); + } else { + sb.append((char)ch); + } + } + } + return sb.toString(); + } + + static String invoke(String clazz, String method) throws + ClassNotFoundException, InvocationTargetException, IllegalAccessException, + InstantiationException, InterruptedException { + final Object r = new Case(null).invokeMethod(clazz, method); + return r == null ? "null" : r.toString().toString(); + } + + /** Helper method that inspects the classpath and loads given resource + * (usually a class file). Used while running tests in Rhino. + * + * @param name resource name to find + * @return the array of bytes in the given resource + * @throws IOException I/O in case something goes wrong + */ + public static byte[] read(String name) throws IOException { + URL u = null; + Enumeration en = Console.class.getClassLoader().getResources(name); + while (en.hasMoreElements()) { + u = en.nextElement(); + } + if (u == null) { + throw new IOException("Can't find " + name); + } + try (InputStream is = u.openStream()) { + byte[] arr; + arr = new byte[is.available()]; + int offset = 0; + while (offset < arr.length) { + int len = is.read(arr, offset, arr.length - offset); + if (len == -1) { + throw new IOException("Can't read " + name); + } + offset += len; + } + return arr; + } + } + + private static void turnAssetionStatusOn() { + } + + private static Object schedule(Runnable r, int time) { + return InvokeJS.CObject.call("schedule", new Run(r), time); + } + + private static final class Case { + private final Object data; + private Object inst; + + private Case(Object data) { + this.data = data; + } + + public static Case parseData(String s) { + return new Case(toJSON(s)); + } + + public String getMethodName() { + return (String) value("methodName", data); + } + + public String getClassName() { + return (String) value("className", data); + } + + public int getRequestId() { + Object v = value("request", data); + if (v instanceof Number) { + return ((Number)v).intValue(); + } + return Integer.parseInt(v.toString()); + } + + public String getHtmlFragment() { + return (String) value("html", data); + } + + void again(Object[] arr) { + try { + textArea = arr[0]; + statusArea = arr[1]; + setAttr(textArea, "value", ""); + runTest(); + } catch (Exception ex) { + log(ex.getClass().getName() + ":" + ex.getMessage()); + } + } + + private Object runTest() throws IllegalAccessException, + IllegalArgumentException, ClassNotFoundException, UnsupportedEncodingException, + InvocationTargetException, InstantiationException, InterruptedException { + if (this.getHtmlFragment() != null) { + setAttr("bck2brwsr.fragment", "innerHTML", this.getHtmlFragment()); + } + log("Invoking " + this.getClassName() + '.' + this.getMethodName() + " as request: " + this.getRequestId()); + Object result = invokeMethod(this.getClassName(), this.getMethodName()); + setAttr("bck2brwsr.fragment", "innerHTML", ""); + log("Result: " + result); + result = encodeURL("" + result); + log("Sending back: ...?request=" + this.getRequestId() + "&result=" + result); + return result; + } + + private Object invokeMethod(String clazz, String method) + throws ClassNotFoundException, InvocationTargetException, + InterruptedException, IllegalAccessException, IllegalArgumentException, + InstantiationException { + Method found = null; + Class c = Class.forName(clazz); + for (Method m : c.getMethods()) { + if (m.getName().equals(method)) { + found = m; + } + } + Object res; + if (found != null) { + try { + if ((found.getModifiers() & Modifier.STATIC) != 0) { + res = found.invoke(null); + } else { + if (inst == null) { + inst = c.newInstance(); + } + res = found.invoke(inst); + } + } catch (Throwable ex) { + if (ex instanceof InvocationTargetException) { + ex = ((InvocationTargetException) ex).getTargetException(); + } + if (ex instanceof InterruptedException) { + throw (InterruptedException)ex; + } + res = ex.getClass().getName() + ":" + ex.getMessage(); + } + } else { + res = "Can't find method " + method + " in " + clazz; + } + return res; + } + + private static Object toJSON(String s) { + return InvokeJS.CObject.call("toJSON", s); + } + + private static Object value(String p, Object d) { + return ((JSObject)d).getMember(p); + } + } + + private static String safe(String txt) { + return "try {" + txt + "} catch (err) { alert(err); }"; + } + + static { + turnAssetionStatusOn(); + } + + private static final class InvokeJS { + static final JSObject CObject = initJS(); + + private static JSObject initJS() { + WebEngine web = (WebEngine) System.getProperties().get("webEngine"); + return (JSObject) web.executeScript("(function() {" + + "var CObject = {};" + + + "CObject.getAttr = function(elem, attr) { return elem[attr].toString(); };" + + + "CObject.setAttrId = function(id, attr, value) { window.document.getElementById(id)[attr] = value; };" + + "CObject.setAttr = function(elem, attr, value) { elem[attr] = value; };" + + + "CObject.beginTest = function(test, c, arr) {" + safe(BEGIN_TEST) + "};" + + + "CObject.loadText = function(url, callback, arr) {" + safe(LOAD_TEXT.replace("run__V", "run")) + "};" + + + "CObject.schedule = function(r, time) { return window.setTimeout(function() { r.run(); }, time); };" + + + "CObject.toJSON = function(s) { return eval('(' + s + ')'); };" + + + "return CObject;" + + "})(this)"); + } + } + +} diff -r d127d41768bd -r ae3f2aa50970 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXBrwsr.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXBrwsr.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,184 @@ +/** + * 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.launcher.fximpl; + +import java.util.List; +import java.util.TooManyListenersException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.geometry.HPos; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.geometry.VPos; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebEvent; +import javafx.scene.web.WebView; +import javafx.stage.Modality; +import javafx.stage.Stage; +import netscape.javascript.JSObject; + +/** + * Demonstrates a WebView object accessing a web page. + * + * @see javafx.scene.web.WebView + * @see javafx.scene.web.WebEngine + */ +public class FXBrwsr extends Application { + private static final Logger LOG = Logger.getLogger(FXBrwsr.class.getName()); + + @Override + public void start(Stage primaryStage) throws Exception { + Pane root = new WebViewPane(getParameters().getUnnamed()); + primaryStage.setScene(new Scene(root, 1024, 768)); + LOG.info("Showing the stage"); + primaryStage.show(); + LOG.log(Level.INFO, "State shown: {0}", primaryStage.isShowing()); + } + + /** + * Create a resizable WebView pane + */ + private class WebViewPane extends Pane { + private final JVMBridge bridge = new JVMBridge(); + + public WebViewPane(List params) { + LOG.log(Level.INFO, "Initializing WebView with {0}", params); + VBox.setVgrow(this, Priority.ALWAYS); + setMaxWidth(Double.MAX_VALUE); + setMaxHeight(Double.MAX_VALUE); + WebView view = new WebView(); + view.setMinSize(500, 400); + view.setPrefSize(500, 400); + final WebEngine eng = view.getEngine(); + try { + JVMBridge.addBck2BrwsrLoad(new InitBck2Brwsr(eng)); + } catch (TooManyListenersException ex) { + LOG.log(Level.SEVERE, null, ex); + } + + if (params.size() > 0) { + LOG.log(Level.INFO, "loading page {0}", params.get(0)); + eng.load(params.get(0)); + LOG.fine("back from load"); + } + eng.setOnAlert(new EventHandler>() { + @Override + public void handle(WebEvent t) { + final Stage dialogStage = new Stage(); + dialogStage.initModality(Modality.WINDOW_MODAL); + dialogStage.setTitle("Warning"); + final Button button = new Button("Close"); + final Text text = new Text(t.getData()); + + VBox box = new VBox(); + box.setAlignment(Pos.CENTER); + box.setSpacing(10); + box.setPadding(new Insets(10)); + box.getChildren().addAll(text, button); + + dialogStage.setScene(new Scene(box)); + + button.setCancelButton(true); + button.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent t) { + dialogStage.close(); + } + }); + + dialogStage.centerOnScreen(); + dialogStage.showAndWait(); + } + }); + GridPane grid = new GridPane(); + grid.setVgap(5); + grid.setHgap(5); + GridPane.setConstraints(view, 0, 1, 2, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.ALWAYS); + grid.getColumnConstraints().addAll(new ColumnConstraints(100, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true), new ColumnConstraints(40, 40, 40, Priority.NEVER, HPos.CENTER, true)); + grid.getChildren().addAll(view); + getChildren().add(grid); + } + + boolean initBck2Brwsr(WebEngine webEngine) { + JSObject jsobj = (JSObject) webEngine.executeScript("window"); + LOG.log(Level.FINE, "window: {0}", jsobj); + Object prev = jsobj.getMember("bck2brwsr"); + if ("undefined".equals(prev)) { + System.getProperties().put("webEngine", webEngine); + jsobj.setMember("bck2brwsr", bridge); + return true; + } + return false; + } + + @Override + protected void layoutChildren() { + List managed = getManagedChildren(); + double width = getWidth(); + double height = getHeight(); + double top = getInsets().getTop(); + double right = getInsets().getRight(); + double left = getInsets().getLeft(); + double bottom = getInsets().getBottom(); + for (int i = 0; i < managed.size(); i++) { + Node child = managed.get(i); + layoutInArea(child, left, top, width - left - right, height - top - bottom, 0, Insets.EMPTY, true, true, HPos.CENTER, VPos.CENTER); + } + } + + private class InitBck2Brwsr implements ChangeListener, Runnable { + private final WebEngine eng; + + public InitBck2Brwsr(WebEngine eng) { + this.eng = eng; + } + + @Override + public synchronized void changed(ObservableValue ov, Void t, Void t1) { + Platform.runLater(this); + try { + wait(); + } catch (InterruptedException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } + + @Override + public synchronized void run() { + initBck2Brwsr(eng); + notifyAll(); + } + } + } + +} diff -r d127d41768bd -r ae3f2aa50970 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,64 @@ +/** + * 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.launcher.fximpl; + +import java.util.TooManyListenersException; +import javafx.beans.value.ChangeListener; + +/** + * + * @author Jaroslav Tulach + */ +public final class JVMBridge { + private static ClassLoader[] ldrs; + private static ChangeListener onBck2BrwsrLoad; + + public static void registerClassLoaders(ClassLoader[] loaders) { + ldrs = loaders.clone(); + } + + public static void addBck2BrwsrLoad(ChangeListener l) throws TooManyListenersException { + if (onBck2BrwsrLoad != null) { + throw new TooManyListenersException(); + } + onBck2BrwsrLoad = l; + } + + public static void onBck2BrwsrLoad() { + ChangeListener l = onBck2BrwsrLoad; + if (l != null) { + l.changed(null, null, null); + } + } + + public Class loadClass(String name) throws ClassNotFoundException { + System.err.println("trying to load " + name); + ClassNotFoundException ex = null; + if (ldrs != null) for (ClassLoader l : ldrs) { + try { + return Class.forName(name, true, l); + } catch (ClassNotFoundException ex2) { + ex = ex2; + } + } + if (ex == null) { + ex = new ClassNotFoundException("No loaders"); + } + throw ex; + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Run.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Run.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,35 @@ +/** + * 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.launcher.fximpl; + +/** + * + * @author Jaroslav Tulach + */ +public final class Run implements Runnable { + private final Runnable r; + Run(Runnable r) { + this.r = r; + } + + @Override + public void run() { + r.run(); + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/harness.xhtml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/harness.xhtml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,52 @@ + + + + + + Bck2Brwsr Harness + + + + + +

Bck2Brwsr Execution Harness

+ +
    +
+ +
+ + + + diff -r d127d41768bd -r ae3f2aa50970 launcher/http/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/http/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,60 @@ + + + 4.0.0 + + org.apidesign.bck2brwsr + launcher-pom + 0.8-SNAPSHOT + + org.apidesign.bck2brwsr + launcher.http + 0.8-SNAPSHOT + Bck2Brwsr Launcher + http://maven.apache.org + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-javadoc-plugin + + org.apidesign.bck2brwsr.launcher.b2b + false + + + + + + UTF-8 + + + + ${project.groupId} + launcher + ${project.version} + + + ${project.groupId} + launcher.fx + ${project.version} + + + org.glassfish.grizzly + grizzly-http-server + ${grizzly.version} + + + ${project.groupId} + vm4brwsr + ${project.version} + + + diff -r d127d41768bd -r ae3f2aa50970 launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,70 @@ +/** + * 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.launcher; + +import java.io.IOException; +import java.io.InputStream; +import org.apidesign.vm4brwsr.Bck2Brwsr; + +/** + * Lightweight server to launch Bck2Brwsr applications and tests. + * Supports execution in native browser as well as Java's internal + * execution engine. + */ +final class Bck2BrwsrLauncher extends BaseHTTPLauncher { + + public Bck2BrwsrLauncher(String cmd) { + super(cmd); + } + + @Override + String harnessResource() { + return "org/apidesign/bck2brwsr/launcher/harness.xhtml"; + } + + @Override + void generateBck2BrwsrJS(StringBuilder sb, final Res loader) throws IOException { + class R implements Bck2Brwsr.Resources { + @Override + public InputStream get(String resource) throws IOException { + return loader.get(resource); + } + } + + Bck2Brwsr.generate(sb, new R()); + sb.append( + "(function WrapperVM(global) {" + + " function ldCls(res) {\n" + + " var request = new XMLHttpRequest();\n" + + " request.open('GET', '/classes/' + res, false);\n" + + " request.send();\n" + + " if (request.status !== 200) return null;\n" + + " var arr = eval('(' + request.responseText + ')');\n" + + " return arr;\n" + + " }\n" + + " var prevvm = global.bck2brwsr;\n" + + " global.bck2brwsr = function() {\n" + + " var args = Array.prototype.slice.apply(arguments);\n" + + " args.unshift(ldCls);\n" + + " return prevvm.apply(null, args);\n" + + " };\n" + + "})(this);\n" + ); + } + +} diff -r d127d41768bd -r ae3f2aa50970 launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,135 @@ +/** + * 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.launcher; + +import org.apidesign.bck2brwsr.launcher.impl.Console; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import org.apidesign.vm4brwsr.Bck2Brwsr; + +/** + * Tests execution in Java's internal scripting engine. + */ +final class JSLauncher extends Launcher { + private static final Logger LOG = Logger.getLogger(JSLauncher.class.getName()); + private Set loaders = new LinkedHashSet<>(); + private final Res resources = new Res(); + private Invocable code; + private StringBuilder codeSeq; + private Object console; + + JSLauncher() { + addClassLoader(Bck2Brwsr.class.getClassLoader()); + } + + @Override InvocationContext runMethod(InvocationContext mi) { + loaders.add(mi.clazz.getClassLoader()); + try { + long time = System.currentTimeMillis(); + LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.clazz.getName(), mi.methodName}); + String res = code.invokeMethod( + console, + "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2", + mi.clazz.getName(), mi.methodName).toString(); + time = System.currentTimeMillis() - time; + LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.clazz.getName(), mi.methodName, res, time}); + mi.result(res, null); + } catch (ScriptException | NoSuchMethodException ex) { + mi.result(null, ex); + } + return mi; + } + + public void addClassLoader(ClassLoader url) { + this.loaders.add(url); + } + + @Override + public void initialize() throws IOException { + try { + initRhino(); + } catch (Exception ex) { + if (ex instanceof IOException) { + throw (IOException)ex; + } + if (ex instanceof RuntimeException) { + throw (RuntimeException)ex; + } + throw new IOException(ex); + } + } + + private void initRhino() throws IOException, ScriptException, NoSuchMethodException { + StringBuilder sb = new StringBuilder(); + Bck2Brwsr.generate(sb, new Res()); + + ScriptEngineManager sem = new ScriptEngineManager(); + ScriptEngine mach = sem.getEngineByExtension("js"); + + sb.append( + "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.impl.Console.read);" + + "\nfunction initVM() { return vm; };" + + "\n"); + + Object res = mach.eval(sb.toString()); + if (!(mach instanceof Invocable)) { + throw new IOException("It is invocable object: " + res); + } + code = (Invocable) mach; + codeSeq = sb; + + Object vm = code.invokeFunction("initVM"); + console = code.invokeMethod(vm, "loadClass", Console.class.getName()); + } + + @Override + public void shutdown() throws IOException { + } + + @Override + public String toString() { + return codeSeq.toString(); + } + + private class Res implements Bck2Brwsr.Resources { + @Override + public InputStream get(String resource) throws IOException { + for (ClassLoader l : loaders) { + URL u = null; + Enumeration en = l.getResources(resource); + while (en.hasMoreElements()) { + u = en.nextElement(); + } + if (u != null) { + return u.openStream(); + } + } + throw new IOException("Can't find " + resource); + } + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/b2b/LauncherBck2Brwsr.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/b2b/LauncherBck2Brwsr.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,33 @@ +/** + * 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.launcher.b2b; + +import java.awt.Desktop; +import org.apidesign.bck2brwsr.launcher.Launcher; + +/** This is a launcher for the Bck2Brwsr + * project that is using {@link Desktop} (or {@link Process}) to display the + * external browser in separate process. Use {@link Launcher} methods to access this + * functionality via public, supported methods. + * + * @author Jaroslav Tulach + */ +public final class LauncherBck2Brwsr { + private LauncherBck2Brwsr() { + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,356 @@ +/** + * 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.launcher.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.Enumeration; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Jaroslav Tulach + */ +public class Console { + private Console() { + } + static { + turnAssetionStatusOn(); + } + + @JavaScriptBody(args = {"id", "attr"}, body = + "return window.document.getElementById(id)[attr].toString();") + private static native Object getAttr(String id, String attr); + @JavaScriptBody(args = {"elem", "attr"}, body = + "return elem[attr].toString();") + private static native Object getAttr(Object elem, String attr); + + @JavaScriptBody(args = {"id", "attr", "value"}, body = + "window.document.getElementById(id)[attr] = value;") + private static native void setAttr(String id, String attr, Object value); + @JavaScriptBody(args = {"elem", "attr", "value"}, body = + "elem[attr] = value;") + private static native void setAttr(Object id, String attr, Object value); + + @JavaScriptBody(args = {}, body = "return; window.close();") + private static native void closeWindow(); + + private static Object textArea; + private static Object statusArea; + + private static void log(String newText) { + if (textArea == null) { + return; + } + String attr = "value"; + setAttr(textArea, attr, getAttr(textArea, attr) + "\n" + newText); + setAttr(textArea, "scrollTop", getAttr(textArea, "scrollHeight")); + } + + private static void beginTest(Case c) { + Object[] arr = new Object[2]; + beginTest(c.getClassName() + "." + c.getMethodName(), c, arr); + textArea = arr[0]; + statusArea = arr[1]; + } + + private static void finishTest(Case c, Object res) { + if ("null".equals(res)) { + setAttr(statusArea, "innerHTML", "Success"); + } else { + setAttr(statusArea, "innerHTML", "Result " + res); + } + statusArea = null; + textArea = null; + } + + @JavaScriptBody(args = { "test", "c", "arr" }, body = + "var ul = window.document.getElementById('bck2brwsr.result');\n" + + "var li = window.document.createElement('li');\n" + + "var span = window.document.createElement('span');" + + "span.innerHTML = test + ' - ';\n" + + "var details = window.document.createElement('a');\n" + + "details.innerHTML = 'Details';\n" + + "details.href = '#';\n" + + "var p = window.document.createElement('p');\n" + + "var status = window.document.createElement('a');\n" + + "status.innerHTML = 'running';" + + "details.onclick = function() { li.appendChild(p); li.removeChild(details); status.innerHTML = 'Run Again'; status.href = '#'; };\n" + + "status.onclick = function() { c.again__V_3Ljava_lang_Object_2(arr); }\n" + + "var pre = window.document.createElement('textarea');\n" + + "pre.cols = 100;" + + "pre.rows = 10;" + + "li.appendChild(span);\n" + + "li.appendChild(status);\n" + + "var span = window.document.createElement('span');" + + "span.innerHTML = ' ';\n" + + "li.appendChild(span);\n" + + "li.appendChild(details);\n" + + "p.appendChild(pre);\n" + + "ul.appendChild(li);\n" + + "arr[0] = pre;\n" + + "arr[1] = status;\n" + ) + private static native void beginTest(String test, Case c, Object[] arr); + + @JavaScriptBody(args = { "url", "callback", "arr" }, body = "" + + "var request = new XMLHttpRequest();\n" + + "request.open('GET', url, true);\n" + + "request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n" + + "request.onreadystatechange = function() {\n" + + " if (this.readyState!==4) return;\n" + + " arr[0] = this.responseText;\n" + + " callback.run__V();\n" + + "};" + + "request.send();" + ) + private static native void loadText(String url, Runnable callback, String[] arr) throws IOException; + + public static void harness(String url) throws IOException { + log("Connecting to " + url); + Request r = new Request(url); + } + + private static class Request implements Runnable { + private final String[] arr = { null }; + private final String url; + private Case c; + private int retries; + + private Request(String url) throws IOException { + this.url = url; + loadText(url, this, arr); + } + private Request(String url, String u) throws IOException { + this.url = url; + loadText(u, this, arr); + } + + @Override + public void run() { + try { + if (c == null) { + String data = arr[0]; + + if (data == null) { + log("Some error exiting"); + closeWindow(); + return; + } + + if (data.isEmpty()) { + log("No data, exiting"); + closeWindow(); + return; + } + + c = Case.parseData(data); + beginTest(c); + log("Got \"" + data + "\""); + } else { + log("Processing \"" + arr[0] + "\" for " + retries + " time"); + } + Object result = retries++ >= 10 ? "java.lang.InterruptedException:timeout" : c.runTest(); + finishTest(c, result); + + String u = url + "?request=" + c.getRequestId() + "&result=" + result; + new Request(url, u); + } catch (Exception ex) { + if (ex instanceof InterruptedException) { + log("Re-scheduling in 100ms"); + schedule(this, 100); + return; + } + log(ex.getClass().getName() + ":" + ex.getMessage()); + } + } + } + + private static String encodeURL(String r) throws UnsupportedEncodingException { + final String SPECIAL = "%$&+,/:;=?@"; + StringBuilder sb = new StringBuilder(); + byte[] utf8 = r.getBytes("UTF-8"); + for (int i = 0; i < utf8.length; i++) { + int ch = utf8[i] & 0xff; + if (ch < 32 || ch > 127 || SPECIAL.indexOf(ch) >= 0) { + final String numbers = "0" + Integer.toHexString(ch); + sb.append("%").append(numbers.substring(numbers.length() - 2)); + } else { + if (ch == 32) { + sb.append("+"); + } else { + sb.append((char)ch); + } + } + } + return sb.toString(); + } + + static String invoke(String clazz, String method) throws + ClassNotFoundException, InvocationTargetException, IllegalAccessException, + InstantiationException, InterruptedException { + final Object r = new Case(null).invokeMethod(clazz, method); + return r == null ? "null" : r.toString().toString(); + } + + /** Helper method that inspects the classpath and loads given resource + * (usually a class file). Used while running tests in Rhino. + * + * @param name resource name to find + * @return the array of bytes in the given resource + * @throws IOException I/O in case something goes wrong + */ + public static byte[] read(String name) throws IOException { + URL u = null; + Enumeration en = Console.class.getClassLoader().getResources(name); + while (en.hasMoreElements()) { + u = en.nextElement(); + } + if (u == null) { + throw new IOException("Can't find " + name); + } + try (InputStream is = u.openStream()) { + byte[] arr; + arr = new byte[is.available()]; + int offset = 0; + while (offset < arr.length) { + int len = is.read(arr, offset, arr.length - offset); + if (len == -1) { + throw new IOException("Can't read " + name); + } + offset += len; + } + return arr; + } + } + + @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;") + private static void turnAssetionStatusOn() { + } + + @JavaScriptBody(args = {"r", "time"}, body = + "return window.setTimeout(function() { r.run__V(); }, time);") + private static native Object schedule(Runnable r, int time); + + private static final class Case { + private final Object data; + private Object inst; + + private Case(Object data) { + this.data = data; + } + + public static Case parseData(String s) { + return new Case(toJSON(s)); + } + + public String getMethodName() { + return value("methodName", data); + } + + public String getClassName() { + return value("className", data); + } + + public String getRequestId() { + return value("request", data); + } + + public String getHtmlFragment() { + return value("html", data); + } + + void again(Object[] arr) { + try { + textArea = arr[0]; + statusArea = arr[1]; + setAttr(textArea, "value", ""); + runTest(); + } catch (Exception ex) { + log(ex.getClass().getName() + ":" + ex.getMessage()); + } + } + + private Object runTest() throws IllegalAccessException, + IllegalArgumentException, ClassNotFoundException, UnsupportedEncodingException, + InvocationTargetException, InstantiationException, InterruptedException { + if (this.getHtmlFragment() != null) { + setAttr("bck2brwsr.fragment", "innerHTML", this.getHtmlFragment()); + } + log("Invoking " + this.getClassName() + '.' + this.getMethodName() + " as request: " + this.getRequestId()); + Object result = invokeMethod(this.getClassName(), this.getMethodName()); + setAttr("bck2brwsr.fragment", "innerHTML", ""); + log("Result: " + result); + result = encodeURL("" + result); + log("Sending back: ...?request=" + this.getRequestId() + "&result=" + result); + return result; + } + + private Object invokeMethod(String clazz, String method) + throws ClassNotFoundException, InvocationTargetException, + InterruptedException, IllegalAccessException, IllegalArgumentException, + InstantiationException { + Method found = null; + Class c = Class.forName(clazz); + for (Method m : c.getMethods()) { + if (m.getName().equals(method)) { + found = m; + } + } + Object res; + if (found != null) { + try { + if ((found.getModifiers() & Modifier.STATIC) != 0) { + res = found.invoke(null); + } else { + if (inst == null) { + inst = c.newInstance(); + } + res = found.invoke(inst); + } + } catch (Throwable ex) { + if (ex instanceof InvocationTargetException) { + ex = ((InvocationTargetException) ex).getTargetException(); + } + if (ex instanceof InterruptedException) { + throw (InterruptedException)ex; + } + res = ex.getClass().getName() + ":" + ex.getMessage(); + } + } else { + res = "Can't find method " + method + " in " + clazz; + } + return res; + } + + @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');") + private static native Object toJSON(String s); + + @JavaScriptBody(args = {"p", "d"}, body = + "var v = d[p];\n" + + "if (typeof v === 'undefined') return null;\n" + + "return v.toString();" + ) + private static native String value(String p, Object d); + } +} diff -r d127d41768bd -r ae3f2aa50970 launcher/http/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/http/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,43 @@ + + + + + + Bck2Brwsr Harness + + + + + +

Bck2Brwsr Execution Harness

+ +
    +
+ +
+ + + + diff -r d127d41768bd -r ae3f2aa50970 launcher/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,22 @@ + + + 4.0.0 + + bck2brwsr + org.apidesign + 0.8-SNAPSHOT + + org.apidesign.bck2brwsr + launcher-pom + 0.8-SNAPSHOT + pom + Launchers + + 2.3.2 + + + api + http + fx + + \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 pom.xml --- a/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -3,7 +3,7 @@ 4.0.0 org.apidesign bck2brwsr - 0.4-SNAPSHOT + 0.8-SNAPSHOT pom Back 2 Browser @@ -11,11 +11,17 @@ jvnet-parent 3 + + UTF-8 + RELEASE73 + COPYING + dew javaquery benchmarks ide + launcher rt @@ -33,6 +39,7 @@ scm:hg:http://source.apidesign.org/hg/bck2brwsr scm:hg:https://source.apidesign.org/hg/bck2brwsr http://source.apidesign.org/hg/bck2brwsr + HEAD @@ -78,14 +85,24 @@ * .*/** rt/emul/*/src/main/** - rt/javap/** - rt/mojo/src/main/resources/archetype-resources/** - rt/vmtest/src/test/resources/** + rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java + rt/archetype/src/main/resources/archetype-resources/** + rt/emul/compact/src/test/resources/** dew/src/main/resources/org/apidesign/bck2brwsr/dew/** javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout*.js + + maven-release-plugin + 2.4 + + forked-path + false + -Pjvnet-release -Pgpg + release-${releaseVersion} + + @@ -102,6 +119,15 @@ true + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + + @@ -122,19 +148,113 @@ org.netbeans.api org-netbeans-modules-classfile - RELEASE72 + ${netbeans.version} jar org.netbeans.api org-openide-util-lookup - RELEASE72 + ${netbeans.version} compile jar + + org.netbeans.api + org-netbeans-api-annotations-common + ${netbeans.version} + + + org.netbeans.api + org-netbeans-modules-java-source + ${netbeans.version} + + + org.netbeans.api + org-netbeans-libs-javacapi + ${netbeans.version} + + + org.netbeans.api + org-netbeans-spi-java-hints + ${netbeans.version} + + + org.netbeans.api + org-netbeans-modules-parsing-api + ${netbeans.version} + + + org.netbeans.api + org-netbeans-spi-editor-hints + ${netbeans.version} + + + org.netbeans.api + org-openide-util + ${netbeans.version} + + + org.netbeans.api + org-netbeans-modules-java-lexer + ${netbeans.version} + + + org.netbeans.api + org-netbeans-modules-lexer + ${netbeans.version} + + + org.netbeans.api + org-netbeans-modules-java-hints-test + ${netbeans.version} + + + org.netbeans.api + org-netbeans-libs-junit4 + ${netbeans.version} + + + org.netbeans.modules + org-netbeans-lib-nbjavac + ${netbeans.version} + + + org.netbeans.modules + org-netbeans-modules-web-browser-api + ${netbeans.version} + + + org-netbeans-core + org.netbeans.modules + + + org-netbeans-core-multiview + org.netbeans.api + + + org-netbeans-libs-lucene + org.netbeans.api + + + org-netbeans-modules-diff + org.netbeans.api + + + org-netbeans-modules-editor-fold + org.netbeans.api + + + org-netbeans-modules-editor-guards + org.netbeans.api + + + + + org-netbeans-modules-projectapi + org.netbeans.api + jar + ${netbeans.version} + - - COPYING - - \ No newline at end of file + diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,87 @@ + + + 4.0.0 + + rt + org.apidesign.bck2brwsr + 0.8-SNAPSHOT + + org.apidesign.bck2brwsr + bck2brwsr-archetype-html-sample + 0.8-SNAPSHOT + jar + Bck2Brwsr Maven Archetype + + Creates a skeletal HTML page and associated Java controller class. + Runs in any browser (even without Java plugin) with the help of 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 + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + test + + test + + integration-test + + + ${project.build.directory}/bck2brwsr-archetype-html-sample-${project.version}.jar + + false + + + + + + + + + + org.testng + testng + test + + + diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/java/org/apidesign/bck2brwsr/archetype/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/java/org/apidesign/bck2brwsr/archetype/package-info.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,18 @@ +/** + * 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.archetype; diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,55 @@ + + + + + + src/main/java + + **/App.java + + + + src/main/resources + + **/*.xhtml + **/*.html + + + + src/test/java + + **/*Test.java + + + + + + nbactions.xml + + + + + + bck2brwsr-assembly.xml + + + + \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/resources/archetype-resources/bck2brwsr-assembly.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/resources/archetype-resources/bck2brwsr-assembly.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,61 @@ + + + + + bck2brwsr + + zip + + public_html + + + false + runtime + lib + + *:jar + *:rt + + + + false + provided + + *:js + + true + / + + + + + ${project.build.directory}/${project.build.finalName}.jar + / + + + ${project.build.directory}/classes/${package.replace('.','/')}/index.html + / + index.html + + + + \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/resources/archetype-resources/nbactions.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/resources/archetype-resources/nbactions.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,10 @@ + + + + run + + process-classes + bck2brwsr:brwsr + + + diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/resources/archetype-resources/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/resources/archetype-resources/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,135 @@ + + + 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 + + + + + org.apidesign.bck2brwsr + bck2brwsr-maven-plugin + ${project.version} + + + + brwsr + + + + + \${package.replace('.','/')}/index.html + + + + 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/ + + + + + + maven-assembly-plugin + 2.4 + + + distro-assembly + package + + single + + + + bck2brwsr-assembly.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 + + + org.apidesign.bck2brwsr + vmtest + ${project.version} + test + + + diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/resources/archetype-resources/src/main/java/App.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/resources/archetype-resources/src/main/java/App.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,88 @@ +package ${package}; + +import java.util.List; +import org.apidesign.bck2brwsr.htmlpage.api.*; +import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; +import org.apidesign.bck2brwsr.htmlpage.api.Page; +import org.apidesign.bck2brwsr.htmlpage.api.Property; +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; + +/** This is the controller class for associated index.html page. The Index + * is autogenerated by parsing the index.html page. It fields represent individual + * elements annotated by "id" in the page. + */ +@Page(xhtml="index.html", className="Index", properties={ + @Property(name="name", type=String.class), + @Property(name="messages", type=String.class, array=true), +}) +public class App { + static { + Index model = new Index(); + model.setName("World"); + model.applyBindings(); + } + + /** + * @param m the model of the index page creates in static initializer + */ + @On(event = CLICK, id="hello") + static void hello(Index m) { + display(m.getHelloMessage(), m); + m.getMessages().add(m.getHelloMessage()); + } + + /** Reacts when mouse moves over the canvas. + * + * @param m the model of the page + * @param x property "x" extracted from the event generated by the browser + * @param y property "y" from the mouse event + */ + @On(event = MOUSE_MOVE, id="canvas") + static void clearPoint(Index m, int x, int y) { + GraphicsContext g = m.canvas.getContext(); + boolean even = (x + y) % 2 == 0; + if (even) { + g.setFillStyle("blue"); + } else { + g.setFillStyle("red"); + } + g.clearRect(0, 0, 1000, 1000); + g.setFont("italic 40px Calibri"); + g.fillText(m.getHelloMessage(), 10, 40); + } + + /** Callback function called by the KnockOut/Java binding on elements + * representing href's with individual messages being their data. + * + * @param data the data associated with the element + * @param m the model of the page + */ + @OnFunction + static void display(String data, Index m) { + GraphicsContext g = m.canvas.getContext(); + g.clearRect(0, 0, 1000, 1000); + g.setFillStyle("black"); + g.setFont("italic 40px Calibri"); + g.fillText(data, 10, 40); + } + + /** Callback function. + * + * @param data data associated with the actual element on the page + * @param m the model of the page + */ + @OnFunction + static void remove(String data, Index m) { + m.getMessages().remove(data); + } + + @ComputedProperty + static String helloMessage(String name) { + return "Hello " + name + "!"; + } + + @ComputedProperty + static boolean noMessages(List messages) { + return messages.isEmpty(); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/resources/archetype-resources/src/main/resources/index.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/resources/archetype-resources/src/main/resources/index.html Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,31 @@ + + + + + Bck2Brwsr's Hello World + + +

Loading Bck2Brwsr's Hello World...

+ Your name: + +

+ + +

+ + +
No message displayed yet.
+ + + + + + diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/resources/archetype-resources/src/test/java/AppTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/resources/archetype-resources/src/test/java/AppTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,26 @@ +package ${package}; + +import static org.testng.Assert.*; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** Demonstrating POJO testing of HTML page model. Runs in good old HotSpot + * as it does not reference any HTML elements or browser functionality. Just + * operates on the page model. + * + * @author Jaroslav Tulach + */ +public class AppTest { + private Index model; + + + @BeforeMethod + public void initModel() { + model = new Index().applyBindings(); + } + + @Test public void testHelloMessage() { + model.setName("Joe"); + assertEquals(model.getHelloMessage(), "Hello Joe!", "Cleared after pressing +"); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,40 @@ +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. + * + * @author Jaroslav Tulach + */ +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 d127d41768bd -r ae3f2aa50970 rt/archetype/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,46 @@ +package ${package}; + +import org.apidesign.bck2brwsr.htmlpage.api.OnEvent; +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. + * + * @author Jaroslav Tulach + */ +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( + "

Loading Bck2Brwsr's Hello World...

\n" + + "Your name: \n" + + "\n" + + "

\n" + + " \n" + + "

\n" + ) + @BrwsrTest + public void modifyValueAssertChangeInModel() { + Index m = new Index(); + m.setName("Joe Hacker"); + m.applyBindings(); + assert "Joe Hacker".equals(m.input.getValue()) : "Value is really Joe Hacker: " + m.input.getValue(); + m.input.setValue("Happy Joe"); + m.triggerEvent(m.input, OnEvent.CHANGE); + assert "Happy Joe".equals(m.getName()) : "Name property updated to Happy Joe: " + m.getName(); + } + + @Factory + public static Object[] create() { + return VMTest.create(IntegrationTest.class); + } + +} diff -r d127d41768bd -r ae3f2aa50970 rt/archetype/src/test/java/org/apidesign/bck2brwsr/archetype/ArchetypeVersionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/archetype/src/test/java/org/apidesign/bck2brwsr/archetype/ArchetypeVersionTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,101 @@ +/** + * 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.archetype; + +import java.net.URL; +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathFactory; +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; + +/** + * + * @author Jaroslav Tulach + */ +public class ArchetypeVersionTest { + private String version; + + public ArchetypeVersionTest() { + } + + @BeforeClass public void readCurrentVersion() throws Exception { + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); + URL u = l.getResource("META-INF/maven/org.apidesign.bck2brwsr/bck2brwsr-archetype-html-sample/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()); + version = xp.evaluate(dom); + + 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( + "//version[../groupId/text() = 'org.apidesign.bck2brwsr']/text()" + ); + + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream()); + NodeList arch = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET); + + if (arch.getLength() < 3) { + fail("There should be at least three dependencies to bck2brwsr APIs: " + arch.getLength()); + } + + for (int i = 0; i < arch.getLength(); i++) { + assertEquals(arch.item(i).getTextContent(), version, i + "th dependency needs to be on latest version of bck2brwsr"); + } + } + + @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("bck2brwsr")) { + assertFalse(s.matches(".*bck2brwsr.*[0-9].*"), "No numbers: " + s); + } + } + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/core/pom.xml --- a/rt/core/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/core/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,11 +4,11 @@ org.apidesign.bck2brwsr rt - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr core - 0.4-SNAPSHOT + 0.8-SNAPSHOT Bck2Brwsr Native Annotations http://maven.apache.org diff -r d127d41768bd -r ae3f2aa50970 rt/emul/brwsrtest/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/brwsrtest/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,52 @@ + + + 4.0.0 + + org.apidesign.bck2brwsr + emul.pom + 0.8-SNAPSHOT + + org.apidesign.bck2brwsr + brwsrtest + 0.8-SNAPSHOT + Tests Inside Real Browser + http://maven.apache.org + + UTF-8 + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.7 + + true + + + + org.apache.maven.plugins + maven-surefire-plugin + + + brwsr + + + + + + + + ${project.groupId} + vmtest + ${project.version} + test + + + ${project.groupId} + launcher.http + ${project.version} + provided + + + diff -r d127d41768bd -r ae3f2aa50970 rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/BooleanTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/BooleanTest.java Fri May 17 10:27:41 2013 +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.bck2brwsr.brwsrtest; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class BooleanTest { + @JavaScriptBody(args = { "tr" }, body = "return tr ? true : false;") + private static native Object trueFalse(boolean tr); + + @BrwsrTest public void isTrueInstanceOfBoolean() { + Object t = trueFalse(true); + assert t instanceof Boolean : "Should be boolean: " + t; + assert ((boolean)t) : "and is true"; + } + + @BrwsrTest public void isFalseInstanceOfBoolean() { + Object t = trueFalse(false); + assert t instanceof Boolean : "Should be boolean: " + t; + assert !((boolean)t) : "and is false: " + t; + } + + @Factory public static Object[] create() { + return VMTest.create(BooleanTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/DoubleBitsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/DoubleBitsTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,42 @@ +/** + * 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.brwsrtest; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class DoubleBitsTest { + + @Compare public String doubleToBits() { + long val = Double.doubleToLongBits(333.456); + return Long.toString(val); + } + + @Compare public int floatToBits() { + return Float.floatToIntBits(333.456f); + } + + @Factory public static Object[] create() { + return VMTest.create(DoubleBitsTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/pom.xml --- a/rt/emul/compact/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/compact/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,11 +4,11 @@ org.apidesign.bck2brwsr emul.pom - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr emul - 0.4-SNAPSHOT + 0.8-SNAPSHOT Bck2Brwsr API Profile http://maven.apache.org @@ -28,6 +28,18 @@ test + ${project.groupId} + launcher.http + ${project.version} + test + + + com.oracle + javafx + + + + org.netbeans.api org-openide-util-lookup test @@ -47,6 +59,15 @@ 1.7 + + org.apache.maven.plugins + maven-javadoc-plugin + + org.apidesign.bck2brwsr.emul.* + false + true + + maven-assembly-plugin 2.4 diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipCompatibilityTest.java --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipCompatibilityTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipCompatibilityTest.java Fri May 17 10:27:41 2013 +0200 @@ -30,7 +30,7 @@ public class ZipCompatibilityTest { @Compare public String testDemoStaticCalculator() throws IOException { - InputStream is = getClass().getResourceAsStream("demo.static.calculator-0.3-SNAPSHOT.jar"); + InputStream is = getClass().getResourceAsStream("demo.static.calculator-TEST.jar"); ZipArchive zip = ZipArchive.createZip(is); final String ts = zip.toString(); return ts.substring(0, 4096) + ts.hashCode(); diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipVsJzLibTest.java --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipVsJzLibTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ZipVsJzLibTest.java Fri May 17 10:27:41 2013 +0200 @@ -27,10 +27,10 @@ */ public class ZipVsJzLibTest { @Test public void r() throws IOException { - InputStream is = getClass().getResourceAsStream("demo.static.calculator-0.3-SNAPSHOT.jar"); + InputStream is = getClass().getResourceAsStream("demo.static.calculator-TEST.jar"); ZipArchive zip = ZipArchive.createZip(is); - is = getClass().getResourceAsStream("demo.static.calculator-0.3-SNAPSHOT.jar"); + is = getClass().getResourceAsStream("demo.static.calculator-TEST.jar"); ZipArchive real = ZipArchive.createReal(is); real.assertEquals(zip, "Are they the same?"); diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/AssertionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/AssertionTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,43 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class AssertionTest { + + @Compare public Object checkAssert() throws ClassNotFoundException { + try { + assert false : "Is assertion status on?"; + return null; + } catch (AssertionError ex) { + return ex.getClass().getName(); + } + } + + @Factory + public static Object[] create() { + return VMTest.create(AssertionTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,57 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; +import org.apidesign.bck2brwsr.vmtest.HtmlFragment; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class BrwsrCheckTest { + + @BrwsrTest public void assertWindowObjectIsDefined() { + assert window() != null : "No window object found!"; + } + + + + + @HtmlFragment("

\n" + + "Hello!\n" + + "

\n") + @BrwsrTest public void accessProvidedFragment() { + assert getElementById("hello") != null : "Element with 'hello' ID found"; + } + + @Factory + public static Object[] create() { + return VMTest.create(BrwsrCheckTest.class); + } + + + @JavaScriptBody(args = {}, body = "return window;") + private static native Object window(); + + @JavaScriptBody(args = { "id" }, body = "return window.document.getElementById(id);") + private static native Object getElementById(String id); +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ByteArithmeticTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ByteArithmeticTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,147 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class ByteArithmeticTest { + + private static byte add(byte x, byte y) { + return (byte)(x + y); + } + + private static byte sub(byte x, byte y) { + return (byte)(x - y); + } + + private static byte mul(byte x, byte y) { + return (byte)(x * y); + } + + private static byte div(byte x, byte y) { + return (byte)(x / y); + } + + private static byte mod(byte x, byte y) { + return (byte)(x % y); + } + + @Compare public byte conversion() { + return (byte)123456; + } + + @Compare public byte addOverflow() { + return add(Byte.MAX_VALUE, (byte)1); + } + + @Compare public byte subUnderflow() { + return sub(Byte.MIN_VALUE, (byte)1); + } + + @Compare public byte addMaxByteAndMaxByte() { + return add(Byte.MAX_VALUE, Byte.MAX_VALUE); + } + + @Compare public byte subMinByteAndMinByte() { + return sub(Byte.MIN_VALUE, Byte.MIN_VALUE); + } + + @Compare public byte multiplyMaxByte() { + return mul(Byte.MAX_VALUE, (byte)2); + } + + @Compare public byte multiplyMaxByteAndMaxByte() { + return mul(Byte.MAX_VALUE, Byte.MAX_VALUE); + } + + @Compare public byte multiplyMinByte() { + return mul(Byte.MIN_VALUE, (byte)2); + } + + @Compare public byte multiplyMinByteAndMinByte() { + return mul(Byte.MIN_VALUE, Byte.MIN_VALUE); + } + + @Compare public byte multiplyPrecision() { + return mul((byte)17638, (byte)1103); + } + + @Compare public byte division() { + return div((byte)1, (byte)2); + } + + @Compare public byte divisionReminder() { + return mod((byte)1, (byte)2); + } + + private static int readShort(byte[] byteCodes, int offset) { + int signed = byteCodes[offset]; + byte b0 = (byte)signed; + return (b0 << 8) | (byteCodes[offset + 1] & 0xff); + } + + private static int readShortArg(byte[] byteCodes, int offsetInstruction) { + return readShort(byteCodes, offsetInstruction + 1); + } + + @Compare public int readIntArgs255and156() { + final byte[] arr = new byte[] { (byte)0, (byte)255, (byte)156 }; + + assert arr[1] == -1 : "First byte: " + arr[1]; + assert arr[2] == -100 : "Second byte: " + arr[2]; + final int ret = readShortArg(arr, 0); + assert ret < 65000: "Value: " + ret; + return ret; + } + + @JavaScriptBody(args = { "arr" }, body = "arr[1] = 255; arr[2] = 156; return arr;") + private static byte[] fill255and156(byte[] arr) { + arr[1] = (byte)255; + arr[2] = (byte)156; + return arr; + } + + @Compare public int readIntArgs255and156JSArray() { + final byte[] arr = fill255and156(new byte[] { 0, 0, 0 }); + + final int ret = readShortArg(arr, 0); + assert ret < 65000: "Value: " + ret; + return ret; + } + + @Compare public int readIntArgsMinus1andMinus100() { + final byte[] arr = new byte[] { (byte)0, (byte)-1, (byte)-100 }; + + assert arr[1] == -1 : "First byte: " + arr[1]; + assert arr[2] == -100 : "Second byte: " + arr[2]; + + return readShortArg(arr, 0); + } + + @Factory + public static Object[] create() { + return VMTest.create(ByteArithmeticTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CloneTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CloneTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,73 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class CloneTest { + private int value; + + @Compare + public Object notSupported() throws CloneNotSupportedException { + return this.clone(); + } + + @Compare public String sameClass() throws CloneNotSupportedException { + return new Clnbl().clone().getClass().getName(); + } + + @Compare public boolean differentInstance() throws CloneNotSupportedException { + Clnbl orig = new Clnbl(); + return orig == orig.clone(); + } + + @Compare public int sameReference() throws CloneNotSupportedException { + CloneTest self = this; + Clnbl orig = new Clnbl(); + self.value = 33; + orig.ref = self; + return ((Clnbl)orig.clone()).ref.value; + } + + @Compare public int sameValue() throws CloneNotSupportedException { + Clnbl orig = new Clnbl(); + orig.value = 10; + return ((Clnbl)orig.clone()).value; + } + + @Factory + public static Object[] create() { + return VMTest.create(CloneTest.class); + } + + public static final class Clnbl implements Cloneable { + public CloneTest ref; + private int value; + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareByteArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareByteArrayTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,103 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class CompareByteArrayTest { + @Compare public int byteArraySum() { + byte[] arr = createArray(); + return sumByteArr(arr); + } + + @Compare public int countZeros() { + int zeros = 0; + for (Byte b : createArray()) { + if (b == 0) { + zeros++; + } + } + return zeros; + } + + private static int sumByteArr(byte[] arr) { + int sum = 0; + for (int i = 0; i < arr.length; i++) { + sum += arr[i]; + } + return sum; + } + + @Compare public String noOutOfBounds() { + return atIndex(1); + } + + @Compare public String outOfBounds() { + return atIndex(5); + } + + @Compare public String outOfBoundsMinus() { + return atIndex(-1); + } + + @Compare public String toOfBounds() { + return toIndex(5); + } + + @Compare public String toOfBoundsMinus() { + return toIndex(-1); + } + + @Compare public int multiArrayLength() { + int[][] arr = new int[1][0]; + return arr[0].length; + } + + @Compare public int multiObjectArrayLength() { + Object[][] arr = new Object[1][0]; + return arr[0].length; + } + + private static final int[] arr = { 0, 1, 2 }; + public static String atIndex(int at) { + return "at@" + arr[at]; + } + public static String toIndex(int at) { + arr[at] = 10; + return "ok"; + } + + + @Factory + public static Object[] create() { + return VMTest.create(CompareByteArrayTest.class); + } + + private byte[] createArray() { + byte[] arr = new byte[10]; + arr[5] = 3; + arr[7] = 8; + return arr; + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,50 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class CompareHashTest { + @Compare public int hashOfString() { + return "Ahoj".hashCode(); + } + + @Compare public int hashRemainsYieldsZero() { + Object o = new Object(); + return o.hashCode() - o.hashCode(); + } + + @Compare public int initializeInStatic() { + return StaticUse.NON_NULL.hashCode() - StaticUse.NON_NULL.hashCode(); + } + + @Compare public int hashOfInt() { + return Integer.valueOf(Integer.MAX_VALUE).hashCode(); + } + + @Factory + public static Object[] create() { + return VMTest.create(CompareHashTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareIntArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareIntArrayTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,63 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class CompareIntArrayTest { + @Compare public int integerArraySum() { + int[] arr = createArray(); + return sumIntArr(arr); + } + + @Compare public int countZeros() { + int zeros = 0; + for (Integer i : createArray()) { + if (i == 0) { + zeros++; + } + } + return zeros; + } + + private static int sumIntArr(int[] arr) { + int sum = 0; + for (int i = 0; i < arr.length; i++) { + sum += arr[i]; + } + return sum; + } + + @Factory + public static Object[] create() { + return VMTest.create(CompareIntArrayTest.class); + } + + private int[] createArray() { + int[] arr = new int[10]; + arr[5] = 3; + arr[7] = 8; + return arr; + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,174 @@ +/** + * 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.tck; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class CompareStringsTest { + @Compare public String firstChar() { + return "" + ("Hello".toCharArray()[0]); + } + + @Compare public String classCast() { + Object o = firstChar(); + return String.class.cast(o); + } + + @Compare public String classCastThrown() { + Object o = null; + return String.class.cast(o); + } + + @Compare public boolean equalToNull() { + return "Ahoj".equals(null); + } + + @Compare public int highByteLenght() { + byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 }; + return new String(arr, 0).length(); + } + + @Compare public String highByte() { + byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 }; + StringBuilder sb = new StringBuilder(); + sb.append("pref:"); + sb.append(new String(arr, 0)); + return sb.toString(); + } + + @Compare public static Object compareURLs() throws MalformedURLException { + return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString(); + } + + @Compare public String deleteLastTwoCharacters() { + StringBuilder sb = new StringBuilder(); + sb.append("453.0"); + if (sb.toString().endsWith(".0")) { + final int l = sb.length(); + sb.delete(l - 2, l); + } + return sb.toString().toString(); + } + + @Compare public String nameOfStringClass() throws Exception { + return Class.forName("java.lang.String").getName(); + } + @Compare public String nameOfArrayClass() throws Exception { + return Class.forName("org.apidesign.bck2brwsr.tck.CompareHashTest").getName(); + } + + @Compare public String lowerHello() { + return "HeLlO".toLowerCase(); + } + + @Compare public String lowerA() { + return String.valueOf(Character.toLowerCase('A')).toString(); + } + @Compare public String upperHello() { + return "hello".toUpperCase(); + } + + @Compare public String upperA() { + return String.valueOf(Character.toUpperCase('a')).toString(); + } + + @Compare public boolean matchRegExp() throws Exception { + return "58038503".matches("\\d*"); + } + + @Compare public boolean doesNotMatchRegExp() throws Exception { + return "58038503GH".matches("\\d*"); + } + + @Compare public boolean doesNotMatchRegExpFully() throws Exception { + return "Hello".matches("Hell"); + } + + @Compare public String emptyCharArray() { + char[] arr = new char[10]; + return new String(arr); + } + + @Compare public String variousCharacterTests() throws Exception { + StringBuilder sb = new StringBuilder(); + + sb.append(Character.isUpperCase('a')); + sb.append(Character.isUpperCase('A')); + sb.append(Character.isLowerCase('a')); + sb.append(Character.isLowerCase('A')); + + sb.append(Character.isLetter('A')); + sb.append(Character.isLetterOrDigit('9')); + sb.append(Character.isLetterOrDigit('A')); + sb.append(Character.isLetter('0')); + + return sb.toString().toString(); + } + + @Compare + public String nullFieldInitialized() { + NullField nf = new NullField(); + return ("" + nf.name).toString(); + } + @Compare + public String toUTFString() throws UnsupportedEncodingException { + byte[] arr = { + (byte) -59, (byte) -67, (byte) 108, (byte) 117, (byte) -59, (byte) -91, + (byte) 111, (byte) 117, (byte) -60, (byte) -115, (byte) 107, (byte) -61, + (byte) -67, (byte) 32, (byte) 107, (byte) -59, (byte) -81, (byte) -59, + (byte) -120 + }; + return new String(arr, "utf-8"); + } + + @Compare + public int stringToBytesLenght() throws UnsupportedEncodingException { + return "\u017dlu\u0165ou\u010dk\u00fd k\u016f\u0148".getBytes("utf8").length; + } + + @Compare public String replaceSeq() { + return "Hello World.".replace(".", "!"); + } + @Compare public String replaceSeqAll() { + return "Hello World! Hello World.".replace("World", "Jarda"); + } + @Compare public String replaceSeqAA() { + String res = "aaa".replace("aa", "b"); + assert res.equals("ba") : "Expecting ba: " + res; + return res; + } + + @Factory + public static Object[] create() { + return VMTest.create(CompareStringsTest.class); + } + + private static final class NullField { + + String name; + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/DoubleTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/DoubleTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,65 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class DoubleTest { + @Compare public String integerToString() { + return toStr(1); + } + + @Compare public String integerAndHalfToString() { + return toStr(1.5); + } + + @Compare public double longToAndBack() { + return Double.parseDouble(toStr(Long.MAX_VALUE / 10)); + } + + @Compare public String negativeIntToString() { + return toStr(-10); + } + + @Compare public String negativeIntAndHalfToString() { + return toStr(-10.5); + } + + @Compare public double negativeLongAndBack() { + return Double.parseDouble(toStr(Long.MIN_VALUE / 10)); + } + + @Compare public double canParseExp() { + return Double.parseDouble(toStr(1.7976931348623157e+308)); + } + + private static String toStr(double d) { + return Double.toString(d); + } + + @Factory + public static Object[] create() { + return VMTest.create(DoubleTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/HttpResourceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/HttpResourceTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,106 @@ +/** + * 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.tck; + +import java.io.InputStream; +import java.net.URL; +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; +import org.apidesign.bck2brwsr.vmtest.Http; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class HttpResourceTest { + + @Http({ + @Http.Resource(path = "/xhr", content = "Hello Brwsr!", mimeType = "text/plain") + }) + @BrwsrTest + + + public String testReadContentViaXHR() throws Exception { + String msg = read("/xhr"); + assert "Hello Brwsr!".equals(msg) : "The message was " + msg; + return msg; + } + + @Http({ + @Http.Resource(path = "/url", content = "Hello via URL!", mimeType = "text/plain") + }) + @BrwsrTest + public String testReadContentViaURL() throws Exception { + URL url = new URL("http:/url"); + String msg = (String) url.getContent(); + assert "Hello via URL!".equals(msg) : "The message was " + msg; + return msg; + } + @Http({ + @Http.Resource(path = "/url", content = "Hello via URL!", mimeType = "text/plain") + }) + @BrwsrTest + public String testReadContentViaURLWithStringParam() throws Exception { + URL url = new URL("http:/url"); + String msg = (String) url.getContent(new Class[] { String.class }); + assert "Hello via URL!".equals(msg) : "The message was " + msg; + return msg; + } + + @Http({ + @Http.Resource(path = "/bytes", content = "", resource = "0xfe", mimeType = "x-application/binary") + }) + @BrwsrTest + public void testReadByte() throws Exception { + URL url = new URL("http:/bytes"); + final Object res = url.getContent(new Class[] { byte[].class }); + assert res instanceof byte[] : "Expecting byte[]: " + res; + byte[] arr = (byte[]) res; + assert arr.length == 1 : "One byte " + arr.length; + assert arr[0] == 0xfe : "It is 0xfe: " + Integer.toHexString(arr[0]); + } + + @Http({ + @Http.Resource(path = "/bytes", content = "", resource = "0xfe", mimeType = "x-application/binary") + }) + @BrwsrTest + public void testReadByteViaInputStream() throws Exception { + URL url = new URL("http:/bytes"); + InputStream is = url.openStream(); + byte[] arr = new byte[10]; + int len = is.read(arr); + assert len == 1 : "One byte " + len; + assert arr[0] == 0xfe : "It is 0xfe: " + Integer.toHexString(arr[0]); + } + + @JavaScriptBody(args = { "url" }, body = + "var req = new XMLHttpRequest();\n" + + "req.open('GET', url, false);\n" + + "req.send();\n" + + "return req.responseText;" + ) + private static native String read(String url); + + + @Factory + public static Object[] create() { + return VMTest.create(HttpResourceTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceA.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceA.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,34 @@ +/** + * 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.tck; + +/** + * + * @author Jaroslav Tulach + */ +public class InheritanceA { + private String name; + + public void setA(String n) { + this.name = n; + } + + public String getA() { + return name; + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceB.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceB.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,34 @@ +/** + * 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.tck; + +/** + * + * @author Jaroslav Tulach + */ +public class InheritanceB extends InheritanceA { + private String name; + + public void setB(String n) { + this.name = n; + } + + public String getB() { + return name; + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,41 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class InheritanceTest { + + @Compare public String checkFieldsIndependent() throws ClassNotFoundException { + InheritanceB ib = new InheritanceB(); + ib.setA("A"); + ib.setB("B"); + return "A: " + ib.getA() + " B: " + ib.getB(); + } + + @Factory + public static Object[] create() { + return VMTest.create(InheritanceTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,166 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class IntegerArithmeticTest { + + private static int add(int x, int y) { + return x + y; + } + + private static int sub(int x, int y) { + return x - y; + } + + private static int mul(int x, int y) { + return x * y; + } + + private static int div(int x, int y) { + return x / y; + } + + private static int mod(int x, int y) { + return x % y; + } + + private static int neg(int x) { + return (-x); + } + + private static float fadd(float x, float y) { + return x + y; + } + + private static double dadd(double x, double y) { + return x + y; + } + + @Compare public int addOverflow() { + return add(Integer.MAX_VALUE, 1); + } + + @Compare public int subUnderflow() { + return sub(Integer.MIN_VALUE, 1); + } + + @Compare public int addMaxIntAndMaxInt() { + return add(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + @Compare public int subMinIntAndMinInt() { + return sub(Integer.MIN_VALUE, Integer.MIN_VALUE); + } + + @Compare public int multiplyMaxInt() { + return mul(Integer.MAX_VALUE, 2); + } + + @Compare public int multiplyMaxIntAndMaxInt() { + return mul(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + @Compare public int multiplyMinInt() { + return mul(Integer.MIN_VALUE, 2); + } + + @Compare public int multiplyMinIntAndMinInt() { + return mul(Integer.MIN_VALUE, Integer.MIN_VALUE); + } + + @Compare public int multiplyPrecision() { + return mul(119106029, 1103515245); + } + + @Compare public int division() { + return div(1, 2); + } + + @Compare public int divisionReminder() { + return mod(1, 2); + } + + @Compare public int negativeDivision() { + return div(-7, 3); + } + + @Compare public int negativeDivisionReminder() { + return mod(-7, 3); + } + + @Compare public int conversionFromFloat() { + return (int) fadd(-2, -0.6f); + } + + @Compare public int conversionFromDouble() { + return (int) dadd(-2, -0.6); + } + + @Compare public boolean divByZeroThrowsArithmeticException() { + try { + div(1, 0); + return false; + } catch (final ArithmeticException e) { + return true; + } + } + + @Compare public boolean modByZeroThrowsArithmeticException() { + try { + mod(1, 0); + return false; + } catch (final ArithmeticException e) { + return true; + } + } + + @Compare public int negate() { + return neg(123456); + } + + @Compare public int negateMaxInt() { + return neg(Integer.MAX_VALUE); + } + + @Compare public int negateMinInt() { + return neg(Integer.MIN_VALUE); + } + + @Compare public int sumTwoDimensions() { + int[][] matrix = createMatrix(4, 3); + matrix[0][0] += 10; + return matrix[0][0]; + } + + static int[][] createMatrix(int x, int y) { + return new int[x][y]; + } + + @Factory + public static Object[] create() { + return VMTest.create(IntegerArithmeticTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,376 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class LongArithmeticTest { + + private static long add(long x, long y) { + return (x + y); + } + + private static long sub(long x, long y) { + return (x - y); + } + + private static long mul(long x, long y) { + return (x * y); + } + + private static long div(long x, long y) { + return (x / y); + } + + private static long mod(long x, long y) { + return (x % y); + } + + private static long neg(long x) { + return (-x); + } + + private static long shl(long x, int b) { + return (x << b); + } + + private static long shr(long x, int b) { + return (x >> b); + } + + private static long ushr(long x, int b) { + return (x >>> b); + } + + private static long and(long x, long y) { + return (x & y); + } + + private static long or(long x, long y) { + return (x | y); + } + + private static long xor(long x, long y) { + return (x ^ y); + } + + private static float fadd(float x, float y) { + return x + y; + } + + private static double dadd(double x, double y) { + return x + y; + } + + public static int compare(long x, long y, int zero) { + final int xyResult = compareL(x, y, zero); + final int yxResult = compareL(y, x, zero); + + return ((xyResult + yxResult) == 0) ? xyResult : -2; + } + + private static int compareL(long x, long y, int zero) { + int result = -2; + int trueCount = 0; + + x += zero; + if (x == y) { + result = 0; + ++trueCount; + } + + x += zero; + if (x < y) { + result = -1; + ++trueCount; + } + + x += zero; + if (x > y) { + result = 1; + ++trueCount; + } + + return (trueCount == 1) ? result : -2; + } + + @Compare public long conversion() { + return Long.MAX_VALUE; + } + + @Compare public long negate1() { + return neg(0x00fa37d7763e0ca1l); + } + + @Compare public long negate2() { + return neg(0x80fa37d7763e0ca1l); + } + + @Compare public long negate3() { + return neg(0xfffffffffffffeddl); + } + + @Compare public long addOverflow() { + return add(Long.MAX_VALUE, 1l); + } + + @Compare public long subUnderflow() { + return sub(Long.MIN_VALUE, 1l); + } + + @Compare public long addMaxLongAndMaxLong() { + return add(Long.MAX_VALUE, Long.MAX_VALUE); + } + + @Compare public long subMinLongAndMinLong() { + return sub(Long.MIN_VALUE, Long.MIN_VALUE); + } + + @Compare public long subMinLongAndMaxLong() { + return sub(Long.MIN_VALUE, Long.MAX_VALUE); + } + + @Compare public long multiplyMaxLong() { + return mul(Long.MAX_VALUE, 2l); + } + + @Compare public long multiplyMaxLongAndMaxLong() { + return mul(Long.MAX_VALUE, Long.MAX_VALUE); + } + + @Compare public long multiplyMinLong() { + return mul(Long.MIN_VALUE, 2l); + } + + @Compare public long multiplyMinLongAndMinLong() { + return mul(Long.MIN_VALUE, Long.MIN_VALUE); + } + + @Compare public long multiplyPrecision() { + return mul(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); + } + + @Compare public long divideSmallPositiveNumbers() { + return div(0xabcdef, 0x123); + } + + @Compare public long divideSmallNegativeNumbers() { + return div(-0xabcdef, -0x123); + } + + @Compare public long divideSmallMixedNumbers() { + return div(0xabcdef, -0x123); + } + + @Compare public long dividePositiveNumbersOneDigitDenom() { + return div(0xabcdef0102ffffl, 0x654); + } + + @Compare public long divideNegativeNumbersOneDigitDenom() { + return div(-0xabcdef0102ffffl, -0x654); + } + + @Compare public long divideMixedNumbersOneDigitDenom() { + return div(-0xabcdef0102ffffl, 0x654); + } + + @Compare public long dividePositiveNumbersMultiDigitDenom() { + return div(0x7ffefc003322aabbl, 0x89ab1000l); + } + + @Compare public long divideNegativeNumbersMultiDigitDenom() { + return div(-0x7ffefc003322aabbl, -0x123489ab1001l); + } + + @Compare public long divideMixedNumbersMultiDigitDenom() { + return div(0x7ffefc003322aabbl, -0x38f49b0b7574e36l); + } + + @Compare public long divideWithOverflow() { + return div(0x8000fffe0000l, 0x8000ffffl); + } + + @Compare public long divideWithCorrection() { + return div(0x7fff800000000000l, 0x800000000001l); + } + + @Compare public long moduloSmallPositiveNumbers() { + return mod(0xabcdef, 0x123); + } + + @Compare public long moduloSmallNegativeNumbers() { + return mod(-0xabcdef, -0x123); + } + + @Compare public long moduloSmallMixedNumbers() { + return mod(0xabcdef, -0x123); + } + + @Compare public long moduloPositiveNumbersOneDigitDenom() { + return mod(0xabcdef0102ffffl, 0x654); + } + + @Compare public long moduloNegativeNumbersOneDigitDenom() { + return mod(-0xabcdef0102ffffl, -0x654); + } + + @Compare public long moduloMixedNumbersOneDigitDenom() { + return mod(-0xabcdef0102ffffl, 0x654); + } + + @Compare public long moduloPositiveNumbersMultiDigitDenom() { + return mod(0x7ffefc003322aabbl, 0x89ab1000l); + } + + @Compare public long moduloNegativeNumbersMultiDigitDenom() { + return mod(-0x7ffefc003322aabbl, -0x123489ab1001l); + } + + @Compare public long moduloMixedNumbersMultiDigitDenom() { + return mod(0x7ffefc003322aabbl, -0x38f49b0b7574e36l); + } + + @Compare public long moduloWithOverflow() { + return mod(0x8000fffe0000l, 0x8000ffffl); + } + + @Compare public long moduloWithCorrection() { + return mod(0x7fff800000000000l, 0x800000000001l); + } + + @Compare public long conversionFromFloatPositive() { + return (long) fadd(2, 0.6f); + } + + @Compare public long conversionFromFloatNegative() { + return (long) fadd(-2, -0.6f); + } + + @Compare public long conversionFromDoublePositive() { + return (long) dadd(0x20ffff0000L, 0.6); + } + + @Compare public long conversionFromDoubleNegative() { + return (long) dadd(-0x20ffff0000L, -0.6); + } + + @Compare public boolean divByZeroThrowsArithmeticException() { + try { + div(1, 0); + return false; + } catch (final ArithmeticException e) { + return true; + } + } + + @Compare public boolean modByZeroThrowsArithmeticException() { + try { + mod(1, 0); + return false; + } catch (final ArithmeticException e) { + return true; + } + } + + @Compare public long shiftL1() { + return shl(0x00fa37d7763e0ca1l, 5); + } + + @Compare public long shiftL2() { + return shl(0x00fa37d7763e0ca1l, 32); + } + + @Compare public long shiftL3() { + return shl(0x00fa37d7763e0ca1l, 45); + } + + @Compare public long shiftR1() { + return shr(0x00fa37d7763e0ca1l, 5); + } + + @Compare public long shiftR2() { + return shr(0x00fa37d7763e0ca1l, 32); + } + + @Compare public long shiftR3() { + return shr(0x00fa37d7763e0ca1l, 45); + } + + @Compare public long uShiftR1() { + return ushr(0x00fa37d7763e0ca1l, 5); + } + + @Compare public long uShiftR2() { + return ushr(0x00fa37d7763e0ca1l, 45); + } + + @Compare public long uShiftR3() { + return ushr(0xf0fa37d7763e0ca1l, 5); + } + + @Compare public long uShiftR4() { + return ushr(0xf0fa37d7763e0ca1l, 45); + } + + @Compare public long and1() { + return and(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); + } + + @Compare public long or1() { + return or(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); + } + + @Compare public long xor1() { + return xor(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); + } + + @Compare public long xor2() { + return xor(0x00fa37d7763e0ca1l, 0x00000000ff00123el); + } + + @Compare public long xor3() { + return xor(0x00000000763e0ca1l, 0x00000000ff00123el); + } + + @Compare public int compareSameNumbers() { + return compare(0x0000000000000000l, 0x0000000000000000l, 0); + } + + @Compare public int comparePositiveNumbers() { + return compare(0x0000000000200000l, 0x0000000010000000l, 0); + } + + @Compare public int compareNegativeNumbers() { + return compare(0xffffffffffffffffl, 0xffffffff00000000l, 0); + } + + @Compare public int compareMixedNumbers() { + return compare(0x8000000000000000l, 0x7fffffffffffffffl, 0); + } + + @Factory + public static Object[] create() { + return VMTest.create(LongArithmeticTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,161 @@ +/** + * 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.tck; + +import java.lang.reflect.Array; +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class ReflectionArrayTest { + @Compare public int lengthOfStringArray() { + String[] arr = (String[]) Array.newInstance(String.class, 10); + return arr.length; + } + + @Compare public int reflectiveLengthOfStringArray() { + Object arr = Array.newInstance(String.class, 10); + return Array.getLength(arr); + } + + @Compare public int reflectiveLengthOneNonArray() { + Object arr = "non-array"; + return Array.getLength(arr); + } + + @Compare public String compTypeOfStringArray() { + String[] arr = (String[]) Array.newInstance(String.class, 10); + return arr.getClass().getComponentType().getName(); + } + + @Compare public Object negativeArrayExcp() { + return Array.newInstance(String.class, -5); + } + + @Compare public int lengthOfIntArray() { + int[] arr = (int[]) Array.newInstance(Integer.TYPE, 10); + return arr.length; + } + + @Compare public int reflectiveLengthOfIntArray() { + Object arr = Array.newInstance(Integer.TYPE, 10); + return Array.getLength(arr); + } + + @Compare public String compTypeOfIntArray() { + int[] arr = (int[]) Array.newInstance(int.class, 10); + return arr.getClass().getComponentType().getName(); + } + + @Compare public Object intNegativeArrayExcp() { + return Array.newInstance(int.class, -5); + } + + @Compare public Integer verifyAutobox() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + return (Integer) Array.get(arr, 0); + } + @Compare public String verifyObjectArray() { + String[] arr = (String[]) Array.newInstance(String.class, 5); + Array.set(arr, 0, "Hello"); + return (String) Array.get(arr, 0); + } + @Compare public int verifyInt() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + return Array.getInt(arr, 0); + } + @Compare public long verifyConvertToLong() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + return Array.getLong(arr, 0); + } + + @Compare public Object verifySetIntToObject() { + try { + Object[] arr = (Object[]) Array.newInstance(Object.class, 5); + Array.setInt(arr, 0, 10); + return Array.get(arr, 0); + } catch (Exception exception) { + return exception.getClass().getName(); + } + } + @Compare public long verifySetShort() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + Array.setShort(arr, 0, (short)10); + return Array.getLong(arr, 0); + } + @Compare public long verifyCantSetLong() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + Array.setLong(arr, 0, 10); + return Array.getLong(arr, 0); + } + @Compare public float verifyLongToFloat() { + Object arr = Array.newInstance(float.class, 5); + Array.setLong(arr, 0, 10); + return Array.getFloat(arr, 0); + } + + @Compare public double verifyConvertToDouble() { + int[] arr = (int[]) Array.newInstance(int.class, 5); + return Array.getDouble(arr, 0); + } + + @Compare public int multiIntArray() { + int[][][] arr = (int[][][]) Array.newInstance(int.class, 3, 3, 3); + return arr[0][1][2] + 5 + arr[2][2][0]; + } + + @Compare public String multiIntArrayCompType() { + return Array.newInstance(int.class, 3, 3, 3).getClass().getName(); + } + + @JavaScriptBody(args = {}, body = "return [1, 2];") + private static native Object crtarr(); + + @JavaScriptBody(args = {}, body = "return new Object();") + private static native Object newobj(); + + @BrwsrTest + public static void toStringArray() { + final Object arr = crtarr(); + final Object real = new Object[2]; + assert arr instanceof Object[] : "Any array is Java array: " + arr; + assert arr.getClass() == real.getClass() : "Same classes " + arr + " and " + real.getClass(); + final String str = arr.toString(); + assert str != null; + assert str.startsWith("[Ljava.lang.Object;@") : str; + } + + @BrwsrTest + public static void objectToString() { + String s = newobj().toString(); + assert s != null : "Some string computed"; + assert s.startsWith("java.lang.Object@") : "Regular object toString(): " + s; + } + + + @Factory + public static Object[] create() { + return VMTest.create(ReflectionArrayTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,272 @@ +/** + * 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.tck; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class ReflectionTest { + @Compare public boolean nonNullThis() { + return this == null; + } + + @Compare public String intType() { + return Integer.TYPE.toString(); + } + + @Compare public String voidType() throws Exception { + return void.class.toString(); + } + + @Compare public String longClass() { + return long.class.toString(); + } + + @Compare public boolean isRunnableInterface() { + return Runnable.class.isInterface(); + } + + @Compare public boolean isAssignableToPrimitiveType() { + return boolean.class.isAssignableFrom(Runnable.class); + } + + @Compare public boolean isAssignableFromPrimitiveType() { + return Runnable.class.isAssignableFrom(boolean.class); + } + + @Compare public boolean isAssignableLongFromInt() { + return long.class.isAssignableFrom(int.class); + } + + @Compare public boolean isAssignableIntFromLong() { + return int.class.isAssignableFrom(long.class); + } + + @Compare public String isRunnableHasRunMethod() throws NoSuchMethodException { + return Runnable.class.getMethod("run").getName(); + } + + @Compare public String namesOfMethods() { + StringBuilder sb = new StringBuilder(); + String[] arr = new String[20]; + int i = 0; + for (Method m : StaticUse.class.getMethods()) { + arr[i++] = m.getName(); + } + for (String s : sort(arr, i)) { + sb.append(s).append("\n"); + } + return sb.toString(); + } + + @Compare public String namesOfDeclaringClassesOfMethods() { + StringBuilder sb = new StringBuilder(); + String[] arr = new String[20]; + int i = 0; + for (Method m : StaticUse.class.getMethods()) { + arr[i++] = m.getName() + "@" + m.getDeclaringClass().getName(); + } + for (String s : sort(arr, i)) { + sb.append(s).append("\n"); + } + return sb.toString(); + } + + @Compare public String cannotCallNonStaticMethodWithNull() throws Exception { + StaticUse.class.getMethod("instanceMethod").invoke(null); + return "should not happen"; + } + + @Compare public String classCastException() { + try { + Integer i = (Integer)StaticUseSub.getNonNull(); + return "" + i.intValue(); + } catch (ClassCastException ex) { + return ex.getClass().getName(); + } + } + + @Compare public String methodThatThrowsException() throws Exception { + StaticUse.class.getMethod("instanceMethod").invoke(new StaticUse()); + return "should not happen"; + } + + @Compare public Object voidReturnType() throws Exception { + return StaticUse.class.getMethod("instanceMethod").getReturnType(); + } + + @Retention(RetentionPolicy.RUNTIME) + @interface Ann { + } + + @Compare public String annoClass() throws Exception { + Retention r = Ann.class.getAnnotation(Retention.class); + assert r != null : "Annotation is present"; + assert r.value() == RetentionPolicy.RUNTIME : "Policy value is OK: " + r.value(); + return r.annotationType().getName(); + } + + @Compare public boolean isAnnotation() { + return Ann.class.isAnnotation(); + } + @Compare public boolean isNotAnnotation() { + return String.class.isAnnotation(); + } + @Compare public boolean isNotAnnotationEnum() { + return E.class.isAnnotation(); + } + enum E { A, B }; + @Compare public boolean isEnum() { + return E.A.getClass().isEnum(); + } + + @Compare public boolean isNotEnum() { + return "".getClass().isEnum(); + } + + @Compare public String newInstanceFails() throws InstantiationException { + try { + return "success: " + StaticUseSub.class.newInstance(); + } catch (IllegalAccessException ex) { + return ex.getClass().getName(); + } + } + + @Compare public String paramTypes() throws Exception { + Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE); + final Class[] pt = plus.getParameterTypes(); + return pt[0].getName(); + } + @Compare public String paramTypesNotFound() throws Exception { + return StaticUse.class.getMethod("plus", int.class, double.class).toString(); + } + @Compare public int methodWithArgs() throws Exception { + Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE); + return (Integer)plus.invoke(null, 2, 3); + } + + @Compare public String classGetNameForByte() { + return byte.class.getName(); + } + @Compare public String classGetNameForBaseObject() { + return newObject().getClass().getName(); + } + @Compare public String classGetNameForJavaObject() { + return new Object().getClass().getName(); + } + @Compare public String classGetNameForObjectArray() { + return (new Object[3]).getClass().getName(); + } + @Compare public String classGetNameForSimpleIntArray() { + return (new int[3]).getClass().getName(); + } + @Compare public boolean sameClassGetNameForSimpleCharArray() { + return (new char[3]).getClass() == (new char[34]).getClass(); + } + @Compare public String classGetNameForMultiIntArray() { + return (new int[3][4][5][6][7][8][9]).getClass().getName(); + } + @Compare public String classGetNameForMultiIntArrayInner() { + final int[][][][][][][] arr = new int[3][4][5][6][7][8][9]; + int[][][][][][] subarr = arr[0]; + int[][][][][] subsubarr = subarr[0]; + return subsubarr.getClass().getName(); + } + @Compare public String classGetNameForMultiStringArray() { + return (new String[3][4][5][6][7][8][9]).getClass().getName(); + } + + @Compare public String classForByte() throws Exception { + return Class.forName("[Z").getName(); + } + + @Compare public String classForUnknownArray() { + try { + return Class.forName("[W").getName(); + } catch (Exception ex) { + return ex.getClass().getName(); + } + } + + @Compare public String classForUnknownDeepArray() { + try { + return Class.forName("[[[[[W").getName(); + } catch (Exception ex) { + return ex.getClass().getName(); + } + } + + @Compare public String componentGetNameForObjectArray() { + return (new Object[3]).getClass().getComponentType().getName(); + } + @Compare public boolean sameComponentGetNameForObjectArray() { + return (new Object[3]).getClass().getComponentType() == Object.class; + } + @Compare public String componentGetNameForSimpleIntArray() { + return (new int[3]).getClass().getComponentType().getName(); + } + @Compare public String componentGetNameForMultiIntArray() { + return (new int[3][4][5][6][7][8][9]).getClass().getComponentType().getName(); + } + @Compare public String componentGetNameForMultiStringArray() { + Class c = (new String[3][4][5][6][7][8][9]).getClass(); + StringBuilder sb = new StringBuilder(); + for (;;) { + sb.append(c.getName()).append("\n"); + c = c.getComponentType(); + if (c == null) { + break; + } + } + return sb.toString(); + } + + @Compare public boolean isArray() { + return new Object[0].getClass().isArray(); + } + + @JavaScriptBody(args = { "arr", "len" }, body="var a = arr.slice(0, len); a.sort(); return a;") + private static String[] sort(String[] arr, int len) { + List list = Arrays.asList(arr).subList(0, len); + Collections.sort(list); + return list.toArray(new String[0]); + } + + @JavaScriptBody(args = {}, body = "return new Object();") + private static Object newObject() { + return new Object(); + } + + @Factory + public static Object[] create() { + return VMTest.create(ReflectionTest.class); + } + +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,45 @@ +/** + * 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.tck; + +import java.io.InputStream; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class ResourcesTest { + + @Compare public String readResourceAsStream() throws Exception { + InputStream is = getClass().getResourceAsStream("Resources.txt"); + byte[] b = new byte[30]; + int len = is.read(b); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i++) { + sb.append((char)b[i]); + } + return sb.toString(); + } + + @Factory public static Object[] create() { + return VMTest.create(ResourcesTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ShortArithmeticTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ShortArithmeticTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,102 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class ShortArithmeticTest { + + private static short add(short x, short y) { + return (short)(x + y); + } + + private static short sub(short x, short y) { + return (short)(x - y); + } + + private static short mul(short x, short y) { + return (short)(x * y); + } + + private static short div(short x, short y) { + return (short)(x / y); + } + + private static short mod(short x, short y) { + return (short)(x % y); + } + + @Compare public short conversion() { + return (short)123456; + } + + @Compare public short addOverflow() { + return add(Short.MAX_VALUE, (short)1); + } + + @Compare public short subUnderflow() { + return sub(Short.MIN_VALUE, (short)1); + } + + @Compare public short addMaxShortAndMaxShort() { + return add(Short.MAX_VALUE, Short.MAX_VALUE); + } + + @Compare public short subMinShortAndMinShort() { + return sub(Short.MIN_VALUE, Short.MIN_VALUE); + } + + @Compare public short multiplyMaxShort() { + return mul(Short.MAX_VALUE, (short)2); + } + + @Compare public short multiplyMaxShortAndMaxShort() { + return mul(Short.MAX_VALUE, Short.MAX_VALUE); + } + + @Compare public short multiplyMinShort() { + return mul(Short.MIN_VALUE, (short)2); + } + + @Compare public short multiplyMinShortAndMinShort() { + return mul(Short.MIN_VALUE, Short.MIN_VALUE); + } + + @Compare public short multiplyPrecision() { + return mul((short)17638, (short)1103); + } + + @Compare public short division() { + return div((short)1, (short)2); + } + + @Compare public short divisionReminder() { + return mod((short)1, (short)2); + } + + @Factory + public static Object[] create() { + return VMTest.create(ShortArithmeticTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,39 @@ +/** + * 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.tck; + +class StaticUse { + public static final Object NON_NULL = new Object(); + public static int cnt; + static { + if (cnt++ != 0) { + throw new IllegalStateException("Multiple initialization of a "); + } + } + + StaticUse() { + } + + public void instanceMethod() { + throw new IllegalStateException(); + } + + public static int plus(int a, int b) { + return a + b; + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSub.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,30 @@ +/** + * 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.tck; + +public class StaticUseSub extends StaticUse { + private StaticUseSub() { + } + + public static Object getNonNull() { + return NON_NULL; + } + static Object getNull() { + return null; + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSubTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSubTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,45 @@ +/** + * 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.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class StaticUseSubTest { + @Compare public String staticFieldInitializationInSuperClass() throws Exception { + Object ret = StaticUseSub.getNonNull(); + return ret.getClass().getName(); + } + + @Compare public String isNullPointerTheSame() throws Exception { + try { + return StaticUseSub.getNull().getClass().toString(); + } catch (NullPointerException ex) { + return ex.getClass().getName(); + } + } + + @Factory public static Object[] create() { + return VMTest.create(StaticUseSubTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/CRC32Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/CRC32Test.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,41 @@ +/** + * 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.vmtest.impl; + +import java.io.UnsupportedEncodingException; +import java.util.zip.CRC32; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class CRC32Test { + + @Compare public long crc1() throws UnsupportedEncodingException { + CRC32 crc = new CRC32(); + crc.update("Hello World!".getBytes("UTF-8")); + return crc.getValue(); + } + + @Factory public static Object[] create() { + return VMTest.create(CRC32Test.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/CallMeTwiceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/CallMeTwiceTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,43 @@ +/** + * 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.vmtest.impl; + +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class CallMeTwiceTest { + int cnt; + + @BrwsrTest public void callMeTwice() throws InterruptedException { + if (cnt++ == 0) { + throw new InterruptedException(); + } + int prevCnt = cnt; + cnt = 0; + assert prevCnt == 2 : "We need to receive two calls " + prevCnt; + } + + @Factory public static Object[] create() { + return VMTest.create(CallMeTwiceTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipEntryTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipEntryTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,67 @@ +/** + * 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.vmtest.impl; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import org.apidesign.bck2brwsr.emul.zip.FastJar; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * + * @author Jaroslav Tulach + */ +@GenerateZip(name = "five.zip", contents = { + "1.txt", "one", + "2.txt", "duo", + "3.txt", "three", + "4.txt", "four", + "5.txt", "five" +}) +public class ZipEntryTest { + @Test + public void readEntriesEffectively() throws IOException { + InputStream is = ZipEntryTest.class.getResourceAsStream("five.zip"); + byte[] arr = new byte[is.available()]; + int len = is.read(arr); + assertEquals(len, arr.length, "Read fully"); + + FastJar fj = new FastJar(arr); + FastJar.Entry[] entrs = fj.list(); + + assertEquals(5, entrs.length, "Five entries"); + + for (int i = 1; i <= 5; i++) { + FastJar.Entry en = entrs[i - 1]; + assertEquals(en.name, i + ".txt"); +// assertEquals(cis.cnt, 0, "Content of the file should be skipped, not read"); + } + + assertContent("three", fj.getInputStream(entrs[3 - 1]), "read OK"); + assertContent("five", fj.getInputStream(entrs[5 - 1]), "read OK"); + } + + private static void assertContent(String exp, InputStream is, String msg) throws IOException { + byte[] arr = new byte[512]; + int len = is.read(arr); + String s = new String(arr, 0, len); + assertEquals(exp, s, msg); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,108 @@ +/** + * 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.vmtest.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.Http; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +@GenerateZip(name = "readAnEntry.zip", contents = { + "my/main/file.txt", "Hello World!" +}) +public class ZipFileTest { + + @Compare public String readAnEntry() throws IOException { + InputStream is = ZipFileTest.class.getResourceAsStream("readAnEntry.zip"); + ZipInputStream zip = new ZipInputStream(is); + ZipEntry entry = zip.getNextEntry(); + assertEquals(entry.getName(), "my/main/file.txt", "Correct entry"); + + byte[] arr = new byte[4096]; + int len = zip.read(arr); + + assertEquals(zip.getNextEntry(), null, "No next entry"); + + final String ret = new String(arr, 0, len, "UTF-8"); + return ret; + } + + @JavaScriptBody(args = { "res", "path" }, body = + "var myvm = bck2brwsr.apply(null, path);\n" + + "var cls = myvm.loadClass('java.lang.String');\n" + + "return cls.getClass__Ljava_lang_Class_2().getResourceAsStream__Ljava_io_InputStream_2Ljava_lang_String_2(res);\n" + ) + private static native Object loadVMResource(String res, String...path); + + @Http({ + @Http.Resource(path = "/readAnEntry.jar", mimeType = "x-application/zip", content = "", resource="readAnEntry.zip") + }) + @BrwsrTest public void canVmLoadResourceFromZip() throws IOException { + Object res = loadVMResource("/my/main/file.txt", "/readAnEntry.jar"); + assert res instanceof InputStream : "Got array of bytes: " + res; + InputStream is = (InputStream)res; + + byte[] arr = new byte[4096]; + int len = is.read(arr); + + final String ret = new String(arr, 0, len, "UTF-8"); + + assertEquals(ret, "Hello World!", "Can read the bytes"); + } + + @GenerateZip(name = "cpattr.zip", contents = { + "META-INF/MANIFEST.MF", "Manifest-Version: 1.0\n" + + "Created-By: hand\n" + + "Class-Path: realJar.jar\n\n\n" + }) + @Http({ + @Http.Resource(path = "/readComplexEntry.jar", mimeType = "x-application/zip", content = "", resource="cpattr.zip"), + @Http.Resource(path = "/realJar.jar", mimeType = "x-application/zip", content = "", resource="readAnEntry.zip"), + }) + @BrwsrTest public void understandsClassPathAttr() throws IOException { + Object res = loadVMResource("/my/main/file.txt", "/readComplexEntry.jar"); + assert res instanceof InputStream : "Got array of bytes: " + res; + InputStream is = (InputStream)res; + + byte[] arr = new byte[4096]; + int len = is.read(arr); + + final String ret = new String(arr, 0, len, "UTF-8"); + + assertEquals(ret, "Hello World!", "Can read the bytes from secondary JAR"); + } + + private static void assertEquals(Object real, Object exp, String msg) { + assert Objects.equals(exp, real) : msg + " exp: " + exp + " real: " + real; + } + + @Factory public static Object[] create() { + return VMTest.create(ZipFileTest.class); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/compact/tck/demo.static.calculator-0.3-SNAPSHOT.jar Binary file rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/compact/tck/demo.static.calculator-0.3-SNAPSHOT.jar has changed diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/compact/tck/demo.static.calculator-TEST.jar Binary file rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/compact/tck/demo.static.calculator-TEST.jar has changed diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/0xfe --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/0xfe Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,1 @@ +þ \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/Resources.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/Resources.txt Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,1 @@ +Ahoj diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/pom.xml --- a/rt/emul/mini/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,11 +4,11 @@ org.apidesign.bck2brwsr emul.pom - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr emul.mini - 0.4-SNAPSHOT + 0.8-SNAPSHOT Minimal API Profile http://maven.apache.org @@ -18,7 +18,7 @@ org.apidesign.bck2brwsr core - 0.4-SNAPSHOT + 0.8-SNAPSHOT jar @@ -42,6 +42,28 @@ 1.7
+ + org.apache.maven.plugins + maven-javadoc-plugin + + org.apidesign.bck2brwsr.emul.* + false + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + prepare-sources + + jar + + package + + +
diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/AbstractStringBuilder.java --- a/rt/emul/mini/src/main/java/java/lang/AbstractStringBuilder.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/AbstractStringBuilder.java Fri May 17 10:27:41 2013 +0200 @@ -126,7 +126,7 @@ throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } - value = copyOf(value, newCapacity); + value = System.expandArray(value, newCapacity); } /** diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/ArithmeticException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/emul/mini/src/main/java/java/lang/ArithmeticException.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown when an exceptional arithmetic condition has occurred. For + * example, an integer "divide by zero" throws an + * instance of this class. + * + * {@code ArithmeticException} objects may be constructed by the + * virtual machine as if {@linkplain Throwable#Throwable(String, + * Throwable, boolean, boolean) suppression were disabled and/or the + * stack trace was not writable}. + * + * @author unascribed + * @since JDK1.0 + */ +public class ArithmeticException extends RuntimeException { + private static final long serialVersionUID = 2256477558314496007L; + + /** + * Constructs an {@code ArithmeticException} with no detail + * message. + */ + public ArithmeticException() { + super(); + } + + /** + * Constructs an {@code ArithmeticException} with the specified + * detail message. + * + * @param s the detail message. + */ + public ArithmeticException(String s) { + super(s); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/Boolean.java --- a/rt/emul/mini/src/main/java/java/lang/Boolean.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Boolean.java Fri May 17 10:27:41 2013 +0200 @@ -26,6 +26,7 @@ package java.lang; import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.core.JavaScriptPrototype; /** * The Boolean class wraps a value of the primitive type @@ -42,6 +43,7 @@ * @author Arthur van Hoff * @since JDK1.0 */ +@JavaScriptPrototype(container = "Boolean.prototype", prototype = "new Boolean") public final class Boolean implements java.io.Serializable, Comparable { @@ -129,6 +131,7 @@ * * @return the primitive {@code boolean} value of this object. */ + @JavaScriptBody(args = {}, body = "return this.valueOf();") public boolean booleanValue() { return value; } @@ -287,7 +290,7 @@ } @JavaScriptBody(args = { }, body = "vm.java_lang_Boolean(false)" + - ".valueOf = function() { return this._value(); };" + ".valueOf = function() { return this._value() ? true : false; };" ) private native static void initValueOf(); } diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/Class.java --- a/rt/emul/mini/src/main/java/java/lang/Class.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java Fri May 17 10:27:41 2013 +0200 @@ -402,8 +402,15 @@ } return cmpType != null && getComponentType().isAssignableFrom(cmpType); } - String prop = "$instOf_" + getName().replace('.', '_'); - return hasCnstrProperty(cls, prop); + if (isPrimitive()) { + return false; + } else { + if (cls.isPrimitive()) { + return false; + } + String prop = "$instOf_" + getName().replace('.', '_'); + return hasCnstrProperty(cls, prop); + } } @JavaScriptBody(args = { "who", "prop" }, body = @@ -1245,6 +1252,7 @@ } @JavaScriptBody(args = { "sig" }, body = + "if (!sig) sig = '[Ljava/lang/Object;';\n" + "var c = Array[sig];\n" + "if (c) return c;\n" + "c = vm.java_lang_Class(true);\n" + diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/Double.java --- a/rt/emul/mini/src/main/java/java/lang/Double.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Double.java Fri May 17 10:27:41 2013 +0200 @@ -190,12 +190,12 @@ * @param d the {@code double} to be converted. * @return a string representation of the argument. */ - @JavaScriptBody(args="d", body="var r = d.toString();" - + "if (isFinite(d) && (r.indexOf('.') === -1)) r = r + '.0';" - + "return r;") - public static String toString(double d) { - throw new UnsupportedOperationException(); - } + @JavaScriptBody(args="d", body="var f = Math.floor(d);\n" + + "var r = d.toString();" + + "if (f === d && isFinite(d) && r.indexOf('e') === -1) return r + '.0';\n" + + " else return r;" + ) + public static native String toString(double d); /** * Returns a hexadecimal string representation of the @@ -810,15 +810,17 @@ * @return the bits that represent the floating-point number. */ public static long doubleToLongBits(double value) { - throw new UnsupportedOperationException(); -// long result = doubleToRawLongBits(value); -// // Check for NaN based on values of bit fields, maximum -// // exponent and nonzero significand. -// if ( ((result & DoubleConsts.EXP_BIT_MASK) == -// DoubleConsts.EXP_BIT_MASK) && -// (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L) -// result = 0x7ff8000000000000L; -// return result; + final long EXP_BIT_MASK = 9218868437227405312L; + final long SIGNIF_BIT_MASK = 4503599627370495L; + + long result = doubleToRawLongBits(value); + // Check for NaN based on values of bit fields, maximum + // exponent and nonzero significand. + if ( ((result & EXP_BIT_MASK) == + EXP_BIT_MASK) && + (result & SIGNIF_BIT_MASK) != 0L) + result = 0x7ff8000000000000L; + return result; } /** @@ -857,7 +859,21 @@ * @return the bits that represent the floating-point number. * @since 1.3 */ - public static native long doubleToRawLongBits(double value); + public static long doubleToRawLongBits(double value) { + int[] arr = { 0, 0 }; + doubleToRawLongBits(value, arr); + long l = arr[1]; + return (l << 32) | arr[0]; + } + + @JavaScriptBody(args = { "value", "arr" }, body = "" + + "var a = new ArrayBuffer(8);" + + "new Float64Array(a)[0] = value;" + + "var out = new Int32Array(a);" + + "arr[0] = out[0];" + + "arr[1] = out[1];" + ) + private static native void doubleToRawLongBits(double value, int[] arr); /** * Returns the {@code double} value corresponding to a given diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/Enum.java --- a/rt/emul/mini/src/main/java/java/lang/Enum.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Enum.java Fri May 17 10:27:41 2013 +0200 @@ -27,6 +27,7 @@ import java.io.Serializable; import java.io.IOException; +import org.apidesign.bck2brwsr.core.JavaScriptBody; /** * This is the common base class of all Java language enumeration types. @@ -225,15 +226,17 @@ */ public static > T valueOf(Class enumType, String name) { - throw new UnsupportedOperationException(); -// T result = enumType.enumConstantDirectory().get(name); -// if (result != null) -// return result; -// if (name == null) -// throw new NullPointerException("Name is null"); -// throw new IllegalArgumentException( -// "No enum constant " + enumType.getCanonicalName() + "." + name); + for (Object o : values(enumType)) { + T t = enumType.cast(o); + if (name.equals(((Enum)t).name)) { + return t; + } + } + throw new IllegalArgumentException(); } + + @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.$VALUES;") + private static native Object[] values(Class enumType); /** * enum classes cannot have finalize methods. diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/Float.java --- a/rt/emul/mini/src/main/java/java/lang/Float.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Float.java Fri May 17 10:27:41 2013 +0200 @@ -710,15 +710,17 @@ * @return the bits that represent the floating-point number. */ public static int floatToIntBits(float value) { - throw new UnsupportedOperationException(); -// int result = floatToRawIntBits(value); -// // Check for NaN based on values of bit fields, maximum -// // exponent and nonzero significand. -// if ( ((result & FloatConsts.EXP_BIT_MASK) == -// FloatConsts.EXP_BIT_MASK) && -// (result & FloatConsts.SIGNIF_BIT_MASK) != 0) -// result = 0x7fc00000; -// return result; + final int EXP_BIT_MASK = 2139095040; + final int SIGNIF_BIT_MASK = 8388607; + + int result = floatToRawIntBits(value); + // Check for NaN based on values of bit fields, maximum + // exponent and nonzero significand. + if ( ((result & EXP_BIT_MASK) == + EXP_BIT_MASK) && + (result & SIGNIF_BIT_MASK) != 0) + result = 0x7fc00000; + return result; } /** @@ -756,6 +758,11 @@ * @return the bits that represent the floating-point number. * @since 1.3 */ + @JavaScriptBody(args = { "value" }, body = "" + + "var a = new ArrayBuffer(4);" + + "new Float32Array(a)[0] = value;" + + "return new Int32Array(a)[0];" + ) public static native int floatToRawIntBits(float value); /** diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/String.java --- a/rt/emul/mini/src/main/java/java/lang/String.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/String.java Fri May 17 10:27:41 2013 +0200 @@ -2220,9 +2220,19 @@ * replacement is null. * @since 1.5 */ - public String replace(CharSequence target, CharSequence replacement) { - throw new UnsupportedOperationException("This one should be supported, but without dep on rest of regexp"); - } + @JavaScriptBody(args = { "target", "replacement" }, body = + "var s = this.toString();\n" + + "target = target.toString();\n" + + "replacement = replacement.toString();\n" + + "for (;;) {\n" + + " var ret = s.replace(target, replacement);\n" + + " if (ret === s) {\n" + + " return ret;\n" + + " }\n" + + " s = ret;\n" + + "}" + ) + public native String replace(CharSequence target, CharSequence replacement); /** * Splits this string around matches of the given diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/Throwable.java --- a/rt/emul/mini/src/main/java/java/lang/Throwable.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Throwable.java Fri May 17 10:27:41 2013 +0200 @@ -1085,4 +1085,22 @@ // else // return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); } + + private static Object bck2BrwsrCnvrt(Object o) { + if (o instanceof Throwable) { + return o; + } + final String msg = msg(o); + if (msg == null || msg.startsWith("TypeError")) { + return new NullPointerException(msg); + } + return new Throwable(msg); + } + + @JavaScriptBody(args = { "o" }, body = "return o ? o.toString() : null;") + private static native String msg(Object o); + + @JavaScriptOnly(name = "bck2BrwsrCnvrt", value = "c.bck2BrwsrCnvrt__Ljava_lang_Object_2Ljava_lang_Object_2") + private static void bck2BrwsrCnvrtVM() { + } } diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/reflect/Array.java --- a/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Fri May 17 10:27:41 2013 +0200 @@ -636,9 +636,9 @@ + "arr.jvmName = sig;\n" + "return arr;" ) - private static native Object newArray(boolean primitive, String sig, int length); + static native Object newArray(boolean primitive, String sig, int length); - private static Object multiNewArray(String sig, int[] dims, int index) + static Object multiNewArray(String sig, int[] dims, int index) throws IllegalArgumentException, NegativeArraySizeException { if (dims.length == index + 1) { return newArray(sig.length() == 2, sig, dims[index]); diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/java/lang/reflect/Method.java --- a/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Fri May 17 10:27:41 2013 +0200 @@ -501,8 +501,8 @@ throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { - final boolean isStatic = (getModifiers() & Modifier.STATIC) == 0; - if (isStatic && obj == null) { + final boolean nonStatic = (getModifiers() & Modifier.STATIC) == 0; + if (nonStatic && obj == null) { throw new NullPointerException(); } Class[] types = getParameterTypes(); @@ -517,7 +517,7 @@ } } } - Object res = invoke0(isStatic, this, obj, args); + Object res = invokeTry(nonStatic, this, obj, args); if (getReturnType().isPrimitive()) { res = fromPrimitive(getReturnType(), res); } @@ -536,6 +536,15 @@ + "return method._data().apply(self, p);\n" ) private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args); + + private static Object invokeTry(boolean isStatic, Method m, Object self, Object[] args) + throws InvocationTargetException { + try { + return invoke0(isStatic, m, self, args); + } catch (Throwable ex) { + throw new InvocationTargetException(ex, ex.getMessage()); + } + } static Object fromPrimitive(Class type, Object o) { if (type == Integer.TYPE) { diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Fri May 17 10:27:41 2013 +0200 @@ -54,6 +54,11 @@ ) public static native byte[] expandArray(byte[] arr, int expectedSize); + @JavaScriptBody(args = { "arr", "expectedSize" }, body = + "while (expectedSize-- > arr.length) { arr.push(0); }; return arr;" + ) + public static native char[] expandArray(char[] arr, int expectedSize); + @JavaScriptBody(args = {}, body = "return new Date().getTime();") private static native double currentTimeMillisDouble(); diff -r d127d41768bd -r ae3f2aa50970 rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Fri May 17 10:27:41 2013 +0200 @@ -1,226 +1,244 @@ // empty line needed here -Number.prototype.add32 = function(x) { return (this + x) | 0; }; -Number.prototype.sub32 = function(x) { return (this - x) | 0; }; -Number.prototype.mul32 = function(x) { - return (((this * (x >> 16)) << 16) + this * (x & 0xFFFF)) | 0; -}; -Number.prototype.neg32 = function() { return (-this) | 0; }; -Number.prototype.toInt8 = function() { return (this << 24) >> 24; }; -Number.prototype.toInt16 = function() { return (this << 16) >> 16; }; +(function(numberPrototype) { + numberPrototype.add32 = function(x) { + return (this + x) | 0; + }; + numberPrototype.sub32 = function(x) { + return (this - x) | 0; + }; + numberPrototype.mul32 = function(x) { + return (((this * (x >> 16)) << 16) + this * (x & 0xFFFF)) | 0; + }; + numberPrototype.neg32 = function() { + return (-this) | 0; + }; -var __m32 = 0xFFFFFFFF; + numberPrototype.toInt8 = function() { + return (this << 24) >> 24; + }; + numberPrototype.toInt16 = function() { + return (this << 16) >> 16; + }; -Number.prototype.next32 = function(low) { - if (this === 0) { - return low; - } - var l = new Number(low); - l.hi = this | 0; - return l; -}; + var __m32 = 0xFFFFFFFF; -Number.prototype.high32 = function() { - return this.hi ? this.hi : (Math.floor(this / (__m32+1))) | 0; -}; -Number.prototype.toInt32 = function() { return this | 0; }; -Number.prototype.toFP = function() { - return this.hi ? this.hi * (__m32+1) + this : this; -}; -Number.prototype.toLong = function() { - var hi = (this / (__m32+1)) | 0; - var low = (this % (__m32+1)) | 0; - if (low < 0) { - low += __m32+1; - } - - if (this < 0) { - hi -= 1; - } + numberPrototype.next32 = function(low) { + if (this === 0) { + return low; + } + var l = new Number(low); + l.hi = this | 0; + return l; + }; - return hi.next32(low); -}; + numberPrototype.high32 = function() { + return this.hi ? this.hi : (Math.floor(this / (__m32 + 1))) | 0; + }; + numberPrototype.toInt32 = function() { + return this | 0; + }; + numberPrototype.toFP = function() { + return this.hi ? this.hi * (__m32 + 1) + this : this; + }; + numberPrototype.toLong = function() { + var hi = (this / (__m32 + 1)) | 0; + var low = (this % (__m32 + 1)) | 0; + if (low < 0) { + low += __m32 + 1; + } -Number.prototype.toExactString = function() { - if (this.hi) { - // check for Long.MIN_VALUE - if ((this.hi == (0x80000000 | 0)) && (this == 0)) { - return '-9223372036854775808'; + if (this < 0) { + hi -= 1; } - var res = 0; - var a = [ 6,9,2,7,6,9,4,9,2,4 ]; - var s = ''; - var digit; - var neg = this.hi < 0; - if (neg) { - var x = this.neg64(); - var hi = x.hi; - var low = x; - } else { - var hi = this.hi; - var low = this; - } - for (var i = 0; i < a.length; i++) { - res += hi * a[i]; - var low_digit = low % 10; - digit = (res % 10) + low_digit; - low = Math.floor(low / 10); - res = Math.floor(res / 10); - - if (digit >= 10) { - digit -= 10; - res++; - } - s = String(digit).concat(s); - } - s = String(res).concat(s).replace(/^0+/, ''); - return (neg ? '-' : '').concat(s); - } - return String(this); -}; - -Number.prototype.add64 = function(x) { - var low = this + x; - carry = 0; - if (low > __m32) { - carry = 1; - low -= (__m32+1); - } - var hi = (this.high32() + x.high32() + carry) | 0; - return hi.next32(low); -}; - -Number.prototype.sub64 = function(x) { - var low = this - x; - carry = 0; - if (low < 0) { - carry = 1; - low += (__m32+1); - } - var hi = (this.high32() - x.high32() - carry) | 0; - return hi.next32(low); -}; - -Number.prototype.mul64 = function(x) { - var low = this.mul32(x); - low += (low < 0) ? (__m32+1) : 0; - // first count upper 32 bits of (this.low * x.low) - var hi_hi = 0; - var hi_low = 0; - var m = 1; - for (var i = 0; i < 32; i++) { - if (x & m) { - hi_hi += this >>> 16; - hi_low += this & 0xFFFF - } - hi_low >>= 1; - hi_low += (hi_hi & 1) ? 0x8000 : 0; - hi_hi >>= 1; - m <<= 1; - } - var hi = (hi_hi << 16) + hi_low; - - var m1 = this.high32().mul32(x); - var m2 = this.mul32(x.high32()); - hi = hi.add32(m1).add32(m2); - - return hi.next32(low); -}; - -Number.prototype.and64 = function(x) { - var low = this & x; - low += (low < 0) ? (__m32+1) : 0; - if (this.hi && x.hi) { - var hi = this.hi & x.hi; return hi.next32(low); }; - return low; -}; -Number.prototype.or64 = function(x) { - var low = this | x; - low += (low < 0) ? (__m32+1) : 0; - if (this.hi || x.hi) { - var hi = this.hi | x.hi; + numberPrototype.toExactString = function() { + if (this.hi) { + // check for Long.MIN_VALUE + if ((this.hi == (0x80000000 | 0)) && (this == 0)) { + return '-9223372036854775808'; + } + var res = 0; + var a = [6, 9, 2, 7, 6, 9, 4, 9, 2, 4]; + var s = ''; + var digit; + var neg = this.hi < 0; + if (neg) { + var x = this.neg64(); + var hi = x.hi; + var low = x; + } else { + var hi = this.hi; + var low = this; + } + for (var i = 0; i < a.length; i++) { + res += hi * a[i]; + var low_digit = low % 10; + digit = (res % 10) + low_digit; + + low = Math.floor(low / 10); + res = Math.floor(res / 10); + + if (digit >= 10) { + digit -= 10; + res++; + } + s = String(digit).concat(s); + } + s = String(res).concat(s).replace(/^0+/, ''); + return (neg ? '-' : '').concat(s); + } + return String(this); + }; + + numberPrototype.add64 = function(x) { + var low = this + x; + carry = 0; + if (low > __m32) { + carry = 1; + low -= (__m32 + 1); + } + var hi = (this.high32() + x.high32() + carry) | 0; return hi.next32(low); }; - return low; -}; -Number.prototype.xor64 = function(x) { - var low = this ^ x; - low += (low < 0) ? (__m32+1) : 0; - if (this.hi || x.hi) { - var hi = this.hi ^ x.hi; + numberPrototype.sub64 = function(x) { + var low = this - x; + carry = 0; + if (low < 0) { + carry = 1; + low += (__m32 + 1); + } + var hi = (this.high32() - x.high32() - carry) | 0; return hi.next32(low); }; - return low; -}; -Number.prototype.shl64 = function(x) { - if (x >= 32) { - var hi = this << (x - 32); - return hi.next32(0); - } else { - var hi = this.high32() << x; - var low_reminder = this >> (32 - x); - hi |= low_reminder; - var low = this << x; - low += (low < 0) ? (__m32+1) : 0; + numberPrototype.mul64 = function(x) { + var low = this.mul32(x); + low += (low < 0) ? (__m32 + 1) : 0; + // first count upper 32 bits of (this.low * x.low) + var hi_hi = 0; + var hi_low = 0; + var m = 1; + for (var i = 0; i < 32; i++) { + if (x & m) { + hi_hi += this >>> 16; + hi_low += this & 0xFFFF + } + hi_low >>= 1; + hi_low += (hi_hi & 1) ? 0x8000 : 0; + hi_hi >>= 1; + m <<= 1; + } + var hi = (hi_hi << 16) + hi_low; + + var m1 = this.high32().mul32(x); + var m2 = this.mul32(x.high32()); + hi = hi.add32(m1).add32(m2); + return hi.next32(low); - } -}; + }; -Number.prototype.shr64 = function(x) { - if (x >= 32) { - var low = this.high32() >> (x - 32); - low += (low < 0) ? (__m32+1) : 0; + numberPrototype.and64 = function(x) { + var low = this & x; + low += (low < 0) ? (__m32 + 1) : 0; + if (this.hi && x.hi) { + var hi = this.hi & x.hi; + return hi.next32(low); + } + ; return low; - } else { - var low = this >> x; - var hi_reminder = this.high32() << (32 - x); - low |= hi_reminder; - low += (low < 0) ? (__m32+1) : 0; - var hi = this.high32() >> x; - return hi.next32(low); - } -}; + }; -Number.prototype.ushr64 = function(x) { - if (x >= 32) { - var low = this.high32() >>> (x - 32); - low += (low < 0) ? (__m32+1) : 0; + numberPrototype.or64 = function(x) { + var low = this | x; + low += (low < 0) ? (__m32 + 1) : 0; + if (this.hi || x.hi) { + var hi = this.hi | x.hi; + return hi.next32(low); + } + ; return low; - } else { - var low = this >>> x; - var hi_reminder = this.high32() << (32 - x); - low |= hi_reminder; - low += (low < 0) ? (__m32+1) : 0; - var hi = this.high32() >>> x; - return hi.next32(low); - } -}; + }; -Number.prototype.compare64 = function(x) { - if (this.high32() === x.high32()) { - return (this < x) ? -1 : ((this > x) ? 1 : 0); - } - return (this.high32() < x.high32()) ? -1 : 1; -}; + numberPrototype.xor64 = function(x) { + var low = this ^ x; + low += (low < 0) ? (__m32 + 1) : 0; + if (this.hi || x.hi) { + var hi = this.hi ^ x.hi; + return hi.next32(low); + } + ; + return low; + }; -Number.prototype.neg64 = function() { - var hi = this.high32(); - var low = this; - if ((hi === 0) && (low < 0)) { return -low; } - hi = ~hi; - low = ~low; - low += (low < 0) ? (__m32+1) : 0; - var ret = hi.next32(low); - return ret.add64(1); -}; + numberPrototype.shl64 = function(x) { + if (x >= 32) { + var hi = this << (x - 32); + return hi.next32(0); + } else { + var hi = this.high32() << x; + var low_reminder = this >> (32 - x); + hi |= low_reminder; + var low = this << x; + low += (low < 0) ? (__m32 + 1) : 0; + return hi.next32(low); + } + }; -(function(numberPrototype) { + numberPrototype.shr64 = function(x) { + if (x >= 32) { + var low = this.high32() >> (x - 32); + low += (low < 0) ? (__m32 + 1) : 0; + return low; + } else { + var low = this >> x; + var hi_reminder = this.high32() << (32 - x); + low |= hi_reminder; + low += (low < 0) ? (__m32 + 1) : 0; + var hi = this.high32() >> x; + return hi.next32(low); + } + }; + + numberPrototype.ushr64 = function(x) { + if (x >= 32) { + var low = this.high32() >>> (x - 32); + low += (low < 0) ? (__m32 + 1) : 0; + return low; + } else { + var low = this >>> x; + var hi_reminder = this.high32() << (32 - x); + low |= hi_reminder; + low += (low < 0) ? (__m32 + 1) : 0; + var hi = this.high32() >>> x; + return hi.next32(low); + } + }; + + numberPrototype.compare64 = function(x) { + if (this.high32() === x.high32()) { + return (this < x) ? -1 : ((this > x) ? 1 : 0); + } + return (this.high32() < x.high32()) ? -1 : 1; + }; + + numberPrototype.neg64 = function() { + var hi = this.high32(); + var low = this; + if ((hi === 0) && (low < 0)) { + return -low; + } + hi = ~hi; + low = ~low; + low += (low < 0) ? (__m32 + 1) : 0; + var ret = hi.next32(low); + return ret.add64(1); + }; + function __handleDivByZero() { var exception = new vm.java_lang_ArithmeticException; vm.java_lang_ArithmeticException(false).constructor @@ -551,3 +569,5 @@ return negateResult ? result.neg64() : result; } })(Number.prototype); + +vm.java_lang_Number(false); diff -r d127d41768bd -r ae3f2aa50970 rt/emul/pom.xml --- a/rt/emul/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/emul/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,15 +4,16 @@ org.apidesign.bck2brwsr rt - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr emul.pom - 0.4-SNAPSHOT + 0.8-SNAPSHOT pom Emulation of Core Libraries mini compact + brwsrtest diff -r d127d41768bd -r ae3f2aa50970 rt/javap/pom.xml --- a/rt/javap/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ - - - 4.0.0 - - org.apidesign.bck2brwsr - rt - 0.4-SNAPSHOT - - org.apidesign.bck2brwsr - javap - 0.4-SNAPSHOT - ByteCode Parser - http://maven.apache.org - - UTF-8 - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.5.1 - - - - - 1.6 - 1.6 - - - - - - - org.apidesign.bck2brwsr - emul.mini - 0.4-SNAPSHOT - - - diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/AnnotationParser.java --- a/rt/javap/src/main/java/org/apidesign/javap/AnnotationParser.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.apidesign.javap; - -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; - -/** An abstract parser for annotation definitions. Analyses the bytes and - * performs some callbacks to the overriden parser methods. - * - * @author Jaroslav Tulach - */ -public class AnnotationParser { - private final boolean textual; - private final boolean iterateArray; - - protected AnnotationParser(boolean textual, boolean iterateArray) { - this.textual = textual; - this.iterateArray = iterateArray; - } - - protected void visitAnnotationStart(String type, boolean top) throws IOException { - } - - protected void visitAnnotationEnd(String type, boolean top) throws IOException { - } - - protected void visitValueStart(String attrName, char type) throws IOException { - } - - protected void visitValueEnd(String attrName, char type) throws IOException { - } - - - protected void visitAttr( - String annoType, String attr, String attrType, String value - ) throws IOException { - } - - protected void visitEnumAttr( - String annoType, String attr, String attrType, String value - ) throws IOException { - visitAttr(annoType, attr, attrType, value); - } - - /** Initialize the parsing with constant pool from cd. - * - * @param attr the attribute defining annotations - * @param cd constant pool - * @throws IOException in case I/O fails - */ - public final void parse(byte[] attr, ClassData cd) throws IOException { - ByteArrayInputStream is = new ByteArrayInputStream(attr); - DataInputStream dis = new DataInputStream(is); - try { - read(dis, cd); - } finally { - is.close(); - } - } - - private void read(DataInputStream dis, ClassData cd) throws IOException { - int cnt = dis.readUnsignedShort(); - for (int i = 0; i < cnt; i++) { - readAnno(dis, cd, true); - } - } - - private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException { - int type = dis.readUnsignedShort(); - String typeName = cd.StringValue(type); - visitAnnotationStart(typeName, top); - int cnt = dis.readUnsignedShort(); - for (int i = 0; i < cnt; i++) { - String attrName = cd.StringValue(dis.readUnsignedShort()); - readValue(dis, cd, typeName, attrName); - } - visitAnnotationEnd(typeName, top); - if (cnt == 0) { - visitAttr(typeName, null, null, null); - } - } - - private void readValue( - DataInputStream dis, ClassData cd, String typeName, String attrName - ) throws IOException { - char type = (char)dis.readByte(); - visitValueStart(attrName, type); - if (type == '@') { - readAnno(dis, cd, false); - } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N - int primitive = dis.readUnsignedShort(); - String val = cd.stringValue(primitive, textual); - String attrType; - if (type == 's') { - attrType = "Ljava_lang_String_2"; - if (textual) { - val = '"' + val + '"'; - } - } else { - attrType = "" + type; - } - visitAttr(typeName, attrName, attrType, val); - } else if (type == 'c') { - int cls = dis.readUnsignedShort(); - } else if (type == '[') { - int cnt = dis.readUnsignedShort(); - for (int i = 0; i < cnt; i++) { - readValue(dis, cd, typeName, iterateArray ? attrName : null); - } - } else if (type == 'e') { - int enumT = dis.readUnsignedShort(); - String attrType = cd.stringValue(enumT, textual); - int enumN = dis.readUnsignedShort(); - String val = cd.stringValue(enumN, textual); - visitEnumAttr(typeName, attrName, attrType, val); - } else { - throw new IOException("Unknown type " + type); - } - visitValueEnd(attrName, type); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/AttrData.java --- a/rt/javap/src/main/java/org/apidesign/javap/AttrData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - - -package org.apidesign.javap; - -import java.io.*; - -/** - * Reads and stores attribute information. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ -class AttrData { - ClassData cls; - int name_cpx; - int datalen; - byte data[]; - - public AttrData (ClassData cls) { - this.cls=cls; - } - - /** - * Reads unknown attribute. - */ - public void read(int name_cpx, DataInputStream in) throws IOException { - this.name_cpx=name_cpx; - datalen=in.readInt(); - data=new byte[datalen]; - in.readFully(data); - } - - /** - * Reads just the name of known attribute. - */ - public void read(int name_cpx){ - this.name_cpx=name_cpx; - } - - /** - * Returns attribute name. - */ - public String getAttrName(){ - return cls.getString(name_cpx); - } - - /** - * Returns attribute data. - */ - public byte[] getData(){ - return data; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/CPX.java --- a/rt/javap/src/main/java/org/apidesign/javap/CPX.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -/** - * Stores constant pool entry information with one field. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ -class CPX { - int cpx; - - CPX (int cpx) { - this.cpx=cpx; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/CPX2.java --- a/rt/javap/src/main/java/org/apidesign/javap/CPX2.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -/** - * Stores constant pool entry information with two fields. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ -class CPX2 { - int cpx1,cpx2; - - CPX2 (int cpx1, int cpx2) { - this.cpx1=cpx1; - this.cpx2=cpx2; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/ClassData.java --- a/rt/javap/src/main/java/org/apidesign/javap/ClassData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,713 +0,0 @@ -/* - * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -import java.io.*; - -/** - * Central data repository of the Java Disassembler. - * Stores all the information in java class file. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ -public final class ClassData implements RuntimeConstants { - - private int magic; - private int minor_version; - private int major_version; - private int cpool_count; - private Object cpool[]; - private int access; - private int this_class = 0;; - private int super_class; - private int interfaces_count; - private int[] interfaces = new int[0];; - private int fields_count; - private FieldData[] fields; - private int methods_count; - private MethodData[] methods; - private InnerClassData[] innerClasses; - private int attributes_count; - private AttrData[] attrs; - private String classname; - private String superclassname; - private int source_cpx=0; - private byte tags[]; - private Hashtable indexHashAscii = new Hashtable(); - private String pkgPrefix=""; - private int pkgPrefixLen=0; - - /** - * Read classfile to disassemble. - */ - public ClassData(InputStream infile) throws IOException { - this.read(new DataInputStream(infile)); - } - - /** - * Reads and stores class file information. - */ - public void read(DataInputStream in) throws IOException { - // Read the header - magic = in.readInt(); - if (magic != JAVA_MAGIC) { - throw new ClassFormatError("wrong magic: " + - toHex(magic) + ", expected " + - toHex(JAVA_MAGIC)); - } - minor_version = in.readShort(); - major_version = in.readShort(); - if (major_version != JAVA_VERSION) { - } - - // Read the constant pool - readCP(in); - access = in.readUnsignedShort(); - this_class = in.readUnsignedShort(); - super_class = in.readUnsignedShort(); - - //Read interfaces. - interfaces_count = in.readUnsignedShort(); - if(interfaces_count > 0){ - interfaces = new int[interfaces_count]; - } - for (int i = 0; i < interfaces_count; i++) { - interfaces[i]=in.readShort(); - } - - // Read the fields - readFields(in); - - // Read the methods - readMethods(in); - - // Read the attributes - attributes_count = in.readUnsignedShort(); - attrs=new AttrData[attributes_count]; - for (int k = 0; k < attributes_count; k++) { - int name_cpx=in.readUnsignedShort(); - if (getTag(name_cpx)==CONSTANT_UTF8 - && getString(name_cpx).equals("SourceFile") - ){ if (in.readInt()!=2) - throw new ClassFormatError("invalid attr length"); - source_cpx=in.readUnsignedShort(); - AttrData attr=new AttrData(this); - attr.read(name_cpx); - attrs[k]=attr; - - } else if (getTag(name_cpx)==CONSTANT_UTF8 - && getString(name_cpx).equals("InnerClasses") - ){ int length=in.readInt(); - int num=in.readUnsignedShort(); - if (2+num*8 != length) - throw new ClassFormatError("invalid attr length"); - innerClasses=new InnerClassData[num]; - for (int j = 0; j < num; j++) { - InnerClassData innerClass=new InnerClassData(this); - innerClass.read(in); - innerClasses[j]=innerClass; - } - AttrData attr=new AttrData(this); - attr.read(name_cpx); - attrs[k]=attr; - } else { - AttrData attr=new AttrData(this); - attr.read(name_cpx, in); - attrs[k]=attr; - } - } - in.close(); - } // end ClassData.read() - - /** - * Reads and stores constant pool info. - */ - void readCP(DataInputStream in) throws IOException { - cpool_count = in.readUnsignedShort(); - tags = new byte[cpool_count]; - cpool = new Object[cpool_count]; - for (int i = 1; i < cpool_count; i++) { - byte tag = in.readByte(); - - switch(tags[i] = tag) { - case CONSTANT_UTF8: - String str=in.readUTF(); - indexHashAscii.put(cpool[i] = str, new Integer(i)); - break; - case CONSTANT_INTEGER: - cpool[i] = new Integer(in.readInt()); - break; - case CONSTANT_FLOAT: - cpool[i] = new Float(in.readFloat()); - break; - case CONSTANT_LONG: - cpool[i++] = new Long(in.readLong()); - break; - case CONSTANT_DOUBLE: - cpool[i++] = new Double(in.readDouble()); - break; - case CONSTANT_CLASS: - case CONSTANT_STRING: - cpool[i] = new CPX(in.readUnsignedShort()); - break; - - case CONSTANT_FIELD: - case CONSTANT_METHOD: - case CONSTANT_INTERFACEMETHOD: - case CONSTANT_NAMEANDTYPE: - cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort()); - break; - - case 0: - default: - throw new ClassFormatError("invalid constant type: " + (int)tags[i]); - } - } - } - - /** - * Reads and strores field info. - */ - protected void readFields(DataInputStream in) throws IOException { - int fields_count = in.readUnsignedShort(); - fields=new FieldData[fields_count]; - for (int k = 0; k < fields_count; k++) { - FieldData field=new FieldData(this); - field.read(in); - fields[k]=field; - } - } - - /** - * Reads and strores Method info. - */ - protected void readMethods(DataInputStream in) throws IOException { - int methods_count = in.readUnsignedShort(); - methods=new MethodData[methods_count]; - for (int k = 0; k < methods_count ; k++) { - MethodData method=new MethodData(this); - method.read(in); - methods[k]=method; - } - } - - /** - * get a string - */ - public String getString(int n) { - if (n == 0) { - return null; - } else { - return (String)cpool[n]; - } - } - - /** - * get the type of constant given an index - */ - public byte getTag(int n) { - try{ - return tags[n]; - } catch (ArrayIndexOutOfBoundsException e) { - return (byte)100; - } - } - - static final String hexString="0123456789ABCDEF"; - - public static char hexTable[]=hexString.toCharArray(); - - static String toHex(long val, int width) { - StringBuffer s = new StringBuffer(); - for (int i=width-1; i>=0; i--) - s.append(hexTable[((int)(val>>(4*i)))&0xF]); - return "0x"+s.toString(); - } - - static String toHex(long val) { - int width; - for (width=16; width>0; width--) { - if ((val>>(width-1)*4)!=0) break; - } - return toHex(val, width); - } - - static String toHex(int val) { - int width; - for (width=8; width>0; width--) { - if ((val>>(width-1)*4)!=0) break; - } - return toHex(val, width); - } - - /** - * Returns the name of this class. - */ - public String getClassName() { - String res=null; - if (this_class==0) { - return res; - } - int tcpx; - try { - if (tags[this_class]!=CONSTANT_CLASS) { - return res; //" "; - } - tcpx=((CPX)cpool[this_class]).cpx; - } catch (ArrayIndexOutOfBoundsException e) { - return res; // "#"+cpx+"// invalid constant pool index"; - } catch (Throwable e) { - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; - } - - try { - return (String)(cpool[tcpx]); - } catch (ArrayIndexOutOfBoundsException e) { - return res; // "class #"+scpx+"// invalid constant pool index"; - } catch (ClassCastException e) { - return res; // "class #"+scpx+"// invalid constant pool reference"; - } catch (Throwable e) { - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; - } - - } - - /** - * Returns the name of class at perticular index. - */ - public String getClassName(int cpx) { - String res="#"+cpx; - if (cpx==0) { - return res; - } - int scpx; - try { - if (tags[cpx]!=CONSTANT_CLASS) { - return res; //" "; - } - scpx=((CPX)cpool[cpx]).cpx; - } catch (ArrayIndexOutOfBoundsException e) { - return res; // "#"+cpx+"// invalid constant pool index"; - } catch (Throwable e) { - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; - } - res="#"+scpx; - try { - return (String)(cpool[scpx]); - } catch (ArrayIndexOutOfBoundsException e) { - return res; // "class #"+scpx+"// invalid constant pool index"; - } catch (ClassCastException e) { - return res; // "class #"+scpx+"// invalid constant pool reference"; - } catch (Throwable e) { - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; - } - } - - public int getAccessFlags() { - return access; - } - - /** - * Returns true if it is a class - */ - public boolean isClass() { - if((access & ACC_INTERFACE) == 0) return true; - return false; - } - - /** - * Returns true if it is a interface. - */ - public boolean isInterface(){ - if((access & ACC_INTERFACE) != 0) return true; - return false; - } - - /** - * Returns true if this member is public, false otherwise. - */ - public boolean isPublic(){ - return (access & ACC_PUBLIC) != 0; - } - - /** - * Returns the access of this class or interface. - */ - public String[] getAccess(){ - Vector v = new Vector(); - if ((access & ACC_PUBLIC) !=0) v.addElement("public"); - if ((access & ACC_FINAL) !=0) v.addElement("final"); - if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract"); - String[] accflags = new String[v.size()]; - v.copyInto(accflags); - return accflags; - } - - /** - * Returns list of innerclasses. - */ - public InnerClassData[] getInnerClasses(){ - return innerClasses; - } - - /** - * Returns list of attributes. - */ - final AttrData[] getAttributes(){ - return attrs; - } - - public byte[] findAnnotationData(boolean classRetention) { - String n = classRetention ? - "RuntimeInvisibleAnnotations" : // NOI18N - "RuntimeVisibleAnnotations"; // NOI18N - return findAttr(n, attrs); - } - - /** - * Returns true if superbit is set. - */ - public boolean isSuperSet(){ - if ((access & ACC_SUPER) !=0) return true; - return false; - } - - /** - * Returns super class name. - */ - public String getSuperClassName(){ - String res=null; - if (super_class==0) { - return res; - } - int scpx; - try { - if (tags[super_class]!=CONSTANT_CLASS) { - return res; //" "; - } - scpx=((CPX)cpool[super_class]).cpx; - } catch (ArrayIndexOutOfBoundsException e) { - return res; // "#"+cpx+"// invalid constant pool index"; - } catch (Throwable e) { - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; - } - - try { - return (String)(cpool[scpx]); - } catch (ArrayIndexOutOfBoundsException e) { - return res; // "class #"+scpx+"// invalid constant pool index"; - } catch (ClassCastException e) { - return res; // "class #"+scpx+"// invalid constant pool reference"; - } catch (Throwable e) { - return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; - } - } - - /** - * Returns list of super interfaces. - */ - public String[] getSuperInterfaces(){ - String interfacenames[] = new String[interfaces.length]; - int interfacecpx = -1; - for(int i = 0; i < interfaces.length; i++){ - interfacecpx=((CPX)cpool[interfaces[i]]).cpx; - interfacenames[i] = (String)(cpool[interfacecpx]); - } - return interfacenames; - } - - /** - * Returns string at prticular constant pool index. - */ - public String getStringValue(int cpoolx) { - try { - return ((String)cpool[cpoolx]); - } catch (ArrayIndexOutOfBoundsException e) { - return "//invalid constant pool index:"+cpoolx; - } catch (ClassCastException e) { - return "//invalid constant pool ref:"+cpoolx; - } - } - - /** - * Returns list of field info. - */ - public FieldData[] getFields(){ - return fields; - } - - /** - * Returns list of method info. - */ - public MethodData[] getMethods(){ - return methods; - } - - /** - * Returns constant pool entry at that index. - */ - public CPX2 getCpoolEntry(int cpx){ - return ((CPX2)(cpool[cpx])); - } - - public Object getCpoolEntryobj(int cpx){ - return (cpool[cpx]); - } - - /** - * Returns index of this class. - */ - public int getthis_cpx(){ - return this_class; - } - - /** - * Returns string at that index. - */ - public String StringValue(int cpx) { - return stringValue(cpx, false); - } - public String stringValue(int cpx, boolean textual) { - return stringValue(cpx, textual, null); - } - public String stringValue(int cpx, String[] classRefs) { - return stringValue(cpx, true, classRefs); - } - private String stringValue(int cpx, boolean textual, String[] refs) { - if (cpx==0) return "#0"; - int tag; - Object x; - String suffix=""; - try { - tag=tags[cpx]; - x=cpool[cpx]; - } catch (IndexOutOfBoundsException e) { - return ""; - } - - if (x==null) return ""; - switch (tag) { - case CONSTANT_UTF8: { - if (!textual) { - return (String)x; - } - StringBuilder sb=new StringBuilder(); - String s=(String)x; - for (int k=0; k"; - } catch (ClassCastException e) { - return ""; - } - } - - /** - * Returns unqualified class name. - */ - public String getShortClassName(int cpx) { - String classname=javaName(getClassName(cpx)); - pkgPrefixLen=classname.lastIndexOf("/")+1; - if (pkgPrefixLen!=0) { - pkgPrefix=classname.substring(0,pkgPrefixLen); - if (classname.startsWith(pkgPrefix)) { - return classname.substring(pkgPrefixLen); - } - } - return classname; - } - - /** - * Returns source file name. - */ - public String getSourceName(){ - return getName(source_cpx); - } - - /** - * Returns package name. - */ - public String getPkgName(){ - String classname=getClassName(this_class); - pkgPrefixLen=classname.lastIndexOf("/")+1; - if (pkgPrefixLen!=0) { - pkgPrefix=classname.substring(0,pkgPrefixLen); - return("package "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n"); - }else return null; - } - - /** - * Returns total constant pool entry count. - */ - public int getCpoolCount(){ - return cpool_count; - } - - /** - * Returns minor version of class file. - */ - public int getMinor_version(){ - return minor_version; - } - - /** - * Returns major version of class file. - */ - public int getMajor_version(){ - return major_version; - } - - private boolean isJavaIdentifierStart(int cp) { - return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z'); - } - - private boolean isJavaIdentifierPart(int cp) { - return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9'); - } - - public String[] getNameAndType(int indx) { - return getNameAndType(indx, 0, new String[2]); - } - - private String[] getNameAndType(int indx, int at, String[] arr) { - CPX2 c2 = getCpoolEntry(indx); - arr[at] = StringValue(c2.cpx1); - arr[at + 1] = StringValue(c2.cpx2); - return arr; - } - - public String[] getFieldInfoName(int indx) { - CPX2 c2 = getCpoolEntry(indx); - String[] arr = new String[3]; - arr[0] = getClassName(c2.cpx1); - return getNameAndType(c2.cpx2, 1, arr); - } - - static byte[] findAttr(String n, AttrData[] attrs) { - for (AttrData ad : attrs) { - if (n.equals(ad.getAttrName())) { - return ad.getData(); - } - } - return null; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/Constants.java --- a/rt/javap/src/main/java/org/apidesign/javap/Constants.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,372 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - - -package org.apidesign.javap; - -/** - * This interface defines constant that are used - * throughout the compiler. It inherits from RuntimeConstants, - * which is an autogenerated class that contains contstants - * defined in the interpreter. - */ - -public -interface Constants extends RuntimeConstants { - - /** - * End of input - */ - public static final int EOF = -1; - - /* - * Flags - */ - public static final int F_VERBOSE = 1 << 0; - public static final int F_DUMP = 1 << 1; - public static final int F_WARNINGS = 1 << 2; - public static final int F_DEBUG = 1 << 3; - public static final int F_OPTIMIZE = 1 << 4; - public static final int F_DEPENDENCIES = 1 << 5; - - /* - * Type codes - */ - public static final int TC_BOOLEAN = 0; - public static final int TC_BYTE = 1; - public static final int TC_CHAR = 2; - public static final int TC_SHORT = 3; - public static final int TC_INT = 4; - public static final int TC_LONG = 5; - public static final int TC_FLOAT = 6; - public static final int TC_DOUBLE = 7; - public static final int TC_NULL = 8; - public static final int TC_ARRAY = 9; - public static final int TC_CLASS = 10; - public static final int TC_VOID = 11; - public static final int TC_METHOD = 12; - public static final int TC_ERROR = 13; - - /* - * Type Masks - */ - public static final int TM_NULL = 1 << TC_NULL; - public static final int TM_VOID = 1 << TC_VOID; - public static final int TM_BOOLEAN = 1 << TC_BOOLEAN; - public static final int TM_BYTE = 1 << TC_BYTE; - public static final int TM_CHAR = 1 << TC_CHAR; - public static final int TM_SHORT = 1 << TC_SHORT; - public static final int TM_INT = 1 << TC_INT; - public static final int TM_LONG = 1 << TC_LONG; - public static final int TM_FLOAT = 1 << TC_FLOAT; - public static final int TM_DOUBLE = 1 << TC_DOUBLE; - public static final int TM_ARRAY = 1 << TC_ARRAY; - public static final int TM_CLASS = 1 << TC_CLASS; - public static final int TM_METHOD = 1 << TC_METHOD; - public static final int TM_ERROR = 1 << TC_ERROR; - - public static final int TM_INT32 = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT; - public static final int TM_NUM32 = TM_INT32 | TM_FLOAT; - public static final int TM_NUM64 = TM_LONG | TM_DOUBLE; - public static final int TM_INTEGER = TM_INT32 | TM_LONG; - public static final int TM_REAL = TM_FLOAT | TM_DOUBLE; - public static final int TM_NUMBER = TM_INTEGER | TM_REAL; - public static final int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL; - - /* - * Class status - */ - public static final int CS_UNDEFINED = 0; - public static final int CS_UNDECIDED = 1; - public static final int CS_BINARY = 2; - public static final int CS_SOURCE = 3; - public static final int CS_PARSED = 4; - public static final int CS_COMPILED = 5; - public static final int CS_NOTFOUND = 6; - - /* - * Attributes - */ - public static final int ATT_ALL = -1; - public static final int ATT_CODE = 1; - - /* - * Number of bits used in file offsets - */ - public static final int OFFSETBITS = 19; - public static final int MAXFILESIZE = (1 << OFFSETBITS) - 1; - public static final int MAXLINENUMBER = (1 << (32 - OFFSETBITS)) - 1; - - /* - * Operators - */ - public final int COMMA = 0; - public final int ASSIGN = 1; - - public final int ASGMUL = 2; - public final int ASGDIV = 3; - public final int ASGREM = 4; - public final int ASGADD = 5; - public final int ASGSUB = 6; - public final int ASGLSHIFT = 7; - public final int ASGRSHIFT = 8; - public final int ASGURSHIFT = 9; - public final int ASGBITAND = 10; - public final int ASGBITOR = 11; - public final int ASGBITXOR = 12; - - public final int COND = 13; - public final int OR = 14; - public final int AND = 15; - public final int BITOR = 16; - public final int BITXOR = 17; - public final int BITAND = 18; - public final int NE = 19; - public final int EQ = 20; - public final int GE = 21; - public final int GT = 22; - public final int LE = 23; - public final int LT = 24; - public final int INSTANCEOF = 25; - public final int LSHIFT = 26; - public final int RSHIFT = 27; - public final int URSHIFT = 28; - public final int ADD = 29; - public final int SUB = 30; - public final int DIV = 31; - public final int REM = 32; - public final int MUL = 33; - public final int CAST = 34; // (x)y - public final int POS = 35; // +x - public final int NEG = 36; // -x - public final int NOT = 37; - public final int BITNOT = 38; - public final int PREINC = 39; // ++x - public final int PREDEC = 40; // --x - public final int NEWARRAY = 41; - public final int NEWINSTANCE = 42; - public final int NEWFROMNAME = 43; - public final int POSTINC = 44; // x++ - public final int POSTDEC = 45; // x-- - public final int FIELD = 46; - public final int METHOD = 47; // x(y) - public final int ARRAYACCESS = 48; // x[y] - public final int NEW = 49; - public final int INC = 50; - public final int DEC = 51; - - public final int CONVERT = 55; // implicit conversion - public final int EXPR = 56; // (x) - public final int ARRAY = 57; // {x, y, ...} - public final int GOTO = 58; - - /* - * Value tokens - */ - public final int IDENT = 60; - public final int BOOLEANVAL = 61; - public final int BYTEVAL = 62; - public final int CHARVAL = 63; - public final int SHORTVAL = 64; - public final int INTVAL = 65; - public final int LONGVAL = 66; - public final int FLOATVAL = 67; - public final int DOUBLEVAL = 68; - public final int STRINGVAL = 69; - - /* - * Type keywords - */ - public final int BYTE = 70; - public final int CHAR = 71; - public final int SHORT = 72; - public final int INT = 73; - public final int LONG = 74; - public final int FLOAT = 75; - public final int DOUBLE = 76; - public final int VOID = 77; - public final int BOOLEAN = 78; - - /* - * Expression keywords - */ - public final int TRUE = 80; - public final int FALSE = 81; - public final int THIS = 82; - public final int SUPER = 83; - public final int NULL = 84; - - /* - * Statement keywords - */ - public final int IF = 90; - public final int ELSE = 91; - public final int FOR = 92; - public final int WHILE = 93; - public final int DO = 94; - public final int SWITCH = 95; - public final int CASE = 96; - public final int DEFAULT = 97; - public final int BREAK = 98; - public final int CONTINUE = 99; - public final int RETURN = 100; - public final int TRY = 101; - public final int CATCH = 102; - public final int FINALLY = 103; - public final int THROW = 104; - public final int STAT = 105; - public final int EXPRESSION = 106; - public final int DECLARATION = 107; - public final int VARDECLARATION = 108; - - /* - * Declaration keywords - */ - public final int IMPORT = 110; - public final int CLASS = 111; - public final int EXTENDS = 112; - public final int IMPLEMENTS = 113; - public final int INTERFACE = 114; - public final int PACKAGE = 115; - - /* - * Modifier keywords - */ - public final int PRIVATE = 120; - public final int PUBLIC = 121; - public final int PROTECTED = 122; - public final int CONST = 123; - public final int STATIC = 124; - public final int TRANSIENT = 125; - public final int SYNCHRONIZED = 126; - public final int NATIVE = 127; - public final int FINAL = 128; - public final int VOLATILE = 129; - public final int ABSTRACT = 130; - public final int STRICT = 165; - - /* - * Punctuation - */ - public final int SEMICOLON = 135; - public final int COLON = 136; - public final int QUESTIONMARK = 137; - public final int LBRACE = 138; - public final int RBRACE = 139; - public final int LPAREN = 140; - public final int RPAREN = 141; - public final int LSQBRACKET = 142; - public final int RSQBRACKET = 143; - public final int THROWS = 144; - - /* - * Special tokens - */ - public final int ERROR = 145; // an error - public final int COMMENT = 146; // not used anymore. - public final int TYPE = 147; - public final int LENGTH = 148; - public final int INLINERETURN = 149; - public final int INLINEMETHOD = 150; - public final int INLINENEWINSTANCE = 151; - - /* - * Added for jasm - */ - public final int METHODREF = 152; - public final int FIELDREF = 153; - public final int STACK = 154; - public final int LOCAL = 155; - public final int CPINDEX = 156; - public final int CPNAME = 157; - public final int SIGN = 158; - public final int BITS = 159; - public final int INF = 160; - public final int NAN = 161; - public final int INNERCLASS = 162; - public final int OF = 163; - public final int SYNTHETIC = 164; -// last used=165; - - /* - * Operator precedence - */ - public static final int opPrecedence[] = { - 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 12, 13, 14, 15, 16, 17, 18, - 18, 19, 19, 19, 19, 19, 20, 20, 20, 21, - 21, 22, 22, 22, 23, 24, 24, 24, 24, 24, - 24, 25, 25, 26, 26, 26, 26, 26, 26 - }; - - /* - * Operator names - */ - public static final String opNames[] = { - ",", "=", "*=", "/=", "%=", - "+=", "-=", "<<=", ">>=", "<<<=", - "&=", "|=", "^=", "?:", "||", - "&&", "|", "^", "&", "!=", - "==", ">=", ">", "<=", "<", - "instanceof", "<<", ">>", "<<<", "+", - "-", "/", "%", "*", "cast", - "+", "-", "!", "~", "++", - "--", "new", "new", "new", "++", - "--", "field", "method", "[]", "new", - "++", "--", null, null, null, - - "convert", "expr", "array", "goto", null, - - "Identifier", "Boolean", "Byte", "Char", "Short", - "Integer", "Long", "Float", "Double", "String", - - "byte", "char", "short", "int", "long", - "float", "double", "void", "boolean", null, - - "true", "false", "this", "super", "null", - null, null, null, null, null, - - "if", "else", "for", "while", "do", - "switch", "case", "default", "break", "continue", - "return", "try", "catch", "finally", "throw", - "stat", "expression", "declaration", "declaration", null, - - "import", "class", "extends", "implements", "interface", - "package", null, null, null, null, - - "private", "public", "protected", "const", "static", - "transient", "synchronized", "native", "final", "volatile", - "abstract", null, null, null, null, - - ";", ":", "?", "{", "}", - "(", ")", "[", "]", "throws", - "error", "comment", "type", "length", "inline-return", - "inline-method", "inline-new", - "method", "field", "stack", "locals", "CPINDEX", "CPName", "SIGN", - "bits", "INF", "NaN", "InnerClass", "of", "synthetic" - }; - -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/FieldData.java --- a/rt/javap/src/main/java/org/apidesign/javap/FieldData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -import java.io.*; - -/** - * Strores field data informastion. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ - -public class FieldData implements RuntimeConstants { - - ClassData cls; - int access; - int name_index; - int descriptor_index; - int attributes_count; - int value_cpx=0; - boolean isSynthetic=false; - boolean isDeprecated=false; - Vector attrs; - - public FieldData(ClassData cls){ - this.cls=cls; - } - - /** - * Read and store field info. - */ - public void read(DataInputStream in) throws IOException { - access = in.readUnsignedShort(); - name_index = in.readUnsignedShort(); - descriptor_index = in.readUnsignedShort(); - // Read the attributes - int attributes_count = in.readUnsignedShort(); - attrs=new Vector(attributes_count); - for (int i = 0; i < attributes_count; i++) { - int attr_name_index=in.readUnsignedShort(); - if (cls.getTag(attr_name_index)!=CONSTANT_UTF8) continue; - String attr_name=cls.getString(attr_name_index); - if (attr_name.equals("ConstantValue")){ - if (in.readInt()!=2) - throw new ClassFormatError("invalid ConstantValue attr length"); - value_cpx=in.readUnsignedShort(); - AttrData attr=new AttrData(cls); - attr.read(attr_name_index); - attrs.addElement(attr); - } else if (attr_name.equals("Synthetic")){ - if (in.readInt()!=0) - throw new ClassFormatError("invalid Synthetic attr length"); - isSynthetic=true; - AttrData attr=new AttrData(cls); - attr.read(attr_name_index); - attrs.addElement(attr); - } else if (attr_name.equals("Deprecated")){ - if (in.readInt()!=0) - throw new ClassFormatError("invalid Synthetic attr length"); - isDeprecated = true; - AttrData attr=new AttrData(cls); - attr.read(attr_name_index); - attrs.addElement(attr); - } else { - AttrData attr=new AttrData(cls); - attr.read(attr_name_index, in); - attrs.addElement(attr); - } - } - - } // end read - - public boolean isStatic() { - return (access & ACC_STATIC) != 0; - } - - /** - * Returns access of a field. - */ - public String[] getAccess(){ - Vector v = new Vector(); - if ((access & ACC_PUBLIC) !=0) v.addElement("public"); - if ((access & ACC_PRIVATE) !=0) v.addElement("private"); - if ((access & ACC_PROTECTED) !=0) v.addElement("protected"); - if ((access & ACC_STATIC) !=0) v.addElement("static"); - if ((access & ACC_FINAL) !=0) v.addElement("final"); - if ((access & ACC_VOLATILE) !=0) v.addElement("volatile"); - if ((access & ACC_TRANSIENT) !=0) v.addElement("transient"); - String[] accflags = new String[v.size()]; - v.copyInto(accflags); - return accflags; - } - - /** - * Returns name of a field. - */ - public String getName(){ - return cls.getStringValue(name_index); - } - - /** - * Returns internal signature of a field - */ - public String getInternalSig(){ - return cls.getStringValue(descriptor_index); - } - - /** - * Returns true if field is synthetic. - */ - public boolean isSynthetic(){ - return isSynthetic; - } - - /** - * Returns true if field is deprecated. - */ - public boolean isDeprecated(){ - return isDeprecated; - } - - /** - * Returns index of constant value in cpool. - */ - public int getConstantValueIndex(){ - return (value_cpx); - } - - /** - * Returns list of attributes of field. - */ - public Vector getAttributes(){ - return attrs; - } - - public byte[] findAnnotationData(boolean classRetention) { - String n = classRetention ? - "RuntimeInvisibleAnnotations" : // NOI18N - "RuntimeVisibleAnnotations"; // NOI18N - AttrData[] arr = new AttrData[attrs.size()]; - attrs.copyInto(arr); - return ClassData.findAttr(n, arr); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/Hashtable.java --- a/rt/javap/src/main/java/org/apidesign/javap/Hashtable.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +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.javap; - -/** A JavaScript optimized replacement for Hashtable. - * - * @author Jaroslav Tulach - */ -final class Hashtable { - private Object[] keys; - private Object[] values; - - Hashtable(int i) { - this(); - } - - Hashtable(int i, double d) { - this(); - } - - Hashtable() { - } - - synchronized void put(Object key, Object val) { - int[] where = { -1, -1 }; - Object found = get(key, where); - if (where[0] != -1) { - // key exists - values[where[0]] = val; - } else { - if (where[1] != -1) { - // null found - keys[where[1]] = key; - values[where[1]] = val; - } else { - if (keys == null) { - keys = new Object[11]; - values = new Object[11]; - keys[0] = key; - values[0] = val; - } else { - Object[] newKeys = new Object[keys.length * 2]; - Object[] newValues = new Object[values.length * 2]; - for (int i = 0; i < keys.length; i++) { - newKeys[i] = keys[i]; - newValues[i] = values[i]; - } - newKeys[keys.length] = key; - newValues[keys.length] = val; - keys = newKeys; - values = newValues; - } - } - } - } - - Object get(Object key) { - return get(key, null); - } - private synchronized Object get(Object key, int[] foundAndNull) { - if (keys == null) { - return null; - } - for (int i = 0; i < keys.length; i++) { - if (keys[i] == null) { - if (foundAndNull != null) { - foundAndNull[1] = i; - } - } else if (keys[i].equals(key)) { - if (foundAndNull != null) { - foundAndNull[0] = i; - } - return values[i]; - } - } - return null; - } - -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/InnerClassData.java --- a/rt/javap/src/main/java/org/apidesign/javap/InnerClassData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -import java.io.*; -import java.util.*; - -/** - * Strores InnerClass data informastion. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ -class InnerClassData implements RuntimeConstants { - ClassData cls; - - - int inner_class_info_index - ,outer_class_info_index - ,inner_name_index - ,access - ; - - public InnerClassData(ClassData cls) { - this.cls=cls; - - } - - /** - * Read Innerclass attribute data. - */ - public void read(DataInputStream in) throws IOException { - inner_class_info_index = in.readUnsignedShort(); - outer_class_info_index = in.readUnsignedShort(); - inner_name_index = in.readUnsignedShort(); - access = in.readUnsignedShort(); - } // end read - - /** - * Returns the access of this class or interface. - */ - public String[] getAccess(){ - Vector v = new Vector(); - if ((access & ACC_PUBLIC) !=0) v.addElement("public"); - if ((access & ACC_FINAL) !=0) v.addElement("final"); - if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract"); - String[] accflags = new String[v.size()]; - v.copyInto(accflags); - return accflags; - } - -} // end InnerClassData diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/LineNumData.java --- a/rt/javap/src/main/java/org/apidesign/javap/LineNumData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -import java.util.*; -import java.io.*; - -/** - * Strores LineNumberTable data information. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ -class LineNumData { - short start_pc, line_number; - - public LineNumData() {} - - /** - * Read LineNumberTable attribute. - */ - public LineNumData(DataInputStream in) throws IOException { - start_pc = in.readShort(); - line_number=in.readShort(); - - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/LocVarData.java --- a/rt/javap/src/main/java/org/apidesign/javap/LocVarData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -import java.util.*; -import java.io.*; - -/** - * Strores LocalVariableTable data information. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ -class LocVarData { - short start_pc, length, name_cpx, sig_cpx, slot; - - public LocVarData() { - } - - /** - * Read LocalVariableTable attribute. - */ - public LocVarData(DataInputStream in) throws IOException { - start_pc = in.readShort(); - length=in.readShort(); - name_cpx=in.readShort(); - sig_cpx=in.readShort(); - slot=in.readShort(); - - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/MethodData.java --- a/rt/javap/src/main/java/org/apidesign/javap/MethodData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +0,0 @@ -/* - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.apidesign.javap; - - -import java.io.DataInputStream; -import java.io.IOException; -import static org.apidesign.javap.RuntimeConstants.*; - -/** - * Strores method data informastion. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ -public class MethodData { - - ClassData cls; - int access; - int name_index; - int descriptor_index; - int attributes_count; - byte[] code; - Vector exception_table = new Vector(0); - Vector lin_num_tb = new Vector(0); - Vector loc_var_tb = new Vector(0); - StackMapTableData[] stackMapTable; - StackMapData[] stackMap; - int[] exc_index_table=null; - Vector attrs=new Vector(0); - Vector code_attrs=new Vector(0); - int max_stack, max_locals; - boolean isSynthetic=false; - boolean isDeprecated=false; - - public MethodData(ClassData cls){ - this.cls=cls; - } - - /** - * Read method info. - */ - public void read(DataInputStream in) throws IOException { - access = in.readUnsignedShort(); - name_index=in.readUnsignedShort(); - descriptor_index =in.readUnsignedShort(); - int attributes_count = in.readUnsignedShort(); - for (int i = 0; i < attributes_count; i++) { - int attr_name_index=in.readUnsignedShort(); - - readAttr: { - if (cls.getTag(attr_name_index)==CONSTANT_UTF8) { - String attr_name=cls.getString(attr_name_index); - if ( attr_name.equals("Code")){ - readCode (in); - AttrData attr=new AttrData(cls); - attr.read(attr_name_index); - attrs.addElement(attr); - break readAttr; - } else if ( attr_name.equals("Exceptions")){ - readExceptions(in); - AttrData attr=new AttrData(cls); - attr.read(attr_name_index); - attrs.addElement(attr); - break readAttr; - } else if (attr_name.equals("Synthetic")){ - if (in.readInt()!=0) - throw new ClassFormatError("invalid Synthetic attr length"); - isSynthetic=true; - AttrData attr=new AttrData(cls); - attr.read(attr_name_index); - attrs.addElement(attr); - break readAttr; - } else if (attr_name.equals("Deprecated")){ - if (in.readInt()!=0) - throw new ClassFormatError("invalid Synthetic attr length"); - isDeprecated = true; - AttrData attr=new AttrData(cls); - attr.read(attr_name_index); - attrs.addElement(attr); - break readAttr; - } - } - AttrData attr=new AttrData(cls); - attr.read(attr_name_index, in); - attrs.addElement(attr); - } - } - } - - /** - * Read code attribute info. - */ - public void readCode(DataInputStream in) throws IOException { - - int attr_length = in.readInt(); - max_stack=in.readUnsignedShort(); - max_locals=in.readUnsignedShort(); - int codelen=in.readInt(); - - code=new byte[codelen]; - int totalread = 0; - while(totalread < codelen){ - totalread += in.read(code, totalread, codelen-totalread); - } - // in.read(code, 0, codelen); - int clen = 0; - readExceptionTable(in); - int code_attributes_count = in.readUnsignedShort(); - - for (int k = 0 ; k < code_attributes_count ; k++) { - int table_name_index=in.readUnsignedShort(); - int table_name_tag=cls.getTag(table_name_index); - AttrData attr=new AttrData(cls); - if (table_name_tag==CONSTANT_UTF8) { - String table_name_tstr=cls.getString(table_name_index); - if (table_name_tstr.equals("LineNumberTable")) { - readLineNumTable(in); - attr.read(table_name_index); - } else if (table_name_tstr.equals("LocalVariableTable")) { - readLocVarTable(in); - attr.read(table_name_index); - } else if (table_name_tstr.equals("StackMapTable")) { - readStackMapTable(in); - attr.read(table_name_index); - } else if (table_name_tstr.equals("StackMap")) { - readStackMap(in); - attr.read(table_name_index); - } else { - attr.read(table_name_index, in); - } - code_attrs.addElement(attr); - continue; - } - - attr.read(table_name_index, in); - code_attrs.addElement(attr); - } - } - - /** - * Read exception table info. - */ - void readExceptionTable (DataInputStream in) throws IOException { - int exception_table_len=in.readUnsignedShort(); - exception_table=new Vector(exception_table_len); - for (int l = 0; l < exception_table_len; l++) { - exception_table.addElement(new TrapData(in, l)); - } - } - - /** - * Read LineNumberTable attribute info. - */ - void readLineNumTable (DataInputStream in) throws IOException { - int attr_len = in.readInt(); // attr_length - int lin_num_tb_len = in.readUnsignedShort(); - lin_num_tb=new Vector(lin_num_tb_len); - for (int l = 0; l < lin_num_tb_len; l++) { - lin_num_tb.addElement(new LineNumData(in)); - } - } - - /** - * Read LocalVariableTable attribute info. - */ - void readLocVarTable (DataInputStream in) throws IOException { - int attr_len=in.readInt(); // attr_length - int loc_var_tb_len = in.readUnsignedShort(); - loc_var_tb = new Vector(loc_var_tb_len); - for (int l = 0; l < loc_var_tb_len; l++) { - loc_var_tb.addElement(new LocVarData(in)); - } - } - - /** - * Read Exception attribute info. - */ - public void readExceptions(DataInputStream in) throws IOException { - int attr_len=in.readInt(); // attr_length in prog - int num_exceptions = in.readUnsignedShort(); - exc_index_table=new int[num_exceptions]; - for (int l = 0; l < num_exceptions; l++) { - int exc=in.readShort(); - exc_index_table[l]=exc; - } - } - - /** - * Read StackMapTable attribute info. - */ - void readStackMapTable(DataInputStream in) throws IOException { - int attr_len = in.readInt(); //attr_length - int stack_map_tb_len = in.readUnsignedShort(); - stackMapTable = new StackMapTableData[stack_map_tb_len]; - for (int i=0; i".equals(getName()); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/RuntimeConstants.java --- a/rt/javap/src/main/java/org/apidesign/javap/RuntimeConstants.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,787 +0,0 @@ -/* - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -public interface RuntimeConstants { - - /* Signature Characters */ - public static final char SIGC_VOID = 'V'; - public static final String SIG_VOID = "V"; - public static final char SIGC_BOOLEAN = 'Z'; - public static final String SIG_BOOLEAN = "Z"; - public static final char SIGC_BYTE = 'B'; - public static final String SIG_BYTE = "B"; - public static final char SIGC_CHAR = 'C'; - public static final String SIG_CHAR = "C"; - public static final char SIGC_SHORT = 'S'; - public static final String SIG_SHORT = "S"; - public static final char SIGC_INT = 'I'; - public static final String SIG_INT = "I"; - public static final char SIGC_LONG = 'J'; - public static final String SIG_LONG = "J"; - public static final char SIGC_FLOAT = 'F'; - public static final String SIG_FLOAT = "F"; - public static final char SIGC_DOUBLE = 'D'; - public static final String SIG_DOUBLE = "D"; - public static final char SIGC_ARRAY = '['; - public static final String SIG_ARRAY = "["; - public static final char SIGC_CLASS = 'L'; - public static final String SIG_CLASS = "L"; - public static final char SIGC_METHOD = '('; - public static final String SIG_METHOD = "("; - public static final char SIGC_ENDCLASS = ';'; - public static final String SIG_ENDCLASS = ";"; - public static final char SIGC_ENDMETHOD = ')'; - public static final String SIG_ENDMETHOD = ")"; - public static final char SIGC_PACKAGE = '/'; - public static final String SIG_PACKAGE = "/"; - - /* Class File Constants */ - public static final int JAVA_MAGIC = 0xcafebabe; - public static final int JAVA_VERSION = 45; - public static final int JAVA_MINOR_VERSION = 3; - - /* Constant table */ - public static final int CONSTANT_UTF8 = 1; - public static final int CONSTANT_UNICODE = 2; - public static final int CONSTANT_INTEGER = 3; - public static final int CONSTANT_FLOAT = 4; - public static final int CONSTANT_LONG = 5; - public static final int CONSTANT_DOUBLE = 6; - public static final int CONSTANT_CLASS = 7; - public static final int CONSTANT_STRING = 8; - public static final int CONSTANT_FIELD = 9; - public static final int CONSTANT_METHOD = 10; - public static final int CONSTANT_INTERFACEMETHOD = 11; - public static final int CONSTANT_NAMEANDTYPE = 12; - - /* Access Flags */ - public static final int ACC_PUBLIC = 0x00000001; - public static final int ACC_PRIVATE = 0x00000002; - public static final int ACC_PROTECTED = 0x00000004; - public static final int ACC_STATIC = 0x00000008; - public static final int ACC_FINAL = 0x00000010; - public static final int ACC_SYNCHRONIZED = 0x00000020; - public static final int ACC_SUPER = 0x00000020; - public static final int ACC_VOLATILE = 0x00000040; - public static final int ACC_TRANSIENT = 0x00000080; - public static final int ACC_NATIVE = 0x00000100; - public static final int ACC_INTERFACE = 0x00000200; - public static final int ACC_ABSTRACT = 0x00000400; - public static final int ACC_STRICT = 0x00000800; - public static final int ACC_EXPLICIT = 0x00001000; - public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute - - /* Type codes */ - public static final int T_CLASS = 0x00000002; - public static final int T_BOOLEAN = 0x00000004; - public static final int T_CHAR = 0x00000005; - public static final int T_FLOAT = 0x00000006; - public static final int T_DOUBLE = 0x00000007; - public static final int T_BYTE = 0x00000008; - public static final int T_SHORT = 0x00000009; - public static final int T_INT = 0x0000000a; - public static final int T_LONG = 0x0000000b; - - /* Type codes for StackMap attribute */ - public static final int ITEM_Bogus =0; // an unknown or uninitialized value - public static final int ITEM_Integer =1; // a 32-bit integer - public static final int ITEM_Float =2; // not used - public static final int ITEM_Double =3; // not used - public static final int ITEM_Long =4; // a 64-bit integer - public static final int ITEM_Null =5; // the type of null - public static final int ITEM_InitObject =6; // "this" in constructor - public static final int ITEM_Object =7; // followed by 2-byte index of class name - public static final int ITEM_NewObject =8; // followed by 2-byte ref to "new" - - /* Constants used in StackMapTable attribute */ - public static final int SAME_FRAME_BOUND = 64; - public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128; - public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; - public static final int SAME_FRAME_EXTENDED = 251; - public static final int FULL_FRAME = 255; - - /* Opcodes */ - public static final int opc_dead = -2; - public static final int opc_label = -1; - public static final int opc_nop = 0; - public static final int opc_aconst_null = 1; - public static final int opc_iconst_m1 = 2; - public static final int opc_iconst_0 = 3; - public static final int opc_iconst_1 = 4; - public static final int opc_iconst_2 = 5; - public static final int opc_iconst_3 = 6; - public static final int opc_iconst_4 = 7; - public static final int opc_iconst_5 = 8; - public static final int opc_lconst_0 = 9; - public static final int opc_lconst_1 = 10; - public static final int opc_fconst_0 = 11; - public static final int opc_fconst_1 = 12; - public static final int opc_fconst_2 = 13; - public static final int opc_dconst_0 = 14; - public static final int opc_dconst_1 = 15; - public static final int opc_bipush = 16; - public static final int opc_sipush = 17; - public static final int opc_ldc = 18; - public static final int opc_ldc_w = 19; - public static final int opc_ldc2_w = 20; - public static final int opc_iload = 21; - public static final int opc_lload = 22; - public static final int opc_fload = 23; - public static final int opc_dload = 24; - public static final int opc_aload = 25; - public static final int opc_iload_0 = 26; - public static final int opc_iload_1 = 27; - public static final int opc_iload_2 = 28; - public static final int opc_iload_3 = 29; - public static final int opc_lload_0 = 30; - public static final int opc_lload_1 = 31; - public static final int opc_lload_2 = 32; - public static final int opc_lload_3 = 33; - public static final int opc_fload_0 = 34; - public static final int opc_fload_1 = 35; - public static final int opc_fload_2 = 36; - public static final int opc_fload_3 = 37; - public static final int opc_dload_0 = 38; - public static final int opc_dload_1 = 39; - public static final int opc_dload_2 = 40; - public static final int opc_dload_3 = 41; - public static final int opc_aload_0 = 42; - public static final int opc_aload_1 = 43; - public static final int opc_aload_2 = 44; - public static final int opc_aload_3 = 45; - public static final int opc_iaload = 46; - public static final int opc_laload = 47; - public static final int opc_faload = 48; - public static final int opc_daload = 49; - public static final int opc_aaload = 50; - public static final int opc_baload = 51; - public static final int opc_caload = 52; - public static final int opc_saload = 53; - public static final int opc_istore = 54; - public static final int opc_lstore = 55; - public static final int opc_fstore = 56; - public static final int opc_dstore = 57; - public static final int opc_astore = 58; - public static final int opc_istore_0 = 59; - public static final int opc_istore_1 = 60; - public static final int opc_istore_2 = 61; - public static final int opc_istore_3 = 62; - public static final int opc_lstore_0 = 63; - public static final int opc_lstore_1 = 64; - public static final int opc_lstore_2 = 65; - public static final int opc_lstore_3 = 66; - public static final int opc_fstore_0 = 67; - public static final int opc_fstore_1 = 68; - public static final int opc_fstore_2 = 69; - public static final int opc_fstore_3 = 70; - public static final int opc_dstore_0 = 71; - public static final int opc_dstore_1 = 72; - public static final int opc_dstore_2 = 73; - public static final int opc_dstore_3 = 74; - public static final int opc_astore_0 = 75; - public static final int opc_astore_1 = 76; - public static final int opc_astore_2 = 77; - public static final int opc_astore_3 = 78; - public static final int opc_iastore = 79; - public static final int opc_lastore = 80; - public static final int opc_fastore = 81; - public static final int opc_dastore = 82; - public static final int opc_aastore = 83; - public static final int opc_bastore = 84; - public static final int opc_castore = 85; - public static final int opc_sastore = 86; - public static final int opc_pop = 87; - public static final int opc_pop2 = 88; - public static final int opc_dup = 89; - public static final int opc_dup_x1 = 90; - public static final int opc_dup_x2 = 91; - public static final int opc_dup2 = 92; - public static final int opc_dup2_x1 = 93; - public static final int opc_dup2_x2 = 94; - public static final int opc_swap = 95; - public static final int opc_iadd = 96; - public static final int opc_ladd = 97; - public static final int opc_fadd = 98; - public static final int opc_dadd = 99; - public static final int opc_isub = 100; - public static final int opc_lsub = 101; - public static final int opc_fsub = 102; - public static final int opc_dsub = 103; - public static final int opc_imul = 104; - public static final int opc_lmul = 105; - public static final int opc_fmul = 106; - public static final int opc_dmul = 107; - public static final int opc_idiv = 108; - public static final int opc_ldiv = 109; - public static final int opc_fdiv = 110; - public static final int opc_ddiv = 111; - public static final int opc_irem = 112; - public static final int opc_lrem = 113; - public static final int opc_frem = 114; - public static final int opc_drem = 115; - public static final int opc_ineg = 116; - public static final int opc_lneg = 117; - public static final int opc_fneg = 118; - public static final int opc_dneg = 119; - public static final int opc_ishl = 120; - public static final int opc_lshl = 121; - public static final int opc_ishr = 122; - public static final int opc_lshr = 123; - public static final int opc_iushr = 124; - public static final int opc_lushr = 125; - public static final int opc_iand = 126; - public static final int opc_land = 127; - public static final int opc_ior = 128; - public static final int opc_lor = 129; - public static final int opc_ixor = 130; - public static final int opc_lxor = 131; - public static final int opc_iinc = 132; - public static final int opc_i2l = 133; - public static final int opc_i2f = 134; - public static final int opc_i2d = 135; - public static final int opc_l2i = 136; - public static final int opc_l2f = 137; - public static final int opc_l2d = 138; - public static final int opc_f2i = 139; - public static final int opc_f2l = 140; - public static final int opc_f2d = 141; - public static final int opc_d2i = 142; - public static final int opc_d2l = 143; - public static final int opc_d2f = 144; - public static final int opc_i2b = 145; - public static final int opc_int2byte = 145; - public static final int opc_i2c = 146; - public static final int opc_int2char = 146; - public static final int opc_i2s = 147; - public static final int opc_int2short = 147; - public static final int opc_lcmp = 148; - public static final int opc_fcmpl = 149; - public static final int opc_fcmpg = 150; - public static final int opc_dcmpl = 151; - public static final int opc_dcmpg = 152; - public static final int opc_ifeq = 153; - public static final int opc_ifne = 154; - public static final int opc_iflt = 155; - public static final int opc_ifge = 156; - public static final int opc_ifgt = 157; - public static final int opc_ifle = 158; - public static final int opc_if_icmpeq = 159; - public static final int opc_if_icmpne = 160; - public static final int opc_if_icmplt = 161; - public static final int opc_if_icmpge = 162; - public static final int opc_if_icmpgt = 163; - public static final int opc_if_icmple = 164; - public static final int opc_if_acmpeq = 165; - public static final int opc_if_acmpne = 166; - public static final int opc_goto = 167; - public static final int opc_jsr = 168; - public static final int opc_ret = 169; - public static final int opc_tableswitch = 170; - public static final int opc_lookupswitch = 171; - public static final int opc_ireturn = 172; - public static final int opc_lreturn = 173; - public static final int opc_freturn = 174; - public static final int opc_dreturn = 175; - public static final int opc_areturn = 176; - public static final int opc_return = 177; - public static final int opc_getstatic = 178; - public static final int opc_putstatic = 179; - public static final int opc_getfield = 180; - public static final int opc_putfield = 181; - public static final int opc_invokevirtual = 182; - public static final int opc_invokenonvirtual = 183; - public static final int opc_invokespecial = 183; - public static final int opc_invokestatic = 184; - public static final int opc_invokeinterface = 185; -// public static final int opc_xxxunusedxxx = 186; - public static final int opc_new = 187; - public static final int opc_newarray = 188; - public static final int opc_anewarray = 189; - public static final int opc_arraylength = 190; - public static final int opc_athrow = 191; - public static final int opc_checkcast = 192; - public static final int opc_instanceof = 193; - public static final int opc_monitorenter = 194; - public static final int opc_monitorexit = 195; - public static final int opc_wide = 196; - public static final int opc_multianewarray = 197; - public static final int opc_ifnull = 198; - public static final int opc_ifnonnull = 199; - public static final int opc_goto_w = 200; - public static final int opc_jsr_w = 201; - /* Pseudo-instructions */ - public static final int opc_bytecode = 203; - public static final int opc_try = 204; - public static final int opc_endtry = 205; - public static final int opc_catch = 206; - public static final int opc_var = 207; - public static final int opc_endvar = 208; - public static final int opc_localsmap = 209; - public static final int opc_stackmap = 210; - /* PicoJava prefixes */ - public static final int opc_nonpriv = 254; - public static final int opc_priv = 255; - - /* Wide instructions */ - public static final int opc_iload_w = (opc_wide<<8)|opc_iload; - public static final int opc_lload_w = (opc_wide<<8)|opc_lload; - public static final int opc_fload_w = (opc_wide<<8)|opc_fload; - public static final int opc_dload_w = (opc_wide<<8)|opc_dload; - public static final int opc_aload_w = (opc_wide<<8)|opc_aload; - public static final int opc_istore_w = (opc_wide<<8)|opc_istore; - public static final int opc_lstore_w = (opc_wide<<8)|opc_lstore; - public static final int opc_fstore_w = (opc_wide<<8)|opc_fstore; - public static final int opc_dstore_w = (opc_wide<<8)|opc_dstore; - public static final int opc_astore_w = (opc_wide<<8)|opc_astore; - public static final int opc_ret_w = (opc_wide<<8)|opc_ret; - public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc; - - /* Opcode Names */ - public static final String opcNamesTab[] = { - "nop", - "aconst_null", - "iconst_m1", - "iconst_0", - "iconst_1", - "iconst_2", - "iconst_3", - "iconst_4", - "iconst_5", - "lconst_0", - "lconst_1", - "fconst_0", - "fconst_1", - "fconst_2", - "dconst_0", - "dconst_1", - "bipush", - "sipush", - "ldc", - "ldc_w", - "ldc2_w", - "iload", - "lload", - "fload", - "dload", - "aload", - "iload_0", - "iload_1", - "iload_2", - "iload_3", - "lload_0", - "lload_1", - "lload_2", - "lload_3", - "fload_0", - "fload_1", - "fload_2", - "fload_3", - "dload_0", - "dload_1", - "dload_2", - "dload_3", - "aload_0", - "aload_1", - "aload_2", - "aload_3", - "iaload", - "laload", - "faload", - "daload", - "aaload", - "baload", - "caload", - "saload", - "istore", - "lstore", - "fstore", - "dstore", - "astore", - "istore_0", - "istore_1", - "istore_2", - "istore_3", - "lstore_0", - "lstore_1", - "lstore_2", - "lstore_3", - "fstore_0", - "fstore_1", - "fstore_2", - "fstore_3", - "dstore_0", - "dstore_1", - "dstore_2", - "dstore_3", - "astore_0", - "astore_1", - "astore_2", - "astore_3", - "iastore", - "lastore", - "fastore", - "dastore", - "aastore", - "bastore", - "castore", - "sastore", - "pop", - "pop2", - "dup", - "dup_x1", - "dup_x2", - "dup2", - "dup2_x1", - "dup2_x2", - "swap", - "iadd", - "ladd", - "fadd", - "dadd", - "isub", - "lsub", - "fsub", - "dsub", - "imul", - "lmul", - "fmul", - "dmul", - "idiv", - "ldiv", - "fdiv", - "ddiv", - "irem", - "lrem", - "frem", - "drem", - "ineg", - "lneg", - "fneg", - "dneg", - "ishl", - "lshl", - "ishr", - "lshr", - "iushr", - "lushr", - "iand", - "land", - "ior", - "lor", - "ixor", - "lxor", - "iinc", - "i2l", - "i2f", - "i2d", - "l2i", - "l2f", - "l2d", - "f2i", - "f2l", - "f2d", - "d2i", - "d2l", - "d2f", - "i2b", - "i2c", - "i2s", - "lcmp", - "fcmpl", - "fcmpg", - "dcmpl", - "dcmpg", - "ifeq", - "ifne", - "iflt", - "ifge", - "ifgt", - "ifle", - "if_icmpeq", - "if_icmpne", - "if_icmplt", - "if_icmpge", - "if_icmpgt", - "if_icmple", - "if_acmpeq", - "if_acmpne", - "goto", - "jsr", - "ret", - "tableswitch", - "lookupswitch", - "ireturn", - "lreturn", - "freturn", - "dreturn", - "areturn", - "return", - "getstatic", - "putstatic", - "getfield", - "putfield", - "invokevirtual", - "invokespecial", // was "invokenonvirtual", - "invokestatic", - "invokeinterface", - "bytecode 186", //"xxxunusedxxx", - "new", - "newarray", - "anewarray", - "arraylength", - "athrow", - "checkcast", - "instanceof", - "monitorenter", - "monitorexit", - null, // "wide", - "multianewarray", - "ifnull", - "ifnonnull", - "goto_w", - "jsr_w", - "bytecode 202", // "breakpoint", - "bytecode", - "try", - "endtry", - "catch", - "var", - "endvar", - "locals_map", - "stack_map" - }; - - /* Opcode Lengths */ - public static final int opcLengthsTab[] = { - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, - 3, - 2, - 3, - 3, - 2, - 2, - 2, - 2, - 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 2, - 99, - 99, - 1, - 1, - 1, - 1, - 1, - 1, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 5, - 0, - 3, - 2, - 3, - 1, - 1, - 3, - 3, - 1, - 1, - 0, // wide - 4, - 3, - 3, - 5, - 5, - 1, - 1, 0, 0, 0, 0, 0 // pseudo - }; - -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/StackMapData.java --- a/rt/javap/src/main/java/org/apidesign/javap/StackMapData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -import java.util.*; -import java.io.*; - -import static org.apidesign.javap.RuntimeConstants.*; - -/* represents one entry of StackMap attribute - */ -class StackMapData { - final int offset; - final int[] locals; - final int[] stack; - - StackMapData(int offset, int[] locals, int[] stack) { - this.offset = offset; - this.locals = locals; - this.stack = stack; - } - - StackMapData(DataInputStream in, MethodData method) throws IOException { - offset = in.readUnsignedShort(); - int local_size = in.readUnsignedShort(); - locals = readTypeArray(in, local_size, method); - int stack_size = in.readUnsignedShort(); - stack = readTypeArray(in, stack_size, method); - } - - static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException { - int[] types = new int[length]; - for (int i=0; i= (stackMapTable[nextFrameIndex].offsetDelta - + 1))) { - final StackMapTableData nextFrame = stackMapTable[nextFrameIndex]; - - lastFrameByteCodeOffset += nextFrame.offsetDelta + 1; - nextFrame.applyTo(localTypes, stackTypes); - - ++nextFrameIndex; - } - } - - public void advanceTo(final int nextByteCodeOffset) { - advanceBy(nextByteCodeOffset - byteCodeOffset); - } - - private static TypeArray getArgTypes(final String methodSignature, - final boolean isStaticMethod) { - final TypeArray argTypes = new TypeArray(); - - if (!isStaticMethod) { - argTypes.add(ITEM_Object); - } - - if (methodSignature.charAt(0) != '(') { - throw new IllegalArgumentException("Invalid method signature"); - } - - final int length = methodSignature.length(); - boolean skipType = false; - int argType; - for (int i = 1; i < length; ++i) { - switch (methodSignature.charAt(i)) { - case 'B': - case 'C': - case 'S': - case 'Z': - case 'I': - argType = ITEM_Integer; - break; - case 'J': - argType = ITEM_Long; - break; - case 'F': - argType = ITEM_Float; - break; - case 'D': - argType = ITEM_Double; - break; - case 'L': { - i = methodSignature.indexOf(';', i + 1); - if (i == -1) { - throw new IllegalArgumentException( - "Invalid method signature"); - } - argType = ITEM_Object; - break; - } - case ')': - // not interested in the return value type - return argTypes; - case '[': - if (!skipType) { - argTypes.add(ITEM_Object); - skipType = true; - } - continue; - - default: - throw new IllegalArgumentException( - "Invalid method signature"); - } - - if (!skipType) { - argTypes.add(argType); - } else { - skipType = false; - } - } - - return argTypes; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/StackMapTableData.java --- a/rt/javap/src/main/java/org/apidesign/javap/StackMapTableData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -import java.io.*; - -import static org.apidesign.javap.RuntimeConstants.*; - -/* represents one entry of StackMapTable attribute - */ -abstract class StackMapTableData { - final int frameType; - int offsetDelta; - - StackMapTableData(int frameType) { - this.frameType = frameType; - } - - abstract void applyTo(TypeArray localTypes, TypeArray stackTypes); - - protected static String toString( - final String frameType, - final int offset, - final int[] localTypes, - final int[] stackTypes) { - final StringBuilder sb = new StringBuilder(frameType); - - sb.append("(off: +").append(offset); - if (localTypes != null) { - sb.append(", locals: "); - appendTypes(sb, localTypes); - } - if (stackTypes != null) { - sb.append(", stack: "); - appendTypes(sb, stackTypes); - } - sb.append(')'); - - return sb.toString(); - } - - private static void appendTypes(final StringBuilder sb, final int[] types) { - sb.append('['); - if (types.length > 0) { - sb.append(TypeArray.typeString(types[0])); - for (int i = 1; i < types.length; ++i) { - sb.append(", "); - sb.append(TypeArray.typeString(types[i])); - } - } - sb.append(']'); - } - - static class SameFrame extends StackMapTableData { - SameFrame(int frameType, int offsetDelta) { - super(frameType); - this.offsetDelta = offsetDelta; - } - - @Override - void applyTo(TypeArray localTypes, TypeArray stackTypes) { - stackTypes.clear(); - } - - @Override - public String toString() { - return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED) - ? "_FRAME_EXTENDED" : ""), - offsetDelta, - null, null); - } - } - - static class SameLocals1StackItem extends StackMapTableData { - final int[] stack; - SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) { - super(frameType); - this.offsetDelta = offsetDelta; - this.stack = stack; - } - - @Override - void applyTo(TypeArray localTypes, TypeArray stackTypes) { - stackTypes.setAll(stack); - } - - @Override - public String toString() { - return toString( - "SAME_LOCALS_1_STACK_ITEM" - + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) - ? "_EXTENDED" : ""), - offsetDelta, - null, stack); - } - } - - static class ChopFrame extends StackMapTableData { - ChopFrame(int frameType, int offsetDelta) { - super(frameType); - this.offsetDelta = offsetDelta; - } - - @Override - void applyTo(TypeArray localTypes, TypeArray stackTypes) { - localTypes.setSize(localTypes.getSize() - - (SAME_FRAME_EXTENDED - frameType)); - stackTypes.clear(); - } - - @Override - public String toString() { - return toString("CHOP", offsetDelta, null, null); - } - } - - static class AppendFrame extends StackMapTableData { - final int[] locals; - AppendFrame(int frameType, int offsetDelta, int[] locals) { - super(frameType); - this.offsetDelta = offsetDelta; - this.locals = locals; - } - - @Override - void applyTo(TypeArray localTypes, TypeArray stackTypes) { - localTypes.addAll(locals); - stackTypes.clear(); - } - - @Override - public String toString() { - return toString("APPEND", offsetDelta, locals, null); - } - } - - static class FullFrame extends StackMapTableData { - final int[] locals; - final int[] stack; - FullFrame(int offsetDelta, int[] locals, int[] stack) { - super(FULL_FRAME); - this.offsetDelta = offsetDelta; - this.locals = locals; - this.stack = stack; - } - - @Override - void applyTo(TypeArray localTypes, TypeArray stackTypes) { - localTypes.setAll(locals); - stackTypes.setAll(stack); - } - - @Override - public String toString() { - return toString("FULL", offsetDelta, locals, stack); - } - } - - static StackMapTableData getInstance(DataInputStream in, MethodData method) - throws IOException { - int frameType = in.readUnsignedByte(); - - if (frameType < SAME_FRAME_BOUND) { - // same_frame - return new SameFrame(frameType, frameType); - } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) { - // same_locals_1_stack_item_frame - // read additional single stack element - return new SameLocals1StackItem(frameType, - (frameType - SAME_FRAME_BOUND), - StackMapData.readTypeArray(in, 1, method)); - } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { - // same_locals_1_stack_item_extended - return new SameLocals1StackItem(frameType, - in.readUnsignedShort(), - StackMapData.readTypeArray(in, 1, method)); - } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) { - // chop_frame or same_frame_extended - return new ChopFrame(frameType, in.readUnsignedShort()); - } else if (frameType == SAME_FRAME_EXTENDED) { - // chop_frame or same_frame_extended - return new SameFrame(frameType, in.readUnsignedShort()); - } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) { - // append_frame - return new AppendFrame(frameType, in.readUnsignedShort(), - StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method)); - } else if (frameType == FULL_FRAME) { - // full_frame - int offsetDelta = in.readUnsignedShort(); - int locals_size = in.readUnsignedShort(); - int[] locals = StackMapData.readTypeArray(in, locals_size, method); - int stack_size = in.readUnsignedShort(); - int[] stack = StackMapData.readTypeArray(in, stack_size, method); - return new FullFrame(offsetDelta, locals, stack); - } else { - throw new ClassFormatError("unrecognized frame_type in StackMapTable"); - } - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/TrapData.java --- a/rt/javap/src/main/java/org/apidesign/javap/TrapData.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.apidesign.javap; - -import java.io.*; - -/** - * Stores exception table data in code attribute. - * - * @author Sucheta Dambalkar (Adopted code from jdis) - */ -public final class TrapData { - public final short start_pc; - public final short end_pc; - public final short handler_pc; - public final short catch_cpx; - final int num; - - - /** - * Read and store exception table data in code attribute. - */ - TrapData(DataInputStream in, int num) throws IOException { - this.num=num; - start_pc = in.readShort(); - end_pc=in.readShort(); - handler_pc=in.readShort(); - catch_cpx=in.readShort(); - } - - /** - * returns recommended identifier - */ - public String ident() { - return "t"+num; - } - -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/TrapDataIterator.java --- a/rt/javap/src/main/java/org/apidesign/javap/TrapDataIterator.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +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.javap; - -/** - * - * @author Jaroslav Tulach - */ -public final class TrapDataIterator { - private final Hashtable exStart = new Hashtable(); - private final Hashtable exStop = new Hashtable(); - private TrapData[] current = new TrapData[10]; - private int currentCount; - - TrapDataIterator(Vector exceptionTable) { - for (int i=0 ; i < exceptionTable.size(); i++) { - final TrapData td = (TrapData)exceptionTable.elementAt(i); - put(exStart, td.start_pc, td); - put(exStop, td.end_pc, td); - } - } - - private static void put(Hashtable h, short key, TrapData td) { - Short s = Short.valueOf((short)key); - Vector v = (Vector) h.get(s); - if (v == null) { - v = new Vector(1); - h.put(s, v); - } - v.add(td); - } - - private boolean processAll(Hashtable h, Short key, boolean add) { - boolean change = false; - Vector v = (Vector)h.get(key); - if (v != null) { - int s = v.size(); - for (int i = 0; i < s; i++) { - TrapData td = (TrapData)v.elementAt(i); - if (add) { - add(td); - change = true; - } else { - remove(td); - change = true; - } - } - } - return change; - } - - public boolean advanceTo(int i) { - Short s = Short.valueOf((short)i); - boolean ch1 = processAll(exStart, s, true); - boolean ch2 = processAll(exStop, s, false); - return ch1 || ch2; - } - - public boolean useTry() { - return currentCount > 0; - } - - public TrapData[] current() { - TrapData[] copy = new TrapData[currentCount]; - for (int i = 0; i < currentCount; i++) { - copy[i] = current[i]; - } - return copy; - } - - private void add(TrapData e) { - if (currentCount == current.length) { - TrapData[] data = new TrapData[currentCount * 2]; - for (int i = 0; i < currentCount; i++) { - data[i] = current[i]; - } - current = data; - } - current[currentCount++] = e; - } - - private void remove(TrapData e) { - if (currentCount == 0) { - return; - } - int from = 0; - while (from < currentCount) { - if (e == current[from++]) { - break; - } - } - while (from < currentCount) { - current[from - 1] = current[from]; - current[from] = null; - from++; - } - currentCount--; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/TypeArray.java --- a/rt/javap/src/main/java/org/apidesign/javap/TypeArray.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.apidesign.javap; - -import static org.apidesign.javap.RuntimeConstants.ITEM_Bogus; -import static org.apidesign.javap.RuntimeConstants.ITEM_Integer; -import static org.apidesign.javap.RuntimeConstants.ITEM_Float; -import static org.apidesign.javap.RuntimeConstants.ITEM_Double; -import static org.apidesign.javap.RuntimeConstants.ITEM_Long; -import static org.apidesign.javap.RuntimeConstants.ITEM_Null; -import static org.apidesign.javap.RuntimeConstants.ITEM_InitObject; -import static org.apidesign.javap.RuntimeConstants.ITEM_Object; -import static org.apidesign.javap.RuntimeConstants.ITEM_NewObject; - -public final class TypeArray { - private static final int CAPACITY_INCREMENT = 16; - - private int[] types; - private int size; - - public TypeArray() { - } - - public TypeArray(final TypeArray initialTypes) { - setAll(initialTypes); - } - - public void add(final int newType) { - ensureCapacity(size + 1); - types[size++] = newType; - } - - public void addAll(final TypeArray newTypes) { - addAll(newTypes.types, 0, newTypes.size); - } - - public void addAll(final int[] newTypes) { - addAll(newTypes, 0, newTypes.length); - } - - public void addAll(final int[] newTypes, - final int offset, - final int count) { - if (count > 0) { - ensureCapacity(size + count); - arraycopy(newTypes, offset, types, size, count); - size += count; - } - } - - public void set(final int index, final int newType) { - types[index] = newType; - } - - public void setAll(final TypeArray newTypes) { - setAll(newTypes.types, 0, newTypes.size); - } - - public void setAll(final int[] newTypes) { - setAll(newTypes, 0, newTypes.length); - } - - public void setAll(final int[] newTypes, - final int offset, - final int count) { - if (count > 0) { - ensureCapacity(count); - arraycopy(newTypes, offset, types, 0, count); - size = count; - } else { - clear(); - } - } - - public void setSize(final int newSize) { - if (size != newSize) { - ensureCapacity(newSize); - - for (int i = size; i < newSize; ++i) { - types[i] = 0; - } - size = newSize; - } - } - - public void clear() { - size = 0; - } - - public int getSize() { - return size; - } - - public int get(final int index) { - return types[index]; - } - - public static String typeString(final int type) { - switch (type & 0xff) { - case ITEM_Bogus: - return "_top_"; - case ITEM_Integer: - return "_int_"; - case ITEM_Float: - return "_float_"; - case ITEM_Double: - return "_double_"; - case ITEM_Long: - return "_long_"; - case ITEM_Null: - return "_null_"; - case ITEM_InitObject: // UninitializedThis - return "_init_"; - case ITEM_Object: - return "_object_"; - case ITEM_NewObject: // Uninitialized - return "_new_"; - default: - throw new IllegalArgumentException("Unknown type"); - } - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("["); - if (size > 0) { - sb.append(typeString(types[0])); - for (int i = 1; i < size; ++i) { - sb.append(", "); - sb.append(typeString(types[i])); - } - } - - return sb.append(']').toString(); - } - - private void ensureCapacity(final int minCapacity) { - if ((minCapacity == 0) - || (types != null) && (minCapacity <= types.length)) { - return; - } - - final int newCapacity = - ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT) - * CAPACITY_INCREMENT; - final int[] newTypes = new int[newCapacity]; - - if (size > 0) { - arraycopy(types, 0, newTypes, 0, size); - } - - types = newTypes; - } - - // no System.arraycopy - private void arraycopy(final int[] src, final int srcPos, - final int[] dest, final int destPos, - final int length) { - for (int i = 0; i < length; ++i) { - dest[destPos + i] = src[srcPos + i]; - } - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/javap/src/main/java/org/apidesign/javap/Vector.java --- a/rt/javap/src/main/java/org/apidesign/javap/Vector.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +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.javap; - -import org.apidesign.bck2brwsr.core.JavaScriptBody; -import org.apidesign.bck2brwsr.core.JavaScriptPrototype; - -/** A JavaScript ready replacement for java.util.Vector - * - * @author Jaroslav Tulach - */ -@JavaScriptPrototype(prototype = "new Array" ) -final class Vector { - private Object[] arr; - - Vector() { - } - - Vector(int i) { - } - - void add(Object objectType) { - addElement(objectType); - } - @JavaScriptBody(args = { "obj" }, body = - "this.push(obj);" - ) - void addElement(Object obj) { - final int s = size(); - setSize(s + 1); - setElementAt(obj, s); - } - - @JavaScriptBody(args = { }, body = - "return this.length;" - ) - int size() { - return arr == null ? 0 : arr.length; - } - - @JavaScriptBody(args = { "newArr" }, body = - "for (var i = 0; i < this.length; i++) {\n" - + " newArr[i] = this[i];\n" - + "}\n") - void copyInto(Object[] newArr) { - if (arr == null) { - return; - } - int min = Math.min(newArr.length, arr.length); - for (int i = 0; i < min; i++) { - newArr[i] = arr[i]; - } - } - - @JavaScriptBody(args = { "index" }, body = - "return this[index];" - ) - Object elementAt(int index) { - return arr[index]; - } - - private void setSize(int len) { - Object[] newArr = new Object[len]; - copyInto(newArr); - arr = newArr; - } - - @JavaScriptBody(args = { "val", "index" }, body = - "this[index] = val;" - ) - void setElementAt(Object val, int index) { - arr[index] = val; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/launcher/pom.xml --- a/rt/launcher/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ - - - 4.0.0 - - org.apidesign.bck2brwsr - rt - 0.4-SNAPSHOT - - org.apidesign.bck2brwsr - launcher - 0.4-SNAPSHOT - Bck2Brwsr Launcher - http://maven.apache.org - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-javadoc-plugin - - org.apidesign.bck2brwsr.launcher.impl - false - - - - - - UTF-8 - - - - junit - junit - 3.8.1 - test - - - org.glassfish.grizzly - grizzly-http-server - 2.2.19 - - - ${project.groupId} - vm4brwsr - ${project.version} - - - diff -r d127d41768bd -r ae3f2aa50970 rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,570 +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.launcher; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.io.Writer; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.apidesign.bck2brwsr.launcher.InvocationContext.Resource; -import org.apidesign.vm4brwsr.Bck2Brwsr; -import org.glassfish.grizzly.PortRange; -import org.glassfish.grizzly.http.server.HttpHandler; -import org.glassfish.grizzly.http.server.HttpServer; -import org.glassfish.grizzly.http.server.NetworkListener; -import org.glassfish.grizzly.http.server.Request; -import org.glassfish.grizzly.http.server.Response; -import org.glassfish.grizzly.http.server.ServerConfiguration; -import org.glassfish.grizzly.http.util.HttpStatus; - -/** - * Lightweight server to launch Bck2Brwsr applications and tests. - * Supports execution in native browser as well as Java's internal - * execution engine. - */ -final class Bck2BrwsrLauncher extends Launcher implements Closeable { - private static final Logger LOG = Logger.getLogger(Bck2BrwsrLauncher.class.getName()); - private static final InvocationContext END = new InvocationContext(null, null, null); - private final Set loaders = new LinkedHashSet<>(); - private final BlockingQueue methods = new LinkedBlockingQueue<>(); - private long timeOut; - private final Res resources = new Res(); - private final String cmd; - private Object[] brwsr; - private HttpServer server; - private CountDownLatch wait; - - public Bck2BrwsrLauncher(String cmd) { - this.cmd = cmd; - } - - @Override - InvocationContext runMethod(InvocationContext c) throws IOException { - loaders.add(c.clazz.getClassLoader()); - methods.add(c); - try { - c.await(timeOut); - } catch (InterruptedException ex) { - throw new IOException(ex); - } - return c; - } - - public void setTimeout(long ms) { - timeOut = ms; - } - - public void addClassLoader(ClassLoader url) { - this.loaders.add(url); - } - - public void showURL(String startpage) throws IOException { - if (!startpage.startsWith("/")) { - startpage = "/" + startpage; - } - HttpServer s = initServer(".", true); - int last = startpage.lastIndexOf('/'); - String simpleName = startpage.substring(last); - s.getServerConfiguration().addHttpHandler(new Page(resources, startpage), simpleName); - s.getServerConfiguration().addHttpHandler(new Page(resources, null), "/"); - try { - launchServerAndBrwsr(s, simpleName); - } catch (URISyntaxException | InterruptedException ex) { - throw new IOException(ex); - } - } - - void showDirectory(File dir, String startpage) throws IOException { - if (!startpage.startsWith("/")) { - startpage = "/" + startpage; - } - HttpServer s = initServer(dir.getPath(), false); - try { - launchServerAndBrwsr(s, startpage); - } catch (URISyntaxException | InterruptedException ex) { - throw new IOException(ex); - } - } - - @Override - public void initialize() throws IOException { - try { - executeInBrowser(); - } catch (InterruptedException ex) { - final InterruptedIOException iio = new InterruptedIOException(ex.getMessage()); - iio.initCause(ex); - throw iio; - } catch (Exception ex) { - if (ex instanceof IOException) { - throw (IOException)ex; - } - if (ex instanceof RuntimeException) { - throw (RuntimeException)ex; - } - throw new IOException(ex); - } - } - - private HttpServer initServer(String path, boolean addClasses) throws IOException { - HttpServer s = HttpServer.createSimpleServer(path, new PortRange(8080, 65535)); - - final ServerConfiguration conf = s.getServerConfiguration(); - if (addClasses) { - conf.addHttpHandler(new VM(resources), "/bck2brwsr.js"); - conf.addHttpHandler(new Classes(resources), "/classes/"); - } - return s; - } - - private void executeInBrowser() throws InterruptedException, URISyntaxException, IOException { - wait = new CountDownLatch(1); - server = initServer(".", true); - final ServerConfiguration conf = server.getServerConfiguration(); - - class DynamicResourceHandler extends HttpHandler { - private final InvocationContext ic; - public DynamicResourceHandler(InvocationContext ic) { - if (ic == null || ic.resources.isEmpty()) { - throw new NullPointerException(); - } - this.ic = ic; - for (Resource r : ic.resources) { - conf.addHttpHandler(this, r.httpPath); - } - } - - public void close() { - conf.removeHttpHandler(this); - } - - @Override - public void service(Request request, Response response) throws Exception { - for (Resource r : ic.resources) { - if (r.httpPath.equals(request.getRequestURI())) { - LOG.log(Level.INFO, "Serving HttpResource for {0}", request.getRequestURI()); - response.setContentType(r.httpType); - copyStream(r.httpContent, response.getOutputStream(), null); - } - } - } - } - - conf.addHttpHandler(new Page(resources, - "org/apidesign/bck2brwsr/launcher/harness.xhtml" - ), "/execute"); - - conf.addHttpHandler(new HttpHandler() { - int cnt; - List cases = new ArrayList<>(); - DynamicResourceHandler prev; - @Override - public void service(Request request, Response response) throws Exception { - String id = request.getParameter("request"); - String value = request.getParameter("result"); - if (value != null && value.indexOf((char)0xC5) != -1) { - value = toUTF8(value); - } - - - InvocationContext mi = null; - int caseNmbr = -1; - - if (id != null && value != null) { - LOG.log(Level.INFO, "Received result for case {0} = {1}", new Object[]{id, value}); - value = decodeURL(value); - int indx = Integer.parseInt(id); - cases.get(indx).result(value, null); - if (++indx < cases.size()) { - mi = cases.get(indx); - LOG.log(Level.INFO, "Re-executing case {0}", indx); - caseNmbr = indx; - } - } else { - if (!cases.isEmpty()) { - LOG.info("Re-executing test cases"); - mi = cases.get(0); - caseNmbr = 0; - } - } - - if (prev != null) { - prev.close(); - prev = null; - } - - if (mi == null) { - mi = methods.take(); - caseNmbr = cnt++; - } - if (mi == END) { - response.getWriter().write(""); - wait.countDown(); - cnt = 0; - LOG.log(Level.INFO, "End of data reached. Exiting."); - return; - } - - if (!mi.resources.isEmpty()) { - prev = new DynamicResourceHandler(mi); - } - - cases.add(mi); - final String cn = mi.clazz.getName(); - final String mn = mi.methodName; - LOG.log(Level.INFO, "Request for {0} case. Sending {1}.{2}", new Object[]{caseNmbr, cn, mn}); - response.getWriter().write("{" - + "className: '" + cn + "', " - + "methodName: '" + mn + "', " - + "request: " + caseNmbr - ); - if (mi.html != null) { - response.getWriter().write(", html: '"); - response.getWriter().write(encodeJSON(mi.html)); - response.getWriter().write("'"); - } - response.getWriter().write("}"); - } - }, "/data"); - - this.brwsr = launchServerAndBrwsr(server, "/execute"); - } - - private static String encodeJSON(String in) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < in.length(); i++) { - char ch = in.charAt(i); - if (ch < 32 || ch == '\'' || ch == '"') { - sb.append("\\u"); - String hs = "0000" + Integer.toHexString(ch); - hs = hs.substring(hs.length() - 4); - sb.append(hs); - } else { - sb.append(ch); - } - } - return sb.toString(); - } - - @Override - public void shutdown() throws IOException { - methods.offer(END); - for (;;) { - int prev = methods.size(); - try { - if (wait != null && wait.await(timeOut, TimeUnit.MILLISECONDS)) { - break; - } - } catch (InterruptedException ex) { - throw new IOException(ex); - } - if (prev == methods.size()) { - LOG.log( - Level.WARNING, - "Timeout and no test has been executed meanwhile (at {0}). Giving up.", - methods.size() - ); - break; - } - LOG.log(Level.INFO, - "Timeout, but tests got from {0} to {1}. Trying again.", - new Object[]{prev, methods.size()} - ); - } - stopServerAndBrwsr(server, brwsr); - } - - static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException { - for (;;) { - int ch = is.read(); - if (ch == -1) { - break; - } - if (ch == '$' && params.length > 0) { - int cnt = is.read() - '0'; - if (cnt == 'U' - '0') { - os.write(baseURL.getBytes("UTF-8")); - } - if (cnt >= 0 && cnt < params.length) { - os.write(params[cnt].getBytes("UTF-8")); - } - } else { - os.write(ch); - } - } - } - - private Object[] launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException { - server.start(); - NetworkListener listener = server.getListeners().iterator().next(); - int port = listener.getPort(); - - URI uri = new URI("http://localhost:" + port + page); - LOG.log(Level.INFO, "Showing {0}", uri); - if (cmd == null) { - try { - LOG.log(Level.INFO, "Trying Desktop.browse on {0} {2} by {1}", new Object[] { - System.getProperty("java.vm.name"), - System.getProperty("java.vm.vendor"), - System.getProperty("java.vm.version"), - }); - java.awt.Desktop.getDesktop().browse(uri); - LOG.log(Level.INFO, "Desktop.browse successfully finished"); - return null; - } catch (UnsupportedOperationException ex) { - LOG.log(Level.INFO, "Desktop.browse not supported: {0}", ex.getMessage()); - LOG.log(Level.FINE, null, ex); - } - } - { - String cmdName = cmd == null ? "xdg-open" : cmd; - String[] cmdArr = { - cmdName, uri.toString() - }; - LOG.log(Level.INFO, "Launching {0}", Arrays.toString(cmdArr)); - final Process process = Runtime.getRuntime().exec(cmdArr); - return new Object[] { process, null }; - } - } - private static String toUTF8(String value) throws UnsupportedEncodingException { - byte[] arr = new byte[value.length()]; - for (int i = 0; i < arr.length; i++) { - arr[i] = (byte)value.charAt(i); - } - return new String(arr, "UTF-8"); - } - - private static String decodeURL(String s) { - for (;;) { - int pos = s.indexOf('%'); - if (pos == -1) { - return s; - } - int i = Integer.parseInt(s.substring(pos + 1, pos + 2), 16); - s = s.substring(0, pos) + (char)i + s.substring(pos + 2); - } - } - - private void stopServerAndBrwsr(HttpServer server, Object[] brwsr) throws IOException { - if (brwsr == null) { - return; - } - Process process = (Process)brwsr[0]; - - server.stop(); - InputStream stdout = process.getInputStream(); - InputStream stderr = process.getErrorStream(); - drain("StdOut", stdout); - drain("StdErr", stderr); - process.destroy(); - int res; - try { - res = process.waitFor(); - } catch (InterruptedException ex) { - throw new IOException(ex); - } - LOG.log(Level.INFO, "Exit code: {0}", res); - - deleteTree((File)brwsr[1]); - } - - private static void drain(String name, InputStream is) throws IOException { - int av = is.available(); - if (av > 0) { - StringBuilder sb = new StringBuilder(); - sb.append("v== ").append(name).append(" ==v\n"); - while (av-- > 0) { - sb.append((char)is.read()); - } - sb.append("\n^== ").append(name).append(" ==^"); - LOG.log(Level.INFO, sb.toString()); - } - } - - private void deleteTree(File file) { - if (file == null) { - return; - } - File[] arr = file.listFiles(); - if (arr != null) { - for (File s : arr) { - deleteTree(s); - } - } - file.delete(); - } - - @Override - public void close() throws IOException { - shutdown(); - } - - private class Res implements Bck2Brwsr.Resources { - @Override - public InputStream get(String resource) throws IOException { - for (ClassLoader l : loaders) { - URL u = null; - Enumeration en = l.getResources(resource); - while (en.hasMoreElements()) { - u = en.nextElement(); - } - if (u != null) { - return u.openStream(); - } - } - throw new IOException("Can't find " + resource); - } - } - - private static class Page extends HttpHandler { - private final String resource; - private final String[] args; - private final Res res; - - public Page(Res res, String resource, String... args) { - this.res = res; - this.resource = resource; - this.args = args.length == 0 ? new String[] { "$0" } : args; - } - - @Override - public void service(Request request, Response response) throws Exception { - String r = resource; - if (r == null) { - r = request.getHttpHandlerPath(); - } - if (r.startsWith("/")) { - r = r.substring(1); - } - String[] replace = {}; - if (r.endsWith(".html")) { - response.setContentType("text/html"); - LOG.info("Content type text/html"); - replace = args; - } - if (r.endsWith(".xhtml")) { - response.setContentType("application/xhtml+xml"); - LOG.info("Content type application/xhtml+xml"); - replace = args; - } - OutputStream os = response.getOutputStream(); - try (InputStream is = res.get(r)) { - copyStream(is, os, request.getRequestURL().toString(), replace); - } catch (IOException ex) { - response.setDetailMessage(ex.getLocalizedMessage()); - response.setError(); - response.setStatus(404); - } - } - } - - private static class VM extends HttpHandler { - private final String bck2brwsr; - - public VM(Res loader) throws IOException { - StringBuilder sb = new StringBuilder(); - Bck2Brwsr.generate(sb, loader); - sb.append( - "(function WrapperVM(global) {" - + " function ldCls(res) {\n" - + " var request = new XMLHttpRequest();\n" - + " request.open('GET', '/classes/' + res, false);\n" - + " request.send();\n" - + " if (request.status !== 200) return null;\n" - + " var arr = eval('(' + request.responseText + ')');\n" - + " return arr;\n" - + " }\n" - + " var prevvm = global.bck2brwsr;\n" - + " global.bck2brwsr = function() {\n" - + " var args = Array.prototype.slice.apply(arguments);\n" - + " args.unshift(ldCls);\n" - + " return prevvm.apply(null, args);\n" - + " };\n" - + "})(this);\n" - ); - this.bck2brwsr = sb.toString(); - } - - @Override - public void service(Request request, Response response) throws Exception { - response.setCharacterEncoding("UTF-8"); - response.setContentType("text/javascript"); - response.getWriter().write(bck2brwsr); - } - } - - private static class Classes extends HttpHandler { - private final Res loader; - - public Classes(Res loader) { - this.loader = loader; - } - - @Override - public void service(Request request, Response response) throws Exception { - String res = request.getHttpHandlerPath(); - if (res.startsWith("/")) { - res = res.substring(1); - } - try (InputStream is = loader.get(res)) { - response.setContentType("text/javascript"); - Writer w = response.getWriter(); - w.append("["); - for (int i = 0;; i++) { - int b = is.read(); - if (b == -1) { - break; - } - if (i > 0) { - w.append(", "); - } - if (i % 20 == 0) { - w.write("\n"); - } - if (b > 127) { - b = b - 256; - } - w.append(Integer.toString(b)); - } - w.append("\n]"); - } catch (IOException ex) { - response.setStatus(HttpStatus.NOT_FOUND_404); - response.setError(); - response.setDetailMessage(ex.getMessage()); - } - } - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +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.launcher; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** Represents individual method invocation, its context and its result. - * - * @author Jaroslav Tulach - */ -public final class InvocationContext { - final CountDownLatch wait = new CountDownLatch(1); - final Class clazz; - final String methodName; - private final Launcher launcher; - private String result; - private Throwable exception; - String html; - final List resources = new ArrayList<>(); - - InvocationContext(Launcher launcher, Class clazz, String methodName) { - this.launcher = launcher; - this.clazz = clazz; - this.methodName = methodName; - } - - /** An HTML fragment to be available for the execution. Useful primarily when - * executing in a browser via {@link Launcher#createBrowser(java.lang.String)}. - * @param html the html fragment - */ - public void setHtmlFragment(String html) { - this.html = html; - } - - /** HTTP resource to be available during execution. An invocation may - * perform an HTTP query and obtain a resource relative to the page. - */ - public void addHttpResource(String relativePath, String mimeType, InputStream content) { - if (relativePath == null || mimeType == null || content == null) { - throw new NullPointerException(); - } - resources.add(new Resource(content, mimeType, relativePath)); - } - - /** Invokes the associated method. - * @return the textual result of the invocation - */ - public String invoke() throws IOException { - launcher.runMethod(this); - return toString(); - } - - /** Obtains textual result of the invocation. - * @return text representing the exception or result value - */ - @Override - public String toString() { - if (exception != null) { - return exception.toString(); - } - return result; - } - - /** - * @param timeOut - * @throws InterruptedException - */ - void await(long timeOut) throws InterruptedException { - wait.await(timeOut, TimeUnit.MILLISECONDS); - } - - void result(String r, Throwable e) { - this.result = r; - this.exception = e; - wait.countDown(); - } - - - static final class Resource { - final InputStream httpContent; - final String httpType; - final String httpPath; - - Resource(InputStream httpContent, String httpType, String httpPath) { - this.httpContent = httpContent; - this.httpType = httpType; - this.httpPath = httpPath; - } - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +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.launcher; - -import org.apidesign.bck2brwsr.launcher.impl.Console; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Enumeration; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.script.Invocable; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; -import org.apidesign.vm4brwsr.Bck2Brwsr; - -/** - * Tests execution in Java's internal scripting engine. - */ -final class JSLauncher extends Launcher { - private static final Logger LOG = Logger.getLogger(JSLauncher.class.getName()); - private Set loaders = new LinkedHashSet<>(); - private final Res resources = new Res(); - private Invocable code; - private StringBuilder codeSeq; - private Object console; - - - @Override InvocationContext runMethod(InvocationContext mi) { - loaders.add(mi.clazz.getClassLoader()); - try { - long time = System.currentTimeMillis(); - LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.clazz.getName(), mi.methodName}); - String res = code.invokeMethod( - console, - "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2", - mi.clazz.getName(), mi.methodName).toString(); - time = System.currentTimeMillis() - time; - LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.clazz.getName(), mi.methodName, res, time}); - mi.result(res, null); - } catch (ScriptException | NoSuchMethodException ex) { - mi.result(null, ex); - } - return mi; - } - - public void addClassLoader(ClassLoader url) { - this.loaders.add(url); - } - - @Override - public void initialize() throws IOException { - try { - initRhino(); - } catch (Exception ex) { - if (ex instanceof IOException) { - throw (IOException)ex; - } - if (ex instanceof RuntimeException) { - throw (RuntimeException)ex; - } - throw new IOException(ex); - } - } - - private void initRhino() throws IOException, ScriptException, NoSuchMethodException { - StringBuilder sb = new StringBuilder(); - Bck2Brwsr.generate(sb, new Res()); - - ScriptEngineManager sem = new ScriptEngineManager(); - ScriptEngine mach = sem.getEngineByExtension("js"); - - sb.append( - "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.impl.Console.read);" - + "\nfunction initVM() { return vm; };" - + "\n"); - - Object res = mach.eval(sb.toString()); - if (!(mach instanceof Invocable)) { - throw new IOException("It is invocable object: " + res); - } - code = (Invocable) mach; - codeSeq = sb; - - Object vm = code.invokeFunction("initVM"); - console = code.invokeMethod(vm, "loadClass", Console.class.getName()); - } - - @Override - public void shutdown() throws IOException { - } - - @Override - public String toString() { - return codeSeq.toString(); - } - - private class Res implements Bck2Brwsr.Resources { - @Override - public InputStream get(String resource) throws IOException { - for (ClassLoader l : loaders) { - URL u = null; - Enumeration en = l.getResources(resource); - while (en.hasMoreElements()) { - u = en.nextElement(); - } - if (u != null) { - return u.openStream(); - } - } - throw new IOException("Can't find " + resource); - } - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +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.launcher; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.net.URLClassLoader; -import org.apidesign.vm4brwsr.Bck2Brwsr; - -/** An abstraction for executing tests in a Bck2Brwsr virtual machine. - * Either in {@linkm Launcher#createJavaScript JavaScript engine}, - * or in {@linkm Launcher#createBrowser external browser}. - *

- * There also are methods to {@link #showDir(java.io.File, java.lang.String) display pages} - * in an external browser served by internal HTTP server. - * - * @author Jaroslav Tulach - */ -public abstract class Launcher { - - Launcher() { - } - - /** Initializes the launcher. This may mean starting a web browser or - * initializing execution engine. - * @throws IOException if something goes wrong - */ - public abstract void initialize() throws IOException; - - /** Shuts down the launcher. - * @throws IOException if something goes wrong - */ - public abstract void shutdown() throws IOException; - - - /** Builds an invocation context. The context can later be customized - * and {@link InvocationContext#invoke() invoked}. - * - * @param clazz the class to execute method from - * @param method the method to execute - * @return the context pointing to the selected method - */ - public InvocationContext createInvocation(Class clazz, String method) { - return new InvocationContext(this, clazz, method); - } - - - /** Creates launcher that uses internal JavaScript engine (Rhino). - * @return the launcher - */ - public static Launcher createJavaScript() { - final JSLauncher l = new JSLauncher(); - l.addClassLoader(Bck2Brwsr.class.getClassLoader()); - return l; - } - - /** Creates launcher that is using external browser. - * - * @param cmd null to use java.awt.Desktop to show the launcher - * or a string to execute in an external process (with a parameter to the URL) - * @return launcher executing in external browser. - */ - public static Launcher createBrowser(String cmd) { - final Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(cmd); - l.addClassLoader(Bck2Brwsr.class.getClassLoader()); - l.setTimeout(180000); - return l; - } - - /** Starts an HTTP server which provides access to classes and resources - * available in the classes URL and shows a start page - * available as {@link ClassLoader#getResource(java.lang.String)} from the - * provide classloader. Opens a browser with URL showing the start page. - * - * @param classes classloader offering access to classes and resources - * @param startpage page to show in the browser - * @return interface that allows one to stop the server - * @throws IOException if something goes wrong - */ - public static Closeable showURL(URLClassLoader classes, String startpage) throws IOException { - Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(null); - l.addClassLoader(classes); - l.showURL(startpage); - return l; - } - /** Starts an HTTP server which provides access to certain directory. - * The startpage should be relative location inside the root - * directory. Opens a browser with URL showing the start page. - * - * @param directory the root directory on disk - * @param startpage relative path from the root to the page - * @exception IOException if something goes wrong. - */ - public static Closeable showDir(File directory, String startpage) throws IOException { - Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(null); - l.showDirectory(directory, startpage); - return l; - } - - abstract InvocationContext runMethod(InvocationContext c) throws IOException; -} diff -r d127d41768bd -r ae3f2aa50970 rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,260 +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.launcher.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.net.URL; -import java.util.Enumeration; -import org.apidesign.bck2brwsr.core.JavaScriptBody; - -/** - * - * @author Jaroslav Tulach - */ -public class Console { - private Console() { - } - static { - turnAssetionStatusOn(); - } - - @JavaScriptBody(args = {"id", "attr"}, body = - "return window.document.getElementById(id)[attr].toString();") - private static native Object getAttr(String id, String attr); - - @JavaScriptBody(args = {"id", "attr", "value"}, body = - "window.document.getElementById(id)[attr] = value;") - private static native void setAttr(String id, String attr, Object value); - - @JavaScriptBody(args = {}, body = "return; window.close();") - private static native void closeWindow(); - - private static void log(String newText) { - String id = "bck2brwsr.result"; - String attr = "value"; - setAttr(id, attr, getAttr(id, attr) + "\n" + newText); - setAttr(id, "scrollTop", getAttr(id, "scrollHeight")); - } - - public static void execute() throws Exception { - String clazz = (String) getAttr("clazz", "value"); - String method = (String) getAttr("method", "value"); - Object res = invokeMethod(clazz, method); - setAttr("bck2brwsr.result", "value", res); - } - - @JavaScriptBody(args = { "url", "callback", "arr" }, body = "" - + "var request = new XMLHttpRequest();\n" - + "request.open('GET', url, true);\n" - + "request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n" - + "request.onreadystatechange = function() {\n" - + " if (this.readyState!==4) return;\n" - + " arr[0] = this.responseText;\n" - + " callback.run__V();\n" - + "};" - + "request.send();" - ) - private static native void loadText(String url, Runnable callback, String[] arr) throws IOException; - - public static void harness(String url) throws IOException { - log("Connecting to " + url); - Request r = new Request(url); - } - - private static class Request implements Runnable { - private final String[] arr = { null }; - private final String url; - - private Request(String url) throws IOException { - this.url = url; - loadText(url, this, arr); - } - - @Override - public void run() { - try { - String data = arr[0]; - log("\nGot \"" + data + "\""); - - if (data == null) { - log("Some error exiting"); - closeWindow(); - return; - } - - if (data.isEmpty()) { - log("No data, exiting"); - closeWindow(); - return; - } - - Case c = Case.parseData(data); - if (c.getHtmlFragment() != null) { - setAttr("bck2brwsr.fragment", "innerHTML", c.getHtmlFragment()); - } - log("Invoking " + c.getClassName() + '.' + c.getMethodName() + " as request: " + c.getRequestId()); - - Object result = invokeMethod(c.getClassName(), c.getMethodName()); - - setAttr("bck2brwsr.fragment", "innerHTML", ""); - log("Result: " + result); - - result = encodeURL("" + result); - - log("Sending back: " + url + "?request=" + c.getRequestId() + "&result=" + result); - String u = url + "?request=" + c.getRequestId() + "&result=" + result; - - loadText(u, this, arr); - - } catch (Exception ex) { - log(ex.getClass().getName() + ":" + ex.getMessage()); - } - } - } - - private static String encodeURL(String r) throws UnsupportedEncodingException { - final String SPECIAL = "%$&+,/:;=?@"; - StringBuilder sb = new StringBuilder(); - byte[] utf8 = r.getBytes("UTF-8"); - for (int i = 0; i < utf8.length; i++) { - int ch = utf8[i] & 0xff; - if (ch < 32 || ch > 127 || SPECIAL.indexOf(ch) >= 0) { - final String numbers = "0" + Integer.toHexString(ch); - sb.append("%").append(numbers.substring(numbers.length() - 2)); - } else { - if (ch == 32) { - sb.append("+"); - } else { - sb.append((char)ch); - } - } - } - return sb.toString(); - } - - static String invoke(String clazz, String method) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException { - final Object r = invokeMethod(clazz, method); - return r == null ? "null" : r.toString().toString(); - } - - /** Helper method that inspects the classpath and loads given resource - * (usually a class file). Used while running tests in Rhino. - * - * @param name resource name to find - * @return the array of bytes in the given resource - * @throws IOException I/O in case something goes wrong - */ - public static byte[] read(String name) throws IOException { - URL u = null; - Enumeration en = Console.class.getClassLoader().getResources(name); - while (en.hasMoreElements()) { - u = en.nextElement(); - } - if (u == null) { - throw new IOException("Can't find " + name); - } - try (InputStream is = u.openStream()) { - byte[] arr; - arr = new byte[is.available()]; - int offset = 0; - while (offset < arr.length) { - int len = is.read(arr, offset, arr.length - offset); - if (len == -1) { - throw new IOException("Can't read " + name); - } - offset += len; - } - return arr; - } - } - - private static Object invokeMethod(String clazz, String method) - throws ClassNotFoundException, InvocationTargetException, - SecurityException, IllegalAccessException, IllegalArgumentException, - InstantiationException { - Method found = null; - Class c = Class.forName(clazz); - for (Method m : c.getMethods()) { - if (m.getName().equals(method)) { - found = m; - } - } - Object res; - if (found != null) { - try { - if ((found.getModifiers() & Modifier.STATIC) != 0) { - res = found.invoke(null); - } else { - res = found.invoke(c.newInstance()); - } - } catch (Throwable ex) { - res = ex.getClass().getName() + ":" + ex.getMessage(); - } - } else { - res = "Can't find method " + method + " in " + clazz; - } - return res; - } - - @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;") - private static void turnAssetionStatusOn() { - } - - private static final class Case { - private final Object data; - - private Case(Object data) { - this.data = data; - } - - public static Case parseData(String s) { - return new Case(toJSON(s)); - } - - public String getMethodName() { - return value("methodName", data); - } - - public String getClassName() { - return value("className", data); - } - - public String getRequestId() { - return value("request", data); - } - - public String getHtmlFragment() { - return value("html", data); - } - - @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');") - private static native Object toJSON(String s); - - @JavaScriptBody(args = {"p", "d"}, body = - "var v = d[p];\n" - + "if (typeof v === 'undefined') return null;\n" - + "return v.toString();" - ) - private static native String value(String p, Object d); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml --- a/rt/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ - - - - - - Bck2Brwsr Harness - - - - - -

Bck2Brwsr Execution Harness

- - - -
- - - - diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/pom.xml --- a/rt/mojo/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/mojo/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,14 +4,14 @@ org.apidesign.bck2brwsr rt - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr - mojo - 0.4-SNAPSHOT + bck2brwsr-maven-plugin + 0.8-SNAPSHOT maven-plugin - Bck2Brwsr Maven Project - http://maven.apache.org + Bck2Brwsr Maven Plugin + http://bck2brwsr.apidesign.org/ @@ -62,7 +62,7 @@ ${project.groupId} vm4brwsr - 0.4-SNAPSHOT + ${project.version} emul.mini @@ -81,5 +81,15 @@ launcher ${project.version} + + ${project.groupId} + launcher.http + ${project.version} + + + ${project.groupId} + launcher.fx + ${project.version} + diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrswrMojo.java --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrswrMojo.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +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.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.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.project.MavenProject; -import org.apidesign.bck2brwsr.launcher.Launcher; - -/** Executes given HTML page in a browser. */ -@Mojo(name="brwsr", defaultPhase=LifecyclePhase.NONE) -public class BrswrMojo extends AbstractMojo { - public BrswrMojo() { - } - /** Resource to show as initial page */ - @Parameter - private String startpage; - - @Parameter(defaultValue="${project}") - private MavenProject prj; - - /** Root of the class files */ - @Parameter(defaultValue="${project.build.directory}/classes") - private File classes; - - /** 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"); - } - - try { - Closeable httpServer; - if (directory != null) { - httpServer = Launcher.showDir(directory, startpage); - } else { - URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts()); - try { - httpServer = Launcher.showURL(url, startpage()); - } catch (Exception ex) { - throw new MojoExecutionException("Can't open " + startpage(), ex); - } - } - System.in.read(); - httpServer.close(); - } catch (IOException ex) { - throw new MojoExecutionException("Can't show the browser", ex); - } - } - - private String startpage() { - return startpage; - } - - private static URLClassLoader buildClassLoader(File root, Collection deps) throws MalformedURLException { - List arr = new ArrayList(); - arr.add(root.toURI().toURL()); - for (Artifact a : deps) { - final File f = a.getFile(); - if (f != null) { - arr.add(f.toURI().toURL()); - } - } - return new URLClassLoader(arr.toArray(new URL[0]), BrswrMojo.class.getClassLoader()); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrwsrMojo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrwsrMojo.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,108 @@ +/** + * 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.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.project.MavenProject; +import org.apidesign.bck2brwsr.launcher.Launcher; + +/** Executes given HTML page in a browser. */ +@Mojo(name="brwsr", defaultPhase=LifecyclePhase.NONE) +public class BrwsrMojo extends AbstractMojo { + public BrwsrMojo() { + } + + /** 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; + + @Parameter(defaultValue="${project}") + private MavenProject prj; + + /** Root of the class files */ + @Parameter(defaultValue="${project.build.directory}/classes") + private File classes; + + /** 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"); + } + + try { + Closeable httpServer; + if (directory != null) { + httpServer = Launcher.showDir(directory, startpage); + } else { + URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts()); + try { + httpServer = Launcher.showURL(launcher, url, startpage()); + } catch (Exception ex) { + throw new MojoExecutionException("Can't open " + startpage(), ex); + } + } + System.in.read(); + httpServer.close(); + } catch (IOException ex) { + throw new MojoExecutionException("Can't show the browser", ex); + } + } + + private String startpage() { + return startpage; + } + + private static URLClassLoader buildClassLoader(File root, Collection deps) throws MalformedURLException { + List arr = new ArrayList(); + arr.add(root.toURI().toURL()); + for (Artifact a : deps) { + final File f = a.getFile(); + if (f != null) { + arr.add(f.toURI().toURL()); + } + } + return new URLClassLoader(arr.toArray(new URL[0]), BrwsrMojo.class.getClassLoader()); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Fri May 17 10:27:41 2013 +0200 @@ -35,6 +35,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.apidesign.vm4brwsr.Bck2Brwsr; +import org.apidesign.vm4brwsr.ObfuscationLevel; /** Compiles classes into JavaScript. */ @Mojo(name="j2js", defaultPhase=LifecyclePhase.PROCESS_CLASSES) @@ -44,15 +45,27 @@ /** Root of the class files */ @Parameter(defaultValue="${project.build.directory}/classes") private File classes; - /** File to generate. Defaults bootjava.js in the first non-empty - package under the classes directory */ + /** JavaScript file to generate */ @Parameter private File javascript; + + /** Additional classes that should be pre-compiled into the javascript + * file. By default compiles all classes found under classes + * directory and their transitive closure. + */ + @Parameter + private List compileclasses; @Parameter(defaultValue="${project}") private MavenProject prj; - - + + /** + * The obfuscation level for the generated JavaScript file. + * + * @since 0.5 + */ + @Parameter(defaultValue="NONE") + private ObfuscationLevel obfuscation; @Override public void execute() throws MojoExecutionException { @@ -60,13 +73,14 @@ throw new MojoExecutionException("Can't find " + classes); } - if (javascript == null) { - javascript = new File(findNonEmptyFolder(classes), "bootjava.js"); - } - List arr = new ArrayList(); long newest = collectAllClasses("", classes, arr); + if (compileclasses != null) { + arr.retainAll(compileclasses); + arr.addAll(compileclasses); + } + if (javascript.lastModified() > newest) { return; } @@ -74,24 +88,17 @@ try { URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts()); FileWriter w = new FileWriter(javascript); - Bck2Brwsr.generate(w, url, arr.toArray(new String[0])); + Bck2Brwsr.newCompiler(). + obfuscation(obfuscation). + resources(url). + addRootClasses(arr.toArray(new String[0])). + generate(w); w.close(); } catch (IOException ex) { throw new MojoExecutionException("Can't compile", ex); } } - private static File findNonEmptyFolder(File dir) throws MojoExecutionException { - if (!dir.isDirectory()) { - throw new MojoExecutionException("Not a directory " + dir); - } - File[] arr = dir.listFiles(); - if (arr.length == 1 && arr[0].isDirectory()) { - return findNonEmptyFolder(arr[0]); - } - return dir; - } - private static long collectAllClasses(String prefix, File toCheck, List arr) { File[] files = toCheck.listFiles(); if (files != null) { @@ -104,7 +111,8 @@ } return newest; } else if (toCheck.getName().endsWith(".class")) { - arr.add(prefix.substring(0, prefix.length() - 7)); + final String cls = prefix.substring(0, prefix.length() - 7); + arr.add(cls); return toCheck.lastModified(); } else { return 0L; @@ -115,7 +123,9 @@ List arr = new ArrayList(); arr.add(root.toURI().toURL()); for (Artifact a : deps) { - arr.add(a.getFile().toURI().toURL()); + if (a.getFile() != null) { + arr.add(a.getFile().toURI().toURL()); + } } return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader()); } diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/resources/META-INF/maven/archetype-metadata.xml --- a/rt/mojo/src/main/resources/META-INF/maven/archetype-metadata.xml Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ - - - - - - src/main/java - - **/App.java - - - - src/main/resources - - **/*.xhtml - **/*.html - - - - src/test/java - - **/*Test.java - - - - - - nbactions.xml - - - - - - bck2brwsr-assembly.xml - - - - \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/resources/archetype-resources/bck2brwsr-assembly.xml --- a/rt/mojo/src/main/resources/archetype-resources/bck2brwsr-assembly.xml Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ - - - - - bck2brwsr - - zip - - public_html - - - false - runtime - lib - - *:jar - *:rt - - - - false - provided - - *:js - - true - / - - - - - ${project.build.directory}/${project.build.finalName}.jar - / - - - ${project.build.directory}/classes/${package.replace('.','/')}/index.html - / - index.html - - - - \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/resources/archetype-resources/nbactions.xml --- a/rt/mojo/src/main/resources/archetype-resources/nbactions.xml Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ - - - - run - - process-classes - org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr - - - diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/resources/archetype-resources/pom.xml --- a/rt/mojo/src/main/resources/archetype-resources/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ - - - 4.0.0 - - ${groupId} - ${artifactId} - ${version} - jar - - ${artifactId} - - - - java.net - Java.net - https://maven.java.net/content/repositories/snapshots/ - - true - - - - netbeans - NetBeans - http://bits.netbeans.org/maven2/ - - - - - java.net - Local Maven repository of releases - https://maven.java.net/content/repositories/snapshots/ - - true - - - - - - UTF-8 - - - - - org.apidesign.bck2brwsr - mojo - 0.3-SNAPSHOT - - - - brwsr - - - - - ${package.replace('.','/')}/index.html - - - - 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/ - - - - - - maven-assembly-plugin - 2.4 - - - distro-assembly - package - - single - - - - bck2brwsr-assembly.xml - - - - - - - - - - - org.apidesign.bck2brwsr - emul - 0.3-SNAPSHOT - rt - - - org.apidesign.bck2brwsr - javaquery.api - 0.3-SNAPSHOT - - - org.testng - testng - 6.5.2 - test - - - org.apidesign.bck2brwsr - vm4brwsr - js - zip - 0.3-SNAPSHOT - provided - - - org.apidesign.bck2brwsr - vmtest - 0.3-SNAPSHOT - test - - - diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/resources/archetype-resources/src/main/java/App.java --- a/rt/mojo/src/main/resources/archetype-resources/src/main/java/App.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -package ${package}; - -import org.apidesign.bck2brwsr.htmlpage.api.*; -import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; -import org.apidesign.bck2brwsr.htmlpage.api.Page; -import org.apidesign.bck2brwsr.htmlpage.api.Property; -import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; - -/** Edit the index.xhtml file. Use 'id' to name certain HTML elements. - * Use this class to define behavior of the elements. - */ -@Page(xhtml="index.html", className="Index", properties={ - @Property(name="name", type=String.class) -}) -public class App { - static { - Index model = new Index(); - model.setName("World"); - model.applyBindings(); - } - - @On(event = CLICK, id="hello") - static void hello(Index m) { - GraphicsContext g = m.CANVAS.getContext(); - g.clearRect(0, 0, 1000, 1000); - g.setFont("italic 40px Calibri"); - g.fillText(m.getHelloMessage(), 10, 40); - } - - @ComputedProperty - static String helloMessage(String name) { - return "Hello " + name + "!"; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/resources/archetype-resources/src/main/resources/index.html --- a/rt/mojo/src/main/resources/archetype-resources/src/main/resources/index.html Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ - - - - - Bck2Brwsr's Hello World - - -

Loading Bck2Brwsr's Hello World...

- Your name: - -

- - -

- - - - - diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/resources/archetype-resources/src/test/java/AppTest.java --- a/rt/mojo/src/main/resources/archetype-resources/src/test/java/AppTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -package ${package}; - -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** Demonstrating POJO testing of HTML page model. Runs in good old HotSpot - * as it does not reference any HTML elements or browser functionality. Just - * operates on the page model. - * - * @author Jaroslav Tulach - */ -public class AppTest { - private Index model; - - - @BeforeMethod - public void initModel() { - model = new Index().applyBindings(); - } - - @Test public void testHelloMessage() { - model.setName("Joe"); - assertEquals(model.getHelloMessage(), "Hello Joe!", "Cleared after pressing +"); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java --- a/rt/mojo/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +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. - * - * @author Jaroslav Tulach - */ -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 d127d41768bd -r ae3f2aa50970 rt/mojo/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java --- a/rt/mojo/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -package ${package}; - -import org.apidesign.bck2brwsr.htmlpage.api.OnEvent; -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. - * - * @author Jaroslav Tulach - */ -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( - "

Loading Bck2Brwsr's Hello World...

\n" + - "Your name: \n" + - "\n" + - "

\n" + - " \n" + - "

\n" - ) - @BrwsrTest - public void modifyValueAssertChangeInModel() { - Index m = new Index(); - m.setName("Joe Hacker"); - m.applyBindings(); - assert "Joe Hacker".equals(m.INPUT.getValue()) : "Value is really Joe Hacker: " + m.INPUT.getValue(); - m.INPUT.setValue("Happy Joe"); - m.triggerEvent(m.INPUT, OnEvent.CHANGE); - assert "Happy Joe".equals(m.getName()) : "Name property updated to Happy Joe: " + m.getName(); - } - - @Factory - public static Object[] create() { - return VMTest.create(IntegrationTest.class); - } - -} diff -r d127d41768bd -r ae3f2aa50970 rt/pom.xml --- a/rt/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -3,21 +3,20 @@ 4.0.0 org.apidesign.bck2brwsr rt - 0.4-SNAPSHOT + 0.8-SNAPSHOT pom Bck2Brwsr Runtime org.apidesign bck2brwsr - 0.4-SNAPSHOT + 0.8-SNAPSHOT core emul - javap - launcher + archetype mojo vm vmtest - \ No newline at end of file + diff -r d127d41768bd -r ae3f2aa50970 rt/vm/pom.xml --- a/rt/vm/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -3,12 +3,12 @@ org.apidesign.bck2brwsr rt - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr vm4brwsr - 0.4-SNAPSHOT + 0.8-SNAPSHOT jar Virtual Machine for Browser @@ -43,6 +43,7 @@ scm:hg:http://source.apidesign.org/hg/bck2brwsr http://source.apidesign.org/hg/bck2brwsr + HEAD @@ -82,18 +83,24 @@ generate-js process-classes + + java + + -Dskip.if.exists=true + -cp + + org.apidesign.vm4brwsr.Main + --obfuscatelevel + MINIMAL + ${project.build.directory}/bck2brwsr.js + org/apidesign/vm4brwsr/Bck2Brwsr + + - java + exec - - org.apidesign.vm4brwsr.Main - - ${project.build.directory}/bck2brwsr.js - org/apidesign/vm4brwsr/Bck2Brwsr - -
maven-assembly-plugin @@ -140,10 +147,10 @@ compile - ${project.groupId} - javap - ${project.version} + com.google.javascript + closure-compiler + r2388 compile - + diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Fri May 17 10:27:41 2013 +0200 @@ -54,46 +54,127 @@ * @author Jaroslav Tulach */ public final class Bck2Brwsr { - private Bck2Brwsr() { + private final ObfuscationLevel level; + private final StringArray classes; + private final Resources res; + + private Bck2Brwsr(ObfuscationLevel level, StringArray classes, Resources resources) { + this.level = level; + this.classes = classes; + this.res = resources; } - /** Generates virtual machine from bytes served by a resources + /** Helper method to generate virtual machine from bytes served by a resources * provider. - * + * * @param out the output to write the generated JavaScript to * @param resources provider of class files to use * @param classes additional classes to include in the generated script * @throws IOException I/O exception can be thrown when something goes wrong */ public static void generate(Appendable out, Resources resources, String... classes) throws IOException { - StringArray arr = StringArray.asList(classes); - arr.add(VM.class.getName().replace('.', '/')); - VM.compile(resources, out, arr); + newCompiler().resources(resources).addRootClasses(classes).generate(out); } - - /** Generates virtual machine from bytes served by a class loader. - * + + /** Helper method to generate virtual machine from bytes served by a class loader. + * * @param out the output to write the generated JavaScript to * @param loader class loader to load needed classes from * @param classes additional classes to include in the generated script * @throws IOException I/O exception can be thrown when something goes wrong */ - public static void generate(Appendable out, final ClassLoader loader, String... classes) throws IOException { - class R implements Resources { - @Override - public InputStream get(String name) throws IOException { - Enumeration en = loader.getResources(name); - URL u = null; - while (en.hasMoreElements()) { - u = en.nextElement(); - } - if (u == null) { - throw new IOException("Can't find " + name); - } - return u.openStream(); + public static void generate(Appendable out, ClassLoader loader, String... classes) throws IOException { + newCompiler().resources(loader).addRootClasses(classes).generate(out); + } + + /** Creates new instance of Bck2Brwsr compiler which is ready to generate + * empty Bck2Brwsr virtual machine. The instance can be further + * configured by calling chain of methods. For example: + *
+     * {@link #createCompiler()}.{@link #resources(org.apidesign.vm4brwsr.Bck2Brwsr.Resources) resources(loader)}.{@link #addRootClasses(java.lang.String[]) addRootClasses("your/Clazz")}.{@link #generate(java.lang.Appendable) generate(out)};
+     * 
+ * + * @return new instance of the Bck2Brwsr compiler + * @since 0.5 + */ + public static Bck2Brwsr newCompiler() { + StringArray arr = StringArray.asList(VM.class.getName().replace('.', '/')); + return new Bck2Brwsr(ObfuscationLevel.NONE, arr, null); + } + + /** Creates new instance of the Bck2Brwsr compiler which inherits + * all values from this instance and adds additional classes + * to the list of those that should be compiled by the {@link #generate(java.lang.Appendable)} + * method. + * + * @param classes the classes to add to the compilation + * @return new instance of the compiler + */ + public Bck2Brwsr addRootClasses(String... classes) { + if (classes.length == 0) { + return this; + } else { + return new Bck2Brwsr(level, this.classes.addAndNew(classes), res); + } + } + + /** Changes the obfuscation level for the compiler by creating new instance + * which inherits all values from this and adjust the level + * of obfuscation. + * + * @param level the new level of obfuscation + * @return new instance of the compiler with changed level of obfuscation + * @since 0.5 + */ + public Bck2Brwsr obfuscation(ObfuscationLevel level) { + return new Bck2Brwsr(level, classes, res); + } + + /** A way to change the provider of additional resources (classes) for the + * compiler. + * + * @param res the implementation of resources provider + * @return new instance of the compiler with all values remaining the same, just + * with different resources provider + * @since 0.5 + */ + public Bck2Brwsr resources(Resources res) { + return new Bck2Brwsr(level, classes, res); + } + + /** A way to change the provider of additional resources (classes) for the + * compiler by specifying classloader to use for loading them. + * + * @param loader class loader to load the resources from + * @return new instance of the compiler with all values being the same, just + * different resources provider + * @since 0.5 + */ + public Bck2Brwsr resources(final ClassLoader loader) { + return resources(new LdrRsrcs(loader)); + } + + /** Generates virtual machine based on previous configuration of the + * compiler. + * + * @param out the output to write the generated JavaScript to + * @since 0.5 + */ + public void generate(Appendable out) throws IOException { + Resources r = res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader()); + if (level != ObfuscationLevel.NONE) { + try { + ClosureWrapper.produceTo(out, level, r, classes); + return; + } catch (IOException ex) { + throw ex; + } catch (Throwable ex) { + out.append("/* Failed to obfuscate: " + ex.getMessage() + + " */\n"); } } - generate(out, new R(), classes); + + VM.compile(r, out, classes); } /** Provider of resources (classes and other files). The diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,3461 @@ +/* + * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.apidesign.vm4brwsr; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.core.JavaScriptPrototype; + +/** This is a byte code parser heavily based on original code of JavaP utility. + * As such I decided to keep the original Oracle's GPLv2 header. + * + * @author Jaroslav Tulach + */ +final class ByteCodeParser { + private ByteCodeParser() { + } + /* Signature Characters */ + public static final char SIGC_VOID = 'V'; + public static final String SIG_VOID = "V"; + public static final char SIGC_BOOLEAN = 'Z'; + public static final String SIG_BOOLEAN = "Z"; + public static final char SIGC_BYTE = 'B'; + public static final String SIG_BYTE = "B"; + public static final char SIGC_CHAR = 'C'; + public static final String SIG_CHAR = "C"; + public static final char SIGC_SHORT = 'S'; + public static final String SIG_SHORT = "S"; + public static final char SIGC_INT = 'I'; + public static final String SIG_INT = "I"; + public static final char SIGC_LONG = 'J'; + public static final String SIG_LONG = "J"; + public static final char SIGC_FLOAT = 'F'; + public static final String SIG_FLOAT = "F"; + public static final char SIGC_DOUBLE = 'D'; + public static final String SIG_DOUBLE = "D"; + public static final char SIGC_ARRAY = '['; + public static final String SIG_ARRAY = "["; + public static final char SIGC_CLASS = 'L'; + public static final String SIG_CLASS = "L"; + public static final char SIGC_METHOD = '('; + public static final String SIG_METHOD = "("; + public static final char SIGC_ENDCLASS = ';'; + public static final String SIG_ENDCLASS = ";"; + public static final char SIGC_ENDMETHOD = ')'; + public static final String SIG_ENDMETHOD = ")"; + public static final char SIGC_PACKAGE = '/'; + public static final String SIG_PACKAGE = "/"; + + /* Class File Constants */ + public static final int JAVA_MAGIC = 0xcafebabe; + public static final int JAVA_VERSION = 45; + public static final int JAVA_MINOR_VERSION = 3; + + /* Constant table */ + public static final int CONSTANT_UTF8 = 1; + public static final int CONSTANT_UNICODE = 2; + public static final int CONSTANT_INTEGER = 3; + public static final int CONSTANT_FLOAT = 4; + public static final int CONSTANT_LONG = 5; + public static final int CONSTANT_DOUBLE = 6; + public static final int CONSTANT_CLASS = 7; + public static final int CONSTANT_STRING = 8; + public static final int CONSTANT_FIELD = 9; + public static final int CONSTANT_METHOD = 10; + public static final int CONSTANT_INTERFACEMETHOD = 11; + public static final int CONSTANT_NAMEANDTYPE = 12; + + /* Access Flags */ + public static final int ACC_PUBLIC = 0x00000001; + public static final int ACC_PRIVATE = 0x00000002; + public static final int ACC_PROTECTED = 0x00000004; + public static final int ACC_STATIC = 0x00000008; + public static final int ACC_FINAL = 0x00000010; + public static final int ACC_SYNCHRONIZED = 0x00000020; + public static final int ACC_SUPER = 0x00000020; + public static final int ACC_VOLATILE = 0x00000040; + public static final int ACC_TRANSIENT = 0x00000080; + public static final int ACC_NATIVE = 0x00000100; + public static final int ACC_INTERFACE = 0x00000200; + public static final int ACC_ABSTRACT = 0x00000400; + public static final int ACC_STRICT = 0x00000800; + public static final int ACC_EXPLICIT = 0x00001000; + public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute + + /* Type codes */ + public static final int T_CLASS = 0x00000002; + public static final int T_BOOLEAN = 0x00000004; + public static final int T_CHAR = 0x00000005; + public static final int T_FLOAT = 0x00000006; + public static final int T_DOUBLE = 0x00000007; + public static final int T_BYTE = 0x00000008; + public static final int T_SHORT = 0x00000009; + public static final int T_INT = 0x0000000a; + public static final int T_LONG = 0x0000000b; + + /* Type codes for StackMap attribute */ + public static final int ITEM_Bogus =0; // an unknown or uninitialized value + public static final int ITEM_Integer =1; // a 32-bit integer + public static final int ITEM_Float =2; // not used + public static final int ITEM_Double =3; // not used + public static final int ITEM_Long =4; // a 64-bit integer + public static final int ITEM_Null =5; // the type of null + public static final int ITEM_InitObject =6; // "this" in constructor + public static final int ITEM_Object =7; // followed by 2-byte index of class name + public static final int ITEM_NewObject =8; // followed by 2-byte ref to "new" + + /* Constants used in StackMapTable attribute */ + public static final int SAME_FRAME_BOUND = 64; + public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128; + public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; + public static final int SAME_FRAME_EXTENDED = 251; + public static final int FULL_FRAME = 255; + + /* Opcodes */ + public static final int opc_dead = -2; + public static final int opc_label = -1; + public static final int opc_nop = 0; + public static final int opc_aconst_null = 1; + public static final int opc_iconst_m1 = 2; + public static final int opc_iconst_0 = 3; + public static final int opc_iconst_1 = 4; + public static final int opc_iconst_2 = 5; + public static final int opc_iconst_3 = 6; + public static final int opc_iconst_4 = 7; + public static final int opc_iconst_5 = 8; + public static final int opc_lconst_0 = 9; + public static final int opc_lconst_1 = 10; + public static final int opc_fconst_0 = 11; + public static final int opc_fconst_1 = 12; + public static final int opc_fconst_2 = 13; + public static final int opc_dconst_0 = 14; + public static final int opc_dconst_1 = 15; + public static final int opc_bipush = 16; + public static final int opc_sipush = 17; + public static final int opc_ldc = 18; + public static final int opc_ldc_w = 19; + public static final int opc_ldc2_w = 20; + public static final int opc_iload = 21; + public static final int opc_lload = 22; + public static final int opc_fload = 23; + public static final int opc_dload = 24; + public static final int opc_aload = 25; + public static final int opc_iload_0 = 26; + public static final int opc_iload_1 = 27; + public static final int opc_iload_2 = 28; + public static final int opc_iload_3 = 29; + public static final int opc_lload_0 = 30; + public static final int opc_lload_1 = 31; + public static final int opc_lload_2 = 32; + public static final int opc_lload_3 = 33; + public static final int opc_fload_0 = 34; + public static final int opc_fload_1 = 35; + public static final int opc_fload_2 = 36; + public static final int opc_fload_3 = 37; + public static final int opc_dload_0 = 38; + public static final int opc_dload_1 = 39; + public static final int opc_dload_2 = 40; + public static final int opc_dload_3 = 41; + public static final int opc_aload_0 = 42; + public static final int opc_aload_1 = 43; + public static final int opc_aload_2 = 44; + public static final int opc_aload_3 = 45; + public static final int opc_iaload = 46; + public static final int opc_laload = 47; + public static final int opc_faload = 48; + public static final int opc_daload = 49; + public static final int opc_aaload = 50; + public static final int opc_baload = 51; + public static final int opc_caload = 52; + public static final int opc_saload = 53; + public static final int opc_istore = 54; + public static final int opc_lstore = 55; + public static final int opc_fstore = 56; + public static final int opc_dstore = 57; + public static final int opc_astore = 58; + public static final int opc_istore_0 = 59; + public static final int opc_istore_1 = 60; + public static final int opc_istore_2 = 61; + public static final int opc_istore_3 = 62; + public static final int opc_lstore_0 = 63; + public static final int opc_lstore_1 = 64; + public static final int opc_lstore_2 = 65; + public static final int opc_lstore_3 = 66; + public static final int opc_fstore_0 = 67; + public static final int opc_fstore_1 = 68; + public static final int opc_fstore_2 = 69; + public static final int opc_fstore_3 = 70; + public static final int opc_dstore_0 = 71; + public static final int opc_dstore_1 = 72; + public static final int opc_dstore_2 = 73; + public static final int opc_dstore_3 = 74; + public static final int opc_astore_0 = 75; + public static final int opc_astore_1 = 76; + public static final int opc_astore_2 = 77; + public static final int opc_astore_3 = 78; + public static final int opc_iastore = 79; + public static final int opc_lastore = 80; + public static final int opc_fastore = 81; + public static final int opc_dastore = 82; + public static final int opc_aastore = 83; + public static final int opc_bastore = 84; + public static final int opc_castore = 85; + public static final int opc_sastore = 86; + public static final int opc_pop = 87; + public static final int opc_pop2 = 88; + public static final int opc_dup = 89; + public static final int opc_dup_x1 = 90; + public static final int opc_dup_x2 = 91; + public static final int opc_dup2 = 92; + public static final int opc_dup2_x1 = 93; + public static final int opc_dup2_x2 = 94; + public static final int opc_swap = 95; + public static final int opc_iadd = 96; + public static final int opc_ladd = 97; + public static final int opc_fadd = 98; + public static final int opc_dadd = 99; + public static final int opc_isub = 100; + public static final int opc_lsub = 101; + public static final int opc_fsub = 102; + public static final int opc_dsub = 103; + public static final int opc_imul = 104; + public static final int opc_lmul = 105; + public static final int opc_fmul = 106; + public static final int opc_dmul = 107; + public static final int opc_idiv = 108; + public static final int opc_ldiv = 109; + public static final int opc_fdiv = 110; + public static final int opc_ddiv = 111; + public static final int opc_irem = 112; + public static final int opc_lrem = 113; + public static final int opc_frem = 114; + public static final int opc_drem = 115; + public static final int opc_ineg = 116; + public static final int opc_lneg = 117; + public static final int opc_fneg = 118; + public static final int opc_dneg = 119; + public static final int opc_ishl = 120; + public static final int opc_lshl = 121; + public static final int opc_ishr = 122; + public static final int opc_lshr = 123; + public static final int opc_iushr = 124; + public static final int opc_lushr = 125; + public static final int opc_iand = 126; + public static final int opc_land = 127; + public static final int opc_ior = 128; + public static final int opc_lor = 129; + public static final int opc_ixor = 130; + public static final int opc_lxor = 131; + public static final int opc_iinc = 132; + public static final int opc_i2l = 133; + public static final int opc_i2f = 134; + public static final int opc_i2d = 135; + public static final int opc_l2i = 136; + public static final int opc_l2f = 137; + public static final int opc_l2d = 138; + public static final int opc_f2i = 139; + public static final int opc_f2l = 140; + public static final int opc_f2d = 141; + public static final int opc_d2i = 142; + public static final int opc_d2l = 143; + public static final int opc_d2f = 144; + public static final int opc_i2b = 145; + public static final int opc_int2byte = 145; + public static final int opc_i2c = 146; + public static final int opc_int2char = 146; + public static final int opc_i2s = 147; + public static final int opc_int2short = 147; + public static final int opc_lcmp = 148; + public static final int opc_fcmpl = 149; + public static final int opc_fcmpg = 150; + public static final int opc_dcmpl = 151; + public static final int opc_dcmpg = 152; + public static final int opc_ifeq = 153; + public static final int opc_ifne = 154; + public static final int opc_iflt = 155; + public static final int opc_ifge = 156; + public static final int opc_ifgt = 157; + public static final int opc_ifle = 158; + public static final int opc_if_icmpeq = 159; + public static final int opc_if_icmpne = 160; + public static final int opc_if_icmplt = 161; + public static final int opc_if_icmpge = 162; + public static final int opc_if_icmpgt = 163; + public static final int opc_if_icmple = 164; + public static final int opc_if_acmpeq = 165; + public static final int opc_if_acmpne = 166; + public static final int opc_goto = 167; + public static final int opc_jsr = 168; + public static final int opc_ret = 169; + public static final int opc_tableswitch = 170; + public static final int opc_lookupswitch = 171; + public static final int opc_ireturn = 172; + public static final int opc_lreturn = 173; + public static final int opc_freturn = 174; + public static final int opc_dreturn = 175; + public static final int opc_areturn = 176; + public static final int opc_return = 177; + public static final int opc_getstatic = 178; + public static final int opc_putstatic = 179; + public static final int opc_getfield = 180; + public static final int opc_putfield = 181; + public static final int opc_invokevirtual = 182; + public static final int opc_invokenonvirtual = 183; + public static final int opc_invokespecial = 183; + public static final int opc_invokestatic = 184; + public static final int opc_invokeinterface = 185; +// public static final int opc_xxxunusedxxx = 186; + public static final int opc_new = 187; + public static final int opc_newarray = 188; + public static final int opc_anewarray = 189; + public static final int opc_arraylength = 190; + public static final int opc_athrow = 191; + public static final int opc_checkcast = 192; + public static final int opc_instanceof = 193; + public static final int opc_monitorenter = 194; + public static final int opc_monitorexit = 195; + public static final int opc_wide = 196; + public static final int opc_multianewarray = 197; + public static final int opc_ifnull = 198; + public static final int opc_ifnonnull = 199; + public static final int opc_goto_w = 200; + public static final int opc_jsr_w = 201; + /* Pseudo-instructions */ + public static final int opc_bytecode = 203; + public static final int opc_try = 204; + public static final int opc_endtry = 205; + public static final int opc_catch = 206; + public static final int opc_var = 207; + public static final int opc_endvar = 208; + public static final int opc_localsmap = 209; + public static final int opc_stackmap = 210; + /* PicoJava prefixes */ + public static final int opc_nonpriv = 254; + public static final int opc_priv = 255; + + /* Wide instructions */ + public static final int opc_iload_w = (opc_wide<<8)|opc_iload; + public static final int opc_lload_w = (opc_wide<<8)|opc_lload; + public static final int opc_fload_w = (opc_wide<<8)|opc_fload; + public static final int opc_dload_w = (opc_wide<<8)|opc_dload; + public static final int opc_aload_w = (opc_wide<<8)|opc_aload; + public static final int opc_istore_w = (opc_wide<<8)|opc_istore; + public static final int opc_lstore_w = (opc_wide<<8)|opc_lstore; + public static final int opc_fstore_w = (opc_wide<<8)|opc_fstore; + public static final int opc_dstore_w = (opc_wide<<8)|opc_dstore; + public static final int opc_astore_w = (opc_wide<<8)|opc_astore; + public static final int opc_ret_w = (opc_wide<<8)|opc_ret; + public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc; + + /* Opcode Names */ + public static final String opcNamesTab[] = { + "nop", + "aconst_null", + "iconst_m1", + "iconst_0", + "iconst_1", + "iconst_2", + "iconst_3", + "iconst_4", + "iconst_5", + "lconst_0", + "lconst_1", + "fconst_0", + "fconst_1", + "fconst_2", + "dconst_0", + "dconst_1", + "bipush", + "sipush", + "ldc", + "ldc_w", + "ldc2_w", + "iload", + "lload", + "fload", + "dload", + "aload", + "iload_0", + "iload_1", + "iload_2", + "iload_3", + "lload_0", + "lload_1", + "lload_2", + "lload_3", + "fload_0", + "fload_1", + "fload_2", + "fload_3", + "dload_0", + "dload_1", + "dload_2", + "dload_3", + "aload_0", + "aload_1", + "aload_2", + "aload_3", + "iaload", + "laload", + "faload", + "daload", + "aaload", + "baload", + "caload", + "saload", + "istore", + "lstore", + "fstore", + "dstore", + "astore", + "istore_0", + "istore_1", + "istore_2", + "istore_3", + "lstore_0", + "lstore_1", + "lstore_2", + "lstore_3", + "fstore_0", + "fstore_1", + "fstore_2", + "fstore_3", + "dstore_0", + "dstore_1", + "dstore_2", + "dstore_3", + "astore_0", + "astore_1", + "astore_2", + "astore_3", + "iastore", + "lastore", + "fastore", + "dastore", + "aastore", + "bastore", + "castore", + "sastore", + "pop", + "pop2", + "dup", + "dup_x1", + "dup_x2", + "dup2", + "dup2_x1", + "dup2_x2", + "swap", + "iadd", + "ladd", + "fadd", + "dadd", + "isub", + "lsub", + "fsub", + "dsub", + "imul", + "lmul", + "fmul", + "dmul", + "idiv", + "ldiv", + "fdiv", + "ddiv", + "irem", + "lrem", + "frem", + "drem", + "ineg", + "lneg", + "fneg", + "dneg", + "ishl", + "lshl", + "ishr", + "lshr", + "iushr", + "lushr", + "iand", + "land", + "ior", + "lor", + "ixor", + "lxor", + "iinc", + "i2l", + "i2f", + "i2d", + "l2i", + "l2f", + "l2d", + "f2i", + "f2l", + "f2d", + "d2i", + "d2l", + "d2f", + "i2b", + "i2c", + "i2s", + "lcmp", + "fcmpl", + "fcmpg", + "dcmpl", + "dcmpg", + "ifeq", + "ifne", + "iflt", + "ifge", + "ifgt", + "ifle", + "if_icmpeq", + "if_icmpne", + "if_icmplt", + "if_icmpge", + "if_icmpgt", + "if_icmple", + "if_acmpeq", + "if_acmpne", + "goto", + "jsr", + "ret", + "tableswitch", + "lookupswitch", + "ireturn", + "lreturn", + "freturn", + "dreturn", + "areturn", + "return", + "getstatic", + "putstatic", + "getfield", + "putfield", + "invokevirtual", + "invokespecial", // was "invokenonvirtual", + "invokestatic", + "invokeinterface", + "bytecode 186", //"xxxunusedxxx", + "new", + "newarray", + "anewarray", + "arraylength", + "athrow", + "checkcast", + "instanceof", + "monitorenter", + "monitorexit", + null, // "wide", + "multianewarray", + "ifnull", + "ifnonnull", + "goto_w", + "jsr_w", + "bytecode 202", // "breakpoint", + "bytecode", + "try", + "endtry", + "catch", + "var", + "endvar", + "locals_map", + "stack_map" + }; + + /* Opcode Lengths */ + public static final int opcLengthsTab[] = { + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 3, + 2, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 99, + 99, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 5, + 0, + 3, + 2, + 3, + 1, + 1, + 3, + 3, + 1, + 1, + 0, // wide + 4, + 3, + 3, + 5, + 5, + 1, + 1, 0, 0, 0, 0, 0 // pseudo + }; + + /** + * End of input + */ + public static final int EOF = -1; + + /* + * Flags + */ + public static final int F_VERBOSE = 1 << 0; + public static final int F_DUMP = 1 << 1; + public static final int F_WARNINGS = 1 << 2; + public static final int F_DEBUG = 1 << 3; + public static final int F_OPTIMIZE = 1 << 4; + public static final int F_DEPENDENCIES = 1 << 5; + + /* + * Type codes + */ + public static final int TC_BOOLEAN = 0; + public static final int TC_BYTE = 1; + public static final int TC_CHAR = 2; + public static final int TC_SHORT = 3; + public static final int TC_INT = 4; + public static final int TC_LONG = 5; + public static final int TC_FLOAT = 6; + public static final int TC_DOUBLE = 7; + public static final int TC_NULL = 8; + public static final int TC_ARRAY = 9; + public static final int TC_CLASS = 10; + public static final int TC_VOID = 11; + public static final int TC_METHOD = 12; + public static final int TC_ERROR = 13; + + /* + * Type Masks + */ + public static final int TM_NULL = 1 << TC_NULL; + public static final int TM_VOID = 1 << TC_VOID; + public static final int TM_BOOLEAN = 1 << TC_BOOLEAN; + public static final int TM_BYTE = 1 << TC_BYTE; + public static final int TM_CHAR = 1 << TC_CHAR; + public static final int TM_SHORT = 1 << TC_SHORT; + public static final int TM_INT = 1 << TC_INT; + public static final int TM_LONG = 1 << TC_LONG; + public static final int TM_FLOAT = 1 << TC_FLOAT; + public static final int TM_DOUBLE = 1 << TC_DOUBLE; + public static final int TM_ARRAY = 1 << TC_ARRAY; + public static final int TM_CLASS = 1 << TC_CLASS; + public static final int TM_METHOD = 1 << TC_METHOD; + public static final int TM_ERROR = 1 << TC_ERROR; + + public static final int TM_INT32 = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT; + public static final int TM_NUM32 = TM_INT32 | TM_FLOAT; + public static final int TM_NUM64 = TM_LONG | TM_DOUBLE; + public static final int TM_INTEGER = TM_INT32 | TM_LONG; + public static final int TM_REAL = TM_FLOAT | TM_DOUBLE; + public static final int TM_NUMBER = TM_INTEGER | TM_REAL; + public static final int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL; + + /* + * Class status + */ + public static final int CS_UNDEFINED = 0; + public static final int CS_UNDECIDED = 1; + public static final int CS_BINARY = 2; + public static final int CS_SOURCE = 3; + public static final int CS_PARSED = 4; + public static final int CS_COMPILED = 5; + public static final int CS_NOTFOUND = 6; + + /* + * Attributes + */ + public static final int ATT_ALL = -1; + public static final int ATT_CODE = 1; + + /* + * Number of bits used in file offsets + */ + public static final int OFFSETBITS = 19; + public static final int MAXFILESIZE = (1 << OFFSETBITS) - 1; + public static final int MAXLINENUMBER = (1 << (32 - OFFSETBITS)) - 1; + + /* + * Operators + */ + public final int COMMA = 0; + public final int ASSIGN = 1; + + public final int ASGMUL = 2; + public final int ASGDIV = 3; + public final int ASGREM = 4; + public final int ASGADD = 5; + public final int ASGSUB = 6; + public final int ASGLSHIFT = 7; + public final int ASGRSHIFT = 8; + public final int ASGURSHIFT = 9; + public final int ASGBITAND = 10; + public final int ASGBITOR = 11; + public final int ASGBITXOR = 12; + + public final int COND = 13; + public final int OR = 14; + public final int AND = 15; + public final int BITOR = 16; + public final int BITXOR = 17; + public final int BITAND = 18; + public final int NE = 19; + public final int EQ = 20; + public final int GE = 21; + public final int GT = 22; + public final int LE = 23; + public final int LT = 24; + public final int INSTANCEOF = 25; + public final int LSHIFT = 26; + public final int RSHIFT = 27; + public final int URSHIFT = 28; + public final int ADD = 29; + public final int SUB = 30; + public final int DIV = 31; + public final int REM = 32; + public final int MUL = 33; + public final int CAST = 34; // (x)y + public final int POS = 35; // +x + public final int NEG = 36; // -x + public final int NOT = 37; + public final int BITNOT = 38; + public final int PREINC = 39; // ++x + public final int PREDEC = 40; // --x + public final int NEWARRAY = 41; + public final int NEWINSTANCE = 42; + public final int NEWFROMNAME = 43; + public final int POSTINC = 44; // x++ + public final int POSTDEC = 45; // x-- + public final int FIELD = 46; + public final int METHOD = 47; // x(y) + public final int ARRAYACCESS = 48; // x[y] + public final int NEW = 49; + public final int INC = 50; + public final int DEC = 51; + + public final int CONVERT = 55; // implicit conversion + public final int EXPR = 56; // (x) + public final int ARRAY = 57; // {x, y, ...} + public final int GOTO = 58; + + /* + * Value tokens + */ + public final int IDENT = 60; + public final int BOOLEANVAL = 61; + public final int BYTEVAL = 62; + public final int CHARVAL = 63; + public final int SHORTVAL = 64; + public final int INTVAL = 65; + public final int LONGVAL = 66; + public final int FLOATVAL = 67; + public final int DOUBLEVAL = 68; + public final int STRINGVAL = 69; + + /* + * Type keywords + */ + public final int BYTE = 70; + public final int CHAR = 71; + public final int SHORT = 72; + public final int INT = 73; + public final int LONG = 74; + public final int FLOAT = 75; + public final int DOUBLE = 76; + public final int VOID = 77; + public final int BOOLEAN = 78; + + /* + * Expression keywords + */ + public final int TRUE = 80; + public final int FALSE = 81; + public final int THIS = 82; + public final int SUPER = 83; + public final int NULL = 84; + + /* + * Statement keywords + */ + public final int IF = 90; + public final int ELSE = 91; + public final int FOR = 92; + public final int WHILE = 93; + public final int DO = 94; + public final int SWITCH = 95; + public final int CASE = 96; + public final int DEFAULT = 97; + public final int BREAK = 98; + public final int CONTINUE = 99; + public final int RETURN = 100; + public final int TRY = 101; + public final int CATCH = 102; + public final int FINALLY = 103; + public final int THROW = 104; + public final int STAT = 105; + public final int EXPRESSION = 106; + public final int DECLARATION = 107; + public final int VARDECLARATION = 108; + + /* + * Declaration keywords + */ + public final int IMPORT = 110; + public final int CLASS = 111; + public final int EXTENDS = 112; + public final int IMPLEMENTS = 113; + public final int INTERFACE = 114; + public final int PACKAGE = 115; + + /* + * Modifier keywords + */ + public final int PRIVATE = 120; + public final int PUBLIC = 121; + public final int PROTECTED = 122; + public final int CONST = 123; + public final int STATIC = 124; + public final int TRANSIENT = 125; + public final int SYNCHRONIZED = 126; + public final int NATIVE = 127; + public final int FINAL = 128; + public final int VOLATILE = 129; + public final int ABSTRACT = 130; + public final int STRICT = 165; + + /* + * Punctuation + */ + public final int SEMICOLON = 135; + public final int COLON = 136; + public final int QUESTIONMARK = 137; + public final int LBRACE = 138; + public final int RBRACE = 139; + public final int LPAREN = 140; + public final int RPAREN = 141; + public final int LSQBRACKET = 142; + public final int RSQBRACKET = 143; + public final int THROWS = 144; + + /* + * Special tokens + */ + public final int ERROR = 145; // an error + public final int COMMENT = 146; // not used anymore. + public final int TYPE = 147; + public final int LENGTH = 148; + public final int INLINERETURN = 149; + public final int INLINEMETHOD = 150; + public final int INLINENEWINSTANCE = 151; + + /* + * Added for jasm + */ + public final int METHODREF = 152; + public final int FIELDREF = 153; + public final int STACK = 154; + public final int LOCAL = 155; + public final int CPINDEX = 156; + public final int CPNAME = 157; + public final int SIGN = 158; + public final int BITS = 159; + public final int INF = 160; + public final int NAN = 161; + public final int INNERCLASS = 162; + public final int OF = 163; + public final int SYNTHETIC = 164; +// last used=165; + + /* + * Operator precedence + */ + public static final int opPrecedence[] = { + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 12, 13, 14, 15, 16, 17, 18, + 18, 19, 19, 19, 19, 19, 20, 20, 20, 21, + 21, 22, 22, 22, 23, 24, 24, 24, 24, 24, + 24, 25, 25, 26, 26, 26, 26, 26, 26 + }; + + /* + * Operator names + */ + public static final String opNames[] = { + ",", "=", "*=", "/=", "%=", + "+=", "-=", "<<=", ">>=", "<<<=", + "&=", "|=", "^=", "?:", "||", + "&&", "|", "^", "&", "!=", + "==", ">=", ">", "<=", "<", + "instanceof", "<<", ">>", "<<<", "+", + "-", "/", "%", "*", "cast", + "+", "-", "!", "~", "++", + "--", "new", "new", "new", "++", + "--", "field", "method", "[]", "new", + "++", "--", null, null, null, + + "convert", "expr", "array", "goto", null, + + "Identifier", "Boolean", "Byte", "Char", "Short", + "Integer", "Long", "Float", "Double", "String", + + "byte", "char", "short", "int", "long", + "float", "double", "void", "boolean", null, + + "true", "false", "this", "super", "null", + null, null, null, null, null, + + "if", "else", "for", "while", "do", + "switch", "case", "default", "break", "continue", + "return", "try", "catch", "finally", "throw", + "stat", "expression", "declaration", "declaration", null, + + "import", "class", "extends", "implements", "interface", + "package", null, null, null, null, + + "private", "public", "protected", "const", "static", + "transient", "synchronized", "native", "final", "volatile", + "abstract", null, null, null, null, + + ";", ":", "?", "{", "}", + "(", ")", "[", "]", "throws", + "error", "comment", "type", "length", "inline-return", + "inline-method", "inline-new", + "method", "field", "stack", "locals", "CPINDEX", "CPName", "SIGN", + "bits", "INF", "NaN", "InnerClass", "of", "synthetic" + }; + + static class AnnotationParser { + + private final boolean textual; + private final boolean iterateArray; + + protected AnnotationParser(boolean textual, boolean iterateArray) { + this.textual = textual; + this.iterateArray = iterateArray; + } + + protected void visitAnnotationStart(String type, boolean top) throws IOException { + } + + protected void visitAnnotationEnd(String type, boolean top) throws IOException { + } + + protected void visitValueStart(String attrName, char type) throws IOException { + } + + protected void visitValueEnd(String attrName, char type) throws IOException { + } + + protected void visitAttr( + String annoType, String attr, String attrType, String value) throws IOException { + } + + protected void visitEnumAttr( + String annoType, String attr, String attrType, String value) throws IOException { + visitAttr(annoType, attr, attrType, value); + } + + /** + * Initialize the parsing with constant pool from + * cd. + * + * @param attr the attribute defining annotations + * @param cd constant pool + * @throws IOException in case I/O fails + */ + public final void parse(byte[] attr, ClassData cd) throws IOException { + ByteArrayInputStream is = new ByteArrayInputStream(attr); + DataInputStream dis = new DataInputStream(is); + try { + read(dis, cd); + } finally { + is.close(); + } + } + + private void read(DataInputStream dis, ClassData cd) throws IOException { + int cnt = dis.readUnsignedShort(); + for (int i = 0; i < cnt; i++) { + readAnno(dis, cd, true); + } + } + + private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException { + int type = dis.readUnsignedShort(); + String typeName = cd.StringValue(type); + visitAnnotationStart(typeName, top); + int cnt = dis.readUnsignedShort(); + for (int i = 0; i < cnt; i++) { + String attrName = cd.StringValue(dis.readUnsignedShort()); + readValue(dis, cd, typeName, attrName); + } + visitAnnotationEnd(typeName, top); + if (cnt == 0) { + visitAttr(typeName, null, null, null); + } + } + + private void readValue( + DataInputStream dis, ClassData cd, String typeName, String attrName) throws IOException { + char type = (char) dis.readByte(); + visitValueStart(attrName, type); + if (type == '@') { + readAnno(dis, cd, false); + } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N + int primitive = dis.readUnsignedShort(); + String val = cd.stringValue(primitive, textual); + String attrType; + if (type == 's') { + attrType = "Ljava_lang_String_2"; + if (textual) { + val = '"' + val + '"'; + } + } else { + attrType = "" + type; + } + visitAttr(typeName, attrName, attrType, val); + } else if (type == 'c') { + int cls = dis.readUnsignedShort(); + } else if (type == '[') { + int cnt = dis.readUnsignedShort(); + for (int i = 0; i < cnt; i++) { + readValue(dis, cd, typeName, iterateArray ? attrName : null); + } + } else if (type == 'e') { + int enumT = dis.readUnsignedShort(); + String attrType = cd.stringValue(enumT, textual); + int enumN = dis.readUnsignedShort(); + String val = cd.stringValue(enumN, textual); + visitEnumAttr(typeName, attrName, attrType, val); + } else { + throw new IOException("Unknown type " + type); + } + visitValueEnd(attrName, type); + } + } + + /** + * Reads and stores attribute information. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class AttrData { + + ClassData cls; + int name_cpx; + int datalen; + byte data[]; + + public AttrData(ClassData cls) { + this.cls = cls; + } + + /** + * Reads unknown attribute. + */ + public void read(int name_cpx, DataInputStream in) throws IOException { + this.name_cpx = name_cpx; + datalen = in.readInt(); + data = new byte[datalen]; + in.readFully(data); + } + + /** + * Reads just the name of known attribute. + */ + public void read(int name_cpx) { + this.name_cpx = name_cpx; + } + + /** + * Returns attribute name. + */ + public String getAttrName() { + return cls.getString(name_cpx); + } + + /** + * Returns attribute data. + */ + public byte[] getData() { + return data; + } + } + + /** + * Stores constant pool entry information with one field. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class CPX { + + int cpx; + + CPX(int cpx) { + this.cpx = cpx; + } + } + + /** + * Stores constant pool entry information with two fields. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class CPX2 { + + int cpx1, cpx2; + + CPX2(int cpx1, int cpx2) { + this.cpx1 = cpx1; + this.cpx2 = cpx2; + } + } + + /** + * Central data repository of the Java Disassembler. Stores all the + * information in java class file. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + static final class ClassData { + + private int magic; + private int minor_version; + private int major_version; + private int cpool_count; + private Object cpool[]; + private int access; + private int this_class = 0; + private int super_class; + private int interfaces_count; + private int[] interfaces = new int[0]; + private int fields_count; + private FieldData[] fields; + private int methods_count; + private MethodData[] methods; + private InnerClassData[] innerClasses; + private int attributes_count; + private AttrData[] attrs; + private String classname; + private String superclassname; + private int source_cpx = 0; + private byte tags[]; + private Hashtable indexHashAscii = new Hashtable(); + private String pkgPrefix = ""; + private int pkgPrefixLen = 0; + + /** + * Read classfile to disassemble. + */ + public ClassData(InputStream infile) throws IOException { + this.read(new DataInputStream(infile)); + } + + /** + * Reads and stores class file information. + */ + public void read(DataInputStream in) throws IOException { + // Read the header + magic = in.readInt(); + if (magic != JAVA_MAGIC) { + throw new ClassFormatError("wrong magic: " + + toHex(magic) + ", expected " + + toHex(JAVA_MAGIC)); + } + minor_version = in.readShort(); + major_version = in.readShort(); + if (major_version != JAVA_VERSION) { + } + + // Read the constant pool + readCP(in); + access = in.readUnsignedShort(); + this_class = in.readUnsignedShort(); + super_class = in.readUnsignedShort(); + + //Read interfaces. + interfaces_count = in.readUnsignedShort(); + if (interfaces_count > 0) { + interfaces = new int[interfaces_count]; + } + for (int i = 0; i < interfaces_count; i++) { + interfaces[i] = in.readShort(); + } + + // Read the fields + readFields(in); + + // Read the methods + readMethods(in); + + // Read the attributes + attributes_count = in.readUnsignedShort(); + attrs = new AttrData[attributes_count]; + for (int k = 0; k < attributes_count; k++) { + int name_cpx = in.readUnsignedShort(); + if (getTag(name_cpx) == CONSTANT_UTF8 + && getString(name_cpx).equals("SourceFile")) { + if (in.readInt() != 2) { + throw new ClassFormatError("invalid attr length"); + } + source_cpx = in.readUnsignedShort(); + AttrData attr = new AttrData(this); + attr.read(name_cpx); + attrs[k] = attr; + + } else if (getTag(name_cpx) == CONSTANT_UTF8 + && getString(name_cpx).equals("InnerClasses")) { + int length = in.readInt(); + int num = in.readUnsignedShort(); + if (2 + num * 8 != length) { + throw new ClassFormatError("invalid attr length"); + } + innerClasses = new InnerClassData[num]; + for (int j = 0; j < num; j++) { + InnerClassData innerClass = new InnerClassData(this); + innerClass.read(in); + innerClasses[j] = innerClass; + } + AttrData attr = new AttrData(this); + attr.read(name_cpx); + attrs[k] = attr; + } else { + AttrData attr = new AttrData(this); + attr.read(name_cpx, in); + attrs[k] = attr; + } + } + in.close(); + } // end ClassData.read() + + /** + * Reads and stores constant pool info. + */ + void readCP(DataInputStream in) throws IOException { + cpool_count = in.readUnsignedShort(); + tags = new byte[cpool_count]; + cpool = new Object[cpool_count]; + for (int i = 1; i < cpool_count; i++) { + byte tag = in.readByte(); + + switch (tags[i] = tag) { + case CONSTANT_UTF8: + String str = in.readUTF(); + indexHashAscii.put(cpool[i] = str, new Integer(i)); + break; + case CONSTANT_INTEGER: + cpool[i] = new Integer(in.readInt()); + break; + case CONSTANT_FLOAT: + cpool[i] = new Float(in.readFloat()); + break; + case CONSTANT_LONG: + cpool[i++] = new Long(in.readLong()); + break; + case CONSTANT_DOUBLE: + cpool[i++] = new Double(in.readDouble()); + break; + case CONSTANT_CLASS: + case CONSTANT_STRING: + cpool[i] = new CPX(in.readUnsignedShort()); + break; + + case CONSTANT_FIELD: + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + case CONSTANT_NAMEANDTYPE: + cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort()); + break; + + case 0: + default: + throw new ClassFormatError("invalid constant type: " + (int) tags[i]); + } + } + } + + /** + * Reads and strores field info. + */ + protected void readFields(DataInputStream in) throws IOException { + int fields_count = in.readUnsignedShort(); + fields = new FieldData[fields_count]; + for (int k = 0; k < fields_count; k++) { + FieldData field = new FieldData(this); + field.read(in); + fields[k] = field; + } + } + + /** + * Reads and strores Method info. + */ + protected void readMethods(DataInputStream in) throws IOException { + int methods_count = in.readUnsignedShort(); + methods = new MethodData[methods_count]; + for (int k = 0; k < methods_count; k++) { + MethodData method = new MethodData(this); + method.read(in); + methods[k] = method; + } + } + + /** + * get a string + */ + public String getString(int n) { + if (n == 0) { + return null; + } else { + return (String) cpool[n]; + } + } + + /** + * get the type of constant given an index + */ + public byte getTag(int n) { + try { + return tags[n]; + } catch (ArrayIndexOutOfBoundsException e) { + return (byte) 100; + } + } + static final String hexString = "0123456789ABCDEF"; + public static char hexTable[] = hexString.toCharArray(); + + static String toHex(long val, int width) { + StringBuffer s = new StringBuffer(); + for (int i = width - 1; i >= 0; i--) { + s.append(hexTable[((int) (val >> (4 * i))) & 0xF]); + } + return "0x" + s.toString(); + } + + static String toHex(long val) { + int width; + for (width = 16; width > 0; width--) { + if ((val >> (width - 1) * 4) != 0) { + break; + } + } + return toHex(val, width); + } + + static String toHex(int val) { + int width; + for (width = 8; width > 0; width--) { + if ((val >> (width - 1) * 4) != 0) { + break; + } + } + return toHex(val, width); + } + + /** + * Returns the name of this class. + */ + public String getClassName() { + String res = null; + if (this_class == 0) { + return res; + } + int tcpx; + try { + if (tags[this_class] != CONSTANT_CLASS) { + return res; //" "; + } + tcpx = ((CPX) cpool[this_class]).cpx; + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "#"+cpx+"// invalid constant pool index"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + + try { + return (String) (cpool[tcpx]); + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "class #"+scpx+"// invalid constant pool index"; + } catch (ClassCastException e) { + return res; // "class #"+scpx+"// invalid constant pool reference"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + + } + + /** + * Returns the name of class at perticular index. + */ + public String getClassName(int cpx) { + String res = "#" + cpx; + if (cpx == 0) { + return res; + } + int scpx; + try { + if (tags[cpx] != CONSTANT_CLASS) { + return res; //" "; + } + scpx = ((CPX) cpool[cpx]).cpx; + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "#"+cpx+"// invalid constant pool index"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + res = "#" + scpx; + try { + return (String) (cpool[scpx]); + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "class #"+scpx+"// invalid constant pool index"; + } catch (ClassCastException e) { + return res; // "class #"+scpx+"// invalid constant pool reference"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + } + + public int getAccessFlags() { + return access; + } + + /** + * Returns true if it is a class + */ + public boolean isClass() { + if ((access & ACC_INTERFACE) == 0) { + return true; + } + return false; + } + + /** + * Returns true if it is a interface. + */ + public boolean isInterface() { + if ((access & ACC_INTERFACE) != 0) { + return true; + } + return false; + } + + /** + * Returns true if this member is public, false otherwise. + */ + public boolean isPublic() { + return (access & ACC_PUBLIC) != 0; + } + + /** + * Returns the access of this class or interface. + */ + public String[] getAccess() { + Vector v = new Vector(); + if ((access & ACC_PUBLIC) != 0) { + v.addElement("public"); + } + if ((access & ACC_FINAL) != 0) { + v.addElement("final"); + } + if ((access & ACC_ABSTRACT) != 0) { + v.addElement("abstract"); + } + String[] accflags = new String[v.size()]; + v.copyInto(accflags); + return accflags; + } + + /** + * Returns list of innerclasses. + */ + public InnerClassData[] getInnerClasses() { + return innerClasses; + } + + /** + * Returns list of attributes. + */ + final AttrData[] getAttributes() { + return attrs; + } + + public byte[] findAnnotationData(boolean classRetention) { + String n = classRetention + ? "RuntimeInvisibleAnnotations" : // NOI18N + "RuntimeVisibleAnnotations"; // NOI18N + return findAttr(n, attrs); + } + + /** + * Returns true if superbit is set. + */ + public boolean isSuperSet() { + if ((access & ACC_SUPER) != 0) { + return true; + } + return false; + } + + /** + * Returns super class name. + */ + public String getSuperClassName() { + String res = null; + if (super_class == 0) { + return res; + } + int scpx; + try { + if (tags[super_class] != CONSTANT_CLASS) { + return res; //" "; + } + scpx = ((CPX) cpool[super_class]).cpx; + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "#"+cpx+"// invalid constant pool index"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + + try { + return (String) (cpool[scpx]); + } catch (ArrayIndexOutOfBoundsException e) { + return res; // "class #"+scpx+"// invalid constant pool index"; + } catch (ClassCastException e) { + return res; // "class #"+scpx+"// invalid constant pool reference"; + } catch (Throwable e) { + return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; + } + } + + /** + * Returns list of super interfaces. + */ + public String[] getSuperInterfaces() { + String interfacenames[] = new String[interfaces.length]; + int interfacecpx = -1; + for (int i = 0; i < interfaces.length; i++) { + interfacecpx = ((CPX) cpool[interfaces[i]]).cpx; + interfacenames[i] = (String) (cpool[interfacecpx]); + } + return interfacenames; + } + + /** + * Returns string at prticular constant pool index. + */ + public String getStringValue(int cpoolx) { + try { + return ((String) cpool[cpoolx]); + } catch (ArrayIndexOutOfBoundsException e) { + return "//invalid constant pool index:" + cpoolx; + } catch (ClassCastException e) { + return "//invalid constant pool ref:" + cpoolx; + } + } + + /** + * Returns list of field info. + */ + public FieldData[] getFields() { + return fields; + } + + /** + * Returns list of method info. + */ + public MethodData[] getMethods() { + return methods; + } + + /** + * Returns constant pool entry at that index. + */ + public CPX2 getCpoolEntry(int cpx) { + return ((CPX2) (cpool[cpx])); + } + + public Object getCpoolEntryobj(int cpx) { + return (cpool[cpx]); + } + + /** + * Returns index of this class. + */ + public int getthis_cpx() { + return this_class; + } + + /** + * Returns string at that index. + */ + public String StringValue(int cpx) { + return stringValue(cpx, false); + } + + public String stringValue(int cpx, boolean textual) { + return stringValue(cpx, textual, null); + } + + public String stringValue(int cpx, String[] classRefs) { + return stringValue(cpx, true, classRefs); + } + + private String stringValue(int cpx, boolean textual, String[] refs) { + if (cpx == 0) { + return "#0"; + } + int tag; + Object x; + String suffix = ""; + try { + tag = tags[cpx]; + x = cpool[cpx]; + } catch (IndexOutOfBoundsException e) { + return ""; + } + + if (x == null) { + return ""; + } + switch (tag) { + case CONSTANT_UTF8: { + if (!textual) { + return (String) x; + } + StringBuilder sb = new StringBuilder(); + String s = (String) x; + for (int k = 0; k < s.length(); k++) { + char c = s.charAt(k); + switch (c) { + case '\\': + sb.append('\\').append('\\'); + break; + case '\t': + sb.append('\\').append('t'); + break; + case '\n': + sb.append('\\').append('n'); + break; + case '\r': + sb.append('\\').append('r'); + break; + case '\"': + sb.append('\\').append('\"'); + break; + default: + sb.append(c); + } + } + return sb.toString(); + } + case CONSTANT_DOUBLE: { + Double d = (Double) x; + String sd = d.toString(); + if (textual) { + return sd; + } + return sd + "d"; + } + case CONSTANT_FLOAT: { + Float f = (Float) x; + String sf = (f).toString(); + if (textual) { + return sf; + } + return sf + "f"; + } + case CONSTANT_LONG: { + Long ln = (Long) x; + if (textual) { + return ln.toString(); + } + return ln.toString() + 'l'; + } + case CONSTANT_INTEGER: { + Integer in = (Integer) x; + return in.toString(); + } + case CONSTANT_CLASS: + String jn = getClassName(cpx); + if (textual) { + if (refs != null) { + refs[0] = jn; + } + return jn; + } + return javaName(jn); + case CONSTANT_STRING: + String sv = stringValue(((CPX) x).cpx, textual); + if (textual) { + return '"' + sv + '"'; + } else { + return sv; + } + case CONSTANT_FIELD: + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2); + return javaName(getClassName(((CPX2) x).cpx1)) + "." + StringValue(((CPX2) x).cpx2); + + case CONSTANT_NAMEANDTYPE: + return getName(((CPX2) x).cpx1) + ":" + StringValue(((CPX2) x).cpx2); + default: + return "UnknownTag"; //TBD + } + } + + /** + * Returns resolved java type name. + */ + public String javaName(String name) { + if (name == null) { + return "null"; + } + int len = name.length(); + if (len == 0) { + return "\"\""; + } + int cc = '/'; + fullname: + { // xxx/yyy/zzz + int cp; + for (int k = 0; k < len; k += Character.charCount(cp)) { + cp = name.codePointAt(k); + if (cc == '/') { + if (!isJavaIdentifierStart(cp)) { + break fullname; + } + } else if (cp != '/') { + if (!isJavaIdentifierPart(cp)) { + break fullname; + } + } + cc = cp; + } + return name; + } + return "\"" + name + "\""; + } + + public String getName(int cpx) { + String res; + try { + return javaName((String) cpool[cpx]); //.replace('/','.'); + } catch (ArrayIndexOutOfBoundsException e) { + return ""; + } catch (ClassCastException e) { + return ""; + } + } + + /** + * Returns unqualified class name. + */ + public String getShortClassName(int cpx) { + String classname = javaName(getClassName(cpx)); + pkgPrefixLen = classname.lastIndexOf("/") + 1; + if (pkgPrefixLen != 0) { + pkgPrefix = classname.substring(0, pkgPrefixLen); + if (classname.startsWith(pkgPrefix)) { + return classname.substring(pkgPrefixLen); + } + } + return classname; + } + + /** + * Returns source file name. + */ + public String getSourceName() { + return getName(source_cpx); + } + + /** + * Returns package name. + */ + public String getPkgName() { + String classname = getClassName(this_class); + pkgPrefixLen = classname.lastIndexOf("/") + 1; + if (pkgPrefixLen != 0) { + pkgPrefix = classname.substring(0, pkgPrefixLen); + return ("package " + pkgPrefix.substring(0, pkgPrefixLen - 1) + ";\n"); + } else { + return null; + } + } + + /** + * Returns total constant pool entry count. + */ + public int getCpoolCount() { + return cpool_count; + } + + /** + * Returns minor version of class file. + */ + public int getMinor_version() { + return minor_version; + } + + /** + * Returns major version of class file. + */ + public int getMajor_version() { + return major_version; + } + + private boolean isJavaIdentifierStart(int cp) { + return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z'); + } + + private boolean isJavaIdentifierPart(int cp) { + return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9'); + } + + public String[] getNameAndType(int indx) { + return getNameAndType(indx, 0, new String[2]); + } + + private String[] getNameAndType(int indx, int at, String[] arr) { + CPX2 c2 = getCpoolEntry(indx); + arr[at] = StringValue(c2.cpx1); + arr[at + 1] = StringValue(c2.cpx2); + return arr; + } + + public String[] getFieldInfoName(int indx) { + CPX2 c2 = getCpoolEntry(indx); + String[] arr = new String[3]; + arr[0] = getClassName(c2.cpx1); + return getNameAndType(c2.cpx2, 1, arr); + } + + static byte[] findAttr(String n, AttrData[] attrs) { + for (AttrData ad : attrs) { + if (n.equals(ad.getAttrName())) { + return ad.getData(); + } + } + return null; + } + } + + /** + * Strores field data informastion. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + static class FieldData { + + ClassData cls; + int access; + int name_index; + int descriptor_index; + int attributes_count; + int value_cpx = 0; + boolean isSynthetic = false; + boolean isDeprecated = false; + Vector attrs; + + public FieldData(ClassData cls) { + this.cls = cls; + } + + /** + * Read and store field info. + */ + public void read(DataInputStream in) throws IOException { + access = in.readUnsignedShort(); + name_index = in.readUnsignedShort(); + descriptor_index = in.readUnsignedShort(); + // Read the attributes + int attributes_count = in.readUnsignedShort(); + attrs = new Vector(attributes_count); + for (int i = 0; i < attributes_count; i++) { + int attr_name_index = in.readUnsignedShort(); + if (cls.getTag(attr_name_index) != CONSTANT_UTF8) { + continue; + } + String attr_name = cls.getString(attr_name_index); + if (attr_name.equals("ConstantValue")) { + if (in.readInt() != 2) { + throw new ClassFormatError("invalid ConstantValue attr length"); + } + value_cpx = in.readUnsignedShort(); + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + } else if (attr_name.equals("Synthetic")) { + if (in.readInt() != 0) { + throw new ClassFormatError("invalid Synthetic attr length"); + } + isSynthetic = true; + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + } else if (attr_name.equals("Deprecated")) { + if (in.readInt() != 0) { + throw new ClassFormatError("invalid Synthetic attr length"); + } + isDeprecated = true; + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + } else { + AttrData attr = new AttrData(cls); + attr.read(attr_name_index, in); + attrs.addElement(attr); + } + } + + } // end read + + public boolean isStatic() { + return (access & ACC_STATIC) != 0; + } + + /** + * Returns access of a field. + */ + public String[] getAccess() { + Vector v = new Vector(); + if ((access & ACC_PUBLIC) != 0) { + v.addElement("public"); + } + if ((access & ACC_PRIVATE) != 0) { + v.addElement("private"); + } + if ((access & ACC_PROTECTED) != 0) { + v.addElement("protected"); + } + if ((access & ACC_STATIC) != 0) { + v.addElement("static"); + } + if ((access & ACC_FINAL) != 0) { + v.addElement("final"); + } + if ((access & ACC_VOLATILE) != 0) { + v.addElement("volatile"); + } + if ((access & ACC_TRANSIENT) != 0) { + v.addElement("transient"); + } + String[] accflags = new String[v.size()]; + v.copyInto(accflags); + return accflags; + } + + /** + * Returns name of a field. + */ + public String getName() { + return cls.getStringValue(name_index); + } + + /** + * Returns internal signature of a field + */ + public String getInternalSig() { + return cls.getStringValue(descriptor_index); + } + + /** + * Returns true if field is synthetic. + */ + public boolean isSynthetic() { + return isSynthetic; + } + + /** + * Returns true if field is deprecated. + */ + public boolean isDeprecated() { + return isDeprecated; + } + + /** + * Returns index of constant value in cpool. + */ + public int getConstantValueIndex() { + return (value_cpx); + } + + /** + * Returns list of attributes of field. + */ + public Vector getAttributes() { + return attrs; + } + + public byte[] findAnnotationData(boolean classRetention) { + String n = classRetention + ? "RuntimeInvisibleAnnotations" : // NOI18N + "RuntimeVisibleAnnotations"; // NOI18N + AttrData[] arr = new AttrData[attrs.size()]; + attrs.copyInto(arr); + return ClassData.findAttr(n, arr); + } + } + + /** + * A JavaScript optimized replacement for Hashtable. + * + * @author Jaroslav Tulach + */ + private static final class Hashtable { + + private Object[] keys; + private Object[] values; + + Hashtable(int i) { + this(); + } + + Hashtable(int i, double d) { + this(); + } + + Hashtable() { + } + + synchronized void put(Object key, Object val) { + int[] where = {-1, -1}; + Object found = get(key, where); + if (where[0] != -1) { + // key exists + values[where[0]] = val; + } else { + if (where[1] != -1) { + // null found + keys[where[1]] = key; + values[where[1]] = val; + } else { + if (keys == null) { + keys = new Object[11]; + values = new Object[11]; + keys[0] = key; + values[0] = val; + } else { + Object[] newKeys = new Object[keys.length * 2]; + Object[] newValues = new Object[values.length * 2]; + for (int i = 0; i < keys.length; i++) { + newKeys[i] = keys[i]; + newValues[i] = values[i]; + } + newKeys[keys.length] = key; + newValues[keys.length] = val; + keys = newKeys; + values = newValues; + } + } + } + } + + Object get(Object key) { + return get(key, null); + } + + private synchronized Object get(Object key, int[] foundAndNull) { + if (keys == null) { + return null; + } + for (int i = 0; i < keys.length; i++) { + if (keys[i] == null) { + if (foundAndNull != null) { + foundAndNull[1] = i; + } + } else if (keys[i].equals(key)) { + if (foundAndNull != null) { + foundAndNull[0] = i; + } + return values[i]; + } + } + return null; + } + } + + /** + * Strores InnerClass data informastion. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class InnerClassData { + + ClassData cls; + int inner_class_info_index, outer_class_info_index, inner_name_index, access; + + public InnerClassData(ClassData cls) { + this.cls = cls; + + } + + /** + * Read Innerclass attribute data. + */ + public void read(DataInputStream in) throws IOException { + inner_class_info_index = in.readUnsignedShort(); + outer_class_info_index = in.readUnsignedShort(); + inner_name_index = in.readUnsignedShort(); + access = in.readUnsignedShort(); + } // end read + + /** + * Returns the access of this class or interface. + */ + public String[] getAccess() { + Vector v = new Vector(); + if ((access & ACC_PUBLIC) != 0) { + v.addElement("public"); + } + if ((access & ACC_FINAL) != 0) { + v.addElement("final"); + } + if ((access & ACC_ABSTRACT) != 0) { + v.addElement("abstract"); + } + String[] accflags = new String[v.size()]; + v.copyInto(accflags); + return accflags; + } + } // end InnerClassData + + /** + * Strores LineNumberTable data information. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class LineNumData { + + short start_pc, line_number; + + public LineNumData() { + } + + /** + * Read LineNumberTable attribute. + */ + public LineNumData(DataInputStream in) throws IOException { + start_pc = in.readShort(); + line_number = in.readShort(); + + } + } + + /** + * Strores LocalVariableTable data information. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + private static class LocVarData { + + short start_pc, length, name_cpx, sig_cpx, slot; + + public LocVarData() { + } + + /** + * Read LocalVariableTable attribute. + */ + public LocVarData(DataInputStream in) throws IOException { + start_pc = in.readShort(); + length = in.readShort(); + name_cpx = in.readShort(); + sig_cpx = in.readShort(); + slot = in.readShort(); + + } + } + /** + * Strores method data informastion. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + static class MethodData { + + ClassData cls; + int access; + int name_index; + int descriptor_index; + int attributes_count; + byte[] code; + Vector exception_table = new Vector(0); + Vector lin_num_tb = new Vector(0); + Vector loc_var_tb = new Vector(0); + StackMapTableData[] stackMapTable; + StackMapData[] stackMap; + int[] exc_index_table = null; + Vector attrs = new Vector(0); + Vector code_attrs = new Vector(0); + int max_stack, max_locals; + boolean isSynthetic = false; + boolean isDeprecated = false; + + public MethodData(ClassData cls) { + this.cls = cls; + } + + /** + * Read method info. + */ + public void read(DataInputStream in) throws IOException { + access = in.readUnsignedShort(); + name_index = in.readUnsignedShort(); + descriptor_index = in.readUnsignedShort(); + int attributes_count = in.readUnsignedShort(); + for (int i = 0; i < attributes_count; i++) { + int attr_name_index = in.readUnsignedShort(); + + readAttr: + { + if (cls.getTag(attr_name_index) == CONSTANT_UTF8) { + String attr_name = cls.getString(attr_name_index); + if (attr_name.equals("Code")) { + readCode(in); + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } else if (attr_name.equals("Exceptions")) { + readExceptions(in); + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } else if (attr_name.equals("Synthetic")) { + if (in.readInt() != 0) { + throw new ClassFormatError("invalid Synthetic attr length"); + } + isSynthetic = true; + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } else if (attr_name.equals("Deprecated")) { + if (in.readInt() != 0) { + throw new ClassFormatError("invalid Synthetic attr length"); + } + isDeprecated = true; + AttrData attr = new AttrData(cls); + attr.read(attr_name_index); + attrs.addElement(attr); + break readAttr; + } + } + AttrData attr = new AttrData(cls); + attr.read(attr_name_index, in); + attrs.addElement(attr); + } + } + } + + /** + * Read code attribute info. + */ + public void readCode(DataInputStream in) throws IOException { + + int attr_length = in.readInt(); + max_stack = in.readUnsignedShort(); + max_locals = in.readUnsignedShort(); + int codelen = in.readInt(); + + code = new byte[codelen]; + int totalread = 0; + while (totalread < codelen) { + totalread += in.read(code, totalread, codelen - totalread); + } + // in.read(code, 0, codelen); + int clen = 0; + readExceptionTable(in); + int code_attributes_count = in.readUnsignedShort(); + + for (int k = 0; k < code_attributes_count; k++) { + int table_name_index = in.readUnsignedShort(); + int table_name_tag = cls.getTag(table_name_index); + AttrData attr = new AttrData(cls); + if (table_name_tag == CONSTANT_UTF8) { + String table_name_tstr = cls.getString(table_name_index); + if (table_name_tstr.equals("LineNumberTable")) { + readLineNumTable(in); + attr.read(table_name_index); + } else if (table_name_tstr.equals("LocalVariableTable")) { + readLocVarTable(in); + attr.read(table_name_index); + } else if (table_name_tstr.equals("StackMapTable")) { + readStackMapTable(in); + attr.read(table_name_index); + } else if (table_name_tstr.equals("StackMap")) { + readStackMap(in); + attr.read(table_name_index); + } else { + attr.read(table_name_index, in); + } + code_attrs.addElement(attr); + continue; + } + + attr.read(table_name_index, in); + code_attrs.addElement(attr); + } + } + + /** + * Read exception table info. + */ + void readExceptionTable(DataInputStream in) throws IOException { + int exception_table_len = in.readUnsignedShort(); + exception_table = new Vector(exception_table_len); + for (int l = 0; l < exception_table_len; l++) { + exception_table.addElement(new TrapData(in, l)); + } + } + + /** + * Read LineNumberTable attribute info. + */ + void readLineNumTable(DataInputStream in) throws IOException { + int attr_len = in.readInt(); // attr_length + int lin_num_tb_len = in.readUnsignedShort(); + lin_num_tb = new Vector(lin_num_tb_len); + for (int l = 0; l < lin_num_tb_len; l++) { + lin_num_tb.addElement(new LineNumData(in)); + } + } + + /** + * Read LocalVariableTable attribute info. + */ + void readLocVarTable(DataInputStream in) throws IOException { + int attr_len = in.readInt(); // attr_length + int loc_var_tb_len = in.readUnsignedShort(); + loc_var_tb = new Vector(loc_var_tb_len); + for (int l = 0; l < loc_var_tb_len; l++) { + loc_var_tb.addElement(new LocVarData(in)); + } + } + + /** + * Read Exception attribute info. + */ + public void readExceptions(DataInputStream in) throws IOException { + int attr_len = in.readInt(); // attr_length in prog + int num_exceptions = in.readUnsignedShort(); + exc_index_table = new int[num_exceptions]; + for (int l = 0; l < num_exceptions; l++) { + int exc = in.readShort(); + exc_index_table[l] = exc; + } + } + + /** + * Read StackMapTable attribute info. + */ + void readStackMapTable(DataInputStream in) throws IOException { + int attr_len = in.readInt(); //attr_length + int stack_map_tb_len = in.readUnsignedShort(); + stackMapTable = new StackMapTableData[stack_map_tb_len]; + for (int i = 0; i < stack_map_tb_len; i++) { + stackMapTable[i] = StackMapTableData.getInstance(in, this); + } + } + + /** + * Read StackMap attribute info. + */ + void readStackMap(DataInputStream in) throws IOException { + int attr_len = in.readInt(); //attr_length + int stack_map_len = in.readUnsignedShort(); + stackMap = new StackMapData[stack_map_len]; + for (int i = 0; i < stack_map_len; i++) { + stackMap[i] = new StackMapData(in, this); + } + } + + /** + * Return access of the method. + */ + public int getAccess() { + return access; + } + + /** + * Return name of the method. + */ + public String getName() { + return cls.getStringValue(name_index); + } + + /** + * Return internal siganature of the method. + */ + public String getInternalSig() { + return cls.getStringValue(descriptor_index); + } + + /** + * Return code attribute data of a method. + */ + public byte[] getCode() { + return code; + } + + /** + * Return LineNumberTable size. + */ + public int getnumlines() { + return lin_num_tb.size(); + } + + /** + * Return LineNumberTable + */ + public Vector getlin_num_tb() { + return lin_num_tb; + } + + /** + * Return LocalVariableTable size. + */ + public int getloc_var_tbsize() { + return loc_var_tb.size(); + } + + /** + * Return LocalVariableTable. + */ + public Vector getloc_var_tb() { + return loc_var_tb; + } + + /** + * Return StackMap. + */ + public StackMapData[] getStackMap() { + return stackMap; + } + + /** + * Return StackMapTable. + */ + public StackMapTableData[] getStackMapTable() { + return stackMapTable; + } + + public StackMapIterator createStackMapIterator() { + return new StackMapIterator(this); + } + + /** + * Return true if method is static + */ + public boolean isStatic() { + if ((access & ACC_STATIC) != 0) { + return true; + } + return false; + } + + /** + * Return max depth of operand stack. + */ + public int getMaxStack() { + return max_stack; + } + + /** + * Return number of local variables. + */ + public int getMaxLocals() { + return max_locals; + } + + /** + * Return exception index table in Exception attribute. + */ + public int[] get_exc_index_table() { + return exc_index_table; + } + + /** + * Return exception table in code attributre. + */ + public TrapDataIterator getTrapDataIterator() { + return new TrapDataIterator(exception_table); + } + + /** + * Return method attributes. + */ + public Vector getAttributes() { + return attrs; + } + + /** + * Return code attributes. + */ + public Vector getCodeAttributes() { + return code_attrs; + } + + /** + * Return true if method id synthetic. + */ + public boolean isSynthetic() { + return isSynthetic; + } + + /** + * Return true if method is deprecated. + */ + public boolean isDeprecated() { + return isDeprecated; + } + + public byte[] findAnnotationData(boolean classRetention) { + String n = classRetention + ? "RuntimeInvisibleAnnotations" : // NOI18N + "RuntimeVisibleAnnotations"; // NOI18N + AttrData[] arr = new AttrData[attrs.size()]; + attrs.copyInto(arr); + return ClassData.findAttr(n, arr); + } + + public boolean isConstructor() { + return "".equals(getName()); + } + } + + /* represents one entry of StackMap attribute + */ + private static class StackMapData { + + final int offset; + final int[] locals; + final int[] stack; + + StackMapData(int offset, int[] locals, int[] stack) { + this.offset = offset; + this.locals = locals; + this.stack = stack; + } + + StackMapData(DataInputStream in, MethodData method) throws IOException { + offset = in.readUnsignedShort(); + int local_size = in.readUnsignedShort(); + locals = readTypeArray(in, local_size, method); + int stack_size = in.readUnsignedShort(); + stack = readTypeArray(in, stack_size, method); + } + + static final int[] readTypeArray(DataInputStream in, int length, MethodData method) throws IOException { + int[] types = new int[length]; + for (int i = 0; i < length; i++) { + types[i] = readType(in, method); + } + return types; + } + + static final int readType(DataInputStream in, MethodData method) throws IOException { + int type = in.readUnsignedByte(); + if (type == ITEM_Object || type == ITEM_NewObject) { + type = type | (in.readUnsignedShort() << 8); + } + return type; + } + } + + static final class StackMapIterator { + + private final StackMapTableData[] stackMapTable; + private final TypeArray argTypes; + private final TypeArray localTypes; + private final TypeArray stackTypes; + private int nextFrameIndex; + private int lastFrameByteCodeOffset; + private int byteCodeOffset; + + StackMapIterator(final MethodData methodData) { + this(methodData.getStackMapTable(), + methodData.getInternalSig(), + methodData.isStatic()); + } + + StackMapIterator(final StackMapTableData[] stackMapTable, + final String methodSignature, + final boolean isStaticMethod) { + this.stackMapTable = (stackMapTable != null) + ? stackMapTable + : new StackMapTableData[0]; + + argTypes = getArgTypes(methodSignature, isStaticMethod); + localTypes = new TypeArray(); + stackTypes = new TypeArray(); + + localTypes.addAll(argTypes); + + lastFrameByteCodeOffset = -1; + advanceBy(0); + } + + public String getFrameAsString() { + return (nextFrameIndex == 0) + ? StackMapTableData.toString("INITIAL", 0, null, null) + : stackMapTable[nextFrameIndex - 1].toString(); + } + + public int getFrameIndex() { + return nextFrameIndex; + } + + public TypeArray getFrameStack() { + return stackTypes; + } + + public TypeArray getFrameLocals() { + return localTypes; + } + + public TypeArray getArguments() { + return argTypes; + } + + public void advanceBy(final int numByteCodes) { + if (numByteCodes < 0) { + throw new IllegalStateException("Forward only iterator"); + } + + byteCodeOffset += numByteCodes; + while ((nextFrameIndex < stackMapTable.length) + && ((byteCodeOffset - lastFrameByteCodeOffset) + >= (stackMapTable[nextFrameIndex].offsetDelta + + 1))) { + final StackMapTableData nextFrame = stackMapTable[nextFrameIndex]; + + lastFrameByteCodeOffset += nextFrame.offsetDelta + 1; + nextFrame.applyTo(localTypes, stackTypes); + + ++nextFrameIndex; + } + } + + public void advanceTo(final int nextByteCodeOffset) { + advanceBy(nextByteCodeOffset - byteCodeOffset); + } + + private static TypeArray getArgTypes(final String methodSignature, + final boolean isStaticMethod) { + final TypeArray argTypes = new TypeArray(); + + if (!isStaticMethod) { + argTypes.add(ITEM_Object); + } + + if (methodSignature.charAt(0) != '(') { + throw new IllegalArgumentException("Invalid method signature"); + } + + final int length = methodSignature.length(); + boolean skipType = false; + int argType; + for (int i = 1; i < length; ++i) { + switch (methodSignature.charAt(i)) { + case 'B': + case 'C': + case 'S': + case 'Z': + case 'I': + argType = ITEM_Integer; + break; + case 'J': + argType = ITEM_Long; + break; + case 'F': + argType = ITEM_Float; + break; + case 'D': + argType = ITEM_Double; + break; + case 'L': { + i = methodSignature.indexOf(';', i + 1); + if (i == -1) { + throw new IllegalArgumentException( + "Invalid method signature"); + } + argType = ITEM_Object; + break; + } + case ')': + // not interested in the return value type + return argTypes; + case '[': + if (!skipType) { + argTypes.add(ITEM_Object); + skipType = true; + } + continue; + + default: + throw new IllegalArgumentException( + "Invalid method signature"); + } + + if (!skipType) { + argTypes.add(argType); + } else { + skipType = false; + } + } + + return argTypes; + } + } + /* represents one entry of StackMapTable attribute + */ + + private static abstract class StackMapTableData { + + final int frameType; + int offsetDelta; + + StackMapTableData(int frameType) { + this.frameType = frameType; + } + + abstract void applyTo(TypeArray localTypes, TypeArray stackTypes); + + protected static String toString( + final String frameType, + final int offset, + final int[] localTypes, + final int[] stackTypes) { + final StringBuilder sb = new StringBuilder(frameType); + + sb.append("(off: +").append(offset); + if (localTypes != null) { + sb.append(", locals: "); + appendTypes(sb, localTypes); + } + if (stackTypes != null) { + sb.append(", stack: "); + appendTypes(sb, stackTypes); + } + sb.append(')'); + + return sb.toString(); + } + + private static void appendTypes(final StringBuilder sb, final int[] types) { + sb.append('['); + if (types.length > 0) { + sb.append(TypeArray.typeString(types[0])); + for (int i = 1; i < types.length; ++i) { + sb.append(", "); + sb.append(TypeArray.typeString(types[i])); + } + } + sb.append(']'); + } + + private static class SameFrame extends StackMapTableData { + + SameFrame(int frameType, int offsetDelta) { + super(frameType); + this.offsetDelta = offsetDelta; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + stackTypes.clear(); + } + + @Override + public String toString() { + return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED) + ? "_FRAME_EXTENDED" : ""), + offsetDelta, + null, null); + } + } + + private static class SameLocals1StackItem extends StackMapTableData { + + final int[] stack; + + SameLocals1StackItem(int frameType, int offsetDelta, int[] stack) { + super(frameType); + this.offsetDelta = offsetDelta; + this.stack = stack; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + stackTypes.setAll(stack); + } + + @Override + public String toString() { + return toString( + "SAME_LOCALS_1_STACK_ITEM" + + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) + ? "_EXTENDED" : ""), + offsetDelta, + null, stack); + } + } + + private static class ChopFrame extends StackMapTableData { + + ChopFrame(int frameType, int offsetDelta) { + super(frameType); + this.offsetDelta = offsetDelta; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.setSize(localTypes.getSize() + - (SAME_FRAME_EXTENDED - frameType)); + stackTypes.clear(); + } + + @Override + public String toString() { + return toString("CHOP", offsetDelta, null, null); + } + } + + private static class AppendFrame extends StackMapTableData { + + final int[] locals; + + AppendFrame(int frameType, int offsetDelta, int[] locals) { + super(frameType); + this.offsetDelta = offsetDelta; + this.locals = locals; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.addAll(locals); + stackTypes.clear(); + } + + @Override + public String toString() { + return toString("APPEND", offsetDelta, locals, null); + } + } + + private static class FullFrame extends StackMapTableData { + + final int[] locals; + final int[] stack; + + FullFrame(int offsetDelta, int[] locals, int[] stack) { + super(FULL_FRAME); + this.offsetDelta = offsetDelta; + this.locals = locals; + this.stack = stack; + } + + @Override + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.setAll(locals); + stackTypes.setAll(stack); + } + + @Override + public String toString() { + return toString("FULL", offsetDelta, locals, stack); + } + } + + static StackMapTableData getInstance(DataInputStream in, MethodData method) + throws IOException { + int frameType = in.readUnsignedByte(); + + if (frameType < SAME_FRAME_BOUND) { + // same_frame + return new SameFrame(frameType, frameType); + } else if (SAME_FRAME_BOUND <= frameType && frameType < SAME_LOCALS_1_STACK_ITEM_BOUND) { + // same_locals_1_stack_item_frame + // read additional single stack element + return new SameLocals1StackItem(frameType, + (frameType - SAME_FRAME_BOUND), + StackMapData.readTypeArray(in, 1, method)); + } else if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { + // same_locals_1_stack_item_extended + return new SameLocals1StackItem(frameType, + in.readUnsignedShort(), + StackMapData.readTypeArray(in, 1, method)); + } else if (SAME_LOCALS_1_STACK_ITEM_EXTENDED < frameType && frameType < SAME_FRAME_EXTENDED) { + // chop_frame or same_frame_extended + return new ChopFrame(frameType, in.readUnsignedShort()); + } else if (frameType == SAME_FRAME_EXTENDED) { + // chop_frame or same_frame_extended + return new SameFrame(frameType, in.readUnsignedShort()); + } else if (SAME_FRAME_EXTENDED < frameType && frameType < FULL_FRAME) { + // append_frame + return new AppendFrame(frameType, in.readUnsignedShort(), + StackMapData.readTypeArray(in, frameType - SAME_FRAME_EXTENDED, method)); + } else if (frameType == FULL_FRAME) { + // full_frame + int offsetDelta = in.readUnsignedShort(); + int locals_size = in.readUnsignedShort(); + int[] locals = StackMapData.readTypeArray(in, locals_size, method); + int stack_size = in.readUnsignedShort(); + int[] stack = StackMapData.readTypeArray(in, stack_size, method); + return new FullFrame(offsetDelta, locals, stack); + } else { + throw new ClassFormatError("unrecognized frame_type in StackMapTable"); + } + } + } + + /** + * Stores exception table data in code attribute. + * + * @author Sucheta Dambalkar (Adopted code from jdis) + */ + static final class TrapData { + + public final short start_pc; + public final short end_pc; + public final short handler_pc; + public final short catch_cpx; + final int num; + + /** + * Read and store exception table data in code attribute. + */ + TrapData(DataInputStream in, int num) throws IOException { + this.num = num; + start_pc = in.readShort(); + end_pc = in.readShort(); + handler_pc = in.readShort(); + catch_cpx = in.readShort(); + } + + /** + * returns recommended identifier + */ + public String ident() { + return "t" + num; + } + } + /** + * + * @author Jaroslav Tulach + */ + static final class TrapDataIterator { + + private final Hashtable exStart = new Hashtable(); + private final Hashtable exStop = new Hashtable(); + private TrapData[] current = new TrapData[10]; + private int currentCount; + + TrapDataIterator(Vector exceptionTable) { + for (int i = 0; i < exceptionTable.size(); i++) { + final TrapData td = (TrapData) exceptionTable.elementAt(i); + put(exStart, td.start_pc, td); + put(exStop, td.end_pc, td); + } + } + + private static void put(Hashtable h, short key, TrapData td) { + Short s = Short.valueOf((short) key); + Vector v = (Vector) h.get(s); + if (v == null) { + v = new Vector(1); + h.put(s, v); + } + v.add(td); + } + + private boolean processAll(Hashtable h, Short key, boolean add) { + boolean change = false; + Vector v = (Vector) h.get(key); + if (v != null) { + int s = v.size(); + for (int i = 0; i < s; i++) { + TrapData td = (TrapData) v.elementAt(i); + if (add) { + add(td); + change = true; + } else { + remove(td); + change = true; + } + } + } + return change; + } + + public boolean advanceTo(int i) { + Short s = Short.valueOf((short) i); + boolean ch1 = processAll(exStart, s, true); + boolean ch2 = processAll(exStop, s, false); + return ch1 || ch2; + } + + public boolean useTry() { + return currentCount > 0; + } + + public TrapData[] current() { + TrapData[] copy = new TrapData[currentCount]; + for (int i = 0; i < currentCount; i++) { + copy[i] = current[i]; + } + return copy; + } + + private void add(TrapData e) { + if (currentCount == current.length) { + TrapData[] data = new TrapData[currentCount * 2]; + for (int i = 0; i < currentCount; i++) { + data[i] = current[i]; + } + current = data; + } + current[currentCount++] = e; + } + + private void remove(TrapData e) { + if (currentCount == 0) { + return; + } + int from = 0; + while (from < currentCount) { + if (e == current[from++]) { + break; + } + } + while (from < currentCount) { + current[from - 1] = current[from]; + current[from] = null; + from++; + } + currentCount--; + } + } + static final class TypeArray { + + private static final int CAPACITY_INCREMENT = 16; + private int[] types; + private int size; + + public TypeArray() { + } + + public TypeArray(final TypeArray initialTypes) { + setAll(initialTypes); + } + + public void add(final int newType) { + ensureCapacity(size + 1); + types[size++] = newType; + } + + public void addAll(final TypeArray newTypes) { + addAll(newTypes.types, 0, newTypes.size); + } + + public void addAll(final int[] newTypes) { + addAll(newTypes, 0, newTypes.length); + } + + public void addAll(final int[] newTypes, + final int offset, + final int count) { + if (count > 0) { + ensureCapacity(size + count); + arraycopy(newTypes, offset, types, size, count); + size += count; + } + } + + public void set(final int index, final int newType) { + types[index] = newType; + } + + public void setAll(final TypeArray newTypes) { + setAll(newTypes.types, 0, newTypes.size); + } + + public void setAll(final int[] newTypes) { + setAll(newTypes, 0, newTypes.length); + } + + public void setAll(final int[] newTypes, + final int offset, + final int count) { + if (count > 0) { + ensureCapacity(count); + arraycopy(newTypes, offset, types, 0, count); + size = count; + } else { + clear(); + } + } + + public void setSize(final int newSize) { + if (size != newSize) { + ensureCapacity(newSize); + + for (int i = size; i < newSize; ++i) { + types[i] = 0; + } + size = newSize; + } + } + + public void clear() { + size = 0; + } + + public int getSize() { + return size; + } + + public int get(final int index) { + return types[index]; + } + + public static String typeString(final int type) { + switch (type & 0xff) { + case ITEM_Bogus: + return "_top_"; + case ITEM_Integer: + return "_int_"; + case ITEM_Float: + return "_float_"; + case ITEM_Double: + return "_double_"; + case ITEM_Long: + return "_long_"; + case ITEM_Null: + return "_null_"; + case ITEM_InitObject: // UninitializedThis + return "_init_"; + case ITEM_Object: + return "_object_"; + case ITEM_NewObject: // Uninitialized + return "_new_"; + default: + throw new IllegalArgumentException("Unknown type"); + } + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("["); + if (size > 0) { + sb.append(typeString(types[0])); + for (int i = 1; i < size; ++i) { + sb.append(", "); + sb.append(typeString(types[i])); + } + } + + return sb.append(']').toString(); + } + + private void ensureCapacity(final int minCapacity) { + if ((minCapacity == 0) + || (types != null) && (minCapacity <= types.length)) { + return; + } + + final int newCapacity = + ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT) + * CAPACITY_INCREMENT; + final int[] newTypes = new int[newCapacity]; + + if (size > 0) { + arraycopy(types, 0, newTypes, 0, size); + } + + types = newTypes; + } + + // no System.arraycopy + private void arraycopy(final int[] src, final int srcPos, + final int[] dest, final int destPos, + final int length) { + for (int i = 0; i < length; ++i) { + dest[destPos + i] = src[srcPos + i]; + } + } + } + /** + * A JavaScript ready replacement for java.util.Vector + * + * @author Jaroslav Tulach + */ + @JavaScriptPrototype(prototype = "new Array") + private static final class Vector { + + private Object[] arr; + + Vector() { + } + + Vector(int i) { + } + + void add(Object objectType) { + addElement(objectType); + } + + @JavaScriptBody(args = {"obj"}, body = + "this.push(obj);") + void addElement(Object obj) { + final int s = size(); + setSize(s + 1); + setElementAt(obj, s); + } + + @JavaScriptBody(args = {}, body = + "return this.length;") + int size() { + return arr == null ? 0 : arr.length; + } + + @JavaScriptBody(args = {"newArr"}, body = + "for (var i = 0; i < this.length; i++) {\n" + + " newArr[i] = this[i];\n" + + "}\n") + void copyInto(Object[] newArr) { + if (arr == null) { + return; + } + int min = Math.min(newArr.length, arr.length); + for (int i = 0; i < min; i++) { + newArr[i] = arr[i]; + } + } + + @JavaScriptBody(args = {"index"}, body = + "return this[index];") + Object elementAt(int index) { + return arr[index]; + } + + private void setSize(int len) { + Object[] newArr = new Object[len]; + copyInto(newArr); + arr = newArr; + } + + @JavaScriptBody(args = {"val", "index"}, body = + "this[index] = val;") + void setElementAt(Object val, int index) { + arr[index] = val; + } + } + +} diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Fri May 17 10:27:41 2013 +0200 @@ -19,15 +19,7 @@ import java.io.IOException; import java.io.InputStream; -import org.apidesign.bck2brwsr.core.JavaScriptBody; -import org.apidesign.javap.AnnotationParser; -import org.apidesign.javap.ClassData; -import org.apidesign.javap.FieldData; -import org.apidesign.javap.MethodData; -import org.apidesign.javap.StackMapIterator; -import static org.apidesign.javap.RuntimeConstants.*; -import org.apidesign.javap.TrapData; -import org.apidesign.javap.TrapDataIterator; +import static org.apidesign.vm4brwsr.ByteCodeParser.*; /** Translator of the code inside class files to JavaScript. * @@ -36,9 +28,16 @@ abstract class ByteCodeToJavaScript { private ClassData jc; final Appendable out; + final ObfuscationDelegate obfuscationDelegate; protected ByteCodeToJavaScript(Appendable out) { + this(out, ObfuscationDelegate.NULL); + } + + protected ByteCodeToJavaScript( + Appendable out, ObfuscationDelegate obfuscationDelegate) { this.out = out; + this.obfuscationDelegate = obfuscationDelegate; } /* Collects additional required resources. @@ -66,7 +65,9 @@ /* protected */ String accessClass(String classOperation) { return classOperation; } - + + abstract String getVMObject(); + /** Prints out a debug message. * * @param msg the message @@ -100,7 +101,9 @@ "resource", "processByteCode" ); if (arr != null) { - requireScript(arr[0]); + if (!arr[0].isEmpty()) { + requireScript(arr[0]); + } if ("0".equals(arr[1])) { return null; } @@ -112,7 +115,8 @@ StringArray toInitilize = new StringArray(); final String className = className(jc); out.append("\n\n").append(assignClass(className)); - out.append("function CLS() {"); + out.append("function ").append(className).append("() {"); + out.append("\n var CLS = ").append(className).append(';'); out.append("\n if (!CLS.$class) {"); if (proto == null) { String sc = jc.getSuperClassName(); // with _ @@ -144,6 +148,8 @@ append(className).append('_').append(v.getName()) .append("; };"); } + + obfuscationDelegate.exportField(out, "c", "_" + v.getName(), v); } for (MethodData m : jc.getMethods()) { byte[] onlyArr = m.findAnnotationData(true); @@ -158,33 +164,39 @@ } continue; } - String prefix; + String destObject; String mn; + out.append("\n "); if (m.isStatic()) { - prefix = "\n c."; - mn = generateStaticMethod(prefix, m, toInitilize); + destObject = "c"; + mn = generateStaticMethod(destObject, m, toInitilize); } else { if (m.isConstructor()) { - prefix = "\n CLS."; - mn = generateInstanceMethod(prefix, m); + destObject = "CLS"; + mn = generateInstanceMethod(destObject, m); } else { - prefix = "\n c."; - mn = generateInstanceMethod(prefix, m); + destObject = "c"; + mn = generateInstanceMethod(destObject, m); } } + obfuscationDelegate.exportMethod(out, destObject, mn, m); byte[] runAnno = m.findAnnotationData(false); if (runAnno != null) { - out.append(prefix).append(mn).append(".anno = {"); + out.append("\n ").append(destObject).append(".").append(mn).append(".anno = {"); generateAnno(jc, out, runAnno); out.append("\n };"); } - out.append(prefix).append(mn).append(".access = " + m.getAccess()).append(";"); - out.append(prefix).append(mn).append(".cls = CLS;"); + out.append("\n ").append(destObject).append(".").append(mn).append(".access = " + m.getAccess()).append(";"); + out.append("\n ").append(destObject).append(".").append(mn).append(".cls = CLS;"); } out.append("\n c.constructor = CLS;"); - out.append("\n c.$instOf_").append(className).append(" = true;"); + String instOfName = "$instOf_" + className; + out.append("\n c.").append(instOfName).append(" = true;"); + obfuscationDelegate.exportJSProperty(out, "c", instOfName); for (String superInterface : jc.getSuperInterfaces()) { - out.append("\n c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;"); + instOfName = "$instOf_" + superInterface.replace('/', '_'); + out.append("\n c.").append(instOfName).append(" = true;"); + obfuscationDelegate.exportJSProperty(out, "c", instOfName); } out.append("\n CLS.$class = 'temp';"); out.append("\n CLS.$class = "); @@ -199,6 +211,9 @@ generateAnno(jc, out, classAnno); out.append("\n };"); } + for (String init : toInitilize.toArray()) { + out.append("\n ").append(init).append("();"); + } out.append("\n }"); out.append("\n if (arguments.length === 0) {"); out.append("\n if (!(this instanceof CLS)) {"); @@ -227,14 +242,17 @@ out.append("\n }"); out.append("\n return arguments[0] ? new CLS() : CLS.prototype;"); out.append("\n};"); - StringBuilder sb = new StringBuilder(); - for (String init : toInitilize.toArray()) { - sb.append("\n").append(init).append("();"); - } - return sb.toString(); + + obfuscationDelegate.exportClass(out, getVMObject(), className, jc); + +// StringBuilder sb = new StringBuilder(); +// for (String init : toInitilize.toArray()) { +// sb.append("\n").append(init).append("();"); +// } + return ""; } - private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException { - String jsb = javaScriptBody(prefix, m, true); + private String generateStaticMethod(String destObject, MethodData m, StringArray toInitilize) throws IOException { + String jsb = javaScriptBody(destObject, m, true); if (jsb != null) { return jsb; } @@ -242,28 +260,28 @@ if (mn.equals("class__V")) { toInitilize.add(accessClass(className(jc)) + "(false)." + mn); } - generateMethod(prefix, mn, m); + generateMethod(destObject, mn, m); return mn; } - private String generateInstanceMethod(String prefix, MethodData m) throws IOException { - String jsb = javaScriptBody(prefix, m, false); + private String generateInstanceMethod(String destObject, MethodData m) throws IOException { + String jsb = javaScriptBody(destObject, m, false); if (jsb != null) { return jsb; } final String mn = findMethodName(m, new StringBuilder()); - generateMethod(prefix, mn, m); + generateMethod(destObject, mn, m); return mn; } - private void generateMethod(String prefix, String name, MethodData m) + private void generateMethod(String destObject, String name, MethodData m) throws IOException { final StackMapIterator stackMapIterator = m.createStackMapIterator(); TrapDataIterator trap = m.getTrapDataIterator(); final LocalsMapper lmapper = new LocalsMapper(stackMapIterator.getArguments()); - out.append(prefix).append(name).append(" = function("); + out.append(destObject).append(".").append(name).append(" = function("); lmapper.outputArguments(out, m.isStatic()); out.append(") {").append("\n"); @@ -286,22 +304,36 @@ TrapData[] previousTrap = null; boolean wide = false; - out.append("\n var gt = 0;\n for(;;) switch(gt) {\n"); + out.append("\n var gt = 0;\n"); + int openBraces = 0; + int topMostLabel = 0; for (int i = 0; i < byteCodes.length; i++) { int prev = i; stackMapIterator.advanceTo(i); boolean changeInCatch = trap.advanceTo(i); if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) { if (previousTrap != null) { - generateCatch(previousTrap); + generateCatch(previousTrap, i, topMostLabel); previousTrap = null; } } if (lastStackFrame != stackMapIterator.getFrameIndex()) { + if (i != 0) { + out.append(" }\n"); + } + if (openBraces > 64) { + for (int c = 0; c < 64; c++) { + out.append("break;}\n"); + } + openBraces = 1; + topMostLabel = i; + } + lastStackFrame = stackMapIterator.getFrameIndex(); lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals()); smapper.syncWithFrameStack(stackMapIterator.getFrameStack()); - out.append(" case " + i).append(": "); + out.append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n"); + openBraces++; changeInCatch = true; } else { debug(" /* " + i + " */ "); @@ -773,7 +805,7 @@ } case opc_ldc_w: case opc_ldc2_w: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); i += 2; String v = encodeConstant(indx); int type = VarType.fromConstantType(jc.getTag(indx)); @@ -804,133 +836,104 @@ break; case opc_if_acmpeq: i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), - "==="); + "===", topMostLabel); break; case opc_if_acmpne: i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), - "!=="); + "!==", topMostLabel); break; case opc_if_icmpeq: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - "=="); + "==", topMostLabel); break; case opc_ifeq: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 == 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 == 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifne: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 != 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 != 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_iflt: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 < 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 < 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifle: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 <= 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 <= 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifgt: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 > 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 > 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifge: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 >= 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 >= 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifnonnull: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 !== null) { gt = @2; continue; }", - smapper.popA(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 !== null) ", + smapper.popA(), i, indx, topMostLabel); i += 2; break; } case opc_ifnull: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 === null) { gt = @2; continue; }", - smapper.popA(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 === null) ", + smapper.popA(), i, indx, topMostLabel); i += 2; break; } case opc_if_icmpne: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - "!="); + "!=", topMostLabel); break; case opc_if_icmplt: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - "<"); + "<", topMostLabel); break; case opc_if_icmple: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - "<="); + "<=", topMostLabel); break; case opc_if_icmpgt: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - ">"); + ">", topMostLabel); break; case opc_if_icmpge: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - ">="); + ">=", topMostLabel); break; case opc_goto: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "gt = @1; continue;", Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + goTo(out, i, indx, topMostLabel); i += 2; break; } case opc_lookupswitch: { - int table = i / 4 * 4 + 4; - int dflt = i + readInt4(byteCodes, table); - table += 4; - int n = readInt4(byteCodes, table); - table += 4; - out.append("switch (").append(smapper.popI()).append(") {\n"); - while (n-- > 0) { - int cnstnt = readInt4(byteCodes, table); - table += 4; - int offset = i + readInt4(byteCodes, table); - table += 4; - out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n"); - } - out.append(" default: gt = " + dflt).append("; continue;\n}"); - i = table - 1; + i = generateLookupSwitch(i, byteCodes, smapper, topMostLabel); break; } case opc_tableswitch: { - int table = i / 4 * 4 + 4; - int dflt = i + readInt4(byteCodes, table); - table += 4; - int low = readInt4(byteCodes, table); - table += 4; - int high = readInt4(byteCodes, table); - table += 4; - out.append("switch (").append(smapper.popI()).append(") {\n"); - while (low <= high) { - int offset = i + readInt4(byteCodes, table); - table += 4; - out.append(" case " + low).append(": gt = " + offset).append("; continue;\n"); - low++; - } - out.append(" default: gt = " + dflt).append("; continue;\n}"); - i = table - 1; + i = generateTableSwitch(i, byteCodes, smapper, topMostLabel); break; } case opc_invokeinterface: { @@ -947,7 +950,7 @@ i = invokeStaticMethod(byteCodes, i, smapper, true); break; case opc_new: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String ci = jc.getClassName(indx); emit(out, "var @1 = new @2;", smapper.pushA(), accessClass(ci.replace('/', '_'))); @@ -957,50 +960,18 @@ } case opc_newarray: int atype = readUByte(byteCodes, ++i); - String jvmType; - switch (atype) { - case 4: jvmType = "[Z"; break; - case 5: jvmType = "[C"; break; - case 6: jvmType = "[F"; break; - case 7: jvmType = "[D"; break; - case 8: jvmType = "[B"; break; - case 9: jvmType = "[S"; break; - case 10: jvmType = "[I"; break; - case 11: jvmType = "[J"; break; - default: throw new IllegalStateException("Array type: " + atype); - } - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);", - smapper.popI(), smapper.pushA(), jvmType); + generateNewArray(atype, smapper); break; case opc_anewarray: { - int type = readIntArg(byteCodes, i); + int type = readUShortArg(byteCodes, i); i += 2; - String typeName = jc.getClassName(type); - if (typeName.startsWith("[")) { - typeName = "[" + typeName; - } else { - typeName = "[L" + typeName + ";"; - } - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);", - smapper.popI(), smapper.pushA(), typeName); + generateANewArray(type, smapper); break; } case opc_multianewarray: { - int type = readIntArg(byteCodes, i); + int type = readUShortArg(byteCodes, i); i += 2; - String typeName = jc.getClassName(type); - int dim = readUByte(byteCodes, ++i); - StringBuilder dims = new StringBuilder(); - dims.append('['); - for (int d = 0; d < dim; d++) { - if (d != 0) { - dims.insert(1, ","); - } - dims.insert(1, smapper.popI()); - } - dims.append(']'); - emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);", - dims.toString(), smapper.pushA(), typeName); + i = generateMultiANewArray(type, byteCodes, i, smapper); break; } case opc_arraylength: @@ -1214,11 +1185,11 @@ case opc_sipush: emit(out, "var @1 = @2;", smapper.pushI(), - Integer.toString(readIntArg(byteCodes, i))); + Integer.toString(readShortArg(byteCodes, i))); i += 2; break; case opc_getfield: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); final String mangleClass = mangleSig(fi[0]); @@ -1231,7 +1202,7 @@ break; } case opc_putfield: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); final String mangleClass = mangleSig(fi[0]); @@ -1245,7 +1216,7 @@ break; } case opc_getstatic: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); emit(out, "var @1 = @2(false)._@3();", @@ -1256,7 +1227,7 @@ break; } case opc_putstatic: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); emit(out, "@1(false)._@2(@3);", @@ -1267,33 +1238,14 @@ break; } case opc_checkcast: { - int indx = readIntArg(byteCodes, i); - final String type = jc.getClassName(indx); - if (!type.startsWith("[")) { - emit(out, - "if (@1 !== null && !@1.$instOf_@2) throw {};", - smapper.getA(0), type.replace('/', '_')); - } else { - emit(out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);", - smapper.getA(0), type - ); - } + int indx = readUShortArg(byteCodes, i); + generateCheckcast(indx, smapper); i += 2; break; } case opc_instanceof: { - int indx = readIntArg(byteCodes, i); - final String type = jc.getClassName(indx); - if (!type.startsWith("[")) { - emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;", - smapper.popA(), smapper.pushI(), - type.replace('/', '_')); - } else { - emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);", - smapper.popA(), smapper.pushI(), - type - ); - } + int indx = readUShortArg(byteCodes, i); + generateInstanceOf(indx, smapper); i += 2; break; } @@ -1329,37 +1281,29 @@ } } if (debug(" //")) { - for (int j = prev; j <= i; j++) { - out.append(" "); - final int cc = readUByte(byteCodes, j); - out.append(Integer.toString(cc)); - } + generateByteCodeComment(prev, i, byteCodes); } out.append("\n"); } if (previousTrap != null) { - generateCatch(previousTrap); + generateCatch(previousTrap, byteCodes.length, topMostLabel); } - out.append(" }\n"); - out.append("};"); + out.append("\n }\n"); + while (openBraces-- > 0) { + out.append('}'); + } + out.append("\n};"); } - private int generateIf(byte[] byteCodes, int i, - final Variable v2, final Variable v1, - final String test) throws IOException { - int indx = i + readIntArg(byteCodes, i); + private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException { + int indx = i + readShortArg(byteCodes, i); out.append("if (").append(v1) .append(' ').append(test).append(' ') - .append(v2).append(") { gt = " + indx) - .append("; continue; }"); + .append(v2).append(") "); + goTo(out, i, indx, topMostLabel); return i + 2; } - - private int readIntArg(byte[] byteCodes, int offsetInstruction) { - final int indxHi = byteCodes[offsetInstruction + 1] << 8; - final int indxLo = byteCodes[offsetInstruction + 2]; - return (indxHi & 0xffffff00) | (indxLo & 0xff); - } + private int readInt4(byte[] byteCodes, int offset) { final int d = byteCodes[offset + 0] << 24; final int c = byteCodes[offset + 1] << 16; @@ -1367,18 +1311,25 @@ final int a = byteCodes[offset + 3]; return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff); } - private int readUByte(byte[] byteCodes, int offset) { + private static int readUByte(byte[] byteCodes, int offset) { return byteCodes[offset] & 0xff; } - private int readUShort(byte[] byteCodes, int offset) { + private static int readUShort(byte[] byteCodes, int offset) { return ((byteCodes[offset] & 0xff) << 8) | (byteCodes[offset + 1] & 0xff); } + private static int readUShortArg(byte[] byteCodes, int offsetInstruction) { + return readUShort(byteCodes, offsetInstruction + 1); + } - private int readShort(byte[] byteCodes, int offset) { - return (byteCodes[offset] << 8) - | (byteCodes[offset + 1] & 0xff); + private static int readShort(byte[] byteCodes, int offset) { + int signed = byteCodes[offset]; + byte b0 = (byte)signed; + return (b0 << 8) | (byteCodes[offset + 1] & 0xff); + } + private static int readShortArg(byte[] byteCodes, int offsetInstruction) { + return readShort(byteCodes, offsetInstruction + 1); } private static void countArgs(String descriptor, char[] returnType, StringBuilder sig, StringBuilder cnt) { @@ -1506,7 +1457,7 @@ private int invokeStaticMethod(byte[] byteCodes, int i, final StackMapper mapper, boolean isStatic) throws IOException { - int methodIndex = readIntArg(byteCodes, i); + int methodIndex = readUShortArg(byteCodes, i); String[] mi = jc.getFieldInfoName(methodIndex); char[] returnType = { 'V' }; StringBuilder cnt = new StringBuilder(); @@ -1551,7 +1502,7 @@ } private int invokeVirtualMethod(byte[] byteCodes, int i, final StackMapper mapper) throws IOException { - int methodIndex = readIntArg(byteCodes, i); + int methodIndex = readUShortArg(byteCodes, i); String[] mi = jc.getFieldInfoName(methodIndex); char[] returnType = { 'V' }; StringBuilder cnt = new StringBuilder(); @@ -1618,7 +1569,7 @@ return s; } - private String javaScriptBody(String prefix, MethodData m, boolean isStatic) throws IOException { + private String javaScriptBody(String destObject, MethodData m, boolean isStatic) throws IOException { byte[] arr = m.findAnnotationData(true); if (arr == null) { return null; @@ -1653,7 +1604,7 @@ } StringBuilder cnt = new StringBuilder(); final String mn = findMethodName(m, cnt); - out.append(prefix).append(mn); + out.append(destObject).append(".").append(mn); out.append(" = function("); String space = ""; int index = 0; @@ -1826,7 +1777,7 @@ out.append(format, processed, length); } - private void generateCatch(TrapData[] traps) throws IOException { + private void generateCatch(TrapData[] traps, int current, int topMostLabel) throws IOException { out.append("} catch (e) {\n"); int finallyPC = -1; for (TrapData e : traps) { @@ -1836,19 +1787,11 @@ if (e.catch_cpx != 0) { //not finally final String classInternalName = jc.getClassName(e.catch_cpx); addReference(classInternalName); - if ("java/lang/Throwable".equals(classInternalName)) { - out.append("if (e.$instOf_java_lang_Throwable) {"); - out.append(" var stA0 = e;"); - out.append("} else {"); - out.append(" var stA0 = vm.java_lang_Throwable(true);"); - out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());"); - out.append("}"); - out.append("gt=" + e.handler_pc + "; continue;"); - } else { - out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {"); - out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;"); - out.append("}\n"); - } + out.append("e = vm.java_lang_Throwable(false).bck2BrwsrCnvrt(e);"); + out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {"); + out.append("var stA0 = e;"); + goTo(out, current, e.handler_pc, topMostLabel); + out.append("}\n"); } else { finallyPC = e.handler_pc; } @@ -1856,8 +1799,152 @@ if (finallyPC == -1) { out.append("throw e;"); } else { - out.append("gt=" + finallyPC + "; var stA0 = e; continue;"); + out.append("var stA0 = e;"); + goTo(out, current, finallyPC, topMostLabel); } out.append("\n}"); } + + private static void goTo(Appendable out, int current, int to, int canBack) throws IOException { + if (to < current) { + if (canBack < to) { + out.append("{ gt = 0; continue X_" + to + "; }"); + } else { + out.append("{ gt = " + to + "; continue X_0; }"); + } + } else { + out.append("{ gt = " + to + "; break IF; }"); + } + } + + private static void emitIf( + Appendable out, String pattern, Variable param, + int current, int to, int canBack + ) throws IOException { + emit(out, pattern, param); + goTo(out, current, to, canBack); + } + + private void generateNewArray(int atype, final StackMapper smapper) throws IOException, IllegalStateException { + String jvmType; + switch (atype) { + case 4: jvmType = "[Z"; break; + case 5: jvmType = "[C"; break; + case 6: jvmType = "[F"; break; + case 7: jvmType = "[D"; break; + case 8: jvmType = "[B"; break; + case 9: jvmType = "[S"; break; + case 10: jvmType = "[I"; break; + case 11: jvmType = "[J"; break; + default: throw new IllegalStateException("Array type: " + atype); + } + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);", + smapper.popI(), smapper.pushA(), jvmType); + } + + private void generateANewArray(int type, final StackMapper smapper) throws IOException { + String typeName = jc.getClassName(type); + if (typeName.startsWith("[")) { + typeName = "[" + typeName; + } else { + typeName = "[L" + typeName + ";"; + } + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);", + smapper.popI(), smapper.pushA(), typeName); + } + + private int generateMultiANewArray(int type, final byte[] byteCodes, int i, final StackMapper smapper) throws IOException { + String typeName = jc.getClassName(type); + int dim = readUByte(byteCodes, ++i); + StringBuilder dims = new StringBuilder(); + dims.append('['); + for (int d = 0; d < dim; d++) { + if (d != 0) { + dims.insert(1, ","); + } + dims.insert(1, smapper.popI()); + } + dims.append(']'); + emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);", + dims.toString(), smapper.pushA(), typeName); + return i; + } + + private int generateTableSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException { + int table = i / 4 * 4 + 4; + int dflt = i + readInt4(byteCodes, table); + table += 4; + int low = readInt4(byteCodes, table); + table += 4; + int high = readInt4(byteCodes, table); + table += 4; + out.append("switch (").append(smapper.popI()).append(") {\n"); + while (low <= high) { + int offset = i + readInt4(byteCodes, table); + table += 4; + out.append(" case " + low).append(":"); goTo(out, i, offset, topMostLabel); out.append('\n'); + low++; + } + out.append(" default: "); + goTo(out, i, dflt, topMostLabel); + out.append("\n}"); + i = table - 1; + return i; + } + + private int generateLookupSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException { + int table = i / 4 * 4 + 4; + int dflt = i + readInt4(byteCodes, table); + table += 4; + int n = readInt4(byteCodes, table); + table += 4; + out.append("switch (").append(smapper.popI()).append(") {\n"); + while (n-- > 0) { + int cnstnt = readInt4(byteCodes, table); + table += 4; + int offset = i + readInt4(byteCodes, table); + table += 4; + out.append(" case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel); out.append('\n'); + } + out.append(" default: "); + goTo(out, i, dflt, topMostLabel); + out.append("\n}"); + i = table - 1; + return i; + } + + private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException { + final String type = jc.getClassName(indx); + if (!type.startsWith("[")) { + emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;", + smapper.popA(), smapper.pushI(), + type.replace('/', '_')); + } else { + emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);", + smapper.popA(), smapper.pushI(), + type + ); + } + } + + private void generateCheckcast(int indx, final StackMapper smapper) throws IOException { + final String type = jc.getClassName(indx); + if (!type.startsWith("[")) { + emit(out, + "if (@1 !== null && !@1.$instOf_@2) throw vm.java_lang_ClassCastException(true);", + smapper.getA(0), type.replace('/', '_')); + } else { + emit(out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);", + smapper.getA(0), type + ); + } + } + + private void generateByteCodeComment(int prev, int i, final byte[] byteCodes) throws IOException { + for (int j = prev; j <= i; j++) { + out.append(" "); + final int cc = readUByte(byteCodes, j); + out.append(Integer.toString(cc)); + } + } } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,334 @@ +/** + * 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 com.google.javascript.jscomp.CommandLineRunner; +import com.google.javascript.jscomp.SourceFile; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.apidesign.bck2brwsr.core.ExtraJavaScript; +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData; +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData; +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData; + +/** + * + * @author Jaroslav Tulach + */ +@ExtraJavaScript(processByteCode = false, resource="") +final class ClosureWrapper extends CommandLineRunner { + private static final String[] ARGS = { "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--js", "bck2brwsr-raw.js" /*, "--debug", "--formatting", "PRETTY_PRINT" */ }; + + private final ClosuresObfuscationDelegate obfuscationDelegate; + private final Bck2Brwsr.Resources res; + private final StringArray classes; + + private String compiledCode; + private String externsCode; + + private ClosureWrapper(Appendable out, + String compilationLevel, + ClosuresObfuscationDelegate obfuscationDelegate, + Bck2Brwsr.Resources res, StringArray classes) { + super( + generateArguments(compilationLevel), + new PrintStream(new APS(out)), System.err + ); + this.obfuscationDelegate = obfuscationDelegate; + this.res = res; + this.classes = classes; + } + + @Override + protected List createInputs(List files, boolean allowStdIn) throws FlagUsageException, IOException { + if (files.size() != 1 || !"bck2brwsr-raw.js".equals(files.get(0))) { + throw new IOException("Unexpected files: " + files); + } + return Collections.nCopies( + 1, + SourceFile.fromGenerator( + "bck2brwsr-raw.js", + new SourceFile.Generator() { + @Override + public String getCode() { + return getCompiledCode(); + } + })); + } + + + @Override + protected List createExterns() + throws FlagUsageException, IOException { + final List externsFiles = + new ArrayList(super.createExterns()); + + externsFiles.add( + SourceFile.fromGenerator( + "bck2brwsr_externs.js", + new SourceFile.Generator() { + @Override + public String getCode() { + return getExternsCode(); + } + })); + return externsFiles; + } + + private String getCompiledCode() { + if (compiledCode == null) { + StringBuilder sb = new StringBuilder(); + try { + VM.compile(res, sb, classes, obfuscationDelegate); + compiledCode = sb.toString(); + } catch (IOException ex) { + compiledCode = ex.getMessage(); + } + } + return compiledCode; + } + + private String getExternsCode() { + if (externsCode == null) { + // need compiled code at this point + getCompiledCode(); + + final StringBuilder sb = new StringBuilder("function RAW() {};\n"); + for (final String extern: obfuscationDelegate.getExterns()) { + sb.append("RAW.prototype.").append(extern).append(";\n"); + } + externsCode = sb.toString(); + } + return externsCode; + } + + private static final class APS extends OutputStream { + private final Appendable out; + + public APS(Appendable out) { + this.out = out; + } + @Override + public void write(int b) throws IOException { + out.append((char)b); + } + } + + private static String[] generateArguments(String compilationLevel) { + String[] finalArgs = ARGS.clone(); + finalArgs[1] = compilationLevel; + + return finalArgs; + } + + static int produceTo(Appendable w, ObfuscationLevel obfuscationLevel, Bck2Brwsr.Resources resources, StringArray arr) throws IOException { + ClosureWrapper cw = create(w, obfuscationLevel, resources, arr); + try { + return cw.doRun(); + } catch (FlagUsageException ex) { + throw new IOException(ex); + } + } + + private static ClosureWrapper create(Appendable w, + ObfuscationLevel obfuscationLevel, + Bck2Brwsr.Resources resources, + StringArray arr) { + switch (obfuscationLevel) { + case MINIMAL: + return new ClosureWrapper(w, "SIMPLE_OPTIMIZATIONS", + new SimpleObfuscationDelegate(), + resources, arr); +/* + case MEDIUM: + return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS", + new MediumObfuscationDelegate(), + resources, arr); +*/ + case FULL: + return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS", + new FullObfuscationDelegate(), + resources, arr); + default: + throw new IllegalArgumentException( + "Unsupported level: " + obfuscationLevel); + } + } + + private static abstract class ClosuresObfuscationDelegate + extends ObfuscationDelegate { + public abstract Collection getExterns(); + } + + private static final class SimpleObfuscationDelegate + extends ClosuresObfuscationDelegate { + @Override + public void exportJSProperty(Appendable out, + String destObject, + String propertyName) throws IOException { + } + + @Override + public void exportClass(Appendable out, + String destObject, + String mangledName, + ClassData classData) throws IOException { + } + + @Override + public void exportMethod(Appendable out, + String destObject, + String mangledName, + MethodData methodData) throws IOException { + } + + @Override + public void exportField(Appendable out, + String destObject, + String mangledName, + FieldData fieldData) throws IOException { + } + + @Override + public Collection getExterns() { + return Collections.EMPTY_LIST; + } + } + + private static abstract class AdvancedObfuscationDelegate + extends ClosuresObfuscationDelegate { + private static final String[] INITIAL_EXTERNS = { + "bck2brwsr", + "$class", + "anno", + "array", + "access", + "cls", + "vm", + "loadClass", + "loadBytes", + "jvmName", + "primitive", + "superclass", + "cnstr", + "add32", + "sub32", + "mul32", + "neg32", + "toInt8", + "toInt16", + "next32", + "high32", + "toInt32", + "toFP", + "toLong", + "toExactString", + "add64", + "sub64", + "mul64", + "and64", + "or64", + "xor64", + "shl64", + "shr64", + "ushr64", + "compare64", + "neg64", + "div32", + "mod32", + "div64", + "mod64", + "at", + "getClass__Ljava_lang_Class_2", + "clone__Ljava_lang_Object_2" + }; + + private final Collection externs; + + protected AdvancedObfuscationDelegate() { + externs = new ArrayList(Arrays.asList(INITIAL_EXTERNS)); + } + + @Override + public void exportClass(Appendable out, + String destObject, + String mangledName, + ClassData classData) throws IOException { + exportJSProperty(out, destObject, mangledName); + } + + @Override + public void exportMethod(Appendable out, + String destObject, + String mangledName, + MethodData methodData) throws IOException { + if ((methodData.access & ByteCodeParser.ACC_PRIVATE) == 0) { + exportJSProperty(out, destObject, mangledName); + } + } + + @Override + public void exportField(Appendable out, + String destObject, + String mangledName, + FieldData fieldData) throws IOException { + if ((fieldData.access & ByteCodeParser.ACC_PRIVATE) == 0) { + exportJSProperty(out, destObject, mangledName); + } + } + + @Override + public Collection getExterns() { + return externs; + } + + protected void addExtern(String extern) { + externs.add(extern); + } + } + + private static final class MediumObfuscationDelegate + extends AdvancedObfuscationDelegate { + @Override + public void exportJSProperty(Appendable out, + String destObject, + String propertyName) { + addExtern(propertyName); + } + } + + private static final class FullObfuscationDelegate + extends AdvancedObfuscationDelegate { + @Override + public void exportJSProperty(Appendable out, + String destObject, + String propertyName) throws IOException { + out.append("\n").append(destObject).append("['") + .append(propertyName) + .append("'] = ") + .append(destObject).append(".").append(propertyName) + .append(";\n"); + } + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,48 @@ +/** + * 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 java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; + +/** Implementation of Resources that delegates to some class loader. + * + * @author Jaroslav Tulach + */ +final class LdrRsrcs implements Bck2Brwsr.Resources { + private final ClassLoader loader; + + LdrRsrcs(ClassLoader loader) { + this.loader = loader; + } + + @Override + public InputStream get(String name) throws IOException { + Enumeration en = loader.getResources(name); + URL u = null; + while (en.hasMoreElements()) { + u = en.nextElement(); + } + if (u == null) { + throw new IOException("Can't find " + name); + } + return u.openStream(); + } +} diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/LocalsMapper.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/LocalsMapper.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LocalsMapper.java Fri May 17 10:27:41 2013 +0200 @@ -18,8 +18,7 @@ package org.apidesign.vm4brwsr; import java.io.IOException; -import org.apidesign.javap.RuntimeConstants; -import org.apidesign.javap.TypeArray; +import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray; final class LocalsMapper { private final TypeArray argTypeRecords; @@ -113,7 +112,7 @@ final int srcSize = stackMapTypes.getSize(); for (int i = 0, dstIndex = 0; i < srcSize; ++i) { final int smType = stackMapTypes.get(i); - if (smType == RuntimeConstants.ITEM_Bogus) { + if (smType == ByteCodeParser.ITEM_Bogus) { ++dstIndex; continue; } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Fri May 17 10:27:41 2013 +0200 @@ -18,6 +18,7 @@ package org.apidesign.vm4brwsr; import java.io.BufferedWriter; +import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; @@ -31,20 +32,69 @@ private Main() {} public static void main(String... args) throws IOException { + final String obfuscate = "--obfuscatelevel"; + if (args.length < 2) { System.err.println("Bck2Brwsr Translator from Java(tm) to JavaScript, (c) Jaroslav Tulach 2012"); - System.err.println("Usage: java -cp ... -jar ... java/lang/Class org/your/App ..."); - return; + System.err.println("Usage: java -cp ... -jar ... ["); + System.err.print(obfuscate); + System.err.print(" ["); + boolean first = true; + for (ObfuscationLevel l : ObfuscationLevel.values()) { + if (!first) { + System.err.print('|'); + } + System.err.print(l.name()); + first = false; + } + + System.err.println("] java/lang/Class org/your/App ..."); + System.exit(9); } - Writer w = new BufferedWriter(new FileWriter(args[0])); - StringArray classes = StringArray.asList(args); - classes.delete(0); - try { - Bck2Brwsr.generate(w, Main.class.getClassLoader(), - classes.toArray()); - } finally { - w.close(); + ObfuscationLevel obfLevel = ObfuscationLevel.NONE; + StringArray classes = new StringArray(); + String generateTo = null; + for (int i = 0; i < args.length; i++) { + if (obfuscate.equals(args[i])) { // NOI18N + i++; + try { + obfLevel = ObfuscationLevel.valueOf(args[i]); + } catch (Exception e) { + System.err.print(obfuscate); + System.err.print(" parameter needs to be followed by one of "); + boolean first = true; + for (ObfuscationLevel l : ObfuscationLevel.values()) { + if (!first) { + System.err.print(", "); + } + System.err.print(l.name()); + first = false; + } + System.err.println(); + System.exit(1); + } + continue; + } + if (generateTo == null) { + generateTo = args[i]; + } else { + classes = classes.addAndNew(args[i]); + } + } + + File gt = new File(generateTo); + if (Boolean.getBoolean("skip.if.exists") && gt.isFile()) { + System.err.println("Skipping as " + gt + " exists."); + System.exit(0); + } + + try (Writer w = new BufferedWriter(new FileWriter(gt))) { + Bck2Brwsr.newCompiler(). + obfuscation(obfLevel). + addRootClasses(classes.toArray()). + resources(Main.class.getClassLoader()). + generate(w); } } } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/ObfuscationDelegate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ObfuscationDelegate.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,75 @@ +/** + * 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 java.io.IOException; +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData; +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData; +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData; + +abstract class ObfuscationDelegate { + static ObfuscationDelegate NULL = + new ObfuscationDelegate() { + @Override + public void exportJSProperty(Appendable out, + String destObject, + String propertyName) + throws IOException { + } + + @Override + public void exportClass(Appendable out, + String destObject, + String mangledName, + ClassData classData) + throws IOException { + } + + @Override + public void exportMethod(Appendable out, + String destObject, + String mangledName, + MethodData methodData) + throws IOException { + } + + @Override + public void exportField(Appendable out, + String destObject, + String mangledName, + FieldData fieldData) + throws IOException { + } + }; + + public abstract void exportJSProperty( + Appendable out, String destObject, String propertyName) + throws IOException; + + public abstract void exportClass( + Appendable out, String destObject, String mangledName, + ClassData classData) throws IOException; + + public abstract void exportMethod( + Appendable out, String destObject, String mangledName, + MethodData methodData) throws IOException; + + public abstract void exportField( + Appendable out, String destObject, String mangledName, + FieldData fieldData) throws IOException; +} diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/ObfuscationLevel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ObfuscationLevel.java Fri May 17 10:27:41 2013 +0200 @@ -0,0 +1,41 @@ +/** + * 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; + +/** + * Defines obfuscation level of produced JavaScript files. + * + * @since 0.5 + */ +public enum ObfuscationLevel { + /** Generated JavaScript is (sort of) human readable. Useful for debugging. + * Dynamic capabilities of the virtual machine work on all classes. + */ + NONE, + /** White spaces are removed. Names of external symbols remain unchanged. + * Dynamic capabilities of the virtual machine work on all classes. + */ + MINIMAL, +// temporarily commented out before merge. not well defined yet: +// MEDIUM, + /** Aggressive obfuscation of everything. Compact, unreadable "one-liner". + * One cannot load classes dynamically. Useful mostly for static compilation + * of self contained application. + */ + FULL +} diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java Fri May 17 10:27:41 2013 +0200 @@ -17,7 +17,7 @@ */ package org.apidesign.vm4brwsr; -import org.apidesign.javap.TypeArray; +import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray; final class StackMapper { private final TypeArray stackTypeIndexPairs; diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Fri May 17 10:27:41 2013 +0200 @@ -43,6 +43,25 @@ } arr[arr.length - 1] = s; } + + StringArray addAndNew(String... values) { + int j; + String[] tmp; + if (arr == null) { + tmp = new String[values.length]; + j = 0; + } else { + tmp = new String[arr.length + values.length]; + for (int i = 0; i < arr.length; i++) { + tmp[i] = arr[i]; + } + j = arr.length; + } + for (int i = 0; i < values.length;) { + tmp[j++] = values[i++]; + } + return new StringArray(tmp); + } public String[] toArray() { return arr == null ? new String[0] : arr; @@ -93,5 +112,4 @@ } return -1; } - } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Fri May 17 10:27:41 2013 +0200 @@ -28,7 +28,11 @@ public VM(Appendable out) { super(out); } - + + private VM(Appendable out, ObfuscationDelegate obfuscationDelegate) { + super(out, obfuscationDelegate); + } + static { // uses VMLazy to load dynamic classes boolean assertsOn = false; @@ -47,6 +51,12 @@ static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names) throws IOException { new VM(out).doCompile(l, names); } + + static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names, + ObfuscationDelegate obfuscationDelegate) throws IOException { + new VM(out, obfuscationDelegate).doCompile(l, names); + } + protected void doCompile(Bck2Brwsr.Resources l, StringArray names) throws IOException { out.append("(function VM(global) {var fillInVMSkeleton = function(vm) {"); StringArray processed = new StringArray(); @@ -110,7 +120,10 @@ for (String ic : toInit.toArray()) { int indx = processed.indexOf(ic); if (indx >= 0) { - out.append(initCode.toArray()[indx]).append("\n"); + final String theCode = initCode.toArray()[indx]; + if (!theCode.isEmpty()) { + out.append(theCode).append("\n"); + } initCode.toArray()[indx] = ""; } } @@ -227,4 +240,9 @@ String accessClass(String className) { return "vm." + className; } + + @Override + String getVMObject() { + return "vm"; + } } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Fri May 17 10:27:41 2013 +0200 @@ -56,7 +56,7 @@ throw new ClassNotFoundException(name); } // beingDefined(loader, name); - StringBuilder out = new StringBuilder(); + StringBuilder out = new StringBuilder(65535); out.append("var loader = arguments[0];\n"); out.append("var vm = loader.vm;\n"); int prelude = out.length(); @@ -151,5 +151,10 @@ String accessClass(String classOperation) { return "vm." + classOperation; } + + @Override + String getVMObject() { + return "vm"; + } } } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/main/java/org/apidesign/vm4brwsr/VarType.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VarType.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VarType.java Fri May 17 10:27:41 2013 +0200 @@ -17,8 +17,6 @@ */ package org.apidesign.vm4brwsr; -import org.apidesign.javap.RuntimeConstants; - final class VarType { public static final int INTEGER = 0; public static final int LONG = 1; @@ -37,21 +35,21 @@ public static int fromStackMapType(final int smType) { switch (smType & 0xff) { - case RuntimeConstants.ITEM_Integer: + case ByteCodeParser.ITEM_Integer: return VarType.INTEGER; - case RuntimeConstants.ITEM_Float: + case ByteCodeParser.ITEM_Float: return VarType.FLOAT; - case RuntimeConstants.ITEM_Double: + case ByteCodeParser.ITEM_Double: return VarType.DOUBLE; - case RuntimeConstants.ITEM_Long: + case ByteCodeParser.ITEM_Long: return VarType.LONG; - case RuntimeConstants.ITEM_Null: - case RuntimeConstants.ITEM_InitObject: - case RuntimeConstants.ITEM_Object: - case RuntimeConstants.ITEM_NewObject: + case ByteCodeParser.ITEM_Null: + case ByteCodeParser.ITEM_InitObject: + case ByteCodeParser.ITEM_Object: + case ByteCodeParser.ITEM_NewObject: return VarType.REFERENCE; - case RuntimeConstants.ITEM_Bogus: + case ByteCodeParser.ITEM_Bogus: /* unclear how to handle for now */ default: throw new IllegalStateException("Unhandled stack map type"); @@ -60,25 +58,25 @@ public static int fromConstantType(final byte constantTag) { switch (constantTag) { - case RuntimeConstants.CONSTANT_INTEGER: + case ByteCodeParser.CONSTANT_INTEGER: return VarType.INTEGER; - case RuntimeConstants.CONSTANT_FLOAT: + case ByteCodeParser.CONSTANT_FLOAT: return VarType.FLOAT; - case RuntimeConstants.CONSTANT_LONG: + case ByteCodeParser.CONSTANT_LONG: return VarType.LONG; - case RuntimeConstants.CONSTANT_DOUBLE: + case ByteCodeParser.CONSTANT_DOUBLE: return VarType.DOUBLE; - case RuntimeConstants.CONSTANT_CLASS: - case RuntimeConstants.CONSTANT_UTF8: - case RuntimeConstants.CONSTANT_UNICODE: - case RuntimeConstants.CONSTANT_STRING: + case ByteCodeParser.CONSTANT_CLASS: + case ByteCodeParser.CONSTANT_UTF8: + case ByteCodeParser.CONSTANT_UNICODE: + case ByteCodeParser.CONSTANT_STRING: return VarType.REFERENCE; - case RuntimeConstants.CONSTANT_FIELD: - case RuntimeConstants.CONSTANT_METHOD: - case RuntimeConstants.CONSTANT_INTERFACEMETHOD: - case RuntimeConstants.CONSTANT_NAMEANDTYPE: + case ByteCodeParser.CONSTANT_FIELD: + case ByteCodeParser.CONSTANT_METHOD: + case ByteCodeParser.CONSTANT_INTERFACEMETHOD: + case ByteCodeParser.CONSTANT_NAMEANDTYPE: /* unclear how to handle for now */ default: throw new IllegalStateException("Unhandled constant tag"); diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Fri May 17 10:27:41 2013 +0200 @@ -207,5 +207,12 @@ true ); } + + @Test public void valueOfEnum() throws Exception { + assertExec("can get value of enum", Classes.class, + "valueEnum__Ljava_lang_String_2Ljava_lang_String_2", + "TWO", "TWO" + ); + } } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Fri May 17 10:27:41 2013 +0200 @@ -230,4 +230,7 @@ return Application.class.isAssignableFrom(MyApplication.class); } + public static String valueEnum(String v) { + return ClassesMarker.E.valueOf(v).toString(); + } } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Fri May 17 10:27:41 2013 +0200 @@ -194,14 +194,14 @@ @Test public void valueOfLongBooleanTrue() throws Exception { assertExec("Can we call JavaScripts valueOf on Boolean?", - Numbers.class, "seven__DI", - Double.valueOf(1), 31 + Numbers.class, "bseven__ZI", + true, 31 ); } @Test public void valueOfLongBooleanFalse() throws Exception { assertExec("Can we call JavaScripts valueOf on Boolean?", - Numbers.class, "seven__DI", - Double.valueOf(0), 30 + Numbers.class, "bseven__ZI", + false, 30 ); } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Fri May 17 10:27:41 2013 +0200 @@ -84,10 +84,20 @@ default: throw new IllegalStateException(); } } + static boolean bseven(int todo) { + switch (todo) { + case 30: return bvalueOf(Boolean.FALSE); + case 31: return bvalueOf(Boolean.TRUE); + default: throw new IllegalStateException(); + } + } @JavaScriptBody(args = {}, body = "return 7;") private static native Number sevenNew(); + + @JavaScriptBody(args = { "o" }, body = "return o.valueOf();") + private static native double valueOf(Object o); @JavaScriptBody(args = { "o" }, body = "return o.valueOf();") - private static native double valueOf(Object o); + private static native boolean bvalueOf(Object o); } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Fri May 17 10:27:41 2013 +0200 @@ -18,6 +18,7 @@ package org.apidesign.vm4brwsr; import java.io.UnsupportedEncodingException; +import org.apidesign.bck2brwsr.core.JavaScriptBody; /** * @@ -129,4 +130,20 @@ public String toString() { return HELLO + cnt; } + + @JavaScriptBody(args = {}, body = "return [1, 2];") + private static native Object crtarr(); + @JavaScriptBody(args = { "o" }, body = "return o.toString();") + private static native String toStrng(Object o); + + public static String toStringArray(boolean fakeArr, boolean toString) { + final Object arr = fakeArr ? crtarr() : new Object[2]; + final String whole = toString ? arr.toString() : toStrng(arr); + int zav = whole.indexOf('@'); + if (zav <= 0) { + zav = whole.length(); + } + return whole.substring(0, zav).toString().toString(); + } + } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Fri May 17 10:27:41 2013 +0200 @@ -194,6 +194,34 @@ } + @Test public void toStringOnJSArray() throws Exception { + String exp = StringSample.toStringArray(false, true); + + assertExec( + "Treated as Java Object array", + StringSample.class, "toStringArray__Ljava_lang_String_2ZZ", + exp, true, true + ); + } + + @Test public void toStringOnRealArray() throws Exception { + String exp = StringSample.toStringArray(false, true); + + assertExec( + "Is Java Object array", + StringSample.class, "toStringArray__Ljava_lang_String_2ZZ", + exp, false, true + ); + } + + @Test public void valueOfOnJSArray() throws Exception { + assertExec( + "Treated as classical JavaScript array", + StringSample.class, "toStringArray__Ljava_lang_String_2ZZ", + "1,2", true, false + ); + } + private static TestVM code; @BeforeClass diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Fri May 17 10:27:41 2013 +0200 @@ -115,7 +115,7 @@ if (sb.length() > 2000) { sb = dumpJS(sb); } - fail("Could not evaluate:\n" + sb, ex); + fail("Could not evaluate:" + ex.getClass() + ":" + ex.getMessage() + "\n" + sb, ex); return null; } } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVM.java Fri May 17 10:27:41 2013 +0200 @@ -43,4 +43,9 @@ @Override protected void requireScript(String resourcePath) { } + + @Override + String getVMObject() { + return "global"; + } } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Fri May 17 10:27:41 2013 +0200 @@ -40,6 +40,14 @@ compareCode("org/apidesign/vm4brwsr/Classes.class"); } + @Test public void compareGeneratedCodeForToolkitClass() throws Exception { + String genCode = compareCode("org/apidesign/vm4brwsr/Bck2BrwsrToolkit.class"); + int indx = genCode.indexOf("gt = 65604"); + if (indx >= 0) { + fail("Goto to an invalid label:\n...." + genCode.substring(indx - 30, indx + 30) + "...."); + } + } + @BeforeClass public static void compileTheCode() throws Exception { code = TestVM.compileClass("org/apidesign/vm4brwsr/VMinVM"); @@ -49,7 +57,7 @@ code = null; } - private void compareCode(final String nm) throws Exception, IOException { + private String compareCode(final String nm) throws Exception, IOException { byte[] arr = BytesLoader.readClass(nm); String ret1 = VMinVM.toJavaScript(arr); @@ -88,5 +96,7 @@ msg.append(code.toString()); fail(msg.toString()); } + + return ret1; } } diff -r d127d41768bd -r ae3f2aa50970 rt/vm/src/test/resources/org/apidesign/vm4brwsr/Bck2BrwsrToolkit.class Binary file rt/vm/src/test/resources/org/apidesign/vm4brwsr/Bck2BrwsrToolkit.class has changed diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/pom.xml --- a/rt/vmtest/pom.xml Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vmtest/pom.xml Fri May 17 10:27:41 2013 +0200 @@ -4,11 +4,11 @@ org.apidesign.bck2brwsr rt - 0.4-SNAPSHOT + 0.8-SNAPSHOT org.apidesign.bck2brwsr vmtest - 0.4-SNAPSHOT + 0.8-SNAPSHOT VM Testing APIs http://bck2brwsr.apidesign.org @@ -50,18 +50,6 @@ ${project.groupId} - vm4brwsr - ${project.version} - jar - - - ${project.groupId} - emul.mini - ${project.version} - test - - - ${project.groupId} launcher ${project.version} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/BrwsrTest.java --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/BrwsrTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/BrwsrTest.java Fri May 17 10:27:41 2013 +0200 @@ -29,6 +29,10 @@ * The browser to is by default executed via {@link java.awt.Desktop#browse(java.net.URI)}, * but one can change that by specifying -Dvmtest.brwsrs=firefox,google-chrome * property. + *

+ * If the annotated method throws {@link InterruptedException}, it will return + * the processing to the browser and after 100ms, called again. This is useful + * for testing asynchronous communication, etc. * * @author Jaroslav Tulach */ diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Http.java --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Http.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Http.java Fri May 17 10:27:41 2013 +0200 @@ -53,5 +53,10 @@ String resource() default ""; /** mime type of the resource */ String mimeType(); + /** query parameters. Can be referenced from the {@link #content} as + * $0, $1, etc. The values will be extracted + * from URL parameters of the request. + */ + String[] parameters() default {}; } } diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/VMTest.java --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/VMTest.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/VMTest.java Fri May 17 10:27:41 2013 +0200 @@ -17,6 +17,9 @@ */ package org.apidesign.bck2brwsr.vmtest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apidesign.bck2brwsr.launcher.Launcher; import org.apidesign.bck2brwsr.vmtest.impl.CompareCase; import org.testng.annotations.Factory; @@ -34,6 +37,9 @@ * @author Jaroslav Tulach */ public final class VMTest { + private final List classes = new ArrayList<>(); + private final List launcher = new ArrayList<>(); + private VMTest() { } @@ -47,10 +53,66 @@ * Each {@link BrwsrTest} annotated method is executed once in {@link Launcher started * browser}. * - * @param clazz the class to inspect + * @param clazz the class (or classes) to inspect * @return the set of created tests */ - public static Object[] create(Class clazz) { - return CompareCase.create(clazz); + public static Object[] create(Class clazz) { + return newTests().withClasses(clazz).build(); + } + + /** Creates new builder for test execution. Continue with methods + * like {@link #withClasses(java.lang.Class[])} or {@link #withLaunchers(java.lang.String[])}. + * Finish the process by calling {@link #build()}. + * + * @return new instance of a builder + * @since 0.7 + */ + public static VMTest newTests() { + return new VMTest(); + } + + /** Adds class (or classes) to the test execution. The classes are inspected + * to contain methods annotated by + * {@link Compare} or {@link BrwsrTest}. Appropriate set of TestNG test + * cases is then created. + *

+ * Each {@link Compare} instance runs the test in different virtual + * machine and at the end they compare the results. + *

+ * Each {@link BrwsrTest} annotated method is executed once in {@link Launcher started + * browser}. + * + * @param classes one or more classes to inspect + * @since 0.7 + */ + public final VMTest withClasses(Class... classes) { + this.classes.addAll(Arrays.asList(classes)); + return this; + } + + /** Adds list of launchers that should be used to execute tests defined + * by {@link Compare} and {@link BrwsrTest} annotations. This value + * can be overrided by using vmtest.brwsrs property. + * List of supported launchers is available in the documentation of + * {@link Launcher}. + * + * @param launcher names of one or more launchers to use for the execution + * of tests + * @since 0.7 + */ + public final VMTest withLaunchers(String... launcher) { + this.launcher.addAll(Arrays.asList(launcher)); + return this; + } + + /** Assembles the provided information into the final array of tests. + * @return array of TestNG tests + * @since 0.7 + */ + public final Object[] build() { + return CompareCase.create( + launcher.toArray(new String[0]), + classes.toArray(new Class[0]) + ); } } diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Fri May 17 10:27:41 2013 +0200 @@ -65,17 +65,17 @@ for (Http.Resource r : http) { if (!r.content().isEmpty()) { InputStream is = new ByteArrayInputStream(r.content().getBytes("UTF-8")); - c.addHttpResource(r.path(), r.mimeType(), is); + c.addHttpResource(r.path(), r.mimeType(), r.parameters(), is); } else { InputStream is = m.getDeclaringClass().getResourceAsStream(r.resource()); - c.addHttpResource(r.path(), r.mimeType(), is); + c.addHttpResource(r.path(), r.mimeType(), r.parameters(), is); } } } String res = c.invoke(); value = res; if (fail) { - int idx = res.indexOf(':'); + int idx = res == null ? -1 : res.indexOf(':'); if (idx >= 0) { Class thrwbl = null; try { diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Tue Mar 05 07:57:16 2013 +0100 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Fri May 17 10:27:41 2013 +0200 @@ -53,26 +53,25 @@ * @param clazz the class to inspect * @return the set of created tests */ - public static Object[] create(Class clazz) { - Method[] arr = clazz.getMethods(); + public static Object[] create(String[] brwsr, Class[] classes) { List ret = new ArrayList<>(); final LaunchSetup l = LaunchSetup.INSTANCE; ret.add(l); - String[] brwsr; { String p = System.getProperty("vmtest.brwsrs"); if (p != null) { brwsr = p.split(","); - } else { - brwsr = new String[0]; } } - for (Method m : arr) { - registerCompareCases(m, l, ret, brwsr); - registerBrwsrCases(m, l, ret, brwsr); + for (Class clazz : classes) { + Method[] arr = clazz.getMethods(); + for (Method m : arr) { + registerCompareCases(m, l, ret, brwsr); + registerBrwsrCases(m, l, ret, brwsr); + } } return ret.toArray(); } @@ -83,10 +82,34 @@ @Test(dependsOnGroups = "run") public void compareResults() throws Throwable { Object v1 = first.value; Object v2 = second.value; - if (v1 != null) { - v1 = v1.toString(); + if (v1 instanceof Integer || v1 instanceof Long || v1 instanceof Byte || v1 instanceof Short) { + try { + v1 = Long.parseLong(v1.toString()); + } catch (NumberFormatException nfe) { + v1 = "Can't parse " + v1.toString(); + } + try { + v2 = Long.parseLong(v2.toString()); + } catch (NumberFormatException nfe) { + v2 = "Can't parse " + v2.toString(); + } + } else if (v1 instanceof Number) { + try { + v1 = Double.parseDouble(v1.toString()); + } catch (NumberFormatException nfe) { + v1 = "Can't parse " + v1.toString(); + } + try { + v2 = Double.parseDouble(v2.toString()); + } catch (NumberFormatException nfe) { + v2 = "Can't parse " + v2.toString(); + } } else { - v1 = "null"; + if (v1 != null) { + v1 = v1.toString(); + } else { + v1 = "null"; + } } try { Assert.assertEquals(v2, v1, "Comparing results"); diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/AssertionTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/AssertionTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class AssertionTest { - - @Compare public Object checkAssert() throws ClassNotFoundException { - try { - assert false : "Is assertion status on?"; - return null; - } catch (AssertionError ex) { - return ex.getClass().getName(); - } - } - - @Factory - public static Object[] create() { - return VMTest.create(AssertionTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +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.tck; - -import org.apidesign.bck2brwsr.core.JavaScriptBody; -import org.apidesign.bck2brwsr.vmtest.BrwsrTest; -import org.apidesign.bck2brwsr.vmtest.HtmlFragment; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class BrwsrCheckTest { - - @BrwsrTest public void assertWindowObjectIsDefined() { - assert window() != null : "No window object found!"; - } - - - - - @HtmlFragment("

\n" - + "Hello!\n" - + "

\n") - @BrwsrTest public void accessProvidedFragment() { - assert getElementById("hello") != null : "Element with 'hello' ID found"; - } - - @Factory - public static Object[] create() { - return VMTest.create(BrwsrCheckTest.class); - } - - - @JavaScriptBody(args = {}, body = "return window;") - private static native Object window(); - - @JavaScriptBody(args = { "id" }, body = "return window.document.getElementById(id);") - private static native Object getElementById(String id); -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ByteArithmeticTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ByteArithmeticTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class ByteArithmeticTest { - - private static byte add(byte x, byte y) { - return (byte)(x + y); - } - - private static byte sub(byte x, byte y) { - return (byte)(x - y); - } - - private static byte mul(byte x, byte y) { - return (byte)(x * y); - } - - private static byte div(byte x, byte y) { - return (byte)(x / y); - } - - private static byte mod(byte x, byte y) { - return (byte)(x % y); - } - - @Compare public byte conversion() { - return (byte)123456; - } - - @Compare public byte addOverflow() { - return add(Byte.MAX_VALUE, (byte)1); - } - - @Compare public byte subUnderflow() { - return sub(Byte.MIN_VALUE, (byte)1); - } - - @Compare public byte addMaxByteAndMaxByte() { - return add(Byte.MAX_VALUE, Byte.MAX_VALUE); - } - - @Compare public byte subMinByteAndMinByte() { - return sub(Byte.MIN_VALUE, Byte.MIN_VALUE); - } - - @Compare public byte multiplyMaxByte() { - return mul(Byte.MAX_VALUE, (byte)2); - } - - @Compare public byte multiplyMaxByteAndMaxByte() { - return mul(Byte.MAX_VALUE, Byte.MAX_VALUE); - } - - @Compare public byte multiplyMinByte() { - return mul(Byte.MIN_VALUE, (byte)2); - } - - @Compare public byte multiplyMinByteAndMinByte() { - return mul(Byte.MIN_VALUE, Byte.MIN_VALUE); - } - - @Compare public byte multiplyPrecision() { - return mul((byte)17638, (byte)1103); - } - - @Compare public byte division() { - return div((byte)1, (byte)2); - } - - @Compare public byte divisionReminder() { - return mod((byte)1, (byte)2); - } - - @Factory - public static Object[] create() { - return VMTest.create(ByteArithmeticTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CloneTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CloneTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class CloneTest { - private int value; - - @Compare - public Object notSupported() throws CloneNotSupportedException { - return this.clone(); - } - - @Compare public String sameClass() throws CloneNotSupportedException { - return new Clnbl().clone().getClass().getName(); - } - - @Compare public boolean differentInstance() throws CloneNotSupportedException { - Clnbl orig = new Clnbl(); - return orig == orig.clone(); - } - - @Compare public int sameReference() throws CloneNotSupportedException { - CloneTest self = this; - Clnbl orig = new Clnbl(); - self.value = 33; - orig.ref = self; - return ((Clnbl)orig.clone()).ref.value; - } - - @Compare public int sameValue() throws CloneNotSupportedException { - Clnbl orig = new Clnbl(); - orig.value = 10; - return ((Clnbl)orig.clone()).value; - } - - @Factory - public static Object[] create() { - return VMTest.create(CloneTest.class); - } - - public static final class Clnbl implements Cloneable { - public CloneTest ref; - private int value; - - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareByteArrayTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareByteArrayTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class CompareByteArrayTest { - @Compare public int byteArraySum() { - byte[] arr = createArray(); - return sumByteArr(arr); - } - - @Compare public int countZeros() { - int zeros = 0; - for (Byte b : createArray()) { - if (b == 0) { - zeros++; - } - } - return zeros; - } - - private static int sumByteArr(byte[] arr) { - int sum = 0; - for (int i = 0; i < arr.length; i++) { - sum += arr[i]; - } - return sum; - } - - @Compare public String noOutOfBounds() { - return atIndex(1); - } - - @Compare public String outOfBounds() { - return atIndex(5); - } - - @Compare public String outOfBoundsMinus() { - return atIndex(-1); - } - - @Compare public String toOfBounds() { - return toIndex(5); - } - - @Compare public String toOfBoundsMinus() { - return toIndex(-1); - } - - @Compare public int multiArrayLength() { - int[][] arr = new int[1][0]; - return arr[0].length; - } - - @Compare public int multiObjectArrayLength() { - Object[][] arr = new Object[1][0]; - return arr[0].length; - } - - private static final int[] arr = { 0, 1, 2 }; - public static String atIndex(int at) { - return "at@" + arr[at]; - } - public static String toIndex(int at) { - arr[at] = 10; - return "ok"; - } - - - @Factory - public static Object[] create() { - return VMTest.create(CompareByteArrayTest.class); - } - - private byte[] createArray() { - byte[] arr = new byte[10]; - arr[5] = 3; - arr[7] = 8; - return arr; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class CompareHashTest { - @Compare public int hashOfString() { - return "Ahoj".hashCode(); - } - - @Compare public int hashRemainsYieldsZero() { - Object o = new Object(); - return o.hashCode() - o.hashCode(); - } - - @Compare public int initializeInStatic() { - return StaticUse.NON_NULL.hashCode() - StaticUse.NON_NULL.hashCode(); - } - - @Compare public int hashOfInt() { - return Integer.valueOf(Integer.MAX_VALUE).hashCode(); - } - - @Factory - public static Object[] create() { - return VMTest.create(CompareHashTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareIntArrayTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareIntArrayTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class CompareIntArrayTest { - @Compare public int integerArraySum() { - int[] arr = createArray(); - return sumIntArr(arr); - } - - @Compare public int countZeros() { - int zeros = 0; - for (Integer i : createArray()) { - if (i == 0) { - zeros++; - } - } - return zeros; - } - - private static int sumIntArr(int[] arr) { - int sum = 0; - for (int i = 0; i < arr.length; i++) { - sum += arr[i]; - } - return sum; - } - - @Factory - public static Object[] create() { - return VMTest.create(CompareIntArrayTest.class); - } - - private int[] createArray() { - int[] arr = new int[10]; - arr[5] = 3; - arr[7] = 8; - return arr; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +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.tck; - -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class CompareStringsTest { - @Compare public String firstChar() { - return "" + ("Hello".toCharArray()[0]); - } - - @Compare public String classCast() { - Object o = firstChar(); - return String.class.cast(o); - } - - @Compare public String classCastThrown() { - Object o = null; - return String.class.cast(o); - } - - @Compare public boolean equalToNull() { - return "Ahoj".equals(null); - } - - @Compare public int highByteLenght() { - byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 }; - return new String(arr, 0).length(); - } - - @Compare public String highByte() { - byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 }; - StringBuilder sb = new StringBuilder(); - sb.append("pref:"); - sb.append(new String(arr, 0)); - return sb.toString(); - } - - @Compare public static Object compareURLs() throws MalformedURLException { - return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString(); - } - - @Compare public String deleteLastTwoCharacters() { - StringBuilder sb = new StringBuilder(); - sb.append("453.0"); - if (sb.toString().endsWith(".0")) { - final int l = sb.length(); - sb.delete(l - 2, l); - } - return sb.toString().toString(); - } - - @Compare public String nameOfStringClass() throws Exception { - return Class.forName("java.lang.String").getName(); - } - @Compare public String nameOfArrayClass() throws Exception { - return Class.forName("org.apidesign.bck2brwsr.tck.CompareHashTest").getName(); - } - - @Compare public String lowerHello() { - return "HeLlO".toLowerCase(); - } - - @Compare public String lowerA() { - return String.valueOf(Character.toLowerCase('A')).toString(); - } - @Compare public String upperHello() { - return "hello".toUpperCase(); - } - - @Compare public String upperA() { - return String.valueOf(Character.toUpperCase('a')).toString(); - } - - @Compare public boolean matchRegExp() throws Exception { - return "58038503".matches("\\d*"); - } - - @Compare public boolean doesNotMatchRegExp() throws Exception { - return "58038503GH".matches("\\d*"); - } - - @Compare public boolean doesNotMatchRegExpFully() throws Exception { - return "Hello".matches("Hell"); - } - - @Compare public String emptyCharArray() { - char[] arr = new char[10]; - return new String(arr); - } - - @Compare public String variousCharacterTests() throws Exception { - StringBuilder sb = new StringBuilder(); - - sb.append(Character.isUpperCase('a')); - sb.append(Character.isUpperCase('A')); - sb.append(Character.isLowerCase('a')); - sb.append(Character.isLowerCase('A')); - - sb.append(Character.isLetter('A')); - sb.append(Character.isLetterOrDigit('9')); - sb.append(Character.isLetterOrDigit('A')); - sb.append(Character.isLetter('0')); - - return sb.toString().toString(); - } - - @Compare - public String nullFieldInitialized() { - NullField nf = new NullField(); - return ("" + nf.name).toString(); - } - @Compare - public String toUTFString() throws UnsupportedEncodingException { - byte[] arr = { - (byte) -59, (byte) -67, (byte) 108, (byte) 117, (byte) -59, (byte) -91, - (byte) 111, (byte) 117, (byte) -60, (byte) -115, (byte) 107, (byte) -61, - (byte) -67, (byte) 32, (byte) 107, (byte) -59, (byte) -81, (byte) -59, - (byte) -120 - }; - return new String(arr, "utf-8"); - } - - @Compare - public int stringToBytesLenght() throws UnsupportedEncodingException { - return "\u017dlu\u0165ou\u010dk\u00fd k\u016f\u0148".getBytes("utf8").length; - } - - @Factory - public static Object[] create() { - return VMTest.create(CompareStringsTest.class); - } - - private static final class NullField { - - String name; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/HttpResourceTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/HttpResourceTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +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.tck; - -import java.io.InputStream; -import java.net.URL; -import org.apidesign.bck2brwsr.core.JavaScriptBody; -import org.apidesign.bck2brwsr.vmtest.BrwsrTest; -import org.apidesign.bck2brwsr.vmtest.Http; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class HttpResourceTest { - - @Http({ - @Http.Resource(path = "/xhr", content = "Hello Brwsr!", mimeType = "text/plain") - }) - @BrwsrTest - - - public String testReadContentViaXHR() throws Exception { - String msg = read("/xhr"); - assert "Hello Brwsr!".equals(msg) : "The message was " + msg; - return msg; - } - - @Http({ - @Http.Resource(path = "/url", content = "Hello via URL!", mimeType = "text/plain") - }) - @BrwsrTest - public String testReadContentViaURL() throws Exception { - URL url = new URL("http:/url"); - String msg = (String) url.getContent(); - assert "Hello via URL!".equals(msg) : "The message was " + msg; - return msg; - } - @Http({ - @Http.Resource(path = "/url", content = "Hello via URL!", mimeType = "text/plain") - }) - @BrwsrTest - public String testReadContentViaURLWithStringParam() throws Exception { - URL url = new URL("http:/url"); - String msg = (String) url.getContent(new Class[] { String.class }); - assert "Hello via URL!".equals(msg) : "The message was " + msg; - return msg; - } - - @Http({ - @Http.Resource(path = "/bytes", content = "", resource = "0xfe", mimeType = "x-application/binary") - }) - @BrwsrTest - public void testReadByte() throws Exception { - URL url = new URL("http:/bytes"); - final Object res = url.getContent(new Class[] { byte[].class }); - assert res instanceof byte[] : "Expecting byte[]: " + res; - byte[] arr = (byte[]) res; - assert arr.length == 1 : "One byte " + arr.length; - assert arr[0] == 0xfe : "It is 0xfe: " + Integer.toHexString(arr[0]); - } - - @Http({ - @Http.Resource(path = "/bytes", content = "", resource = "0xfe", mimeType = "x-application/binary") - }) - @BrwsrTest - public void testReadByteViaInputStream() throws Exception { - URL url = new URL("http:/bytes"); - InputStream is = url.openStream(); - byte[] arr = new byte[10]; - int len = is.read(arr); - assert len == 1 : "One byte " + len; - assert arr[0] == 0xfe : "It is 0xfe: " + Integer.toHexString(arr[0]); - } - - @JavaScriptBody(args = { "url" }, body = - "var req = new XMLHttpRequest();\n" - + "req.open('GET', url, false);\n" - + "req.send();\n" - + "return req.responseText;" - ) - private static native String read(String url); - - - @Factory - public static Object[] create() { - return VMTest.create(HttpResourceTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceA.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceA.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +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.tck; - -/** - * - * @author Jaroslav Tulach - */ -public class InheritanceA { - private String name; - - public void setA(String n) { - this.name = n; - } - - public String getA() { - return name; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceB.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceB.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +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.tck; - -/** - * - * @author Jaroslav Tulach - */ -public class InheritanceB extends InheritanceA { - private String name; - - public void setB(String n) { - this.name = n; - } - - public String getB() { - return name; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/InheritanceTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class InheritanceTest { - - @Compare public String checkFieldsIndependent() throws ClassNotFoundException { - InheritanceB ib = new InheritanceB(); - ib.setA("A"); - ib.setB("B"); - return "A: " + ib.getA() + " B: " + ib.getB(); - } - - @Factory - public static Object[] create() { - return VMTest.create(InheritanceTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class IntegerArithmeticTest { - - private static int add(int x, int y) { - return x + y; - } - - private static int sub(int x, int y) { - return x - y; - } - - private static int mul(int x, int y) { - return x * y; - } - - private static int div(int x, int y) { - return x / y; - } - - private static int mod(int x, int y) { - return x % y; - } - - private static int neg(int x) { - return (-x); - } - - private static float fadd(float x, float y) { - return x + y; - } - - private static double dadd(double x, double y) { - return x + y; - } - - @Compare public int addOverflow() { - return add(Integer.MAX_VALUE, 1); - } - - @Compare public int subUnderflow() { - return sub(Integer.MIN_VALUE, 1); - } - - @Compare public int addMaxIntAndMaxInt() { - return add(Integer.MAX_VALUE, Integer.MAX_VALUE); - } - - @Compare public int subMinIntAndMinInt() { - return sub(Integer.MIN_VALUE, Integer.MIN_VALUE); - } - - @Compare public int multiplyMaxInt() { - return mul(Integer.MAX_VALUE, 2); - } - - @Compare public int multiplyMaxIntAndMaxInt() { - return mul(Integer.MAX_VALUE, Integer.MAX_VALUE); - } - - @Compare public int multiplyMinInt() { - return mul(Integer.MIN_VALUE, 2); - } - - @Compare public int multiplyMinIntAndMinInt() { - return mul(Integer.MIN_VALUE, Integer.MIN_VALUE); - } - - @Compare public int multiplyPrecision() { - return mul(119106029, 1103515245); - } - - @Compare public int division() { - return div(1, 2); - } - - @Compare public int divisionReminder() { - return mod(1, 2); - } - - @Compare public int negativeDivision() { - return div(-7, 3); - } - - @Compare public int negativeDivisionReminder() { - return mod(-7, 3); - } - - @Compare public int conversionFromFloat() { - return (int) fadd(-2, -0.6f); - } - - @Compare public int conversionFromDouble() { - return (int) dadd(-2, -0.6); - } - - @Compare public boolean divByZeroThrowsArithmeticException() { - try { - div(1, 0); - return false; - } catch (final ArithmeticException e) { - return true; - } - } - - @Compare public boolean modByZeroThrowsArithmeticException() { - try { - mod(1, 0); - return false; - } catch (final ArithmeticException e) { - return true; - } - } - - @Compare public int negate() { - return neg(123456); - } - - @Compare public int negateMaxInt() { - return neg(Integer.MAX_VALUE); - } - - @Compare public int negateMinInt() { - return neg(Integer.MIN_VALUE); - } - - @Compare public int sumTwoDimensions() { - int[][] matrix = createMatrix(4, 3); - matrix[0][0] += 10; - return matrix[0][0]; - } - - static int[][] createMatrix(int x, int y) { - return new int[x][y]; - } - - @Factory - public static Object[] create() { - return VMTest.create(IntegerArithmeticTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,376 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class LongArithmeticTest { - - private static long add(long x, long y) { - return (x + y); - } - - private static long sub(long x, long y) { - return (x - y); - } - - private static long mul(long x, long y) { - return (x * y); - } - - private static long div(long x, long y) { - return (x / y); - } - - private static long mod(long x, long y) { - return (x % y); - } - - private static long neg(long x) { - return (-x); - } - - private static long shl(long x, int b) { - return (x << b); - } - - private static long shr(long x, int b) { - return (x >> b); - } - - private static long ushr(long x, int b) { - return (x >>> b); - } - - private static long and(long x, long y) { - return (x & y); - } - - private static long or(long x, long y) { - return (x | y); - } - - private static long xor(long x, long y) { - return (x ^ y); - } - - private static float fadd(float x, float y) { - return x + y; - } - - private static double dadd(double x, double y) { - return x + y; - } - - public static int compare(long x, long y, int zero) { - final int xyResult = compareL(x, y, zero); - final int yxResult = compareL(y, x, zero); - - return ((xyResult + yxResult) == 0) ? xyResult : -2; - } - - private static int compareL(long x, long y, int zero) { - int result = -2; - int trueCount = 0; - - x += zero; - if (x == y) { - result = 0; - ++trueCount; - } - - x += zero; - if (x < y) { - result = -1; - ++trueCount; - } - - x += zero; - if (x > y) { - result = 1; - ++trueCount; - } - - return (trueCount == 1) ? result : -2; - } - - @Compare public long conversion() { - return Long.MAX_VALUE; - } - - @Compare public long negate1() { - return neg(0x00fa37d7763e0ca1l); - } - - @Compare public long negate2() { - return neg(0x80fa37d7763e0ca1l); - } - - @Compare public long negate3() { - return neg(0xfffffffffffffeddl); - } - - @Compare public long addOverflow() { - return add(Long.MAX_VALUE, 1l); - } - - @Compare public long subUnderflow() { - return sub(Long.MIN_VALUE, 1l); - } - - @Compare public long addMaxLongAndMaxLong() { - return add(Long.MAX_VALUE, Long.MAX_VALUE); - } - - @Compare public long subMinLongAndMinLong() { - return sub(Long.MIN_VALUE, Long.MIN_VALUE); - } - - @Compare public long subMinLongAndMaxLong() { - return sub(Long.MIN_VALUE, Long.MAX_VALUE); - } - - @Compare public long multiplyMaxLong() { - return mul(Long.MAX_VALUE, 2l); - } - - @Compare public long multiplyMaxLongAndMaxLong() { - return mul(Long.MAX_VALUE, Long.MAX_VALUE); - } - - @Compare public long multiplyMinLong() { - return mul(Long.MIN_VALUE, 2l); - } - - @Compare public long multiplyMinLongAndMinLong() { - return mul(Long.MIN_VALUE, Long.MIN_VALUE); - } - - @Compare public long multiplyPrecision() { - return mul(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); - } - - @Compare public long divideSmallPositiveNumbers() { - return div(0xabcdef, 0x123); - } - - @Compare public long divideSmallNegativeNumbers() { - return div(-0xabcdef, -0x123); - } - - @Compare public long divideSmallMixedNumbers() { - return div(0xabcdef, -0x123); - } - - @Compare public long dividePositiveNumbersOneDigitDenom() { - return div(0xabcdef0102ffffl, 0x654); - } - - @Compare public long divideNegativeNumbersOneDigitDenom() { - return div(-0xabcdef0102ffffl, -0x654); - } - - @Compare public long divideMixedNumbersOneDigitDenom() { - return div(-0xabcdef0102ffffl, 0x654); - } - - @Compare public long dividePositiveNumbersMultiDigitDenom() { - return div(0x7ffefc003322aabbl, 0x89ab1000l); - } - - @Compare public long divideNegativeNumbersMultiDigitDenom() { - return div(-0x7ffefc003322aabbl, -0x123489ab1001l); - } - - @Compare public long divideMixedNumbersMultiDigitDenom() { - return div(0x7ffefc003322aabbl, -0x38f49b0b7574e36l); - } - - @Compare public long divideWithOverflow() { - return div(0x8000fffe0000l, 0x8000ffffl); - } - - @Compare public long divideWithCorrection() { - return div(0x7fff800000000000l, 0x800000000001l); - } - - @Compare public long moduloSmallPositiveNumbers() { - return mod(0xabcdef, 0x123); - } - - @Compare public long moduloSmallNegativeNumbers() { - return mod(-0xabcdef, -0x123); - } - - @Compare public long moduloSmallMixedNumbers() { - return mod(0xabcdef, -0x123); - } - - @Compare public long moduloPositiveNumbersOneDigitDenom() { - return mod(0xabcdef0102ffffl, 0x654); - } - - @Compare public long moduloNegativeNumbersOneDigitDenom() { - return mod(-0xabcdef0102ffffl, -0x654); - } - - @Compare public long moduloMixedNumbersOneDigitDenom() { - return mod(-0xabcdef0102ffffl, 0x654); - } - - @Compare public long moduloPositiveNumbersMultiDigitDenom() { - return mod(0x7ffefc003322aabbl, 0x89ab1000l); - } - - @Compare public long moduloNegativeNumbersMultiDigitDenom() { - return mod(-0x7ffefc003322aabbl, -0x123489ab1001l); - } - - @Compare public long moduloMixedNumbersMultiDigitDenom() { - return mod(0x7ffefc003322aabbl, -0x38f49b0b7574e36l); - } - - @Compare public long moduloWithOverflow() { - return mod(0x8000fffe0000l, 0x8000ffffl); - } - - @Compare public long moduloWithCorrection() { - return mod(0x7fff800000000000l, 0x800000000001l); - } - - @Compare public long conversionFromFloatPositive() { - return (long) fadd(2, 0.6f); - } - - @Compare public long conversionFromFloatNegative() { - return (long) fadd(-2, -0.6f); - } - - @Compare public long conversionFromDoublePositive() { - return (long) dadd(0x20ffff0000L, 0.6); - } - - @Compare public long conversionFromDoubleNegative() { - return (long) dadd(-0x20ffff0000L, -0.6); - } - - @Compare public boolean divByZeroThrowsArithmeticException() { - try { - div(1, 0); - return false; - } catch (final ArithmeticException e) { - return true; - } - } - - @Compare public boolean modByZeroThrowsArithmeticException() { - try { - mod(1, 0); - return false; - } catch (final ArithmeticException e) { - return true; - } - } - - @Compare public long shiftL1() { - return shl(0x00fa37d7763e0ca1l, 5); - } - - @Compare public long shiftL2() { - return shl(0x00fa37d7763e0ca1l, 32); - } - - @Compare public long shiftL3() { - return shl(0x00fa37d7763e0ca1l, 45); - } - - @Compare public long shiftR1() { - return shr(0x00fa37d7763e0ca1l, 5); - } - - @Compare public long shiftR2() { - return shr(0x00fa37d7763e0ca1l, 32); - } - - @Compare public long shiftR3() { - return shr(0x00fa37d7763e0ca1l, 45); - } - - @Compare public long uShiftR1() { - return ushr(0x00fa37d7763e0ca1l, 5); - } - - @Compare public long uShiftR2() { - return ushr(0x00fa37d7763e0ca1l, 45); - } - - @Compare public long uShiftR3() { - return ushr(0xf0fa37d7763e0ca1l, 5); - } - - @Compare public long uShiftR4() { - return ushr(0xf0fa37d7763e0ca1l, 45); - } - - @Compare public long and1() { - return and(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); - } - - @Compare public long or1() { - return or(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); - } - - @Compare public long xor1() { - return xor(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); - } - - @Compare public long xor2() { - return xor(0x00fa37d7763e0ca1l, 0x00000000ff00123el); - } - - @Compare public long xor3() { - return xor(0x00000000763e0ca1l, 0x00000000ff00123el); - } - - @Compare public int compareSameNumbers() { - return compare(0x0000000000000000l, 0x0000000000000000l, 0); - } - - @Compare public int comparePositiveNumbers() { - return compare(0x0000000000200000l, 0x0000000010000000l, 0); - } - - @Compare public int compareNegativeNumbers() { - return compare(0xffffffffffffffffl, 0xffffffff00000000l, 0); - } - - @Compare public int compareMixedNumbers() { - return compare(0x8000000000000000l, 0x7fffffffffffffffl, 0); - } - - @Factory - public static Object[] create() { - return VMTest.create(LongArithmeticTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +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.tck; - -import java.lang.reflect.Array; -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class ReflectionArrayTest { - @Compare public int lengthOfStringArray() { - String[] arr = (String[]) Array.newInstance(String.class, 10); - return arr.length; - } - - @Compare public int reflectiveLengthOfStringArray() { - Object arr = Array.newInstance(String.class, 10); - return Array.getLength(arr); - } - - @Compare public int reflectiveLengthOneNonArray() { - Object arr = "non-array"; - return Array.getLength(arr); - } - - @Compare public String compTypeOfStringArray() { - String[] arr = (String[]) Array.newInstance(String.class, 10); - return arr.getClass().getComponentType().getName(); - } - - @Compare public Object negativeArrayExcp() { - return Array.newInstance(String.class, -5); - } - - @Compare public int lengthOfIntArray() { - int[] arr = (int[]) Array.newInstance(Integer.TYPE, 10); - return arr.length; - } - - @Compare public int reflectiveLengthOfIntArray() { - Object arr = Array.newInstance(Integer.TYPE, 10); - return Array.getLength(arr); - } - - @Compare public String compTypeOfIntArray() { - int[] arr = (int[]) Array.newInstance(int.class, 10); - return arr.getClass().getComponentType().getName(); - } - - @Compare public Object intNegativeArrayExcp() { - return Array.newInstance(int.class, -5); - } - - @Compare public Integer verifyAutobox() { - int[] arr = (int[]) Array.newInstance(int.class, 5); - return (Integer) Array.get(arr, 0); - } - @Compare public String verifyObjectArray() { - String[] arr = (String[]) Array.newInstance(String.class, 5); - Array.set(arr, 0, "Hello"); - return (String) Array.get(arr, 0); - } - @Compare public int verifyInt() { - int[] arr = (int[]) Array.newInstance(int.class, 5); - return Array.getInt(arr, 0); - } - @Compare public long verifyConvertToLong() { - int[] arr = (int[]) Array.newInstance(int.class, 5); - return Array.getLong(arr, 0); - } - - @Compare public Object verifySetIntToObject() { - try { - Object[] arr = (Object[]) Array.newInstance(Object.class, 5); - Array.setInt(arr, 0, 10); - return Array.get(arr, 0); - } catch (Exception exception) { - return exception.getClass().getName(); - } - } - @Compare public long verifySetShort() { - int[] arr = (int[]) Array.newInstance(int.class, 5); - Array.setShort(arr, 0, (short)10); - return Array.getLong(arr, 0); - } - @Compare public long verifyCantSetLong() { - int[] arr = (int[]) Array.newInstance(int.class, 5); - Array.setLong(arr, 0, 10); - return Array.getLong(arr, 0); - } - @Compare public float verifyLongToFloat() { - Object arr = Array.newInstance(float.class, 5); - Array.setLong(arr, 0, 10); - return Array.getFloat(arr, 0); - } - - @Compare public double verifyConvertToDouble() { - int[] arr = (int[]) Array.newInstance(int.class, 5); - return Array.getDouble(arr, 0); - } - - @Compare public int multiIntArray() { - int[][][] arr = (int[][][]) Array.newInstance(int.class, 3, 3, 3); - return arr[0][1][2] + 5 + arr[2][2][0]; - } - - @Compare public String multiIntArrayCompType() { - return Array.newInstance(int.class, 3, 3, 3).getClass().getName(); - } - - - @Factory - public static Object[] create() { - return VMTest.create(ReflectionArrayTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,242 +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.tck; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.apidesign.bck2brwsr.core.JavaScriptBody; -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class ReflectionTest { - @Compare public boolean nonNullThis() { - return this == null; - } - - @Compare public String intType() { - return Integer.TYPE.toString(); - } - - @Compare public String voidType() throws Exception { - return void.class.toString(); - } - - @Compare public String longClass() { - return long.class.toString(); - } - - @Compare public boolean isRunnableInterface() { - return Runnable.class.isInterface(); - } - - @Compare public String isRunnableHasRunMethod() throws NoSuchMethodException { - return Runnable.class.getMethod("run").getName(); - } - - @Compare public String namesOfMethods() { - StringBuilder sb = new StringBuilder(); - String[] arr = new String[20]; - int i = 0; - for (Method m : StaticUse.class.getMethods()) { - arr[i++] = m.getName(); - } - for (String s : sort(arr, i)) { - sb.append(s).append("\n"); - } - return sb.toString(); - } - - @Compare public String namesOfDeclaringClassesOfMethods() { - StringBuilder sb = new StringBuilder(); - String[] arr = new String[20]; - int i = 0; - for (Method m : StaticUse.class.getMethods()) { - arr[i++] = m.getName() + "@" + m.getDeclaringClass().getName(); - } - for (String s : sort(arr, i)) { - sb.append(s).append("\n"); - } - return sb.toString(); - } - - @Compare public String cannotCallNonStaticMethodWithNull() throws Exception { - StaticUse.class.getMethod("instanceMethod").invoke(null); - return "should not happen"; - } - - @Compare public Object voidReturnType() throws Exception { - return StaticUse.class.getMethod("instanceMethod").getReturnType(); - } - - @Retention(RetentionPolicy.RUNTIME) - @interface Ann { - } - - @Compare public String annoClass() throws Exception { - Retention r = Ann.class.getAnnotation(Retention.class); - assert r != null : "Annotation is present"; - assert r.value() == RetentionPolicy.RUNTIME : "Policy value is OK: " + r.value(); - return r.annotationType().getName(); - } - - @Compare public boolean isAnnotation() { - return Ann.class.isAnnotation(); - } - @Compare public boolean isNotAnnotation() { - return String.class.isAnnotation(); - } - @Compare public boolean isNotAnnotationEnum() { - return E.class.isAnnotation(); - } - enum E { A, B }; - @Compare public boolean isEnum() { - return E.A.getClass().isEnum(); - } - - @Compare public boolean isNotEnum() { - return "".getClass().isEnum(); - } - - @Compare public String newInstanceFails() throws InstantiationException { - try { - return "success: " + StaticUseSub.class.newInstance(); - } catch (IllegalAccessException ex) { - return ex.getClass().getName(); - } - } - - @Compare public String paramTypes() throws Exception { - Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE); - final Class[] pt = plus.getParameterTypes(); - return pt[0].getName(); - } - @Compare public String paramTypesNotFound() throws Exception { - return StaticUse.class.getMethod("plus", int.class, double.class).toString(); - } - @Compare public int methodWithArgs() throws Exception { - Method plus = StaticUse.class.getMethod("plus", int.class, Integer.TYPE); - return (Integer)plus.invoke(null, 2, 3); - } - - @Compare public String classGetNameForByte() { - return byte.class.getName(); - } - @Compare public String classGetNameForBaseObject() { - return newObject().getClass().getName(); - } - @Compare public String classGetNameForJavaObject() { - return new Object().getClass().getName(); - } - @Compare public String classGetNameForObjectArray() { - return (new Object[3]).getClass().getName(); - } - @Compare public String classGetNameForSimpleIntArray() { - return (new int[3]).getClass().getName(); - } - @Compare public boolean sameClassGetNameForSimpleCharArray() { - return (new char[3]).getClass() == (new char[34]).getClass(); - } - @Compare public String classGetNameForMultiIntArray() { - return (new int[3][4][5][6][7][8][9]).getClass().getName(); - } - @Compare public String classGetNameForMultiIntArrayInner() { - final int[][][][][][][] arr = new int[3][4][5][6][7][8][9]; - int[][][][][][] subarr = arr[0]; - int[][][][][] subsubarr = subarr[0]; - return subsubarr.getClass().getName(); - } - @Compare public String classGetNameForMultiStringArray() { - return (new String[3][4][5][6][7][8][9]).getClass().getName(); - } - - @Compare public String classForByte() throws Exception { - return Class.forName("[Z").getName(); - } - - @Compare public String classForUnknownArray() { - try { - return Class.forName("[W").getName(); - } catch (Exception ex) { - return ex.getClass().getName(); - } - } - - @Compare public String classForUnknownDeepArray() { - try { - return Class.forName("[[[[[W").getName(); - } catch (Exception ex) { - return ex.getClass().getName(); - } - } - - @Compare public String componentGetNameForObjectArray() { - return (new Object[3]).getClass().getComponentType().getName(); - } - @Compare public boolean sameComponentGetNameForObjectArray() { - return (new Object[3]).getClass().getComponentType() == Object.class; - } - @Compare public String componentGetNameForSimpleIntArray() { - return (new int[3]).getClass().getComponentType().getName(); - } - @Compare public String componentGetNameForMultiIntArray() { - return (new int[3][4][5][6][7][8][9]).getClass().getComponentType().getName(); - } - @Compare public String componentGetNameForMultiStringArray() { - Class c = (new String[3][4][5][6][7][8][9]).getClass(); - StringBuilder sb = new StringBuilder(); - for (;;) { - sb.append(c.getName()).append("\n"); - c = c.getComponentType(); - if (c == null) { - break; - } - } - return sb.toString(); - } - - @Compare public boolean isArray() { - return new Object[0].getClass().isArray(); - } - - @JavaScriptBody(args = { "arr", "len" }, body="var a = arr.slice(0, len); a.sort(); return a;") - private static String[] sort(String[] arr, int len) { - List list = Arrays.asList(arr).subList(0, len); - Collections.sort(list); - return list.toArray(new String[0]); - } - - @JavaScriptBody(args = {}, body = "return new Object();") - private static Object newObject() { - return new Object(); - } - - @Factory - public static Object[] create() { - return VMTest.create(ReflectionTest.class); - } - -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +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.tck; - -import java.io.InputStream; -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class ResourcesTest { - - @Compare public String readResourceAsStream() throws Exception { - InputStream is = getClass().getResourceAsStream("Resources.txt"); - byte[] b = new byte[30]; - int len = is.read(b); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < len; i++) { - sb.append((char)b[i]); - } - return sb.toString(); - } - - @Factory public static Object[] create() { - return VMTest.create(ResourcesTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ShortArithmeticTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ShortArithmeticTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class ShortArithmeticTest { - - private static short add(short x, short y) { - return (short)(x + y); - } - - private static short sub(short x, short y) { - return (short)(x - y); - } - - private static short mul(short x, short y) { - return (short)(x * y); - } - - private static short div(short x, short y) { - return (short)(x / y); - } - - private static short mod(short x, short y) { - return (short)(x % y); - } - - @Compare public short conversion() { - return (short)123456; - } - - @Compare public short addOverflow() { - return add(Short.MAX_VALUE, (short)1); - } - - @Compare public short subUnderflow() { - return sub(Short.MIN_VALUE, (short)1); - } - - @Compare public short addMaxShortAndMaxShort() { - return add(Short.MAX_VALUE, Short.MAX_VALUE); - } - - @Compare public short subMinShortAndMinShort() { - return sub(Short.MIN_VALUE, Short.MIN_VALUE); - } - - @Compare public short multiplyMaxShort() { - return mul(Short.MAX_VALUE, (short)2); - } - - @Compare public short multiplyMaxShortAndMaxShort() { - return mul(Short.MAX_VALUE, Short.MAX_VALUE); - } - - @Compare public short multiplyMinShort() { - return mul(Short.MIN_VALUE, (short)2); - } - - @Compare public short multiplyMinShortAndMinShort() { - return mul(Short.MIN_VALUE, Short.MIN_VALUE); - } - - @Compare public short multiplyPrecision() { - return mul((short)17638, (short)1103); - } - - @Compare public short division() { - return div((short)1, (short)2); - } - - @Compare public short divisionReminder() { - return mod((short)1, (short)2); - } - - @Factory - public static Object[] create() { - return VMTest.create(ShortArithmeticTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +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.tck; - -class StaticUse { - public static final Object NON_NULL = new Object(); - StaticUse() { - } - - public void instanceMethod() { - } - - public static int plus(int a, int b) { - return a + b; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSub.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSub.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +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.tck; - -public class StaticUseSub extends StaticUse { - private StaticUseSub() { - } - - public static Object getNonNull() { - return NON_NULL; - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSubTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUseSubTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +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.tck; - -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class StaticUseSubTest { - @Compare public String staticFieldInitializationInSuperClass() throws Exception { - Object ret = StaticUseSub.getNonNull(); - return ret.getClass().getName(); - } - - @Factory public static Object[] create() { - return VMTest.create(StaticUseSubTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/CRC32Test.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/CRC32Test.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +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.vmtest.impl; - -import java.io.UnsupportedEncodingException; -import java.util.zip.CRC32; -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -public class CRC32Test { - - @Compare public long crc1() throws UnsupportedEncodingException { - CRC32 crc = new CRC32(); - crc.update("Hello World!".getBytes("UTF-8")); - return crc.getValue(); - } - - @Factory public static Object[] create() { - return VMTest.create(CRC32Test.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipEntryTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipEntryTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +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.vmtest.impl; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import org.apidesign.bck2brwsr.emul.zip.FastJar; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/** - * - * @author Jaroslav Tulach - */ -@GenerateZip(name = "five.zip", contents = { - "1.txt", "one", - "2.txt", "duo", - "3.txt", "three", - "4.txt", "four", - "5.txt", "five" -}) -public class ZipEntryTest { - @Test - public void readEntriesEffectively() throws IOException { - InputStream is = ZipEntryTest.class.getResourceAsStream("five.zip"); - byte[] arr = new byte[is.available()]; - int len = is.read(arr); - assertEquals(len, arr.length, "Read fully"); - - FastJar fj = new FastJar(arr); - FastJar.Entry[] entrs = fj.list(); - - assertEquals(5, entrs.length, "Five entries"); - - for (int i = 1; i <= 5; i++) { - FastJar.Entry en = entrs[i - 1]; - assertEquals(en.name, i + ".txt"); -// assertEquals(cis.cnt, 0, "Content of the file should be skipped, not read"); - } - - assertContent("three", fj.getInputStream(entrs[3 - 1]), "read OK"); - assertContent("five", fj.getInputStream(entrs[5 - 1]), "read OK"); - } - - private static void assertContent(String exp, InputStream is, String msg) throws IOException { - byte[] arr = new byte[512]; - int len = is.read(arr); - String s = new String(arr, 0, len); - assertEquals(exp, s, msg); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +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.vmtest.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import org.apidesign.bck2brwsr.core.JavaScriptBody; -import org.apidesign.bck2brwsr.vmtest.BrwsrTest; -import org.apidesign.bck2brwsr.vmtest.Compare; -import org.apidesign.bck2brwsr.vmtest.Http; -import org.apidesign.bck2brwsr.vmtest.VMTest; -import org.testng.annotations.Factory; - -/** - * - * @author Jaroslav Tulach - */ -@GenerateZip(name = "readAnEntry.zip", contents = { - "my/main/file.txt", "Hello World!" -}) -public class ZipFileTest { - - @Compare public String readAnEntry() throws IOException { - InputStream is = ZipFileTest.class.getResourceAsStream("readAnEntry.zip"); - ZipInputStream zip = new ZipInputStream(is); - ZipEntry entry = zip.getNextEntry(); - assertEquals(entry.getName(), "my/main/file.txt", "Correct entry"); - - byte[] arr = new byte[4096]; - int len = zip.read(arr); - - assertEquals(zip.getNextEntry(), null, "No next entry"); - - final String ret = new String(arr, 0, len, "UTF-8"); - return ret; - } - - @JavaScriptBody(args = { "res", "path" }, body = - "var myvm = bck2brwsr.apply(null, path);\n" - + "var cls = myvm.loadClass('java.lang.String');\n" - + "return cls.getClass__Ljava_lang_Class_2().getResourceAsStream__Ljava_io_InputStream_2Ljava_lang_String_2(res);\n" - ) - private static native Object loadVMResource(String res, String...path); - - @Http({ - @Http.Resource(path = "/readAnEntry.jar", mimeType = "x-application/zip", content = "", resource="readAnEntry.zip") - }) - @BrwsrTest public void canVmLoadResourceFromZip() throws IOException { - Object res = loadVMResource("/my/main/file.txt", "/readAnEntry.jar"); - assert res instanceof InputStream : "Got array of bytes: " + res; - InputStream is = (InputStream)res; - - byte[] arr = new byte[4096]; - int len = is.read(arr); - - final String ret = new String(arr, 0, len, "UTF-8"); - - assertEquals(ret, "Hello World!", "Can read the bytes"); - } - - @GenerateZip(name = "cpattr.zip", contents = { - "META-INF/MANIFEST.MF", "Manifest-Version: 1.0\n" - + "Created-By: hand\n" - + "Class-Path: realJar.jar\n\n\n" - }) - @Http({ - @Http.Resource(path = "/readComplexEntry.jar", mimeType = "x-application/zip", content = "", resource="cpattr.zip"), - @Http.Resource(path = "/realJar.jar", mimeType = "x-application/zip", content = "", resource="readAnEntry.zip"), - }) - @BrwsrTest public void understandsClassPathAttr() throws IOException { - Object res = loadVMResource("/my/main/file.txt", "/readComplexEntry.jar"); - assert res instanceof InputStream : "Got array of bytes: " + res; - InputStream is = (InputStream)res; - - byte[] arr = new byte[4096]; - int len = is.read(arr); - - final String ret = new String(arr, 0, len, "UTF-8"); - - assertEquals(ret, "Hello World!", "Can read the bytes from secondary JAR"); - } - - private static void assertEquals(Object real, Object exp, String msg) { - assert Objects.equals(exp, real) : msg + " exp: " + exp + " real: " + real; - } - - @Factory public static Object[] create() { - return VMTest.create(ZipFileTest.class); - } -} diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/resources/org/apidesign/bck2brwsr/tck/0xfe --- a/rt/vmtest/src/test/resources/org/apidesign/bck2brwsr/tck/0xfe Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -þ \ No newline at end of file diff -r d127d41768bd -r ae3f2aa50970 rt/vmtest/src/test/resources/org/apidesign/bck2brwsr/tck/Resources.txt --- a/rt/vmtest/src/test/resources/org/apidesign/bck2brwsr/tck/Resources.txt Tue Mar 05 07:57:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -Ahoj