1.1 --- a/launcher/fx/pom.xml Sat Jun 08 12:09:10 2013 +0200
1.2 +++ b/launcher/fx/pom.xml Mon Jun 10 18:12:38 2013 +0200
1.3 @@ -64,5 +64,16 @@
1.4 <artifactId>org-netbeans-bootstrap</artifactId>
1.5 <version>RELEASE73</version>
1.6 </dependency>
1.7 + <dependency>
1.8 + <groupId>${project.groupId}</groupId>
1.9 + <artifactId>core</artifactId>
1.10 + <version>${project.version}</version>
1.11 + <scope>test</scope>
1.12 + </dependency>
1.13 + <dependency>
1.14 + <groupId>org.ow2.asm</groupId>
1.15 + <artifactId>asm</artifactId>
1.16 + <version>4.1</version>
1.17 + </dependency>
1.18 </dependencies>
1.19 </project>
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader.java Mon Jun 10 18:12:38 2013 +0200
2.3 @@ -0,0 +1,228 @@
2.4 +/**
2.5 + * Back 2 Browser Bytecode Translator
2.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
2.7 + *
2.8 + * This program is free software: you can redistribute it and/or modify
2.9 + * it under the terms of the GNU General Public License as published by
2.10 + * the Free Software Foundation, version 2 of the License.
2.11 + *
2.12 + * This program is distributed in the hope that it will be useful,
2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.15 + * GNU General Public License for more details.
2.16 + *
2.17 + * You should have received a copy of the GNU General Public License
2.18 + * along with this program. Look for COPYING file in the top folder.
2.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
2.20 + */
2.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
2.22 +
2.23 +import java.io.IOException;
2.24 +import java.io.InputStream;
2.25 +import java.net.URL;
2.26 +import java.net.URLClassLoader;
2.27 +import java.util.ArrayList;
2.28 +import java.util.Arrays;
2.29 +import java.util.List;
2.30 +import org.objectweb.asm.AnnotationVisitor;
2.31 +import org.objectweb.asm.ClassReader;
2.32 +import org.objectweb.asm.ClassVisitor;
2.33 +import org.objectweb.asm.ClassWriter;
2.34 +import org.objectweb.asm.Label;
2.35 +import org.objectweb.asm.MethodVisitor;
2.36 +import org.objectweb.asm.Opcodes;
2.37 +import org.objectweb.asm.Type;
2.38 +
2.39 +/**
2.40 + *
2.41 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
2.42 + */
2.43 +public abstract class JsClassLoader extends URLClassLoader {
2.44 + JsClassLoader(URL[] urls, ClassLoader parent) {
2.45 + super(urls, parent);
2.46 + }
2.47 +
2.48 + @Override
2.49 + protected Class<?> findClass(String name) throws ClassNotFoundException {
2.50 + URL u = findResource(name.replace('.', '/') + ".class");
2.51 + if (u != null) {
2.52 + InputStream is = null;
2.53 + try {
2.54 + is = u.openStream();
2.55 + ClassReader cr = new ClassReader(is);
2.56 + ClassWriter w = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
2.57 + FindInClass fic = new FindInClass(w);
2.58 + cr.accept(fic, 0);
2.59 + byte[] arr = w.toByteArray();
2.60 + return defineClass(name, arr, 0, arr.length);
2.61 + } catch (IOException ex) {
2.62 + throw new ClassNotFoundException("Can't load " + name, ex);
2.63 + } finally {
2.64 + try {
2.65 + if (is != null) is.close();
2.66 + } catch (IOException ex) {
2.67 + throw new ClassNotFoundException(null, ex);
2.68 + }
2.69 + }
2.70 + }
2.71 + if (name.startsWith("org.apidesign.bck2brwsr.launcher.fximpl.JsClassLoader")) {
2.72 + return Class.forName(name);
2.73 + }
2.74 +
2.75 + return super.findClass(name);
2.76 + }
2.77 +
2.78 + public final Fn define(String code, String... names) {
2.79 + return defineFn(code, names);
2.80 + }
2.81 +
2.82 +
2.83 + protected abstract Fn defineFn(String code, String... names);
2.84 +
2.85 + public static abstract class Fn {
2.86 + public abstract Object invoke(Object... args) throws Exception;
2.87 + }
2.88 +
2.89 +
2.90 + private static final class FindInClass extends ClassVisitor {
2.91 + private String name;
2.92 +
2.93 + public FindInClass(ClassVisitor cv) {
2.94 + super(Opcodes.ASM4, cv);
2.95 + }
2.96 +
2.97 + @Override
2.98 + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
2.99 + this.name = name;
2.100 + super.visit(version, access, name, signature, superName, interfaces);
2.101 + }
2.102 +
2.103 +
2.104 +
2.105 + @Override
2.106 + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
2.107 + return new FindInMethod(name,
2.108 + super.visitMethod(access, name, desc, signature, exceptions)
2.109 + );
2.110 + }
2.111 +
2.112 + private final class FindInMethod extends MethodVisitor {
2.113 + private final String name;
2.114 + private List<String> args;
2.115 + private String body;
2.116 +
2.117 + public FindInMethod(String name, MethodVisitor mv) {
2.118 + super(Opcodes.ASM4, mv);
2.119 + this.name = name;
2.120 + }
2.121 +
2.122 + @Override
2.123 + public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
2.124 + if ("Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc)) { // NOI18N
2.125 + return new FindInAnno();
2.126 + }
2.127 + return super.visitAnnotation(desc, visible);
2.128 + }
2.129 +
2.130 + private void generateJSBody(List<String> args, String body) {
2.131 + this.args = args;
2.132 + this.body = body;
2.133 + }
2.134 +
2.135 + @Override
2.136 + public void visitCode() {
2.137 + if (body == null) {
2.138 + return;
2.139 + }
2.140 +
2.141 + super.visitFieldInsn(
2.142 + Opcodes.GETSTATIC, FindInClass.this.name,
2.143 + "$$bck2brwsr$$" + name,
2.144 + "Lorg/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader$Fn;"
2.145 + );
2.146 + super.visitInsn(Opcodes.DUP);
2.147 + Label ifNotNull = new Label();
2.148 + super.visitJumpInsn(Opcodes.IFNONNULL, ifNotNull);
2.149 +
2.150 + // init Fn
2.151 + super.visitInsn(Opcodes.POP);
2.152 + super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
2.153 + super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
2.154 + "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;"
2.155 + );
2.156 + super.visitTypeInsn(Opcodes.CHECKCAST, "org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader");
2.157 + super.visitLdcInsn(body);
2.158 + super.visitIntInsn(Opcodes.SIPUSH, args.size());
2.159 + super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
2.160 + for (int i = 0; i < args.size(); i++) {
2.161 + String name = args.get(i);
2.162 + super.visitInsn(Opcodes.DUP);
2.163 + super.visitIntInsn(Opcodes.BIPUSH, i);
2.164 + super.visitLdcInsn(name);
2.165 + super.visitInsn(Opcodes.AASTORE);
2.166 + }
2.167 + super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
2.168 + "org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader",
2.169 + "define", "(Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader$Fn;"
2.170 + );
2.171 + // end of Fn init
2.172 +
2.173 + super.visitLabel(ifNotNull);
2.174 + super.visitIntInsn(Opcodes.SIPUSH, args.size());
2.175 + super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
2.176 + super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
2.177 + "org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader$Fn", "invoke", "([Ljava/lang/Object;)Ljava/lang/Object;"
2.178 + );
2.179 + super.visitInsn(Opcodes.ARETURN);
2.180 + }
2.181 +
2.182 + @Override
2.183 + public void visitEnd() {
2.184 + super.visitEnd();
2.185 + if (body != null) {
2.186 + FindInClass.this.visitField(
2.187 + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
2.188 + "$$bck2brwsr$$" + name,
2.189 + "Lorg/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader$Fn;",
2.190 + null, null
2.191 + );
2.192 + }
2.193 + }
2.194 +
2.195 +
2.196 +
2.197 +
2.198 +
2.199 + private final class FindInAnno extends AnnotationVisitor {
2.200 + private List<String> args = new ArrayList<String>();
2.201 + private String body;
2.202 +
2.203 + public FindInAnno() {
2.204 + super(Opcodes.ASM4);
2.205 + }
2.206 +
2.207 + @Override
2.208 + public void visit(String name, Object value) {
2.209 + if (name == null) {
2.210 + args.add((String) value);
2.211 + return;
2.212 + }
2.213 + assert name.equals("body");
2.214 + body = (String) value;
2.215 + }
2.216 +
2.217 + @Override
2.218 + public AnnotationVisitor visitArray(String name) {
2.219 + return this;
2.220 + }
2.221 +
2.222 + @Override
2.223 + public void visitEnd() {
2.224 + if (body != null) {
2.225 + generateJSBody(args, body);
2.226 + }
2.227 + }
2.228 + }
2.229 + }
2.230 + }
2.231 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoaderTest.java Mon Jun 10 18:12:38 2013 +0200
3.3 @@ -0,0 +1,106 @@
3.4 +/**
3.5 + * Back 2 Browser Bytecode Translator
3.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
3.7 + *
3.8 + * This program is free software: you can redistribute it and/or modify
3.9 + * it under the terms of the GNU General Public License as published by
3.10 + * the Free Software Foundation, version 2 of the License.
3.11 + *
3.12 + * This program is distributed in the hope that it will be useful,
3.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.15 + * GNU General Public License for more details.
3.16 + *
3.17 + * You should have received a copy of the GNU General Public License
3.18 + * along with this program. Look for COPYING file in the top folder.
3.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
3.20 + */
3.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
3.22 +
3.23 +import java.lang.reflect.InvocationTargetException;
3.24 +import java.lang.reflect.Method;
3.25 +import java.net.URL;
3.26 +import javax.script.Invocable;
3.27 +import javax.script.ScriptEngine;
3.28 +import javax.script.ScriptEngineManager;
3.29 +import javax.script.ScriptException;
3.30 +import static org.testng.Assert.*;
3.31 +import org.testng.annotations.BeforeClass;
3.32 +import org.testng.annotations.Test;
3.33 +
3.34 +/**
3.35 + *
3.36 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
3.37 + */
3.38 +public class JsClassLoaderTest {
3.39 + private static ClassLoader loader;
3.40 + private static Class<?> methodClass;
3.41 +
3.42 + public JsClassLoaderTest() {
3.43 + }
3.44 +
3.45 + @BeforeClass
3.46 + public static void setUpClass() throws Exception {
3.47 + ScriptEngineManager sem = new ScriptEngineManager();
3.48 + final ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
3.49 +
3.50 + URL my = JsClassLoaderTest.class.getProtectionDomain().getCodeSource().getLocation();
3.51 + ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent();
3.52 + loader = new JsClassLoader(new URL[] { my }, parent) {
3.53 + @Override
3.54 + protected JsClassLoader.Fn defineFn(String code, String... names) {
3.55 + StringBuilder sb = new StringBuilder();
3.56 + sb.append("(function() {");
3.57 + sb.append("var r = {};");
3.58 + sb.append("r.fn = function(");
3.59 + String sep = "";
3.60 + for (String n : names) {
3.61 + sb.append(sep);
3.62 + sb.append(n);
3.63 + sep = ", ";
3.64 + }
3.65 + sb.append(") {");
3.66 + sb.append(code);
3.67 + sb.append("};");
3.68 + sb.append("return r;");
3.69 + sb.append("})()");
3.70 + try {
3.71 + final Object val = eng.eval(sb.toString());
3.72 + return new JsClassLoader.Fn() {
3.73 + @Override
3.74 + public Object invoke(Object... args) throws Exception {
3.75 + Invocable inv = (Invocable)eng;
3.76 + return inv.invokeMethod(val, "fn", args);
3.77 + }
3.78 + };
3.79 + } catch (ScriptException ex) {
3.80 + throw new LinkageError("Can't parse: " + sb, ex);
3.81 + }
3.82 + }
3.83 + };
3.84 +
3.85 + methodClass = loader.loadClass(JsMethods.class.getName());
3.86 + }
3.87 +
3.88 + @Test public void noParamMethod() throws Throwable {
3.89 + Method plus = methodClass.getMethod("fortyTwo");
3.90 + try {
3.91 + final Object val = plus.invoke(null);
3.92 + assertTrue(val instanceof Number, "A number returned " + val);
3.93 + assertEquals(((Number)val).intValue(), 42);
3.94 + } catch (InvocationTargetException ex) {
3.95 + throw ex.getTargetException();
3.96 + }
3.97 + }
3.98 + /*
3.99 + @Test public void testExecuteScript() throws Throwable {
3.100 + Method plus = methodClass.getMethod("plus", int.class, int.class);
3.101 + try {
3.102 + assertEquals(plus.invoke(null, 10, 20), 30);
3.103 + } catch (InvocationTargetException ex) {
3.104 + throw ex.getTargetException();
3.105 + }
3.106 + }
3.107 + */
3.108 +
3.109 +}
3.110 \ No newline at end of file
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsMethods.java Mon Jun 10 18:12:38 2013 +0200
4.3 @@ -0,0 +1,38 @@
4.4 +/**
4.5 + * Back 2 Browser Bytecode Translator
4.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
4.7 + *
4.8 + * This program is free software: you can redistribute it and/or modify
4.9 + * it under the terms of the GNU General Public License as published by
4.10 + * the Free Software Foundation, version 2 of the License.
4.11 + *
4.12 + * This program is distributed in the hope that it will be useful,
4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.15 + * GNU General Public License for more details.
4.16 + *
4.17 + * You should have received a copy of the GNU General Public License
4.18 + * along with this program. Look for COPYING file in the top folder.
4.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
4.20 + */
4.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
4.22 +
4.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
4.24 +
4.25 +/**
4.26 + *
4.27 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
4.28 + */
4.29 +public class JsMethods {
4.30 + @JavaScriptBody(args = {}, body = "return 42;")
4.31 + public static Object fortyTwo() {
4.32 + return -42;
4.33 + }
4.34 +
4.35 +/*
4.36 + @JavaScriptBody(args = {"x", "y" }, body = "return x + y;")
4.37 + public static int plus(int x, int y) {
4.38 + return 0;
4.39 + }
4.40 + */
4.41 +}