# HG changeset patch # User Jaroslav Tulach # Date 1358942003 -3600 # Node ID 1adce93fea0f6ec576057e53b260db5bb2b3cad2 # Parent 7400dc9f48fb3f40429fa08a670156ca0e9b29cc# Parent 839badc5b393350c7f8b604a37a6a95944279a67 Bringing the most recent default branch (especially the @Property MVVC) to the dew code diff -r 7400dc9f48fb -r 1adce93fea0f benchmarks/matrix-multiplication/src/main/java/org/apidesign/benchmark/matrixmul/Matrix.java --- a/benchmarks/matrix-multiplication/src/main/java/org/apidesign/benchmark/matrixmul/Matrix.java Tue Jan 22 19:48:10 2013 +0100 +++ b/benchmarks/matrix-multiplication/src/main/java/org/apidesign/benchmark/matrixmul/Matrix.java Wed Jan 23 12:53:23 2013 +0100 @@ -45,7 +45,7 @@ //final int x = 10; for (int i = 0; i < rank; i++) { for (int j = 0; j < rank; j++) { - data[i][j] = i + j; + data[i][j] = 1 / (1 + i + j); } } } diff -r 7400dc9f48fb -r 1adce93fea0f 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 Jan 22 19:48:10 2013 +0100 +++ b/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -27,12 +27,11 @@ * @author Jaroslav Tulach */ public class MatrixTest { - public static final int ITERATION_COUNT = 10; - public MatrixTest() { } - @Compare public String tenThousandIterations() throws IOException { + @Compare(scripting = false) + public String tenThousandIterations() throws IOException { Matrix m1 = new Matrix(5); Matrix m2 = new Matrix(5); @@ -41,12 +40,9 @@ m2.generateData(); Matrix res = null; - for (int i = 0; i < ITERATION_COUNT; i++) { - Matrix m = m1.multiply(m2); - if (res != null && !res.equals(m)) { - return "different"; - } - res = m; + for (int i = 0; i < 10000; i++) { + res = m1.multiply(m2); + m1 = res; } StringBuilder sb = new StringBuilder(); diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/java/java/lang/Class.java --- a/emul/src/main/java/java/lang/Class.java Tue Jan 22 19:48:10 2013 +0100 +++ b/emul/src/main/java/java/lang/Class.java Wed Jan 23 12:53:23 2013 +0100 @@ -1198,7 +1198,8 @@ ) native static Class getPrimitiveClass(String type); - public boolean desiredAssertionStatus() { - return false; - } + @JavaScriptBody(args = {}, body = + "return vm.desiredAssertionStatus ? vm.desiredAssertionStatus : false;" + ) + public native boolean desiredAssertionStatus(); } diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/java/java/lang/Double.java --- a/emul/src/main/java/java/lang/Double.java Tue Jan 22 19:48:10 2013 +0100 +++ b/emul/src/main/java/java/lang/Double.java Wed Jan 23 12:53:23 2013 +0100 @@ -774,8 +774,7 @@ */ public boolean equals(Object obj) { return (obj instanceof Double) - && (doubleToLongBits(((Double)obj).value) == - doubleToLongBits(value)); + && (((Double)obj).value) == value; } /** diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/java/java/lang/NegativeArraySizeException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/lang/NegativeArraySizeException.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1994, 2008, 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 if an application tries to create an array with negative size. + * + * @author unascribed + * @since JDK1.0 + */ +public +class NegativeArraySizeException extends RuntimeException { + private static final long serialVersionUID = -8960118058596991861L; + + /** + * Constructs a NegativeArraySizeException with no + * detail message. + */ + public NegativeArraySizeException() { + super(); + } + + /** + * Constructs a NegativeArraySizeException with the + * specified detail message. + * + * @param s the detail message. + */ + public NegativeArraySizeException(String s) { + super(s); + } +} diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/java/java/lang/Object.java --- a/emul/src/main/java/java/lang/Object.java Tue Jan 22 19:48:10 2013 +0100 +++ b/emul/src/main/java/java/lang/Object.java Wed Jan 23 12:53:23 2013 +0100 @@ -25,6 +25,7 @@ package java.lang; +import java.lang.reflect.Array; import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.bck2brwsr.core.JavaScriptPrototype; @@ -40,8 +41,13 @@ @JavaScriptPrototype(container = "Object.prototype", prototype = "new Object") public class Object { - @JavaScriptBody(args = {}, body = "") - private static native void registerNatives(); + private static void registerNatives() { + try { + Array.get(null, 0); + } catch (Throwable ex) { + // ignore + } + } static { registerNatives(); } diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/java/java/lang/Runnable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/lang/Runnable.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1994, 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 java.lang; + +/** + * The Runnable interface should be implemented by any + * class whose instances are intended to be executed by a thread. The + * class must define a method of no arguments called run. + *

+ * This interface is designed to provide a common protocol for objects that + * wish to execute code while they are active. For example, + * Runnable is implemented by class Thread. + * Being active simply means that a thread has been started and has not + * yet been stopped. + *

+ * In addition, Runnable provides the means for a class to be + * active while not subclassing Thread. A class that implements + * Runnable can run without subclassing Thread + * by instantiating a Thread instance and passing itself in + * as the target. In most cases, the Runnable interface should + * be used if you are only planning to override the run() + * method and no other Thread methods. + * This is important because classes should not be subclassed + * unless the programmer intends on modifying or enhancing the fundamental + * behavior of the class. + * + * @author Arthur van Hoff + * @see java.lang.Thread + * @see java.util.concurrent.Callable + * @since JDK1.0 + */ +public +interface Runnable { + /** + * When an object implementing interface Runnable is used + * to create a thread, starting the thread causes the object's + * run method to be called in that separately executing + * thread. + *

+ * The general contract of the method run is that it may + * take any action whatsoever. + * + * @see java.lang.Thread#run() + */ + public abstract void run(); +} diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/java/java/lang/String.java --- a/emul/src/main/java/java/lang/String.java Tue Jan 22 19:48:10 2013 +0100 +++ b/emul/src/main/java/java/lang/String.java Wed Jan 23 12:53:23 2013 +0100 @@ -994,7 +994,7 @@ * @see #equalsIgnoreCase(String) */ @JavaScriptBody(args = { "obj" }, body = - "return obj.$instOf_java_lang_String && " + "return obj != null && obj.$instOf_java_lang_String && " + "this.toString() === obj.toString();" ) public boolean equals(Object anObject) { diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/java/java/lang/Throwable.java --- a/emul/src/main/java/java/lang/Throwable.java Tue Jan 22 19:48:10 2013 +0100 +++ b/emul/src/main/java/java/lang/Throwable.java Wed Jan 23 12:53:23 2013 +0100 @@ -26,6 +26,7 @@ package java.lang; import java.io.*; import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.core.JavaScriptOnly; /** * The {@code Throwable} class is the superclass of all errors and @@ -234,6 +235,13 @@ private static final String SELF_SUPPRESSION_MESSAGE = "Self-suppression not permitted"; /** Caption for labeling causative exception stack traces */ + @JavaScriptOnly(name="toString", value="function() { return this.toString__Ljava_lang_String_2().toString(); }") + private static void jsToString() { + } + + @JavaScriptOnly(name="valueOf", value="function() { return this.toString().valueOf(); }") + private static void jsValudOf() { + } private static final String CAUSE_CAPTION = "Caused by: "; /** Caption for labeling suppressed exception stack traces */ diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/java/java/lang/reflect/Array.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/src/main/java/java/lang/reflect/Array.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,659 @@ +/* + * Copyright (c) 1996, 2006, 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.reflect; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.core.JavaScriptPrototype; + +/** + * The {@code Array} class provides static methods to dynamically create and + * access Java arrays. + * + *

{@code Array} permits widening conversions to occur during a get or set + * operation, but throws an {@code IllegalArgumentException} if a narrowing + * conversion would occur. + * + * @author Nakul Saraiya + */ +@JavaScriptPrototype(prototype = "new Array", container = "Array.prototype") +public final +class Array { + + /** + * Constructor. Class Array is not instantiable. + */ + private Array() {} + + /** + * Creates a new array with the specified component type and + * length. + * Invoking this method is equivalent to creating an array + * as follows: + *

+ *
+     * int[] x = {length};
+     * Array.newInstance(componentType, x);
+     * 
+ *
+ * + * @param componentType the {@code Class} object representing the + * component type of the new array + * @param length the length of the new array + * @return the new array + * @exception NullPointerException if the specified + * {@code componentType} parameter is null + * @exception IllegalArgumentException if componentType is {@link Void#TYPE} + * @exception NegativeArraySizeException if the specified {@code length} + * is negative + */ + public static Object newInstance(Class componentType, int length) + throws NegativeArraySizeException { + if (length < 0) { + throw new NegativeArraySizeException(); + } + String sig = findSignature(componentType); + return newArray(componentType.isPrimitive(), sig, length); + } + + private static String findSignature(Class type) { + if (type == Integer.TYPE) { + return "[I"; + } + if (type == Long.TYPE) { + return "[J"; + } + if (type == Double.TYPE) { + return "[D"; + } + if (type == Float.TYPE) { + return "[F"; + } + if (type == Byte.TYPE) { + return "[B"; + } + if (type == Boolean.TYPE) { + return "[Z"; + } + if (type == Short.TYPE) { + return "[S"; + } + if (type == Character.TYPE) { + return "[C"; + } + if (type.getName().equals("void")) { + throw new IllegalStateException("Can't create array for " + type); + } + return "[L" + type.getName() + ";"; + } + /** + * Creates a new array + * with the specified component type and dimensions. + * If {@code componentType} + * represents a non-array class or interface, the new array + * has {@code dimensions.length} dimensions and + * {@code componentType} as its component type. If + * {@code componentType} represents an array class, the + * number of dimensions of the new array is equal to the sum + * of {@code dimensions.length} and the number of + * dimensions of {@code componentType}. In this case, the + * component type of the new array is the component type of + * {@code componentType}. + * + *

The number of dimensions of the new array must not + * exceed the number of array dimensions supported by the + * implementation (typically 255). + * + * @param componentType the {@code Class} object representing the component + * type of the new array + * @param dimensions an array of {@code int} representing the dimensions of + * the new array + * @return the new array + * @exception NullPointerException if the specified + * {@code componentType} argument is null + * @exception IllegalArgumentException if the specified {@code dimensions} + * argument is a zero-dimensional array, or if the number of + * requested dimensions exceeds the limit on the number of array dimensions + * supported by the implementation (typically 255), or if componentType + * is {@link Void#TYPE}. + * @exception NegativeArraySizeException if any of the components in + * the specified {@code dimensions} argument is negative. + */ + public static Object newInstance(Class componentType, int... dimensions) + throws IllegalArgumentException, NegativeArraySizeException { + StringBuilder sig = new StringBuilder(); + for (int i = 1; i < dimensions.length; i++) { + sig.append('['); + } + sig.append(findSignature(componentType)); + return multiNewArray(sig.toString(), dimensions, 0); + } + + /** + * Returns the length of the specified array object, as an {@code int}. + * + * @param array the array + * @return the length of the array + * @exception IllegalArgumentException if the object argument is not + * an array + */ + public static int getLength(Object array) + throws IllegalArgumentException { + if (!array.getClass().isArray()) { + throw new IllegalArgumentException("Argument is not an array"); + } + return length(array); + } + + @JavaScriptBody(args = { "arr" }, body = "return arr.length;") + private static native int length(Object arr); + + /** + * Returns the value of the indexed component in the specified + * array object. The value is automatically wrapped in an object + * if it has a primitive type. + * + * @param array the array + * @param index the index + * @return the (possibly wrapped) value of the indexed component in + * the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + */ + public static Object get(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t.isPrimitive()) { + return Array.fromPrimitive(t, array, index); + } else { + return ((Object[])array)[index]; + } + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code boolean}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static native boolean getBoolean(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException; + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code byte}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static byte getByte(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + if (array.getClass().getComponentType() != Byte.TYPE) { + throw new IllegalArgumentException(); + } + byte[] arr = (byte[]) array; + return arr[index]; + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code char}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static native char getChar(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException; + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code short}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static short getShort(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Short.TYPE) { + short[] arr = (short[]) array; + return arr[index]; + } + return getByte(array, index); + } + + /** + * Returns the value of the indexed component in the specified + * array object, as an {@code int}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static int getInt(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Integer.TYPE) { + int[] arr = (int[]) array; + return arr[index]; + } + return getShort(array, index); + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code long}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static long getLong(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Long.TYPE) { + long[] arr = (long[]) array; + return arr[index]; + } + return getInt(array, index); + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code float}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static float getFloat(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Float.TYPE) { + float[] arr = (float[]) array; + return arr[index]; + } + return getLong(array, index); + } + + /** + * Returns the value of the indexed component in the specified + * array object, as a {@code double}. + * + * @param array the array + * @param index the index + * @return the value of the indexed component in the specified array + * @exception NullPointerException If the specified object is null + * @exception IllegalArgumentException If the specified object is not + * an array, or if the indexed element cannot be converted to the + * return type by an identity or widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to the + * length of the specified array + * @see Array#get + */ + public static double getDouble(Object array, int index) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + final Class t = array.getClass().getComponentType(); + if (t == Double.TYPE) { + double[] arr = (double[]) array; + return arr[index]; + } + return getFloat(array, index); + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified new value. The new value is first + * automatically unwrapped if the array has a primitive component + * type. + * @param array the array + * @param index the index into the array + * @param value the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the array component type is primitive and + * an unwrapping conversion fails + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + */ + public static void set(Object array, int index, Object value) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + if (array.getClass().getComponentType().isPrimitive()) { + throw new IllegalArgumentException(); + } else { + Object[] arr = (Object[])array; + arr[index] = value; + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code boolean} value. + * @param array the array + * @param index the index into the array + * @param z the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static native void setBoolean(Object array, int index, boolean z) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException; + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code byte} value. + * @param array the array + * @param index the index into the array + * @param b the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setByte(Object array, int index, byte b) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Byte.TYPE) { + byte[] arr = (byte[]) array; + arr[index] = b; + } else { + setShort(array, index, b); + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code char} value. + * @param array the array + * @param index the index into the array + * @param c the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static native void setChar(Object array, int index, char c) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException; + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code short} value. + * @param array the array + * @param index the index into the array + * @param s the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setShort(Object array, int index, short s) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Short.TYPE) { + short[] arr = (short[]) array; + arr[index] = s; + } else { + setInt(array, index, s); + } + + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code int} value. + * @param array the array + * @param index the index into the array + * @param i the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setInt(Object array, int index, int i) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Integer.TYPE) { + long[] arr = (long[]) array; + arr[index] = i; + } else { + setLong(array, index, i); + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code long} value. + * @param array the array + * @param index the index into the array + * @param l the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setLong(Object array, int index, long l) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Long.TYPE) { + long[] arr = (long[]) array; + arr[index] = l; + } else { + setFloat(array, index, l); + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code float} value. + * @param array the array + * @param index the index into the array + * @param f the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setFloat(Object array, int index, float f) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Float.TYPE) { + float[] arr = (float[])array; + arr[index] = f; + } else { + setDouble(array, index, f); + } + } + + /** + * Sets the value of the indexed component of the specified array + * object to the specified {@code double} value. + * @param array the array + * @param index the index into the array + * @param d the new value of the indexed component + * @exception NullPointerException If the specified object argument + * is null + * @exception IllegalArgumentException If the specified object argument + * is not an array, or if the specified value cannot be converted + * to the underlying array's component type by an identity or a + * primitive widening conversion + * @exception ArrayIndexOutOfBoundsException If the specified {@code index} + * argument is negative, or if it is greater than or equal to + * the length of the specified array + * @see Array#set + */ + public static void setDouble(Object array, int index, double d) + throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + Class t = array.getClass().getComponentType(); + if (t == Double.TYPE) { + double[] arr = (double[])array; + arr[index] = d; + } else { + throw new IllegalArgumentException("argument type mismatch"); + } + } + + /* + * Private + */ + + @JavaScriptBody(args = { "primitive", "sig", "length" }, body = + "var arr = new Array(length);\n" + + "var value = primitive ? 0 : null;\n" + + "for(var i = 0; i < length; i++) arr[i] = value;\n" + + "arr.jvmName = sig;\n" + + "return arr;" + ) + private static native Object newArray(boolean primitive, String sig, int length); + + private 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]); + } + Object[] arr = (Object[]) newArray(false, sig, dims[index]); + String compsig = sig.substring(1); + for (int i = 0; i < arr.length; i++) { + arr[i] = multiNewArray(compsig, dims, index + 1); + } + return arr; + } + private static Object fromPrimitive(Class t, Object array, int index) { + return Method.fromPrimitive(t, atArray(array, index)); + } + + @JavaScriptBody(args = { "array", "index" }, body = "return array[index]") + private static native Object atArray(Object array, int index); +} diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/java/java/lang/reflect/Method.java --- a/emul/src/main/java/java/lang/reflect/Method.java Tue Jan 22 19:48:10 2013 +0100 +++ b/emul/src/main/java/java/lang/reflect/Method.java Wed Jan 23 12:53:23 2013 +0100 @@ -537,7 +537,7 @@ ) private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args); - private static Object fromPrimitive(Class type, Object o) { + static Object fromPrimitive(Class type, Object o) { if (type == Integer.TYPE) { return fromRaw(Integer.class, "valueOf__Ljava_lang_Integer_2I", o); } diff -r 7400dc9f48fb -r 1adce93fea0f emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js --- a/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Tue Jan 22 19:48:10 2013 +0100 +++ b/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Wed Jan 23 12:53:23 2013 +0100 @@ -1,12 +1,7 @@ -// initialize methods on String constants +// initialize methods on arrays and String constants +vm.java_lang_reflect_Array(false); vm.java_lang_String(false); -// we need initialized arrays -Array.prototype.initWith = function(sig, value) { - for(var i = 0; i < this.length; i++) this[i] = value; - this.jvmName = sig; - return this; -}; Array.prototype.at = function(indx, value) { if (indx < 0 || indx > this.length) { var e = vm.java_lang_ArrayIndexOutOfBoundsException(true); diff -r 7400dc9f48fb -r 1adce93fea0f javap/src/main/java/org/apidesign/javap/StackMapIterator.java --- a/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Tue Jan 22 19:48:10 2013 +0100 +++ b/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Wed Jan 23 12:53:23 2013 +0100 @@ -123,7 +123,7 @@ } final int length = methodSignature.length(); - int skipType = 0; + boolean skipType = false; int argType; for (int i = 1; i < length; ++i) { switch (methodSignature.charAt(i)) { @@ -156,10 +156,10 @@ // not interested in the return value type return argTypes; case '[': - if (skipType == 0) { + if (!skipType) { argTypes.add(ITEM_Object); + skipType = true; } - ++skipType; continue; default: @@ -167,10 +167,10 @@ "Invalid method signature"); } - if (skipType == 0) { + if (!skipType) { argTypes.add(argType); } else { - --skipType; + skipType = false; } } diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/pom.xml --- a/javaquery/api/pom.xml Tue Jan 22 19:48:10 2013 +0100 +++ b/javaquery/api/pom.xml Wed Jan 23 12:53:23 2013 +0100 @@ -64,5 +64,11 @@ jar test + + ${project.groupId} + vmtest + ${project.version} + test + diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,93 @@ +/** + * 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.lang.reflect.Method; +import org.apidesign.bck2brwsr.core.ExtraJavaScript; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** Provides binding between models and + * + * @author Jaroslav Tulach + */ +@ExtraJavaScript(resource = "/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js") +public class Knockout { + /** used by tests */ + static Knockout next; + + Knockout() { + } + + public static Knockout applyBindings( + Class modelClass, M model, String[] propsGettersAndSetters + ) { + Knockout bindings = next; + next = null; + if (bindings == null) { + bindings = new Knockout(); + } + 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()); + } + } + applyBindings(bindings); + return bindings; + } + + @JavaScriptBody(args = { "prop" }, body = + "this[prop].valueHasMutated();" + ) + public void valueHasMutated(String prop) { + } + + + @JavaScriptBody(args = { "id", "ev" }, body = "ko.utils.triggerEvent(window.document.getElementById(id), ev.substring(2));") + public static void triggerEvent(String id, String ev) { + } + + @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive" }, body = + "var bnd = {\n" + + " read: function() {\n" + + " var v = model[getter]();\n" + + " return v;\n" + + " },\n" + + " owner: bindings\n" + + "};\n" + + "if (setter != null) {\n" + + " bnd.write = function(val) {\n" + + " model[setter](primitive ? new Number(val) : val);\n" + + " };\n" + + "}\n" + + "bindings[prop] = ko.computed(bnd);" + ) + private static void bind( + Object bindings, Object model, String prop, String getter, String setter, boolean primitive + ) { + } + + @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);") + private static void applyBindings(Object bindings) {} +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Tue Jan 22 19:48:10 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Wed Jan 23 12:53:23 2013 +0100 @@ -22,9 +22,13 @@ import java.io.OutputStreamWriter; import java.io.Writer; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Completion; @@ -39,12 +43,16 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.MirroredTypeException; import javax.lang.model.type.TypeMirror; 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.On; import org.apidesign.bck2brwsr.htmlpage.api.Page; +import org.apidesign.bck2brwsr.htmlpage.api.Property; import org.openide.util.lookup.ServiceProvider; /** Annotation processor to process an XHTML page and generate appropriate @@ -89,19 +97,44 @@ try { w.append("package " + pkg + ";\n"); w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n"); - w.append("class ").append(className).append(" {\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 static final "). + w.append(" ").append("public final "). append(type).append(' ').append(cnstnt(id)).append(" = new "). append(type).append("(\"").append(id).append("\");\n"); } - w.append(" static {\n"); - if (!initializeOnClick(pe, w, pp)) { - return false; + 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"); w.append("}\n"); } finally { w.close(); @@ -134,21 +167,31 @@ if (tag.equals("input")) { return "Input"; } + if (tag.equals("canvas")) { + return "Canvas"; + } + if (tag.equals("img")) { + return "Image"; + } return "Element"; } private static String cnstnt(String id) { - return id.toUpperCase(Locale.ENGLISH).replace('.', '_'); + return id.toUpperCase(Locale.ENGLISH).replace('.', '_').replace('-', '_'); } - private boolean initializeOnClick(PackageElement pe, Writer w, ProcessPage pp) throws IOException { + private boolean initializeOnClick( + String className, TypeElement type, Writer w, ProcessPage pp + ) throws IOException { TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); - for (Element clazz : pe.getEnclosedElements()) { - if (clazz.getKind() != ElementKind.CLASS) { - continue; - } - TypeElement type = (TypeElement)clazz; - for (Element method : clazz.getEnclosedElements()) { + { //for (Element clazz : pe.getEnclosedElements()) { + // if (clazz.getKind() != ElementKind.CLASS) { + // continue; + // } + w.append(" public ").append(className).append("() {\n"); + StringBuilder dispatch = new StringBuilder(); + int dispatchCnt = 0; + for (Element method : type.getEnclosedElements()) { On oc = method.getAnnotation(On.class); if (oc != null) { for (String id : oc.id()) { @@ -157,15 +200,33 @@ return false; } ExecutableElement ee = (ExecutableElement)method; - boolean hasParam; - if (ee.getParameters().isEmpty()) { - hasParam = false; - } else { - if (ee.getParameters().size() != 1 || ee.getParameters().get(0).asType() != stringType) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method should either have no arguments or one String argument", ee); + 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; } - hasParam = true; } if (!ee.getModifiers().contains(Modifier.STATIC)) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method has to be static", ee); @@ -176,17 +237,33 @@ return false; } w.append(" OnEvent." + oc.event()).append(".of(").append(cnstnt(id)). - append(").perform(new Runnable() { public void run() {\n"); - w.append(" ").append(type.getSimpleName().toString()). - append('.').append(ee.getSimpleName()).append("("); - if (hasParam) { - w.append("\"").append(id).append("\""); - } - w.append(");\n"); - w.append(" }});\n"); - } + append(").perform(new OnDispatch(" + dispatchCnt + "));\n"); + + dispatch. + append(" case ").append(dispatchCnt).append(": "). + append(type.getSimpleName().toString()). + append('.').append(ee.getSimpleName()).append("("). + append(params). + append("); break;\n"); + + dispatchCnt++; + } } } + w.append(" }\n"); + if (dispatchCnt > 0) { + w.append("class OnDispatch implements Runnable {\n"); + w.append(" private final int dispatch;\n"); + w.append(" OnDispatch(int d) { dispatch = d; }\n"); + w.append(" public void run() {\n"); + w.append(" switch (dispatch) {\n"); + w.append(dispatch); + w.append(" }\n"); + w.append(" }\n"); + w.append("}\n"); + } + + } return true; } @@ -233,4 +310,126 @@ } return e.getEnclosingElement(); } + + private static void generateProperties( + Writer w, Property[] properties, Collection props, + Map> deps + ) throws IOException { + for (Property p : properties) { + final String tn = typeName(p); + String[] gs = toGetSet(p.name(), tn); + + 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"); + } + } + w.write(" }\n"); + w.write("}\n"); + + props.add(p.name()); + props.add(gs[2]); + props.add(gs[3]); + props.add(gs[0]); + } + } + + private boolean generateComputedProperties( + Writer w, Collection arr, Collection props, + Map> deps + ) throws IOException { + for (Element e : arr) { + if (e.getKind() != ElementKind.METHOD) { + continue; + } + if (e.getAnnotation(ComputedProperty.class) == null) { + continue; + } + ExecutableElement ee = (ExecutableElement)e; + final String tn = ee.getReturnType().toString(); + final String sn = ee.getSimpleName().toString(); + String[] gs = toGetSet(sn, tn); + + 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); + w.write(" " + dt + " arg" + (++arg) + " = "); + w.write(call[0] + "();\n"); + + Collection depends = deps.get(dn); + if (depends == null) { + 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() + "("); + String sep = ""; + for (int i = 1; i <= arg; i++) { + w.write(sep); + w.write("arg" + i); + sep = ", "; + } + w.write(");\n"); + w.write(" } finally {\n"); + 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; + } + + private static String[] toGetSet(String name, String type) { + String n = Character.toUpperCase(name.charAt(0)) + name.substring(1); + String bck2brwsrType = "L" + type.replace('.', '_') + "_2"; + if ("int".equals(type)) { + bck2brwsrType = "I"; + } + if ("double".equals(type)) { + bck2brwsrType = "D"; + } + String pref = "get"; + if ("boolean".equals(type)) { + pref = "is"; + bck2brwsrType = "Z"; + } + final String nu = n.replace('.', '_'); + return new String[]{ + pref + n, + "set" + n, + pref + nu + "__" + bck2brwsrType, + "set" + nu + "__V" + bck2brwsrType + }; + } + + private static String typeName(Property p) { + try { + return p.type().getName(); + } catch (MirroredTypeException ex) { + return ex.getTypeMirror().toString(); + } + } } diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Canvas.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Canvas.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,61 @@ +/** + * 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 org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Anton Epple + */ +public class Canvas extends Element { + + public Canvas(String id) { + super(id); + } + + public void setHeight(int height) { + setAttribute(this, "height", height); + } + + public int getHeight() { + return (Integer) getAttribute(this, "height"); + } + + public void setWidth(int width) { + setAttribute(this, "width", width); + } + + public int getWidth() { + return (Integer) getAttribute(this, "width"); + } + + @JavaScriptBody( + args = {"el"}, + body = "var e = window.document.getElementById(el.fld_id);\n" + + "return e.getContext('2d');\n") + private native static Object getContextImpl(Canvas el); + + public GraphicsContext getContext() { + return new GraphicsContext(getContextImpl(this)); + } + + @Override + void dontSubclass() { + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ComputedProperty.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ComputedProperty.java Wed Jan 23 12:53:23 2013 +0100 @@ -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; + +/** 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. + * + * @author Jaroslav Tulach + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.METHOD) +public @interface ComputedProperty { +} diff -r 7400dc9f48fb -r 1adce93fea0f 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 Jan 22 19:48:10 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Wed Jan 23 12:53:23 2013 +0100 @@ -30,6 +30,13 @@ this.id = id; } + /** Id of the element in the document. + * @return the id for this element + */ + public String getId() { + return id; + } + abstract void dontSubclass(); @JavaScriptBody( @@ -46,6 +53,12 @@ ) static native Object getAttribute(Element el, String property); + @JavaScriptBody( + args={"el"}, + body="return window.document.getElementById(el.fld_id);" + ) + static native Object getElementById(Element el); + /** Executes given runnable when user performs a "click" on the given * element. * @param r the runnable to execute, never null @@ -55,7 +68,8 @@ body="var e = window.document.getElementById(this.fld_id);\n" + "e[ev.fld_id] = function() { r.run__V(); };\n" ) - final native void on(OnEvent ev, Runnable r); + final void on(OnEvent ev, Runnable r) { + } /** Shows alert message dialog in a browser. * @param msg the message to show diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/GraphicsContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/GraphicsContext.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,335 @@ +/** + * 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 org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Anton Epple + */ +public class GraphicsContext { + + Object context; + + GraphicsContext(Object contextImpl) { + this.context = contextImpl; + } + + @JavaScriptBody(args = {"centerx", "centery", "radius", "startangle", "endangle", "ccw"}, + body = "this.fld_context.arc(centerx,centery, radius, startangle, endangle,ccw);") + public native void arc(double centerX, + double centerY, + double startAngle, + double radius, + double endAngle, + boolean ccw); + + @JavaScriptBody(args = {"x1", "y1", "x2", "y2", "r"}, + body = "this.fld_context.arcTo(x1,y1,x2,y2,r);") + public native void arcTo(double x1, + double y1, + double x2, + double y2, + double r); + + @JavaScriptBody(args = {"x", "y"}, + body = "return this.fld_context.isPointInPath(x,y);") + public native boolean isPointInPath(double x, double y); + + @JavaScriptBody(args = {}, body = "this.fld_context.fill();") + public native void fill(); + + @JavaScriptBody(args = {}, body = "this.fld_context.stroke();") + public native void stroke(); + + @JavaScriptBody(args = {}, body = "this.fld_context.beginPath();") + public native void beginPath(); + + @JavaScriptBody(args = {}, body = "this.fld_context.closePath();") + public native void closePath(); + + @JavaScriptBody(args = {}, body = "this.fld_context.clip();") + public native void clip(); + + @JavaScriptBody(args = {"x", "y"}, body = "this.fld_context.moveTo(x,y);") + public native void moveTo(double x, double y); + + @JavaScriptBody(args = {"x", "y"}, body = "this.fld_context.lineTo(x,y);") + public native void lineTo(double x, double y); + + @JavaScriptBody(args = {"cpx", "cpy", "x", "y"}, body = "this.fld_context.quadraticCurveTo(cpx,cpy,x,y);") + public native void quadraticCurveTo(double cpx, double cpy, double x, double y); + + @JavaScriptBody(args = {"cp1x", "cp1y", "cp2x", "cp2y", "x", "y"}, + body = "this.fld_context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);") + public native void bezierCurveTo(double cp1x, double cp1y, double cp2x, double cp2y, double x, double y); + + @JavaScriptBody(args = {"x", "y", "width", "height"}, body = "this.fld_context.fillRect(x,y,width,height);") + public native void fillRect(double x, double y, double width, double height); + + @JavaScriptBody(args = {"x", "y", "width", "height"}, body = "this.fld_context.strokeRect(x,y,width,height);") + public native void strokeRect(double x, double y, double width, double height); + + @JavaScriptBody(args = {"x", "y", "width", "height"}, body = "this.fld_context.clearRect(x,y,width,height);") + public native void clearRect(double x, double y, double width, double height); + + @JavaScriptBody(args = {"x", "y", "width", "height"}, body = "this.fld_context.rectect(x,y,width,height);") + public native void rect(double x, double y, double width, double height); + + @JavaScriptBody(args = {}, body = "this.fld_context.save();") + public native void save(); + + @JavaScriptBody(args = {}, body = "this.fld_context.restore();") + public native void restore(); + + @JavaScriptBody(args = {"angle"}, body = "this.fld_context.rotate(angle);") + public native void rotate(double angle); + + @JavaScriptBody(args = {"a", "b", "c", "d", "e", "f"}, body = "this.fld_context.transform(a,b,c,d,e,f);") + public native void transform(double a, double b, double c, double d, double e, double f); + + @JavaScriptBody(args = {"a", "b", "c", "d", "e", "f"}, body = "this.fld_context.setTransform(a,b,c,d,e,f);") + public native void setTransform(double a, double b, double c, double d, double e, double f); + + @JavaScriptBody(args = {"x", "y"}, body = "this.fld_context.translate(x,y);") + public native void translate(double x, double y); + + @JavaScriptBody(args = {"x", "y"}, body = "this.fld_context.scale(x,y);") + public native void scale(double x, double y); + + public void drawImage(Image image, double x, double y) { + drawImageImpl(context, Element.getElementById(image), x, y); + } + + public void drawImage(Image image, double x, double y, double width, double height) { + drawImageImpl(context, Element.getElementById(image), x, y, width, height); + } + + public void drawImage(Image image, double sx, double sy, double sWidth, double sHeight, double x, double y, double width, double height) { + drawImageImpl(context, Element.getElementById(image), sx, sy, sWidth, sHeight, x, y, width, height); + } + + @JavaScriptBody(args = {"ctx", "img", "x", "y", "width", "height"}, body = "ctx.drawImage(img,x,y,width,height);") + private native static void drawImageImpl(Object ctx, Object img, double x, double y, double width, double height); + + @JavaScriptBody(args = {"ctx", "img", "sx", "sy", "swidth", "sheight", "x", "y", "width", "height"}, body = "ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);") + private native static void drawImageImpl(Object ctx, Object img, double sx, double sy, double sWidth, double sHeight, double x, double y, double width, double height); + + @JavaScriptBody(args = {"ctx", "img", "x", "y"}, body = "ctx.drawImage(img,x,y);") + private native static void drawImageImpl(Object ctx, Object img, double x, double y); + + @JavaScriptBody(args = {"style"}, body = "this.fld_context.fillStyle=style;") + public native void setFillStyle(String style); + + @JavaScriptBody(args = {}, body = "return this.fld_context.fillStyle;") + public native String getFillStyle(); + + public void setFillStyle(LinearGradient style) { + setFillStyleImpl(context, style.object()); + } + + public void setFillStyle(RadialGradient style) { + setFillStyleImpl(context, style.object()); + } + + public void setFillStyle(Pattern style) { + setFillStyleImpl(context, style.object()); + } + + @JavaScriptBody(args = {"context","obj"}, body = "context.fillStyle=obj;") + private native void setFillStyleImpl(Object context, Object obj); + + @JavaScriptBody(args = {"style"}, body = "this.fld_context.strokeStyle=style;") + public native void setStrokeStyle(String style); + + public void setStrokeStyle(LinearGradient style) { + setStrokeStyleImpl(context, style.object()); + } + + public void setStrokeStyle(RadialGradient style) { + setStrokeStyleImpl(context, style.object()); + } + + @JavaScriptBody(args = {"style"}, body = "this.fld_context.fillStyle=style;") + public void setStrokeStyle(Pattern style) { + setStrokeStyleImpl(context, style.object()); + } + + @JavaScriptBody(args = {"context","obj"}, body = "context.strokeStyle=obj;") + private native void setStrokeStyleImpl(Object context, Object obj); + + @JavaScriptBody(args = {"color"}, body = "this.fld_context.shadowColor=color;") + public native void setShadowColor(String color); + + @JavaScriptBody(args = {"blur"}, body = "this.fld_context.shadowBlur=blur;") + public native void setShadowBlur(double blur); + + @JavaScriptBody(args = {"x"}, body = "this.fld_context.shadowOffsetX=x;") + public native void setShadowOffsetX(double x); + + @JavaScriptBody(args = {"y"}, body = "this.fld_context.shadowOffsetY=y;") + public native void setShadowOffsetY(double y); + + @JavaScriptBody(args = {}, body = "return this.fld_context.strokeStyle;") + public native String getStrokeStyle(); + + @JavaScriptBody(args = {}, body = "return this.fld_context.shadowColor;") + public native String getShadowColor(); + + @JavaScriptBody(args = {}, body = "return this.fld_context.shadowBlur;") + public native double getShadowBlur(); + + @JavaScriptBody(args = {}, body = "return this.fld_context.shadowOffsetX;") + public native double getShadowOffsetX(); + + @JavaScriptBody(args = {}, body = "return this.fld_context.shadowOffsetY;") + public native double getShadowOffsetY(); + + @JavaScriptBody(args = {}, body = "return this.fld_context.lineCap;") + public native String getLineCap(); + + @JavaScriptBody(args = {"style"}, body = "this.fld_context.lineCap=style;") + public native void setLineCap(String style); + + @JavaScriptBody(args = {}, body = "return this.fld_context.lineJoin;") + public native String getLineJoin(); + + @JavaScriptBody(args = {"style"}, body = "this.fld_context.lineJoin=style;") + public native void setLineJoin(String style) ; + + @JavaScriptBody(args = {}, body = "return this.fld_context.lineWidth;") + public native double getLineWidth(); + + @JavaScriptBody(args = {"width"}, body = "this.fld_context.lineJoin=width;") + public native void setLineWidth(double width); + + @JavaScriptBody(args = {}, body = "return this.fld_context.miterLimit;") + public native double getMiterLimit(); + + @JavaScriptBody(args = {"limit"}, body = "this.fld_context.miterLimit=limit;") + public native void setMiterLimit(double limit); + + @JavaScriptBody(args = {}, body = "return this.fld_context.font;") + public native String getFont(); + + @JavaScriptBody(args = {"font"}, body = "this.fld_context.font=font;") + public native void setFont(String font); + + @JavaScriptBody(args = {}, body = "return this.fld_context.textAlign;") + public native String getTextAlign(); + + @JavaScriptBody(args = {"textalign"}, body = "this.fld_context.textAlign=textalign;") + public native void setTextAlign(String textAlign); + + @JavaScriptBody(args = {}, body = "return this.fld_context.textBaseline;") + public native String getTextBaseline(); + + @JavaScriptBody(args = {"textbaseline"}, body = "this.fld_context.textBaseline=textbaseline;") + public native void setTextBaseline(String textbaseline); + + @JavaScriptBody(args = {"text", "x", "y"}, body = "this.fld_context.fillText(text,x,y);") + public native void fillText(String text, double x, double y); + + @JavaScriptBody(args = {"text", "x", "y", "maxwidth"}, body = "this.fld_context.fillText(text,x,y,maxwidth);") + public void fillText(String text, double x, double y, double maxWidth) { + } + + public TextMetrics measureText(String text) { + return new TextMetrics(measureTextImpl(text)); + } + + @JavaScriptBody(args = {"text"}, + body = "return this.fld_context.measureText(text);") + private native Object measureTextImpl(String text); + + @JavaScriptBody(args = {"text", "x", "y"}, body = "this.fld_context.strokeText(text,x,y);") + public native void strokeText(String text, double x, double y); + + @JavaScriptBody(args = {"text", "x", "y", "maxWidth"}, body = "this.fld_context.strokeText(text,x,y,maxWidth);") + public native void strokeText(String text, double x, double y, double maxWidth) ; + + public ImageData createImageData(double x, double y) { + return new ImageData(createImageDataImpl(x, y)); + } + + @JavaScriptBody(args = {"x", "y"}, + body = "return this.fld_context.createImageData(x,y);") + private native Object createImageDataImpl(double x, double y); + + public ImageData createImageData(ImageData imageData) { + return new ImageData(createImageDataImpl(imageData.getWidth(), imageData.getHeight())); + } + + public ImageData getImageData(double x, double y, double width, double height) { + return new ImageData(getImageDataImpl(x, y, width, height)); + } + + @JavaScriptBody(args = {"x", "y", "width", "height"}, + body = "return this.fld_context.getImageData(x,y,width,height);") + private native Object getImageDataImpl(double x, double y, double width, double height); + + public void putImageData(ImageData imageData, double x, double y) { + putImageDataImpl(imageData.object(), x, y); + } + + @JavaScriptBody(args = {"imageData", "x", "y"}, + body = "this.fld_context.putImageData(imageData,x,y);") + private native void putImageDataImpl(Object imageData, double x, double y); + + public void putImageData(ImageData imageData, double x, double y, double dirtyx, double dirtyy, double dirtywidth, double dirtyheight) { + putImageDataImpl(imageData.object(), x, y, dirtyx, dirtyy, dirtywidth, dirtyheight); + } + + @JavaScriptBody(args = {"imageData", "x", "y", "dirtyx", "dirtyy", "dirtywidth", "dirtyheight"}, + body = "this.fld_context.putImageData(imageData,x,y, dirtyx, dirtyy, dirtywidth,dirtyheight);") + private native void putImageDataImpl(Object imageData, double x, double y, double dirtyx, double dirtyy, double dirtywidth, double dirtyheight); + + @JavaScriptBody(args = {"alpha"}, body = "this.fld_context.globalAlpha=alpha;") + public native void setGlobalAlpha(double alpha) ; + + @JavaScriptBody(args = {}, body = "return this.fld_context.globalAlpha;") + public native double getGlobalAlpha(); + + @JavaScriptBody(args = {"operation"}, body = "this.fld_context.globalCompositeOperation=operation;") + public native void setGlobalCompositeOperation(double alpha); + + @JavaScriptBody(args = {}, body = "return this.fld_context.globalCompositeOperation;") + public native double getGlobalCompositeOperation(); + + public LinearGradient createLinearGradient(double x0, double y0, double x1, double y1) { + return new LinearGradient(createLinearGradientImpl(context, x0, y0, x1, y1)); + } + + @JavaScriptBody(args = {"context", "x0", "y0", "x1", "y1"}, body = "return context.createLinearGradient(x0,y0,x1,y1);") + private native Object createLinearGradientImpl(Object context, double x0, double y0, double x1, double y1); + + public Pattern createPattern(Image image, String repeat) { + return new Pattern(createPatternImpl(context, image, repeat)); + } + + @JavaScriptBody(args = {"context", "image", "repeat"}, body = "return context.createPattern(image, repeat);") + private static native Object createPatternImpl(Object context, Image image, String repeat); + + public RadialGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1) { + return new RadialGradient(createRadialGradientImpl(context, x0, y0, r0, x1, y1, r1)); + } + + @JavaScriptBody(args = {"context", "x0", "y0", "r0", "x1", "y1", "r1"}, body = "return context.createRadialGradient(x0,y0,r0,x1,y1,r1);") + private static native Object createRadialGradientImpl(Object context, double x0, double y0, double r0, double x1, double y1, double r1); +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Image.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Image.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,36 @@ +/** + * 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; + +/** + * + * @author Anton Epple + */ +public class Image extends Element{ + + public Image(String id) { + super(id); + } + + + + @Override + void dontSubclass() { + } + +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ImageData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ImageData.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,89 @@ +/** + * 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. + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.apidesign.bck2brwsr.htmlpage.api; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Anton Epple + */ +public class ImageData { + + private Object imageData; + private Data data; + + public ImageData(Object imageData) { + this.imageData = imageData; + } + + public Data getData(){ + if (data == null){ + data = new Data(getDataImpl(imageData)); + } + return data; + } + + @JavaScriptBody(args = {"imageData"}, body = "return imageData.data") + public native Object getDataImpl(Object imageData); + + public double getWidth() { + return getWidthImpl(imageData); + } + + @JavaScriptBody(args = {"imageData"}, body = "return imagedata.width;") + private static native double getWidthImpl(Object imageData); + + public double getHeight() { + return getHeightImpl(imageData); + } + + @JavaScriptBody(args = {"imageData"}, body = "return imagedata.height;") + private static native double getHeightImpl(Object imageData); + + Object object() { + return imageData; + } + + public static class Data { + + Object data; + + public Data(Object data) { + this.data = data; + } + + public int get(int index) { + return getImpl(data, index); + } + + public void set(int index, int value) { + setImpl(data, index, value); + } + + @JavaScriptBody(args = {"data", "index", "value"}, body = "data[index]=value;") + private static native void setImpl(Object data, int index, int value); + + @JavaScriptBody(args = {"imagedata", "index"}, body = "return data[index];") + private static native int getImpl(Object data, int index); + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/LinearGradient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/LinearGradient.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.htmlpage.api; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Anton Epple + */ +public class LinearGradient { + + private final Object gradient; + + LinearGradient(Object linearGradient) { + this.gradient = linearGradient; + } + + Object object() { + return gradient; + } + + public void addColorStop(double position, String color) { + addColorStopImpl(gradient, position, color); + } + + @JavaScriptBody(args = {"gradient", "position", "color"}, body = + "gradient.addColorStop(position,color)") + private static native void addColorStopImpl(Object gradient, double position, String color); +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnEvent.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnEvent.java Tue Jan 22 19:48:10 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnEvent.java Wed Jan 23 12:53:23 2013 +0100 @@ -26,6 +26,7 @@ BLUR("onblur"), CAN_PLAY("oncanplay"), CAN_PLAY_THROUGH("oncanplaythrough"), + CHANGE("onchange"), CLICK("onclick"), CONTEXT_MENU("oncontextmenu"), DBL_CLICK("ondblclick"), @@ -82,6 +83,13 @@ this.id = id; } + /** The name of property this event is referenced by from an {@link Element}. + * For {@link OnEvent#CHANGE}, it is onchange. + */ + public String getElementPropertyName() { + return id; + } + /** What should happen when this even happen on one * of associated elements. Continue by calling {@link OnController#perform(java.lang.Runnable)} * method. diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Page.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Page.java Tue Jan 22 19:48:10 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Page.java Wed Jan 23 12:53:23 2013 +0100 @@ -36,4 +36,7 @@ * found elements with IDs. */ String className() default ""; + /** List of properties generated into the page. + */ + Property[] properties() default {}; } diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Paint.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Paint.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.htmlpage.api; + +/** + * + * @author Anton Epple + */ +public class Paint { + + + String asString(){ + return ""; + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Pattern.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Pattern.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.htmlpage.api; + +/** + * + * @author Anton Epple + */ +public class Pattern { + + private Object pattern; + + public Pattern(Object pattern) { + this.pattern = pattern; + } + + Object object() { + return pattern; + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Property.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Property.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.htmlpage.api; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** Represents a property in a generated model of an HTML + * {@link Page}. + * + * @author Jaroslav Tulach + */ +@Retention(RetentionPolicy.SOURCE) +@Target({}) +public @interface Property { + String name(); + Class type(); +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/RadialGradient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/RadialGradient.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.htmlpage.api; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Anton Epple + */ +public class RadialGradient { + + private Object gradient; + + public RadialGradient(Object radialGradient) { + this.gradient = radialGradient; + } + + public void addColorStop(double position, String color) { + addColorStopImpl(gradient, position, color); + } + + @JavaScriptBody(args = {"gradient", "position", "color"}, body = + "gradient.addColorStop(position,color)") + private static native void addColorStopImpl(Object gradient, double position, String color); + + Object object() { + return gradient; + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/TextMetrics.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/TextMetrics.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.bck2brwsr.htmlpage.api; + +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Anton Epple + */ +public class TextMetrics { + + private Object textMetrics; + + TextMetrics(Object measureTextImpl) { + this.textMetrics = measureTextImpl; + } + + @JavaScriptBody(args = {"textMetrics"}, body = "return textMetrics.width;") + private native double getWidth(Object textMetrics); + + @JavaScriptBody(args = {"textMetrics"}, body = "return textMetrics.height;") + private native double getHeight(Object textMetrics); + + public double getWidth() { + return getWidth(textMetrics); + } + + public double getHeight() { + return getHeight(textMetrics); + + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,3587 @@ +// Knockout JavaScript library v2.2.1 +// (c) Steven Sanderson - http://knockoutjs.com/ +// License: MIT (http://www.opensource.org/licenses/mit-license.php) + +(function(){ +var DEBUG=true; +(function(window,document,navigator,jQuery,undefined){ +!function(factory) { + // Support three module loading scenarios + if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { + // [1] CommonJS/Node.js + var target = module['exports'] || exports; // module.exports is for Node.js + factory(target); + } else if (typeof define === 'function' && define['amd']) { + // [2] AMD anonymous module + define(['exports'], factory); + } else { + // [3] No module loader (plain "); + }; + + if (jQueryTmplVersion > 0) { + jQuery['tmpl']['tag']['ko_code'] = { + open: "__.push($1 || '');" + }; + jQuery['tmpl']['tag']['ko_with'] = { + open: "with($1) {", + close: "} " + }; + } + }; + + ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine(); + + // Use this one by default *only if jquery.tmpl is referenced* + var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine(); + if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0) + ko.setTemplateEngine(jqueryTmplTemplateEngineInstance); + + ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine); +})(); +}); +})(window,document,navigator,window["jQuery"]); +})(); \ No newline at end of file diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.OnEvent; +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 org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +@Page(xhtml="Knockout.xhtml", className="KnockoutModel", properties={ + @Property(name="name", type=String.class) +}) +public class KnockoutTest { + + @HtmlFragment( + "

Loading Bck2Brwsr's Hello World...

\n" + + "Your name: \n" + + "\n" + ) + @BrwsrTest public void modifyValueAssertChangeInModel() { + 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 "Jardo".equals(m.getName()) : "Name property updated: " + m.getName(); + } + + @ComputedProperty + static String helloMessage(String name) { + return "Hello " + name + "!"; + } + + @Factory + public static Object[] create() { + return VMTest.create(KnockoutTest.class); + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,119 @@ +/** + * 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.List; +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; +import org.apidesign.bck2brwsr.htmlpage.api.Page; +import org.apidesign.bck2brwsr.htmlpage.api.Property; +import static org.testng.Assert.*; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +@Page(xhtml = "Empty.html", className = "Model", properties = { + @Property(name = "value", type = int.class), + @Property(name = "unrelated", type = long.class) +}) +public class ModelTest { + private Model model; + private static Model leakedModel; + + @BeforeMethod + public void createModel() { + model = new Model(); + } + + @Test public void classGeneratedWithSetterGetter() { + model.setValue(10); + assertEquals(10, model.getValue(), "Value changed"); + } + + @Test public void computedMethod() { + model.setValue(4); + assertEquals(16, model.getPowerValue()); + } + + @Test public void derivedPropertiesAreNotified() { + MockKnockout my = new MockKnockout(); + MockKnockout.next = my; + + model.applyBindings(); + + model.setValue(33); + + 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); + + my.mutated.clear(); + + model.setUnrelated(44); + assertEquals(my.mutated.size(), 1, "One property changed"); + assertTrue(my.mutated.contains("unrelated"), "Its name is unrelated"); + } + + @Test public void computedPropertyCannotWriteToModel() { + leakedModel = model; + try { + String res = model.getNotAllowedWrite(); + fail("We should not be allowed to write to the model: " + res); + } catch (IllegalStateException ex) { + // OK, we can't read + } + } + + @Test public void computedPropertyCannotReadToModel() { + leakedModel = model; + try { + String res = model.getNotAllowedRead(); + fail("We should not be allowed to read from the model: " + res); + } catch (IllegalStateException ex) { + // OK, we can't read + } + } + + @ComputedProperty + static int powerValue(int value) { + return value * value; + } + + @ComputedProperty + static String notAllowedRead() { + return "Not allowed callback: " + leakedModel.getUnrelated(); + } + + @ComputedProperty + static String notAllowedWrite() { + leakedModel.setUnrelated(11); + return "Not allowed callback!"; + } + + static class MockKnockout extends Knockout { + List mutated = new ArrayList(); + + @Override + public void valueHasMutated(String prop) { + mutated.add(prop); + } + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Tue Jan 22 19:48:10 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Wed Jan 23 12:53:23 2013 +0100 @@ -43,9 +43,14 @@ */ @Page(xhtml="TestPage.html") public class PageController { + private static final TestPage PAGE = new TestPage(); + @On(event = CLICK, id="pg.button") - static void updateTitle() { - TestPage.PG_TITLE.setText("You want this window to be named " + TestPage.PG_TEXT.getValue()); + static void updateTitle(TestPage ref) { + 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()); } @On(event = CLICK, id={ "pg.title", "pg.text" }) @@ -53,6 +58,6 @@ if (!id.equals("pg.title")) { throw new IllegalStateException(); } - TestPage.PG_TITLE.setText(id); + PAGE.PG_TITLE.setText(id); } } diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Tue Jan 22 19:48:10 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -108,7 +108,9 @@ + "\n" + "window.document = doc;\n" ); - Invocable i = compileClass(sb, "org/apidesign/bck2brwsr/htmlpage/PageController"); + Invocable i = compileClass(sb, + "org/apidesign/bck2brwsr/htmlpage/PageController" + ); Object ret = null; try { diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/Empty.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/Empty.html Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,29 @@ + + + + + + Empty + + + Empty page + + diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/Knockout.xhtml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/Knockout.xhtml Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,25 @@ + + +

+

Loading Bck2Brwsr's Hello World...

+ Your name: + +

diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator-dynamic/pom.xml --- a/javaquery/demo-calculator-dynamic/pom.xml Tue Jan 22 19:48:10 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/pom.xml Wed Jan 23 12:53:23 2013 +0100 @@ -28,7 +28,7 @@ - org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml + org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml @@ -54,5 +54,11 @@ javaquery.api 0.3-SNAPSHOT + + org.testng + testng + 6.5.2 + test + diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,112 @@ +/** + * 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.On; +import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; +import org.apidesign.bck2brwsr.htmlpage.api.Page; +import org.apidesign.bck2brwsr.htmlpage.api.Property; + +/** HTML5 & Java demo showing the power of + * annotation processors + * as well as other goodies. + * + * @author Jaroslav Tulach + */ +@Page(xhtml="Calculator.xhtml", properties = { + @Property(name = "memory", type = double.class), + @Property(name = "display", type = double.class), + @Property(name = "operation", type = String.class), + @Property(name = "hover", type = boolean.class) +}) +public class Calc { + static { + new Calculator().applyBindings(); + } + + @On(event = CLICK, id="clear") + static void clear(Calculator c) { + c.setMemory(0); + c.setOperation(null); + c.setDisplay(0); + } + + @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) + static void applyOp(Calculator c, String op) { + c.setMemory(c.getDisplay()); + c.setOperation(op); + c.setDisplay(0); + } + + @On(event = MOUSE_OVER, id= { "result" }) + static void attemptingIn(Calculator c, String op) { + c.setHover(true); + } + @On(event = MOUSE_OUT, id= { "result" }) + static void attemptingOut(Calculator c, String op) { + c.setHover(false); + } + + @On(event = CLICK, id="result") + static void computeTheValue(Calculator c) { + c.setDisplay(compute( + c.getOperation(), + c.getMemory(), + c.getDisplay() + )); + c.setMemory(0); + } + + private static double compute(String op, double memory, double display) { + switch (op) { + case "plus": return memory + display; + case "minus": return memory - display; + case "mul": return memory * display; + case "div": return memory / display; + default: throw new IllegalStateException(op); + } + } + + @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) + static void addDigit(String digit, Calculator c) { + digit = digit.substring(1); + + double v = c.getDisplay(); + if (v == 0.0) { + c.setDisplay(Integer.parseInt(digit)); + } else { + String txt = Double.toString(v); + if (txt.endsWith(".0")) { + txt = txt.substring(0, txt.length() - 2); + } + txt = txt + digit; + c.setDisplay(Double.parseDouble(txt)); + } + } + + @ComputedProperty + public static String displayPreview( + double display, boolean hover, double memory, String operation + ) { + if (!hover) { + return "Type numbers and perform simple operations! Press '=' to get result."; + } + return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display); + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java --- a/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Tue Jan 22 19:48:10 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.bck2brwsr.mavenhtml; - -import org.apidesign.bck2brwsr.htmlpage.api.On; -import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; -import org.apidesign.bck2brwsr.htmlpage.api.Page; - -/** HTML5 & Java demo showing the power of - * annotation processors - * as well as other goodies. - * - * @author Jaroslav Tulach - */ -@Page(xhtml="Calculator.xhtml") -public class App { - private static double memory; - private static String operation; - - @On(event = CLICK, id="clear") - static void clear() { - memory = 0; - operation = null; - Calculator.DISPLAY.setValue("0"); - } - - @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) - static void applyOp(String op) { - memory = getValue(); - operation = op; - Calculator.DISPLAY.setValue("0"); - } - - @On(event = CLICK, 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); - } - } - - @On(event = CLICK, 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); - if (sb.toString().endsWith(".0")) { - final int l = sb.length(); - sb.delete(l - 2, l); - } - 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 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,159 @@ + + + + + + Simple Calculator in HTML5 and Java + + + + +

Java and HTML5 - Together at Last!

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + +
+
+    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 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml --- a/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml Tue Jan 22 19:48:10 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ - - - - - - Simple Calculator in HTML5 and Java - - - - -

Java and HTML5 - Together at Last!

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - -
-
-    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 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator-dynamic/src/test/java/org/apidesign/bck2brwsr/demo/calc/CalcTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-calculator-dynamic/src/test/java/org/apidesign/bck2brwsr/demo/calc/CalcTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,46 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.demo.calc; + +import static org.testng.Assert.*; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** Demonstrating POJO testing of HTML page model. + * + * @author Jaroslav Tulach + */ +public class CalcTest { + private Calculator model; + + + @BeforeMethod + public void initModel() { + model = new Calculator().applyBindings(); + } + + @Test + public void testSomeMethod() { + model.setDisplay(10); + Calc.applyOp(model, "plus"); + assertEquals(0.0, model.getDisplay(), "Cleared after pressing +"); + model.setDisplay(5); + Calc.computeTheValue(model); + assertEquals(15.0, model.getDisplay(), "Shows fifteen"); + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator/pom.xml --- a/javaquery/demo-calculator/pom.xml Tue Jan 22 19:48:10 2013 +0100 +++ b/javaquery/demo-calculator/pom.xml Wed Jan 23 12:53:23 2013 +0100 @@ -42,7 +42,7 @@ xdg-open - ${project.build.directory}/classes/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml + ${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml
diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,112 @@ +/** + * 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.staticcompilation; + +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.Page; +import org.apidesign.bck2brwsr.htmlpage.api.Property; + +/** HTML5 & Java demo showing the power of + * annotation processors + * as well as other goodies. + * + * @author Jaroslav Tulach + */ +@Page(xhtml="Calculator.xhtml", properties = { + @Property(name = "memory", type = double.class), + @Property(name = "display", type = double.class), + @Property(name = "operation", type = String.class), + @Property(name = "hover", type = boolean.class) +}) +public class Calc { + static { + new Calculator().applyBindings(); + } + + @On(event = CLICK, id="clear") + static void clear(Calculator c) { + c.setMemory(0); + c.setOperation(null); + c.setDisplay(0); + } + + @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) + static void applyOp(Calculator c, String op) { + c.setMemory(c.getDisplay()); + c.setOperation(op); + c.setDisplay(0); + } + + @On(event = MOUSE_OVER, id= { "result" }) + static void attemptingIn(Calculator c, String op) { + c.setHover(true); + } + @On(event = MOUSE_OUT, id= { "result" }) + static void attemptingOut(Calculator c, String op) { + c.setHover(false); + } + + @On(event = CLICK, id="result") + static void computeTheValue(Calculator c) { + c.setDisplay(compute( + c.getOperation(), + c.getMemory(), + c.getDisplay() + )); + c.setMemory(0); + } + + private static double compute(String op, double memory, double display) { + switch (op) { + case "plus": return memory + display; + case "minus": return memory - display; + case "mul": return memory * display; + case "div": return memory / display; + default: throw new IllegalStateException(op); + } + } + + @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) + static void addDigit(String digit, Calculator c) { + digit = digit.substring(1); + + double v = c.getDisplay(); + if (v == 0.0) { + c.setDisplay(Integer.parseInt(digit)); + } else { + String txt = Double.toString(v); + if (txt.endsWith(".0")) { + txt = txt.substring(0, txt.length() - 2); + } + txt = txt + digit; + c.setDisplay(Double.parseDouble(txt)); + } + } + + @ComputedProperty + public static String displayPreview( + double display, boolean hover, double memory, String operation + ) { + if (!hover) { + return "Type numbers and perform simple operations! Press '=' to get result."; + } + return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display); + } +} diff -r 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java --- a/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Tue Jan 22 19:48:10 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.bck2brwsr.mavenhtml; - -import org.apidesign.bck2brwsr.htmlpage.api.On; -import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*; -import org.apidesign.bck2brwsr.htmlpage.api.Page; - -/** HTML5 & Java demo showing the power of - * annotation processors - * as well as other goodies. - * - * @author Jaroslav Tulach - */ -@Page(xhtml="Calculator.xhtml") -public class App { - private static double memory; - private static String operation; - - @On(event = CLICK, id="clear") - static void clear() { - memory = 0; - operation = null; - Calculator.DISPLAY.setValue("0"); - } - - @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) - static void applyOp(String op) { - memory = getValue(); - operation = op; - Calculator.DISPLAY.setValue("0"); - } - - @On(event = CLICK, 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); - } - } - - @On(event = CLICK, 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); - if (sb.toString().endsWith(".0")) { - final int l = sb.length(); - sb.delete(l - 2, l); - } - 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 7400dc9f48fb -r 1adce93fea0f javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,154 @@ + + + + + + Simple Calculator in HTML5 and Java + + + + +

Java and HTML5 - Together at Last!

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ - - -

Bck2Browser Console Launcher

- - Class Name: - -
- Method Name: - - -
- - - -
- - - - - diff -r 7400dc9f48fb -r 1adce93fea0f launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml --- a/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Tue Jan 22 19:48:10 2013 +0100 +++ b/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Wed Jan 23 12:53:23 2013 +0100 @@ -27,10 +27,12 @@ -

Bck2Browser Execution Harness

+

Bck2Brwsr Execution Harness

- + +
diff -r 7400dc9f48fb -r 1adce93fea0f mojo/src/main/resources/archetype-resources/src/test/java/AppTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mojo/src/main/resources/archetype-resources/src/test/java/AppTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -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 7400dc9f48fb -r 1adce93fea0f mojo/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mojo/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -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 7400dc9f48fb -r 1adce93fea0f mojo/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mojo/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -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 7400dc9f48fb -r 1adce93fea0f pom.xml --- a/pom.xml Tue Jan 22 19:48:10 2013 +0100 +++ b/pom.xml Wed Jan 23 12:53:23 2013 +0100 @@ -76,6 +76,7 @@ mojo/src/main/resources/archetype-resources/** launcher/src/main/resources/org/apidesign/bck2brwsr/dew/** vmtest/src/test/resources/** + javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout*.js diff -r 7400dc9f48fb -r 1adce93fea0f vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Jan 22 19:48:10 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Jan 23 12:53:23 2013 +0100 @@ -52,7 +52,7 @@ /* * @param resourcePath name of resources to read */ - protected abstract void requireScript(String resourcePath); + protected abstract void requireScript(String resourcePath) throws IOException; /** Allows subclasses to redefine what field a function representing a * class gets assigned. By default it returns the suggested name followed @@ -212,7 +212,7 @@ out.append("\n return this;"); out.append("\n }"); out.append("\n return arguments[0] ? new CLS() : CLS.prototype;"); - out.append("\n}"); + out.append("\n};"); StringBuilder sb = new StringBuilder(); for (String init : toInitilize.toArray()) { sb.append("\n").append(init).append("();"); @@ -264,37 +264,10 @@ final StackMapper smapper = new StackMapper(); - final int maxLocals = m.getMaxLocals(); - if (maxLocals > 0) { - // TODO: generate only used local variables - for (int j = 0; j <= VarType.LAST; ++j) { - out.append("\n var ").append(Variable.getLocalVariable(j, 0)); - for (int i = 1; i < maxLocals; ++i) { - out.append(", "); - out.append(Variable.getLocalVariable(j, i)); - } - out.append(';'); - } - } if (!m.isStatic()) { out.append(" var ").append(" lcA0 = this;\n"); } - // maxStack includes two stack positions for every pushed long / double - // so this might generate more stack variables than we need - final int maxStack = m.getMaxStack(); - if (maxStack > 0) { - // TODO: generate only used stack variables - for (int j = 0; j <= VarType.LAST; ++j) { - out.append("\n var ").append(Variable.getStackVariable(j, 0)); - for (int i = 1; i < maxStack; ++i) { - out.append(", "); - out.append(Variable.getStackVariable(j, i)); - } - out.append(';'); - } - } - int lastStackFrame = -1; TrapData[] previousTrap = null; @@ -325,174 +298,184 @@ final int c = readByte(byteCodes, i); switch (c) { case opc_aload_0: - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(0)); + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(0)); break; case opc_iload_0: - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(0)); + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(0)); break; case opc_lload_0: - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(0)); + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(0)); break; case opc_fload_0: - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(0)); + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(0)); break; case opc_dload_0: - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(0)); + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(0)); break; case opc_aload_1: - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(1)); + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(1)); break; case opc_iload_1: - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(1)); + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(1)); break; case opc_lload_1: - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(1)); + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(1)); break; case opc_fload_1: - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(1)); + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(1)); break; case opc_dload_1: - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(1)); + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(1)); break; case opc_aload_2: - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(2)); + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(2)); break; case opc_iload_2: - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(2)); + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(2)); break; case opc_lload_2: - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(2)); + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(2)); break; case opc_fload_2: - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(2)); + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(2)); break; case opc_dload_2: - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(2)); + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(2)); break; case opc_aload_3: - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(3)); + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(3)); break; case opc_iload_3: - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(3)); + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(3)); break; case opc_lload_3: - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(3)); + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(3)); break; case opc_fload_3: - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(3)); + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(3)); break; case opc_dload_3: - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(3)); + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(3)); break; case opc_iload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(indx)); + emit(out, "var @1 = @2;", + smapper.pushI(), lmapper.getI(indx)); break; } case opc_lload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(indx)); + emit(out, "var @1 = @2;", + smapper.pushL(), lmapper.getL(indx)); break; } case opc_fload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(indx)); + emit(out, "var @1 = @2;", + smapper.pushF(), lmapper.getF(indx)); break; } case opc_dload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(indx)); + emit(out, "var @1 = @2;", + smapper.pushD(), lmapper.getD(indx)); break; } case opc_aload: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(indx)); + emit(out, "var @1 = @2;", + smapper.pushA(), lmapper.getA(indx)); break; } case opc_istore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setI(indx), smapper.popI()); + emit(out, "var @1 = @2;", + lmapper.setI(indx), smapper.popI()); break; } case opc_lstore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setL(indx), smapper.popL()); + emit(out, "var @1 = @2;", + lmapper.setL(indx), smapper.popL()); break; } case opc_fstore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setF(indx), smapper.popF()); + emit(out, "var @1 = @2;", + lmapper.setF(indx), smapper.popF()); break; } case opc_dstore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setD(indx), smapper.popD()); + emit(out, "var @1 = @2;", + lmapper.setD(indx), smapper.popD()); break; } case opc_astore: { final int indx = readByte(byteCodes, ++i); - emit(out, "@1 = @2;", lmapper.setA(indx), smapper.popA()); + emit(out, "var @1 = @2;", + lmapper.setA(indx), smapper.popA()); break; } case opc_astore_0: - emit(out, "@1 = @2;", lmapper.setA(0), smapper.popA()); + emit(out, "var @1 = @2;", lmapper.setA(0), smapper.popA()); break; case opc_istore_0: - emit(out, "@1 = @2;", lmapper.setI(0), smapper.popI()); + emit(out, "var @1 = @2;", lmapper.setI(0), smapper.popI()); break; case opc_lstore_0: - emit(out, "@1 = @2;", lmapper.setL(0), smapper.popL()); + emit(out, "var @1 = @2;", lmapper.setL(0), smapper.popL()); break; case opc_fstore_0: - emit(out, "@1 = @2;", lmapper.setF(0), smapper.popF()); + emit(out, "var @1 = @2;", lmapper.setF(0), smapper.popF()); break; case opc_dstore_0: - emit(out, "@1 = @2;", lmapper.setD(0), smapper.popD()); + emit(out, "var @1 = @2;", lmapper.setD(0), smapper.popD()); break; case opc_astore_1: - emit(out, "@1 = @2;", lmapper.setA(1), smapper.popA()); + emit(out, "var @1 = @2;", lmapper.setA(1), smapper.popA()); break; case opc_istore_1: - emit(out, "@1 = @2;", lmapper.setI(1), smapper.popI()); + emit(out, "var @1 = @2;", lmapper.setI(1), smapper.popI()); break; case opc_lstore_1: - emit(out, "@1 = @2;", lmapper.setL(1), smapper.popL()); + emit(out, "var @1 = @2;", lmapper.setL(1), smapper.popL()); break; case opc_fstore_1: - emit(out, "@1 = @2;", lmapper.setF(1), smapper.popF()); + emit(out, "var @1 = @2;", lmapper.setF(1), smapper.popF()); break; case opc_dstore_1: - emit(out, "@1 = @2;", lmapper.setD(1), smapper.popD()); + emit(out, "var @1 = @2;", lmapper.setD(1), smapper.popD()); break; case opc_astore_2: - emit(out, "@1 = @2;", lmapper.setA(2), smapper.popA()); + emit(out, "var @1 = @2;", lmapper.setA(2), smapper.popA()); break; case opc_istore_2: - emit(out, "@1 = @2;", lmapper.setI(2), smapper.popI()); + emit(out, "var @1 = @2;", lmapper.setI(2), smapper.popI()); break; case opc_lstore_2: - emit(out, "@1 = @2;", lmapper.setL(2), smapper.popL()); + emit(out, "var @1 = @2;", lmapper.setL(2), smapper.popL()); break; case opc_fstore_2: - emit(out, "@1 = @2;", lmapper.setF(2), smapper.popF()); + emit(out, "var @1 = @2;", lmapper.setF(2), smapper.popF()); break; case opc_dstore_2: - emit(out, "@1 = @2;", lmapper.setD(2), smapper.popD()); + emit(out, "var @1 = @2;", lmapper.setD(2), smapper.popD()); break; case opc_astore_3: - emit(out, "@1 = @2;", lmapper.setA(3), smapper.popA()); + emit(out, "var @1 = @2;", lmapper.setA(3), smapper.popA()); break; case opc_istore_3: - emit(out, "@1 = @2;", lmapper.setI(3), smapper.popI()); + emit(out, "var @1 = @2;", lmapper.setI(3), smapper.popI()); break; case opc_lstore_3: - emit(out, "@1 = @2;", lmapper.setL(3), smapper.popL()); + emit(out, "var @1 = @2;", lmapper.setL(3), smapper.popL()); break; case opc_fstore_3: - emit(out, "@1 = @2;", lmapper.setF(3), smapper.popF()); + emit(out, "var @1 = @2;", lmapper.setF(3), smapper.popF()); break; case opc_dstore_3: - emit(out, "@1 = @2;", lmapper.setD(3), smapper.popD()); + emit(out, "var @1 = @2;", lmapper.setD(3), smapper.popD()); break; case opc_iadd: emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI()); @@ -635,105 +618,105 @@ emit(out, "return @1;", smapper.popA()); break; case opc_i2l: - emit(out, "@2 = @1;", smapper.popI(), smapper.pushL()); + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushL()); break; case opc_i2f: - emit(out, "@2 = @1;", smapper.popI(), smapper.pushF()); + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushF()); break; case opc_i2d: - emit(out, "@2 = @1;", smapper.popI(), smapper.pushD()); + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD()); break; case opc_l2i: - emit(out, "@2 = @1;", smapper.popL(), smapper.pushI()); + emit(out, "var @2 = @1;", smapper.popL(), smapper.pushI()); break; // max int check? case opc_l2f: - emit(out, "@2 = @1;", smapper.popL(), smapper.pushF()); + emit(out, "var @2 = @1;", smapper.popL(), smapper.pushF()); break; case opc_l2d: - emit(out, "@2 = @1;", smapper.popL(), smapper.pushD()); + emit(out, "var @2 = @1;", smapper.popL(), smapper.pushD()); break; case opc_f2d: - emit(out, "@2 = @1;", smapper.popF(), smapper.pushD()); + emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD()); break; case opc_d2f: - emit(out, "@2 = @1;", smapper.popD(), smapper.pushF()); + emit(out, "var @2 = @1;", smapper.popD(), smapper.pushF()); break; case opc_f2i: - emit(out, "@2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1);", smapper.popF(), smapper.pushI()); break; case opc_f2l: - emit(out, "@2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1);", smapper.popF(), smapper.pushL()); break; case opc_d2i: - emit(out, "@2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1);", smapper.popD(), smapper.pushI()); break; case opc_d2l: - emit(out, "@2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1);", smapper.popD(), smapper.pushL()); break; case opc_i2b: - emit(out, "@1 = @1.toInt8();", smapper.getI(0)); + emit(out, "var @1 = @1.toInt8();", smapper.getI(0)); break; case opc_i2c: out.append("{ /* number conversion */ }"); break; case opc_i2s: - emit(out, "@1 = @1.toInt16();", smapper.getI(0)); + emit(out, "var @1 = @1.toInt16();", smapper.getI(0)); break; case opc_aconst_null: - emit(out, "@1 = null;", smapper.pushA()); + emit(out, "var @1 = null;", smapper.pushA()); break; case opc_iconst_m1: - emit(out, "@1 = -1;", smapper.pushI()); + emit(out, "var @1 = -1;", smapper.pushI()); break; case opc_iconst_0: - emit(out, "@1 = 0;", smapper.pushI()); + emit(out, "var @1 = 0;", smapper.pushI()); break; case opc_dconst_0: - emit(out, "@1 = 0;", smapper.pushD()); + emit(out, "var @1 = 0;", smapper.pushD()); break; case opc_lconst_0: - emit(out, "@1 = 0;", smapper.pushL()); + emit(out, "var @1 = 0;", smapper.pushL()); break; case opc_fconst_0: - emit(out, "@1 = 0;", smapper.pushF()); + emit(out, "var @1 = 0;", smapper.pushF()); break; case opc_iconst_1: - emit(out, "@1 = 1;", smapper.pushI()); + emit(out, "var @1 = 1;", smapper.pushI()); break; case opc_lconst_1: - emit(out, "@1 = 1;", smapper.pushL()); + emit(out, "var @1 = 1;", smapper.pushL()); break; case opc_fconst_1: - emit(out, "@1 = 1;", smapper.pushF()); + emit(out, "var @1 = 1;", smapper.pushF()); break; case opc_dconst_1: - emit(out, "@1 = 1;", smapper.pushD()); + emit(out, "var @1 = 1;", smapper.pushD()); break; case opc_iconst_2: - emit(out, "@1 = 2;", smapper.pushI()); + emit(out, "var @1 = 2;", smapper.pushI()); break; case opc_fconst_2: - emit(out, "@1 = 2;", smapper.pushF()); + emit(out, "var @1 = 2;", smapper.pushF()); break; case opc_iconst_3: - emit(out, "@1 = 3;", smapper.pushI()); + emit(out, "var @1 = 3;", smapper.pushI()); break; case opc_iconst_4: - emit(out, "@1 = 4;", smapper.pushI()); + emit(out, "var @1 = 4;", smapper.pushI()); break; case opc_iconst_5: - emit(out, "@1 = 5;", smapper.pushI()); + emit(out, "var @1 = 5;", smapper.pushI()); break; case opc_ldc: { int indx = readByte(byteCodes, ++i); String v = encodeConstant(indx); int type = VarType.fromConstantType(jc.getTag(indx)); - emit(out, "@1 = @2;", smapper.pushT(type), v); + emit(out, "var @1 = @2;", smapper.pushT(type), v); break; } case opc_ldc_w: @@ -742,21 +725,21 @@ i += 2; String v = encodeConstant(indx); int type = VarType.fromConstantType(jc.getTag(indx)); - emit(out, "@1 = @2;", smapper.pushT(type), v); + emit(out, "var @1 = @2;", smapper.pushT(type), v); break; } case opc_lcmp: - emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popL(), smapper.popL(), smapper.pushI()); break; case opc_fcmpl: case opc_fcmpg: - emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popF(), smapper.popF(), smapper.pushI()); break; case opc_dcmpl: case opc_dcmpg: - emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", smapper.popD(), smapper.popD(), smapper.pushI()); break; case opc_if_acmpeq: @@ -906,7 +889,7 @@ case opc_new: { int indx = readIntArg(byteCodes, i); String ci = jc.getClassName(indx); - emit(out, "@1 = new @2;", + emit(out, "var @1 = new @2;", smapper.pushA(), accessClass(ci.replace('/', '_'))); addReference(ci); i += 2; @@ -926,7 +909,7 @@ case 11: jvmType = "[J"; break; default: throw new IllegalStateException("Array type: " + atype); } - emit(out, "@2 = new Array(@1).initWith('@3', 0);", + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);", smapper.popI(), smapper.pushA(), jvmType); break; case opc_anewarray: { @@ -938,7 +921,7 @@ } else { typeName = "[L" + typeName + ";"; } - emit(out, "@2 = new Array(@1).initWith('@3', null);", + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);", smapper.popI(), smapper.pushA(), typeName); break; } @@ -947,30 +930,22 @@ i += 2; String typeName = jc.getClassName(type); int dim = readByte(byteCodes, ++i); - out.append("{ var a0 = new Array(").append(smapper.popI()) - .append(").initWith('").append(typeName).append("', null);"); - for (int d = 1; d < dim; d++) { - typeName = typeName.substring(1); - out.append("\n var l" + d).append(" = ") - .append(smapper.popI()).append(';'); - out.append("\n for (var i" + d).append (" = 0; i" + d). - append(" < a" + (d - 1)). - append(".length; i" + d).append("++) {"); - out.append("\n var a" + d). - append (" = new Array(l" + d).append(").initWith('") - .append(typeName).append("', ") - .append(typeName.length() == 2 ? "0" : "null").append(");"); - out.append("\n a" + (d - 1)).append("[i" + d).append("] = a" + d). - append(";"); + StringBuilder dims = new StringBuilder(); + dims.append('['); + for (int d = 0; d < dim; d++) { + if (d != 0) { + dims.append(","); + } + dims.append(smapper.popI()); } - for (int d = 1; d < dim; d++) { - out.append("\n }"); - } - out.append("\n").append(smapper.pushA()).append(" = a0; }"); + 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); break; } case opc_arraylength: - emit(out, "@2 = @1.length;", smapper.popA(), smapper.pushI()); + emit(out, "var @2 = @1.length;", + smapper.popA(), smapper.pushI()); break; case opc_lastore: emit(out, "@3.at(@2, @1);", @@ -996,26 +971,26 @@ smapper.popI(), smapper.popI(), smapper.popA()); break; case opc_laload: - emit(out, "@3 = @2.at(@1);", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushL()); break; case opc_faload: - emit(out, "@3 = @2.at(@1);", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushF()); break; case opc_daload: - emit(out, "@3 = @2.at(@1);", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushD()); break; case opc_aaload: - emit(out, "@3 = @2.at(@1);", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushA()); break; case opc_iaload: case opc_baload: case opc_caload: case opc_saload: - emit(out, "@3 = @2.at(@1);", + emit(out, "var @3 = @2.at(@1);", smapper.popI(), smapper.popA(), smapper.pushI()); break; case opc_pop: @@ -1025,17 +1000,18 @@ break; case opc_dup: { final Variable v = smapper.get(0); - emit(out, "@1 = @2;", smapper.pushT(v.getType()), v); + emit(out, "var @1 = @2;", smapper.pushT(v.getType()), v); break; } case opc_dup2: { if (smapper.get(0).isCategory2()) { final Variable v = smapper.get(0); - emit(out, "@1 = @2;", smapper.pushT(v.getType()), v); + emit(out, "var @1 = @2;", + smapper.pushT(v.getType()), v); } else { final Variable v1 = smapper.get(0); final Variable v2 = smapper.get(1); - emit(out, "{ @1 = @2; @3 = @4; }", + emit(out, "var @1 = @2, @3 = @4;", smapper.pushT(v2.getType()), v2, smapper.pushT(v1.getType()), v1); } @@ -1048,7 +1024,7 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "{ @1 = @2; @3 = @4; @5 = @6; }", + emit(out, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); break; } @@ -1060,7 +1036,7 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "{ @1 = @2; @3 = @4; @5 = @6; }", + emit(out, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); } else { final Variable vi1 = smapper.pop(); @@ -1071,17 +1047,17 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "{ @1 = @2; @3 = @4; @5 = @6; @7 = @8; }", + emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1); } break; } case opc_bipush: - emit(out, "@1 = @2;", + emit(out, "var @1 = @2;", smapper.pushI(), Integer.toString(byteCodes[++i])); break; case opc_sipush: - emit(out, "@1 = @2;", + emit(out, "var @1 = @2;", smapper.pushI(), Integer.toString(readIntArg(byteCodes, i))); i += 2; @@ -1090,7 +1066,7 @@ int indx = readIntArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "@2 = @1.fld_@3;", + emit(out, "var @2 = @1.fld_@3;", smapper.popA(), smapper.pushT(type), fi[1]); i += 2; break; @@ -1099,7 +1075,7 @@ int indx = readIntArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "@1 = @2(false).constructor.@3;", + emit(out, "var @1 = @2(false).constructor.@3;", smapper.pushT(type), accessClass(fi[0].replace('/', '_')), fi[1]); i += 2; @@ -1142,7 +1118,7 @@ case opc_instanceof: { int indx = readIntArg(byteCodes, i); final String type = jc.getClassName(indx); - emit(out, "@2 = @1.$instOf_@3 ? 1 : 0;", + emit(out, "var @2 = @1.$instOf_@3 ? 1 : 0;", smapper.popA(), smapper.pushI(), type.replace('/', '_')); i += 2; @@ -1152,7 +1128,7 @@ final Variable v = smapper.popA(); smapper.clear(); - emit(out, "{ @1 = @2; throw @2; }", + emit(out, "{ var @1 = @2; throw @2; }", smapper.pushA(), v); break; } @@ -1352,7 +1328,8 @@ } if (returnType[0] != 'V') { - out.append(mapper.pushT(VarType.fromFieldType(returnType[0]))) + out.append("var ") + .append(mapper.pushT(VarType.fromFieldType(returnType[0]))) .append(" = "); } @@ -1396,7 +1373,8 @@ } if (returnType[0] != 'V') { - out.append(mapper.pushT(VarType.fromFieldType(returnType[0]))) + out.append("var ") + .append(mapper.pushT(VarType.fromFieldType(returnType[0]))) .append(" = "); } @@ -1628,15 +1606,15 @@ addReference(classInternalName); if ("java/lang/Throwable".equals(classInternalName)) { out.append("if (e.$instOf_java_lang_Throwable) {"); - out.append(" stA0 = e;"); + out.append(" var stA0 = e;"); out.append("} else {"); - out.append(" stA0 = vm.java_lang_Throwable(true);"); + 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 + "; stA0 = e; continue;"); + out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;"); out.append("}\n"); } } else { @@ -1646,7 +1624,7 @@ if (finallyPC == -1) { out.append("throw e;"); } else { - out.append("gt=" + finallyPC + "; stA0 = e; continue;"); + out.append("gt=" + finallyPC + "; var stA0 = e; continue;"); } out.append("\n}"); } diff -r 7400dc9f48fb -r 1adce93fea0f vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Tue Jan 22 19:48:10 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Wed Jan 23 12:53:23 2013 +0100 @@ -19,6 +19,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import org.apidesign.bck2brwsr.core.JavaScriptBody; /** @@ -131,7 +132,17 @@ } @Override - protected void requireScript(String resourcePath) { + protected void requireScript(String resourcePath) throws IOException { + InputStream is = getClass().getResourceAsStream(resourcePath); + StringBuilder sb = new StringBuilder(); + for (;;) { + int ch = is.read(); + if (ch == -1) { + break; + } + sb.append((char)ch); + } + applyCode(lazy.loader, null, sb.toString(), false); } @Override diff -r 7400dc9f48fb -r 1adce93fea0f vm/src/test/java/org/apidesign/vm4brwsr/Script.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Script.java Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,31 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr; + +import org.apidesign.bck2brwsr.core.ExtraJavaScript; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** Test to verify external scripts are processed in lazy mode. + * + * @author Jaroslav Tulach + */ +@ExtraJavaScript(resource = "/org/apidesign/vm4brwsr/ko.js") +public class Script { + @JavaScriptBody(args = { }, body = "return ko !== null;") + public static native boolean checkNotNull(); +} diff -r 7400dc9f48fb -r 1adce93fea0f vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Tue Jan 22 19:48:10 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -45,7 +45,9 @@ sb.append("\n return c[method]();"); sb.append("\n}"); - + sb.append("\nfunction checkKO() {"); + sb.append("\n return ko !== null;"); + sb.append("\n}"); ScriptEngine[] arr = { null }; code = StaticMethodTest.compileClass(sb, arr, @@ -67,6 +69,15 @@ ); } + @Test public void loadClassWithAssociatedScript() throws Exception { + assertExec("ko is defined", "test", true, + Script.class.getName(), "checkNotNull__Z" + ); + + Object res = code.invokeFunction("checkKO"); + assertEquals(res, true, "KO is defined on a global level"); + } + private static void assertExec(String msg, String methodName, Object expRes, Object... args) throws Exception { Object ret = null; try { diff -r 7400dc9f48fb -r 1adce93fea0f vm/src/test/resources/org/apidesign/vm4brwsr/ko.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/resources/org/apidesign/vm4brwsr/ko.js Wed Jan 23 12:53:23 2013 +0100 @@ -0,0 +1,20 @@ +/* + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +this.ko = {}; + + diff -r 7400dc9f48fb -r 1adce93fea0f vmtest/pom.xml --- a/vmtest/pom.xml Tue Jan 22 19:48:10 2013 +0100 +++ b/vmtest/pom.xml Wed Jan 23 12:53:23 2013 +0100 @@ -44,13 +44,14 @@ ${project.groupId} vm4brwsr - 0.3-SNAPSHOT + ${project.version} jar ${project.groupId} emul - 0.3-SNAPSHOT + ${project.version} + test ${project.groupId} diff -r 7400dc9f48fb -r 1adce93fea0f vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/BrwsrTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/BrwsrTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.vmtest; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** Annotation to indicate that given method should be executed + * in a browser environment. Has to be used in conjunction with {@link VMTest#create(java.lang.Class)} + * factory method. + *

+ * 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. + * + * @author Jaroslav Tulach + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface BrwsrTest { +} diff -r 7400dc9f48fb -r 1adce93fea0f vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Compare.java --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Compare.java Tue Jan 22 19:48:10 2013 +0100 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Compare.java Wed Jan 23 12:53:23 2013 +0100 @@ -24,7 +24,7 @@ /** Can be applied on a method that yields a return value. * Together with {@link VMTest#create} it can be used to write - * methods which are executed in real as well as JavaScript VMs and + * methods which are executed in real VM as well as JavaScript VMs and * their results are compared. * * @author Jaroslav Tulach @@ -32,5 +32,14 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Compare { - + /** Specifies whether the system should internal JavaScript interpreter + * as available via {@link javax.script.ScriptEngine}. Defaults to true, + * but in some situations (benchmarking comes to my mind), one may set this + * to false. In such case only browsers provided via + * vmtest.brwsrs property are used. For example + * "vmtest.brwsrs=firefox,google-chrome" would run the test + * in HotSpot VM, firefox and chrome and would compare the results. + * @return + */ + boolean scripting() default true; } diff -r 7400dc9f48fb -r 1adce93fea0f vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/HtmlFragment.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/HtmlFragment.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.vmtest; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** Allows to specify an HTML fragment for a given {@link BrwsrTest}. + * Apply either to the method or to enclosing class. The fragment will be + * made available in the page that executes given test. Its elements shall + * be regularly accessible from the test. + * + * @author Jaroslav Tulach + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE}) +public @interface HtmlFragment { + /** HTML code fragment to be exposed on the testing page. + */ + String value(); +} diff -r 7400dc9f48fb -r 1adce93fea0f vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Tue Jan 22 19:48:10 2013 +0100 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Wed Jan 23 12:53:23 2013 +0100 @@ -20,6 +20,7 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; @@ -37,21 +38,56 @@ private final Method m; private final Launcher l; private final String type; + private final boolean fail; Object value; - private static final Map compiled = new WeakHashMap<>(); - private Object inst; + private final String html; - Bck2BrwsrCase(Method m, String type, Launcher l) { + Bck2BrwsrCase(Method m, String type, Launcher l, boolean fail, String html) { this.l = l; this.m = m; this.type = type; + this.fail = fail; + this.html = html; } @Test(groups = "run") public void executeCode() throws Throwable { if (l != null) { - MethodInvocation c = l.invokeMethod(m.getDeclaringClass(), m.getName()); - value = c.toString(); + MethodInvocation c = l.invokeMethod(m.getDeclaringClass(), m.getName(), html); + String res = c.toString(); + value = res; + if (fail) { + int idx = res.indexOf(':'); + if (idx >= 0) { + Class thrwbl = null; + try { + Class exCls = Class.forName(res.substring(0, idx)); + if (Throwable.class.isAssignableFrom(exCls)) { + thrwbl = exCls.asSubclass(Throwable.class); + } + } catch (Exception ex) { + // ignore + } + if (thrwbl != null) { + Throwable t = null; + try { + for (Constructor cnstr : thrwbl.getConstructors()) { + if (cnstr.getParameterTypes().length == 1 && cnstr.getParameterTypes()[0].isAssignableFrom(String.class)) { + t = (Throwable) cnstr.newInstance(res.substring(idx + 1)); + break; + } + } + } catch (Throwable ex) { + t = thrwbl.newInstance().initCause(ex); + } + if (t == null) { + t = thrwbl.newInstance().initCause(new Exception(res.substring(idx))); + } + throw t; + } + throw new AssertionError(res); + } + } } else { try { value = m.invoke(m.getDeclaringClass().newInstance()); diff -r 7400dc9f48fb -r 1adce93fea0f vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Tue Jan 22 19:48:10 2013 +0100 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Wed Jan 23 12:53:23 2013 +0100 @@ -18,9 +18,6 @@ package org.apidesign.bck2brwsr.vmtest.impl; import org.apidesign.bck2brwsr.vmtest.*; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -74,23 +71,8 @@ } for (Method m : arr) { - Compare c = m.getAnnotation(Compare.class); - if (c == null) { - continue; - } - final Bck2BrwsrCase real = new Bck2BrwsrCase(m, "Java", null); - final Bck2BrwsrCase js = new Bck2BrwsrCase(m, "JavaScript", l.javaScript()); - ret.add(real); - ret.add(js); - ret.add(new CompareCase(m, real, js)); - - for (String b : brwsr) { - final Launcher s = l.brwsr(b); - ret.add(s); - final Bck2BrwsrCase cse = new Bck2BrwsrCase(m, b, s); - ret.add(cse); - ret.add(new CompareCase(m, real, cse)); - } + registerCompareCases(m, l, ret, brwsr); + registerBrwsrCases(m, l, ret, brwsr); } return ret.toArray(); } @@ -123,4 +105,47 @@ public String getTestName() { return m.getName() + "[Compare " + second.typeName() + "]"; } + + private static void registerCompareCases(Method m, final LaunchSetup l, List ret, String[] brwsr) { + Compare c = m.getAnnotation(Compare.class); + if (c == null) { + return; + } + final Bck2BrwsrCase real = new Bck2BrwsrCase(m, "Java", null, false, null); + ret.add(real); + if (c.scripting()) { + final Bck2BrwsrCase js = new Bck2BrwsrCase(m, "JavaScript", l.javaScript(), false, null); + ret.add(js); + ret.add(new CompareCase(m, real, js)); + } + for (String b : brwsr) { + final Launcher s = l.brwsr(b); + ret.add(s); + final Bck2BrwsrCase cse = new Bck2BrwsrCase(m, b, s, false, null); + ret.add(cse); + ret.add(new CompareCase(m, real, cse)); + } + } + private static void registerBrwsrCases(Method m, final LaunchSetup l, List ret, String[] brwsr) { + BrwsrTest c = m.getAnnotation(BrwsrTest.class); + if (c == null) { + return; + } + HtmlFragment f = m.getAnnotation(HtmlFragment.class); + if (f == null) { + f = m.getDeclaringClass().getAnnotation(HtmlFragment.class); + } + String html = f == null ? null : f.value(); + if (brwsr.length == 0) { + final Launcher s = l.brwsr(null); + ret.add(s); + ret.add(new Bck2BrwsrCase(m, "Brwsr", s, true, html)); + } else { + for (String b : brwsr) { + final Launcher s = l.brwsr(b); + ret.add(s); + ret.add(new Bck2BrwsrCase(m, b, s, true, html)); + } + } + } } diff -r 7400dc9f48fb -r 1adce93fea0f vmtest/src/test/java/org/apidesign/bck2brwsr/tck/AssertionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/AssertionTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -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; + +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 { + assert false : "Is assertion status on?"; + return null; + } + + @Factory + public static Object[] create() { + return VMTest.create(AssertionTest.class); + } +} diff -r 7400dc9f48fb -r 1adce93fea0f vmtest/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -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 7400dc9f48fb -r 1adce93fea0f vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Tue Jan 22 19:48:10 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -42,6 +42,10 @@ return String.class.cast(o); } + @Compare public boolean equalToNull() { + return "Ahoj".equals(null); + } + @Compare public static Object compareURLs() throws MalformedURLException { return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString(); } diff -r 7400dc9f48fb -r 1adce93fea0f vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java Wed Jan 23 12:53:23 2013 +0100 @@ -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.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); + } +}