1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/launcher/api/pom.xml Sun Apr 28 10:14:31 2013 +0200
1.3 @@ -0,0 +1,20 @@
1.4 +<?xml version="1.0"?>
1.5 +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
1.6 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1.7 + <modelVersion>4.0.0</modelVersion>
1.8 + <parent>
1.9 + <groupId>org.apidesign.bck2brwsr</groupId>
1.10 + <artifactId>launcher-pom</artifactId>
1.11 + <version>0.7-SNAPSHOT</version>
1.12 + </parent>
1.13 + <groupId>org.apidesign.bck2brwsr</groupId>
1.14 + <artifactId>launcher</artifactId>
1.15 + <version>0.7-SNAPSHOT</version>
1.16 + <name>Launcher API</name>
1.17 + <url>http://maven.apache.org</url>
1.18 + <properties>
1.19 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1.20 + </properties>
1.21 + <dependencies>
1.22 + </dependencies>
1.23 +</project>
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java Sun Apr 28 10:14:31 2013 +0200
2.3 @@ -0,0 +1,115 @@
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;
2.22 +
2.23 +import java.io.IOException;
2.24 +import java.io.InputStream;
2.25 +import java.util.ArrayList;
2.26 +import java.util.List;
2.27 +import java.util.concurrent.CountDownLatch;
2.28 +import java.util.concurrent.TimeUnit;
2.29 +
2.30 +/** Represents individual method invocation, its context and its result.
2.31 + *
2.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
2.33 + */
2.34 +public final class InvocationContext {
2.35 + final CountDownLatch wait = new CountDownLatch(1);
2.36 + final Class<?> clazz;
2.37 + final String methodName;
2.38 + private final Launcher launcher;
2.39 + private String result;
2.40 + private Throwable exception;
2.41 + String html;
2.42 + final List<Resource> resources = new ArrayList<>();
2.43 +
2.44 + InvocationContext(Launcher launcher, Class<?> clazz, String methodName) {
2.45 + this.launcher = launcher;
2.46 + this.clazz = clazz;
2.47 + this.methodName = methodName;
2.48 + }
2.49 +
2.50 + /** An HTML fragment to be available for the execution. Useful primarily when
2.51 + * executing in a browser via {@link Launcher#createBrowser(java.lang.String)}.
2.52 + * @param html the html fragment
2.53 + */
2.54 + public void setHtmlFragment(String html) {
2.55 + this.html = html;
2.56 + }
2.57 +
2.58 + /** HTTP resource to be available during execution. An invocation may
2.59 + * perform an HTTP query and obtain a resource relative to the page.
2.60 + */
2.61 + public void addHttpResource(String relativePath, String mimeType, String[] parameters, InputStream content) {
2.62 + if (relativePath == null || mimeType == null || content == null || parameters == null) {
2.63 + throw new NullPointerException();
2.64 + }
2.65 + resources.add(new Resource(content, mimeType, relativePath, parameters));
2.66 + }
2.67 +
2.68 + /** Invokes the associated method.
2.69 + * @return the textual result of the invocation
2.70 + */
2.71 + public String invoke() throws IOException {
2.72 + launcher.runMethod(this);
2.73 + return toString();
2.74 + }
2.75 +
2.76 + /** Obtains textual result of the invocation.
2.77 + * @return text representing the exception or result value
2.78 + */
2.79 + @Override
2.80 + public String toString() {
2.81 + if (exception != null) {
2.82 + return exception.toString();
2.83 + }
2.84 + return result;
2.85 + }
2.86 +
2.87 + /**
2.88 + * @param timeOut
2.89 + * @throws InterruptedException
2.90 + */
2.91 + void await(long timeOut) throws InterruptedException {
2.92 + wait.await(timeOut, TimeUnit.MILLISECONDS);
2.93 + }
2.94 +
2.95 + void result(String r, Throwable e) {
2.96 + this.result = r;
2.97 + this.exception = e;
2.98 + wait.countDown();
2.99 + }
2.100 +
2.101 +
2.102 + static final class Resource {
2.103 + final InputStream httpContent;
2.104 + final String httpType;
2.105 + final String httpPath;
2.106 + final String[] parameters;
2.107 +
2.108 + Resource(InputStream httpContent, String httpType, String httpPath,
2.109 + String[] parameters
2.110 + ) {
2.111 + httpContent.mark(Integer.MAX_VALUE);
2.112 + this.httpContent = httpContent;
2.113 + this.httpType = httpType;
2.114 + this.httpPath = httpPath;
2.115 + this.parameters = parameters;
2.116 + }
2.117 + }
2.118 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Sun Apr 28 10:14:31 2013 +0200
3.3 @@ -0,0 +1,139 @@
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;
3.22 +
3.23 +import java.io.Closeable;
3.24 +import java.io.File;
3.25 +import java.io.IOException;
3.26 +import java.lang.reflect.Constructor;
3.27 +
3.28 +/** An abstraction for executing tests in a Bck2Brwsr virtual machine.
3.29 + * Either in {@link Launcher#createJavaScript JavaScript engine},
3.30 + * or in {@link Launcher#createBrowser external browser}.
3.31 + * <p>
3.32 + * There also are methods to {@link #showDir(java.io.File, java.lang.String) display pages}
3.33 + * in an external browser served by internal HTTP server.
3.34 + *
3.35 + * @author Jaroslav Tulach <jtulach@netbeans.org>
3.36 + */
3.37 +public abstract class Launcher {
3.38 +
3.39 + Launcher() {
3.40 + }
3.41 +
3.42 + /** Initializes the launcher. This may mean starting a web browser or
3.43 + * initializing execution engine.
3.44 + * @throws IOException if something goes wrong
3.45 + */
3.46 + public abstract void initialize() throws IOException;
3.47 +
3.48 + /** Shuts down the launcher.
3.49 + * @throws IOException if something goes wrong
3.50 + */
3.51 + public abstract void shutdown() throws IOException;
3.52 +
3.53 +
3.54 + /** Builds an invocation context. The context can later be customized
3.55 + * and {@link InvocationContext#invoke() invoked}.
3.56 + *
3.57 + * @param clazz the class to execute method from
3.58 + * @param method the method to execute
3.59 + * @return the context pointing to the selected method
3.60 + */
3.61 + public InvocationContext createInvocation(Class<?> clazz, String method) {
3.62 + return new InvocationContext(this, clazz, method);
3.63 + }
3.64 +
3.65 +
3.66 + /** Creates launcher that uses internal JavaScript engine (Rhino).
3.67 + * @return the launcher
3.68 + */
3.69 + public static Launcher createJavaScript() {
3.70 + try {
3.71 + Class<?> c = loadClass("org.apidesign.bck2brwsr.launcher.JSLauncher");
3.72 + return (Launcher) c.newInstance();
3.73 + } catch (Exception ex) {
3.74 + throw new IllegalStateException("Please include org.apidesign.bck2brwsr:launcher.html dependency!", ex);
3.75 + }
3.76 + }
3.77 +
3.78 + /** Creates launcher that is using external browser.
3.79 + *
3.80 + * @param cmd <code>null</code> to use <code>java.awt.Desktop</code> to show the launcher
3.81 + * or a string to execute in an external process (with a parameter to the URL)
3.82 + * @return launcher executing in external browser.
3.83 + */
3.84 + public static Launcher createBrowser(String cmd) {
3.85 + try {
3.86 + Class<?> c = loadClass("org.apidesign.bck2brwsr.launcher.Bck2BrwsrLauncher");
3.87 + Constructor<?> cnstr = c.getConstructor(String.class);
3.88 + return (Launcher) cnstr.newInstance(cmd);
3.89 + } catch (Exception ex) {
3.90 + throw new IllegalStateException("Please include org.apidesign.bck2brwsr:launcher.html dependency!", ex);
3.91 + }
3.92 + }
3.93 +
3.94 + /** Starts an HTTP server which provides access to classes and resources
3.95 + * available in the <code>classes</code> URL and shows a start page
3.96 + * available as {@link ClassLoader#getResource(java.lang.String)} from the
3.97 + * provide classloader. Opens a browser with URL showing the start page.
3.98 + *
3.99 + * @param classes classloader offering access to classes and resources
3.100 + * @param startpage page to show in the browser
3.101 + * @return interface that allows one to stop the server
3.102 + * @throws IOException if something goes wrong
3.103 + */
3.104 + public static Closeable showURL(ClassLoader classes, String startpage) throws IOException {
3.105 + Launcher l = createBrowser(null);
3.106 + l.addClassLoader(classes);
3.107 + l.showURL(startpage);
3.108 + return (Closeable) l;
3.109 + }
3.110 + /** Starts an HTTP server which provides access to certain directory.
3.111 + * The <code>startpage</code> should be relative location inside the root
3.112 + * directory. Opens a browser with URL showing the start page.
3.113 + *
3.114 + * @param directory the root directory on disk
3.115 + * @param startpage relative path from the root to the page
3.116 + * @exception IOException if something goes wrong.
3.117 + */
3.118 + public static Closeable showDir(File directory, String startpage) throws IOException {
3.119 + Launcher l = createBrowser(null);
3.120 + l.showDirectory(directory, startpage);
3.121 + return (Closeable) l;
3.122 + }
3.123 +
3.124 + abstract InvocationContext runMethod(InvocationContext c) throws IOException;
3.125 +
3.126 +
3.127 + private static Class<?> loadClass(String cn) throws ClassNotFoundException {
3.128 + return Launcher.class.getClassLoader().loadClass(cn);
3.129 + }
3.130 +
3.131 + void showDirectory(File directory, String startpage) throws IOException {
3.132 + throw new UnsupportedOperationException();
3.133 + }
3.134 +
3.135 + void showURL(String startpage) throws IOException {
3.136 + throw new UnsupportedOperationException();
3.137 + }
3.138 +
3.139 + void addClassLoader(ClassLoader classes) {
3.140 + throw new UnsupportedOperationException();
3.141 + }
3.142 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/launcher/http/pom.xml Sun Apr 28 10:14:31 2013 +0200
4.3 @@ -0,0 +1,55 @@
4.4 +<?xml version="1.0"?>
4.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.6 + <modelVersion>4.0.0</modelVersion>
4.7 + <parent>
4.8 + <groupId>org.apidesign.bck2brwsr</groupId>
4.9 + <artifactId>rt</artifactId>
4.10 + <version>0.7-SNAPSHOT</version>
4.11 + </parent>
4.12 + <groupId>org.apidesign.bck2brwsr</groupId>
4.13 + <artifactId>launcher.http</artifactId>
4.14 + <version>0.7-SNAPSHOT</version>
4.15 + <name>Bck2Brwsr Launcher</name>
4.16 + <url>http://maven.apache.org</url>
4.17 + <build>
4.18 + <plugins>
4.19 + <plugin>
4.20 + <groupId>org.apache.maven.plugins</groupId>
4.21 + <artifactId>maven-compiler-plugin</artifactId>
4.22 + <version>2.3.2</version>
4.23 + <configuration>
4.24 + <source>1.7</source>
4.25 + <target>1.7</target>
4.26 + </configuration>
4.27 + </plugin>
4.28 + <plugin>
4.29 + <groupId>org.apache.maven.plugins</groupId>
4.30 + <artifactId>maven-javadoc-plugin</artifactId>
4.31 + <configuration>
4.32 + <excludePackageNames>org.apidesign.bck2brwsr.launcher.impl</excludePackageNames>
4.33 + <skip>false</skip>
4.34 + </configuration>
4.35 + </plugin>
4.36 + </plugins>
4.37 + </build>
4.38 + <properties>
4.39 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
4.40 + </properties>
4.41 + <dependencies>
4.42 + <dependency>
4.43 + <groupId>${project.groupId}</groupId>
4.44 + <artifactId>launcher</artifactId>
4.45 + <version>${project.version}</version>
4.46 + </dependency>
4.47 + <dependency>
4.48 + <groupId>org.glassfish.grizzly</groupId>
4.49 + <artifactId>grizzly-http-server</artifactId>
4.50 + <version>2.2.19</version>
4.51 + </dependency>
4.52 + <dependency>
4.53 + <groupId>${project.groupId}</groupId>
4.54 + <artifactId>vm4brwsr</artifactId>
4.55 + <version>${project.version}</version>
4.56 + </dependency>
4.57 + </dependencies>
4.58 +</project>
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Sun Apr 28 10:14:31 2013 +0200
5.3 @@ -0,0 +1,604 @@
5.4 +/**
5.5 + * Back 2 Browser Bytecode Translator
5.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5.7 + *
5.8 + * This program is free software: you can redistribute it and/or modify
5.9 + * it under the terms of the GNU General Public License as published by
5.10 + * the Free Software Foundation, version 2 of the License.
5.11 + *
5.12 + * This program is distributed in the hope that it will be useful,
5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.15 + * GNU General Public License for more details.
5.16 + *
5.17 + * You should have received a copy of the GNU General Public License
5.18 + * along with this program. Look for COPYING file in the top folder.
5.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
5.20 + */
5.21 +package org.apidesign.bck2brwsr.launcher;
5.22 +
5.23 +import java.io.Closeable;
5.24 +import java.io.File;
5.25 +import java.io.IOException;
5.26 +import java.io.InputStream;
5.27 +import java.io.InterruptedIOException;
5.28 +import java.io.OutputStream;
5.29 +import java.io.UnsupportedEncodingException;
5.30 +import java.io.Writer;
5.31 +import java.net.URI;
5.32 +import java.net.URISyntaxException;
5.33 +import java.net.URL;
5.34 +import java.util.ArrayList;
5.35 +import java.util.Arrays;
5.36 +import java.util.Enumeration;
5.37 +import java.util.LinkedHashSet;
5.38 +import java.util.List;
5.39 +import java.util.Set;
5.40 +import java.util.concurrent.BlockingQueue;
5.41 +import java.util.concurrent.CountDownLatch;
5.42 +import java.util.concurrent.LinkedBlockingQueue;
5.43 +import java.util.concurrent.TimeUnit;
5.44 +import java.util.logging.Level;
5.45 +import java.util.logging.Logger;
5.46 +import org.apidesign.bck2brwsr.launcher.InvocationContext.Resource;
5.47 +import org.apidesign.vm4brwsr.Bck2Brwsr;
5.48 +import org.glassfish.grizzly.PortRange;
5.49 +import org.glassfish.grizzly.http.server.HttpHandler;
5.50 +import org.glassfish.grizzly.http.server.HttpServer;
5.51 +import org.glassfish.grizzly.http.server.NetworkListener;
5.52 +import org.glassfish.grizzly.http.server.Request;
5.53 +import org.glassfish.grizzly.http.server.Response;
5.54 +import org.glassfish.grizzly.http.server.ServerConfiguration;
5.55 +import org.glassfish.grizzly.http.util.HttpStatus;
5.56 +
5.57 +/**
5.58 + * Lightweight server to launch Bck2Brwsr applications and tests.
5.59 + * Supports execution in native browser as well as Java's internal
5.60 + * execution engine.
5.61 + */
5.62 +final class Bck2BrwsrLauncher extends Launcher implements Closeable {
5.63 + private static final Logger LOG = Logger.getLogger(Bck2BrwsrLauncher.class.getName());
5.64 + private static final InvocationContext END = new InvocationContext(null, null, null);
5.65 + private final Set<ClassLoader> loaders = new LinkedHashSet<>();
5.66 + private final BlockingQueue<InvocationContext> methods = new LinkedBlockingQueue<>();
5.67 + private long timeOut;
5.68 + private final Res resources = new Res();
5.69 + private final String cmd;
5.70 + private Object[] brwsr;
5.71 + private HttpServer server;
5.72 + private CountDownLatch wait;
5.73 +
5.74 + public Bck2BrwsrLauncher(String cmd) {
5.75 + this.cmd = cmd;
5.76 + addClassLoader(Bck2Brwsr.class.getClassLoader());
5.77 + setTimeout(180000);
5.78 + }
5.79 +
5.80 + @Override
5.81 + InvocationContext runMethod(InvocationContext c) throws IOException {
5.82 + loaders.add(c.clazz.getClassLoader());
5.83 + methods.add(c);
5.84 + try {
5.85 + c.await(timeOut);
5.86 + } catch (InterruptedException ex) {
5.87 + throw new IOException(ex);
5.88 + }
5.89 + return c;
5.90 + }
5.91 +
5.92 + public void setTimeout(long ms) {
5.93 + timeOut = ms;
5.94 + }
5.95 +
5.96 + public void addClassLoader(ClassLoader url) {
5.97 + this.loaders.add(url);
5.98 + }
5.99 +
5.100 + public void showURL(String startpage) throws IOException {
5.101 + if (!startpage.startsWith("/")) {
5.102 + startpage = "/" + startpage;
5.103 + }
5.104 + HttpServer s = initServer(".", true);
5.105 + int last = startpage.lastIndexOf('/');
5.106 + String prefix = startpage.substring(0, last);
5.107 + String simpleName = startpage.substring(last);
5.108 + s.getServerConfiguration().addHttpHandler(new SubTree(resources, prefix), "/");
5.109 + try {
5.110 + launchServerAndBrwsr(s, simpleName);
5.111 + } catch (URISyntaxException | InterruptedException ex) {
5.112 + throw new IOException(ex);
5.113 + }
5.114 + }
5.115 +
5.116 + void showDirectory(File dir, String startpage) throws IOException {
5.117 + if (!startpage.startsWith("/")) {
5.118 + startpage = "/" + startpage;
5.119 + }
5.120 + HttpServer s = initServer(dir.getPath(), false);
5.121 + try {
5.122 + launchServerAndBrwsr(s, startpage);
5.123 + } catch (URISyntaxException | InterruptedException ex) {
5.124 + throw new IOException(ex);
5.125 + }
5.126 + }
5.127 +
5.128 + @Override
5.129 + public void initialize() throws IOException {
5.130 + try {
5.131 + executeInBrowser();
5.132 + } catch (InterruptedException ex) {
5.133 + final InterruptedIOException iio = new InterruptedIOException(ex.getMessage());
5.134 + iio.initCause(ex);
5.135 + throw iio;
5.136 + } catch (Exception ex) {
5.137 + if (ex instanceof IOException) {
5.138 + throw (IOException)ex;
5.139 + }
5.140 + if (ex instanceof RuntimeException) {
5.141 + throw (RuntimeException)ex;
5.142 + }
5.143 + throw new IOException(ex);
5.144 + }
5.145 + }
5.146 +
5.147 + private HttpServer initServer(String path, boolean addClasses) throws IOException {
5.148 + HttpServer s = HttpServer.createSimpleServer(path, new PortRange(8080, 65535));
5.149 +
5.150 + final ServerConfiguration conf = s.getServerConfiguration();
5.151 + if (addClasses) {
5.152 + conf.addHttpHandler(new VM(resources), "/bck2brwsr.js");
5.153 + conf.addHttpHandler(new Classes(resources), "/classes/");
5.154 + }
5.155 + return s;
5.156 + }
5.157 +
5.158 + private void executeInBrowser() throws InterruptedException, URISyntaxException, IOException {
5.159 + wait = new CountDownLatch(1);
5.160 + server = initServer(".", true);
5.161 + final ServerConfiguration conf = server.getServerConfiguration();
5.162 +
5.163 + class DynamicResourceHandler extends HttpHandler {
5.164 + private final InvocationContext ic;
5.165 + public DynamicResourceHandler(InvocationContext ic) {
5.166 + if (ic == null || ic.resources.isEmpty()) {
5.167 + throw new NullPointerException();
5.168 + }
5.169 + this.ic = ic;
5.170 + for (Resource r : ic.resources) {
5.171 + conf.addHttpHandler(this, r.httpPath);
5.172 + }
5.173 + }
5.174 +
5.175 + public void close() {
5.176 + conf.removeHttpHandler(this);
5.177 + }
5.178 +
5.179 + @Override
5.180 + public void service(Request request, Response response) throws Exception {
5.181 + for (Resource r : ic.resources) {
5.182 + if (r.httpPath.equals(request.getRequestURI())) {
5.183 + LOG.log(Level.INFO, "Serving HttpResource for {0}", request.getRequestURI());
5.184 + response.setContentType(r.httpType);
5.185 + r.httpContent.reset();
5.186 + String[] params = null;
5.187 + if (r.parameters.length != 0) {
5.188 + params = new String[r.parameters.length];
5.189 + for (int i = 0; i < r.parameters.length; i++) {
5.190 + params[i] = request.getParameter(r.parameters[i]);
5.191 + }
5.192 + }
5.193 +
5.194 + copyStream(r.httpContent, response.getOutputStream(), null, params);
5.195 + }
5.196 + }
5.197 + }
5.198 + }
5.199 +
5.200 + conf.addHttpHandler(new Page(resources,
5.201 + "org/apidesign/bck2brwsr/launcher/harness.xhtml"
5.202 + ), "/execute");
5.203 +
5.204 + conf.addHttpHandler(new HttpHandler() {
5.205 + int cnt;
5.206 + List<InvocationContext> cases = new ArrayList<>();
5.207 + DynamicResourceHandler prev;
5.208 + @Override
5.209 + public void service(Request request, Response response) throws Exception {
5.210 + String id = request.getParameter("request");
5.211 + String value = request.getParameter("result");
5.212 + if (value != null && value.indexOf((char)0xC5) != -1) {
5.213 + value = toUTF8(value);
5.214 + }
5.215 +
5.216 +
5.217 + InvocationContext mi = null;
5.218 + int caseNmbr = -1;
5.219 +
5.220 + if (id != null && value != null) {
5.221 + LOG.log(Level.INFO, "Received result for case {0} = {1}", new Object[]{id, value});
5.222 + value = decodeURL(value);
5.223 + int indx = Integer.parseInt(id);
5.224 + cases.get(indx).result(value, null);
5.225 + if (++indx < cases.size()) {
5.226 + mi = cases.get(indx);
5.227 + LOG.log(Level.INFO, "Re-executing case {0}", indx);
5.228 + caseNmbr = indx;
5.229 + }
5.230 + } else {
5.231 + if (!cases.isEmpty()) {
5.232 + LOG.info("Re-executing test cases");
5.233 + mi = cases.get(0);
5.234 + caseNmbr = 0;
5.235 + }
5.236 + }
5.237 +
5.238 + if (prev != null) {
5.239 + prev.close();
5.240 + prev = null;
5.241 + }
5.242 +
5.243 + if (mi == null) {
5.244 + mi = methods.take();
5.245 + caseNmbr = cnt++;
5.246 + }
5.247 + if (mi == END) {
5.248 + response.getWriter().write("");
5.249 + wait.countDown();
5.250 + cnt = 0;
5.251 + LOG.log(Level.INFO, "End of data reached. Exiting.");
5.252 + return;
5.253 + }
5.254 +
5.255 + if (!mi.resources.isEmpty()) {
5.256 + prev = new DynamicResourceHandler(mi);
5.257 + }
5.258 +
5.259 + cases.add(mi);
5.260 + final String cn = mi.clazz.getName();
5.261 + final String mn = mi.methodName;
5.262 + LOG.log(Level.INFO, "Request for {0} case. Sending {1}.{2}", new Object[]{caseNmbr, cn, mn});
5.263 + response.getWriter().write("{"
5.264 + + "className: '" + cn + "', "
5.265 + + "methodName: '" + mn + "', "
5.266 + + "request: " + caseNmbr
5.267 + );
5.268 + if (mi.html != null) {
5.269 + response.getWriter().write(", html: '");
5.270 + response.getWriter().write(encodeJSON(mi.html));
5.271 + response.getWriter().write("'");
5.272 + }
5.273 + response.getWriter().write("}");
5.274 + }
5.275 + }, "/data");
5.276 +
5.277 + this.brwsr = launchServerAndBrwsr(server, "/execute");
5.278 + }
5.279 +
5.280 + private static String encodeJSON(String in) {
5.281 + StringBuilder sb = new StringBuilder();
5.282 + for (int i = 0; i < in.length(); i++) {
5.283 + char ch = in.charAt(i);
5.284 + if (ch < 32 || ch == '\'' || ch == '"') {
5.285 + sb.append("\\u");
5.286 + String hs = "0000" + Integer.toHexString(ch);
5.287 + hs = hs.substring(hs.length() - 4);
5.288 + sb.append(hs);
5.289 + } else {
5.290 + sb.append(ch);
5.291 + }
5.292 + }
5.293 + return sb.toString();
5.294 + }
5.295 +
5.296 + @Override
5.297 + public void shutdown() throws IOException {
5.298 + methods.offer(END);
5.299 + for (;;) {
5.300 + int prev = methods.size();
5.301 + try {
5.302 + if (wait != null && wait.await(timeOut, TimeUnit.MILLISECONDS)) {
5.303 + break;
5.304 + }
5.305 + } catch (InterruptedException ex) {
5.306 + throw new IOException(ex);
5.307 + }
5.308 + if (prev == methods.size()) {
5.309 + LOG.log(
5.310 + Level.WARNING,
5.311 + "Timeout and no test has been executed meanwhile (at {0}). Giving up.",
5.312 + methods.size()
5.313 + );
5.314 + break;
5.315 + }
5.316 + LOG.log(Level.INFO,
5.317 + "Timeout, but tests got from {0} to {1}. Trying again.",
5.318 + new Object[]{prev, methods.size()}
5.319 + );
5.320 + }
5.321 + stopServerAndBrwsr(server, brwsr);
5.322 + }
5.323 +
5.324 + static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
5.325 + for (;;) {
5.326 + int ch = is.read();
5.327 + if (ch == -1) {
5.328 + break;
5.329 + }
5.330 + if (ch == '$' && params.length > 0) {
5.331 + int cnt = is.read() - '0';
5.332 + if (baseURL != null && cnt == 'U' - '0') {
5.333 + os.write(baseURL.getBytes("UTF-8"));
5.334 + } else {
5.335 + if (cnt >= 0 && cnt < params.length) {
5.336 + os.write(params[cnt].getBytes("UTF-8"));
5.337 + } else {
5.338 + os.write('$');
5.339 + os.write(cnt + '0');
5.340 + }
5.341 + }
5.342 + } else {
5.343 + os.write(ch);
5.344 + }
5.345 + }
5.346 + }
5.347 +
5.348 + private Object[] launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException {
5.349 + server.start();
5.350 + NetworkListener listener = server.getListeners().iterator().next();
5.351 + int port = listener.getPort();
5.352 +
5.353 + URI uri = new URI("http://localhost:" + port + page);
5.354 + LOG.log(Level.INFO, "Showing {0}", uri);
5.355 + if (cmd == null) {
5.356 + try {
5.357 + LOG.log(Level.INFO, "Trying Desktop.browse on {0} {2} by {1}", new Object[] {
5.358 + System.getProperty("java.vm.name"),
5.359 + System.getProperty("java.vm.vendor"),
5.360 + System.getProperty("java.vm.version"),
5.361 + });
5.362 + java.awt.Desktop.getDesktop().browse(uri);
5.363 + LOG.log(Level.INFO, "Desktop.browse successfully finished");
5.364 + return null;
5.365 + } catch (UnsupportedOperationException ex) {
5.366 + LOG.log(Level.INFO, "Desktop.browse not supported: {0}", ex.getMessage());
5.367 + LOG.log(Level.FINE, null, ex);
5.368 + }
5.369 + }
5.370 + {
5.371 + String cmdName = cmd == null ? "xdg-open" : cmd;
5.372 + String[] cmdArr = {
5.373 + cmdName, uri.toString()
5.374 + };
5.375 + LOG.log(Level.INFO, "Launching {0}", Arrays.toString(cmdArr));
5.376 + final Process process = Runtime.getRuntime().exec(cmdArr);
5.377 + return new Object[] { process, null };
5.378 + }
5.379 + }
5.380 + private static String toUTF8(String value) throws UnsupportedEncodingException {
5.381 + byte[] arr = new byte[value.length()];
5.382 + for (int i = 0; i < arr.length; i++) {
5.383 + arr[i] = (byte)value.charAt(i);
5.384 + }
5.385 + return new String(arr, "UTF-8");
5.386 + }
5.387 +
5.388 + private static String decodeURL(String s) {
5.389 + for (;;) {
5.390 + int pos = s.indexOf('%');
5.391 + if (pos == -1) {
5.392 + return s;
5.393 + }
5.394 + int i = Integer.parseInt(s.substring(pos + 1, pos + 2), 16);
5.395 + s = s.substring(0, pos) + (char)i + s.substring(pos + 2);
5.396 + }
5.397 + }
5.398 +
5.399 + private void stopServerAndBrwsr(HttpServer server, Object[] brwsr) throws IOException {
5.400 + if (brwsr == null) {
5.401 + return;
5.402 + }
5.403 + Process process = (Process)brwsr[0];
5.404 +
5.405 + server.stop();
5.406 + InputStream stdout = process.getInputStream();
5.407 + InputStream stderr = process.getErrorStream();
5.408 + drain("StdOut", stdout);
5.409 + drain("StdErr", stderr);
5.410 + process.destroy();
5.411 + int res;
5.412 + try {
5.413 + res = process.waitFor();
5.414 + } catch (InterruptedException ex) {
5.415 + throw new IOException(ex);
5.416 + }
5.417 + LOG.log(Level.INFO, "Exit code: {0}", res);
5.418 +
5.419 + deleteTree((File)brwsr[1]);
5.420 + }
5.421 +
5.422 + private static void drain(String name, InputStream is) throws IOException {
5.423 + int av = is.available();
5.424 + if (av > 0) {
5.425 + StringBuilder sb = new StringBuilder();
5.426 + sb.append("v== ").append(name).append(" ==v\n");
5.427 + while (av-- > 0) {
5.428 + sb.append((char)is.read());
5.429 + }
5.430 + sb.append("\n^== ").append(name).append(" ==^");
5.431 + LOG.log(Level.INFO, sb.toString());
5.432 + }
5.433 + }
5.434 +
5.435 + private void deleteTree(File file) {
5.436 + if (file == null) {
5.437 + return;
5.438 + }
5.439 + File[] arr = file.listFiles();
5.440 + if (arr != null) {
5.441 + for (File s : arr) {
5.442 + deleteTree(s);
5.443 + }
5.444 + }
5.445 + file.delete();
5.446 + }
5.447 +
5.448 + @Override
5.449 + public void close() throws IOException {
5.450 + shutdown();
5.451 + }
5.452 +
5.453 + private class Res implements Bck2Brwsr.Resources {
5.454 + @Override
5.455 + public InputStream get(String resource) throws IOException {
5.456 + for (ClassLoader l : loaders) {
5.457 + URL u = null;
5.458 + Enumeration<URL> en = l.getResources(resource);
5.459 + while (en.hasMoreElements()) {
5.460 + u = en.nextElement();
5.461 + }
5.462 + if (u != null) {
5.463 + return u.openStream();
5.464 + }
5.465 + }
5.466 + throw new IOException("Can't find " + resource);
5.467 + }
5.468 + }
5.469 +
5.470 + private static class Page extends HttpHandler {
5.471 + final String resource;
5.472 + private final String[] args;
5.473 + private final Res res;
5.474 +
5.475 + public Page(Res res, String resource, String... args) {
5.476 + this.res = res;
5.477 + this.resource = resource;
5.478 + this.args = args.length == 0 ? new String[] { "$0" } : args;
5.479 + }
5.480 +
5.481 + @Override
5.482 + public void service(Request request, Response response) throws Exception {
5.483 + String r = computePage(request);
5.484 + if (r.startsWith("/")) {
5.485 + r = r.substring(1);
5.486 + }
5.487 + String[] replace = {};
5.488 + if (r.endsWith(".html")) {
5.489 + response.setContentType("text/html");
5.490 + LOG.info("Content type text/html");
5.491 + replace = args;
5.492 + }
5.493 + if (r.endsWith(".xhtml")) {
5.494 + response.setContentType("application/xhtml+xml");
5.495 + LOG.info("Content type application/xhtml+xml");
5.496 + replace = args;
5.497 + }
5.498 + OutputStream os = response.getOutputStream();
5.499 + try (InputStream is = res.get(r)) {
5.500 + copyStream(is, os, request.getRequestURL().toString(), replace);
5.501 + } catch (IOException ex) {
5.502 + response.setDetailMessage(ex.getLocalizedMessage());
5.503 + response.setError();
5.504 + response.setStatus(404);
5.505 + }
5.506 + }
5.507 +
5.508 + protected String computePage(Request request) {
5.509 + String r = resource;
5.510 + if (r == null) {
5.511 + r = request.getHttpHandlerPath();
5.512 + }
5.513 + return r;
5.514 + }
5.515 + }
5.516 +
5.517 + private static class SubTree extends Page {
5.518 +
5.519 + public SubTree(Res res, String resource, String... args) {
5.520 + super(res, resource, args);
5.521 + }
5.522 +
5.523 + @Override
5.524 + protected String computePage(Request request) {
5.525 + return resource + request.getHttpHandlerPath();
5.526 + }
5.527 +
5.528 +
5.529 + }
5.530 +
5.531 + private static class VM extends HttpHandler {
5.532 + private final String bck2brwsr;
5.533 +
5.534 + public VM(Res loader) throws IOException {
5.535 + StringBuilder sb = new StringBuilder();
5.536 + Bck2Brwsr.generate(sb, loader);
5.537 + sb.append(
5.538 + "(function WrapperVM(global) {"
5.539 + + " function ldCls(res) {\n"
5.540 + + " var request = new XMLHttpRequest();\n"
5.541 + + " request.open('GET', '/classes/' + res, false);\n"
5.542 + + " request.send();\n"
5.543 + + " if (request.status !== 200) return null;\n"
5.544 + + " var arr = eval('(' + request.responseText + ')');\n"
5.545 + + " return arr;\n"
5.546 + + " }\n"
5.547 + + " var prevvm = global.bck2brwsr;\n"
5.548 + + " global.bck2brwsr = function() {\n"
5.549 + + " var args = Array.prototype.slice.apply(arguments);\n"
5.550 + + " args.unshift(ldCls);\n"
5.551 + + " return prevvm.apply(null, args);\n"
5.552 + + " };\n"
5.553 + + "})(this);\n"
5.554 + );
5.555 + this.bck2brwsr = sb.toString();
5.556 + }
5.557 +
5.558 + @Override
5.559 + public void service(Request request, Response response) throws Exception {
5.560 + response.setCharacterEncoding("UTF-8");
5.561 + response.setContentType("text/javascript");
5.562 + response.getWriter().write(bck2brwsr);
5.563 + }
5.564 + }
5.565 +
5.566 + private static class Classes extends HttpHandler {
5.567 + private final Res loader;
5.568 +
5.569 + public Classes(Res loader) {
5.570 + this.loader = loader;
5.571 + }
5.572 +
5.573 + @Override
5.574 + public void service(Request request, Response response) throws Exception {
5.575 + String res = request.getHttpHandlerPath();
5.576 + if (res.startsWith("/")) {
5.577 + res = res.substring(1);
5.578 + }
5.579 + try (InputStream is = loader.get(res)) {
5.580 + response.setContentType("text/javascript");
5.581 + Writer w = response.getWriter();
5.582 + w.append("[");
5.583 + for (int i = 0;; i++) {
5.584 + int b = is.read();
5.585 + if (b == -1) {
5.586 + break;
5.587 + }
5.588 + if (i > 0) {
5.589 + w.append(", ");
5.590 + }
5.591 + if (i % 20 == 0) {
5.592 + w.write("\n");
5.593 + }
5.594 + if (b > 127) {
5.595 + b = b - 256;
5.596 + }
5.597 + w.append(Integer.toString(b));
5.598 + }
5.599 + w.append("\n]");
5.600 + } catch (IOException ex) {
5.601 + response.setStatus(HttpStatus.NOT_FOUND_404);
5.602 + response.setError();
5.603 + response.setDetailMessage(ex.getMessage());
5.604 + }
5.605 + }
5.606 + }
5.607 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Sun Apr 28 10:14:31 2013 +0200
6.3 @@ -0,0 +1,135 @@
6.4 +/**
6.5 + * Back 2 Browser Bytecode Translator
6.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
6.7 + *
6.8 + * This program is free software: you can redistribute it and/or modify
6.9 + * it under the terms of the GNU General Public License as published by
6.10 + * the Free Software Foundation, version 2 of the License.
6.11 + *
6.12 + * This program is distributed in the hope that it will be useful,
6.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
6.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6.15 + * GNU General Public License for more details.
6.16 + *
6.17 + * You should have received a copy of the GNU General Public License
6.18 + * along with this program. Look for COPYING file in the top folder.
6.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
6.20 + */
6.21 +package org.apidesign.bck2brwsr.launcher;
6.22 +
6.23 +import org.apidesign.bck2brwsr.launcher.impl.Console;
6.24 +import java.io.IOException;
6.25 +import java.io.InputStream;
6.26 +import java.net.URL;
6.27 +import java.util.Enumeration;
6.28 +import java.util.LinkedHashSet;
6.29 +import java.util.Set;
6.30 +import java.util.logging.Level;
6.31 +import java.util.logging.Logger;
6.32 +import javax.script.Invocable;
6.33 +import javax.script.ScriptEngine;
6.34 +import javax.script.ScriptEngineManager;
6.35 +import javax.script.ScriptException;
6.36 +import org.apidesign.vm4brwsr.Bck2Brwsr;
6.37 +
6.38 +/**
6.39 + * Tests execution in Java's internal scripting engine.
6.40 + */
6.41 +final class JSLauncher extends Launcher {
6.42 + private static final Logger LOG = Logger.getLogger(JSLauncher.class.getName());
6.43 + private Set<ClassLoader> loaders = new LinkedHashSet<>();
6.44 + private final Res resources = new Res();
6.45 + private Invocable code;
6.46 + private StringBuilder codeSeq;
6.47 + private Object console;
6.48 +
6.49 + JSLauncher() {
6.50 + addClassLoader(Bck2Brwsr.class.getClassLoader());
6.51 + }
6.52 +
6.53 + @Override InvocationContext runMethod(InvocationContext mi) {
6.54 + loaders.add(mi.clazz.getClassLoader());
6.55 + try {
6.56 + long time = System.currentTimeMillis();
6.57 + LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.clazz.getName(), mi.methodName});
6.58 + String res = code.invokeMethod(
6.59 + console,
6.60 + "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2",
6.61 + mi.clazz.getName(), mi.methodName).toString();
6.62 + time = System.currentTimeMillis() - time;
6.63 + LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.clazz.getName(), mi.methodName, res, time});
6.64 + mi.result(res, null);
6.65 + } catch (ScriptException | NoSuchMethodException ex) {
6.66 + mi.result(null, ex);
6.67 + }
6.68 + return mi;
6.69 + }
6.70 +
6.71 + public void addClassLoader(ClassLoader url) {
6.72 + this.loaders.add(url);
6.73 + }
6.74 +
6.75 + @Override
6.76 + public void initialize() throws IOException {
6.77 + try {
6.78 + initRhino();
6.79 + } catch (Exception ex) {
6.80 + if (ex instanceof IOException) {
6.81 + throw (IOException)ex;
6.82 + }
6.83 + if (ex instanceof RuntimeException) {
6.84 + throw (RuntimeException)ex;
6.85 + }
6.86 + throw new IOException(ex);
6.87 + }
6.88 + }
6.89 +
6.90 + private void initRhino() throws IOException, ScriptException, NoSuchMethodException {
6.91 + StringBuilder sb = new StringBuilder();
6.92 + Bck2Brwsr.generate(sb, new Res());
6.93 +
6.94 + ScriptEngineManager sem = new ScriptEngineManager();
6.95 + ScriptEngine mach = sem.getEngineByExtension("js");
6.96 +
6.97 + sb.append(
6.98 + "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.impl.Console.read);"
6.99 + + "\nfunction initVM() { return vm; };"
6.100 + + "\n");
6.101 +
6.102 + Object res = mach.eval(sb.toString());
6.103 + if (!(mach instanceof Invocable)) {
6.104 + throw new IOException("It is invocable object: " + res);
6.105 + }
6.106 + code = (Invocable) mach;
6.107 + codeSeq = sb;
6.108 +
6.109 + Object vm = code.invokeFunction("initVM");
6.110 + console = code.invokeMethod(vm, "loadClass", Console.class.getName());
6.111 + }
6.112 +
6.113 + @Override
6.114 + public void shutdown() throws IOException {
6.115 + }
6.116 +
6.117 + @Override
6.118 + public String toString() {
6.119 + return codeSeq.toString();
6.120 + }
6.121 +
6.122 + private class Res implements Bck2Brwsr.Resources {
6.123 + @Override
6.124 + public InputStream get(String resource) throws IOException {
6.125 + for (ClassLoader l : loaders) {
6.126 + URL u = null;
6.127 + Enumeration<URL> en = l.getResources(resource);
6.128 + while (en.hasMoreElements()) {
6.129 + u = en.nextElement();
6.130 + }
6.131 + if (u != null) {
6.132 + return u.openStream();
6.133 + }
6.134 + }
6.135 + throw new IOException("Can't find " + resource);
6.136 + }
6.137 + }
6.138 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java Sun Apr 28 10:14:31 2013 +0200
7.3 @@ -0,0 +1,356 @@
7.4 +/**
7.5 + * Back 2 Browser Bytecode Translator
7.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
7.7 + *
7.8 + * This program is free software: you can redistribute it and/or modify
7.9 + * it under the terms of the GNU General Public License as published by
7.10 + * the Free Software Foundation, version 2 of the License.
7.11 + *
7.12 + * This program is distributed in the hope that it will be useful,
7.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.15 + * GNU General Public License for more details.
7.16 + *
7.17 + * You should have received a copy of the GNU General Public License
7.18 + * along with this program. Look for COPYING file in the top folder.
7.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
7.20 + */
7.21 +package org.apidesign.bck2brwsr.launcher.impl;
7.22 +
7.23 +import java.io.IOException;
7.24 +import java.io.InputStream;
7.25 +import java.io.UnsupportedEncodingException;
7.26 +import java.lang.reflect.InvocationTargetException;
7.27 +import java.lang.reflect.Method;
7.28 +import java.lang.reflect.Modifier;
7.29 +import java.net.URL;
7.30 +import java.util.Enumeration;
7.31 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
7.32 +
7.33 +/**
7.34 + *
7.35 + * @author Jaroslav Tulach <jtulach@netbeans.org>
7.36 + */
7.37 +public class Console {
7.38 + private Console() {
7.39 + }
7.40 + static {
7.41 + turnAssetionStatusOn();
7.42 + }
7.43 +
7.44 + @JavaScriptBody(args = {"id", "attr"}, body =
7.45 + "return window.document.getElementById(id)[attr].toString();")
7.46 + private static native Object getAttr(String id, String attr);
7.47 + @JavaScriptBody(args = {"elem", "attr"}, body =
7.48 + "return elem[attr].toString();")
7.49 + private static native Object getAttr(Object elem, String attr);
7.50 +
7.51 + @JavaScriptBody(args = {"id", "attr", "value"}, body =
7.52 + "window.document.getElementById(id)[attr] = value;")
7.53 + private static native void setAttr(String id, String attr, Object value);
7.54 + @JavaScriptBody(args = {"elem", "attr", "value"}, body =
7.55 + "elem[attr] = value;")
7.56 + private static native void setAttr(Object id, String attr, Object value);
7.57 +
7.58 + @JavaScriptBody(args = {}, body = "return; window.close();")
7.59 + private static native void closeWindow();
7.60 +
7.61 + private static Object textArea;
7.62 + private static Object statusArea;
7.63 +
7.64 + private static void log(String newText) {
7.65 + if (textArea == null) {
7.66 + return;
7.67 + }
7.68 + String attr = "value";
7.69 + setAttr(textArea, attr, getAttr(textArea, attr) + "\n" + newText);
7.70 + setAttr(textArea, "scrollTop", getAttr(textArea, "scrollHeight"));
7.71 + }
7.72 +
7.73 + private static void beginTest(Case c) {
7.74 + Object[] arr = new Object[2];
7.75 + beginTest(c.getClassName() + "." + c.getMethodName(), c, arr);
7.76 + textArea = arr[0];
7.77 + statusArea = arr[1];
7.78 + }
7.79 +
7.80 + private static void finishTest(Case c, Object res) {
7.81 + if ("null".equals(res)) {
7.82 + setAttr(statusArea, "innerHTML", "Success");
7.83 + } else {
7.84 + setAttr(statusArea, "innerHTML", "Result " + res);
7.85 + }
7.86 + statusArea = null;
7.87 + textArea = null;
7.88 + }
7.89 +
7.90 + @JavaScriptBody(args = { "test", "c", "arr" }, body =
7.91 + "var ul = window.document.getElementById('bck2brwsr.result');\n"
7.92 + + "var li = window.document.createElement('li');\n"
7.93 + + "var span = window.document.createElement('span');"
7.94 + + "span.innerHTML = test + ' - ';\n"
7.95 + + "var details = window.document.createElement('a');\n"
7.96 + + "details.innerHTML = 'Details';\n"
7.97 + + "details.href = '#';\n"
7.98 + + "var p = window.document.createElement('p');\n"
7.99 + + "var status = window.document.createElement('a');\n"
7.100 + + "status.innerHTML = 'running';"
7.101 + + "details.onclick = function() { li.appendChild(p); li.removeChild(details); status.innerHTML = 'Run Again'; status.href = '#'; };\n"
7.102 + + "status.onclick = function() { c.again__V_3Ljava_lang_Object_2(arr); }\n"
7.103 + + "var pre = window.document.createElement('textarea');\n"
7.104 + + "pre.cols = 100;"
7.105 + + "pre.rows = 10;"
7.106 + + "li.appendChild(span);\n"
7.107 + + "li.appendChild(status);\n"
7.108 + + "var span = window.document.createElement('span');"
7.109 + + "span.innerHTML = ' ';\n"
7.110 + + "li.appendChild(span);\n"
7.111 + + "li.appendChild(details);\n"
7.112 + + "p.appendChild(pre);\n"
7.113 + + "ul.appendChild(li);\n"
7.114 + + "arr[0] = pre;\n"
7.115 + + "arr[1] = status;\n"
7.116 + )
7.117 + private static native void beginTest(String test, Case c, Object[] arr);
7.118 +
7.119 + @JavaScriptBody(args = { "url", "callback", "arr" }, body = ""
7.120 + + "var request = new XMLHttpRequest();\n"
7.121 + + "request.open('GET', url, true);\n"
7.122 + + "request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n"
7.123 + + "request.onreadystatechange = function() {\n"
7.124 + + " if (this.readyState!==4) return;\n"
7.125 + + " arr[0] = this.responseText;\n"
7.126 + + " callback.run__V();\n"
7.127 + + "};"
7.128 + + "request.send();"
7.129 + )
7.130 + private static native void loadText(String url, Runnable callback, String[] arr) throws IOException;
7.131 +
7.132 + public static void harness(String url) throws IOException {
7.133 + log("Connecting to " + url);
7.134 + Request r = new Request(url);
7.135 + }
7.136 +
7.137 + private static class Request implements Runnable {
7.138 + private final String[] arr = { null };
7.139 + private final String url;
7.140 + private Case c;
7.141 + private int retries;
7.142 +
7.143 + private Request(String url) throws IOException {
7.144 + this.url = url;
7.145 + loadText(url, this, arr);
7.146 + }
7.147 + private Request(String url, String u) throws IOException {
7.148 + this.url = url;
7.149 + loadText(u, this, arr);
7.150 + }
7.151 +
7.152 + @Override
7.153 + public void run() {
7.154 + try {
7.155 + if (c == null) {
7.156 + String data = arr[0];
7.157 +
7.158 + if (data == null) {
7.159 + log("Some error exiting");
7.160 + closeWindow();
7.161 + return;
7.162 + }
7.163 +
7.164 + if (data.isEmpty()) {
7.165 + log("No data, exiting");
7.166 + closeWindow();
7.167 + return;
7.168 + }
7.169 +
7.170 + c = Case.parseData(data);
7.171 + beginTest(c);
7.172 + log("Got \"" + data + "\"");
7.173 + } else {
7.174 + log("Processing \"" + arr[0] + "\" for " + retries + " time");
7.175 + }
7.176 + Object result = retries++ >= 10 ? "java.lang.InterruptedException:timeout" : c.runTest();
7.177 + finishTest(c, result);
7.178 +
7.179 + String u = url + "?request=" + c.getRequestId() + "&result=" + result;
7.180 + new Request(url, u);
7.181 + } catch (Exception ex) {
7.182 + if (ex instanceof InterruptedException) {
7.183 + log("Re-scheduling in 100ms");
7.184 + schedule(this, 100);
7.185 + return;
7.186 + }
7.187 + log(ex.getClass().getName() + ":" + ex.getMessage());
7.188 + }
7.189 + }
7.190 + }
7.191 +
7.192 + private static String encodeURL(String r) throws UnsupportedEncodingException {
7.193 + final String SPECIAL = "%$&+,/:;=?@";
7.194 + StringBuilder sb = new StringBuilder();
7.195 + byte[] utf8 = r.getBytes("UTF-8");
7.196 + for (int i = 0; i < utf8.length; i++) {
7.197 + int ch = utf8[i] & 0xff;
7.198 + if (ch < 32 || ch > 127 || SPECIAL.indexOf(ch) >= 0) {
7.199 + final String numbers = "0" + Integer.toHexString(ch);
7.200 + sb.append("%").append(numbers.substring(numbers.length() - 2));
7.201 + } else {
7.202 + if (ch == 32) {
7.203 + sb.append("+");
7.204 + } else {
7.205 + sb.append((char)ch);
7.206 + }
7.207 + }
7.208 + }
7.209 + return sb.toString();
7.210 + }
7.211 +
7.212 + static String invoke(String clazz, String method) throws
7.213 + ClassNotFoundException, InvocationTargetException, IllegalAccessException,
7.214 + InstantiationException, InterruptedException {
7.215 + final Object r = new Case(null).invokeMethod(clazz, method);
7.216 + return r == null ? "null" : r.toString().toString();
7.217 + }
7.218 +
7.219 + /** Helper method that inspects the classpath and loads given resource
7.220 + * (usually a class file). Used while running tests in Rhino.
7.221 + *
7.222 + * @param name resource name to find
7.223 + * @return the array of bytes in the given resource
7.224 + * @throws IOException I/O in case something goes wrong
7.225 + */
7.226 + public static byte[] read(String name) throws IOException {
7.227 + URL u = null;
7.228 + Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
7.229 + while (en.hasMoreElements()) {
7.230 + u = en.nextElement();
7.231 + }
7.232 + if (u == null) {
7.233 + throw new IOException("Can't find " + name);
7.234 + }
7.235 + try (InputStream is = u.openStream()) {
7.236 + byte[] arr;
7.237 + arr = new byte[is.available()];
7.238 + int offset = 0;
7.239 + while (offset < arr.length) {
7.240 + int len = is.read(arr, offset, arr.length - offset);
7.241 + if (len == -1) {
7.242 + throw new IOException("Can't read " + name);
7.243 + }
7.244 + offset += len;
7.245 + }
7.246 + return arr;
7.247 + }
7.248 + }
7.249 +
7.250 + @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
7.251 + private static void turnAssetionStatusOn() {
7.252 + }
7.253 +
7.254 + @JavaScriptBody(args = {"r", "time"}, body =
7.255 + "return window.setTimeout(function() { r.run__V(); }, time);")
7.256 + private static native Object schedule(Runnable r, int time);
7.257 +
7.258 + private static final class Case {
7.259 + private final Object data;
7.260 + private Object inst;
7.261 +
7.262 + private Case(Object data) {
7.263 + this.data = data;
7.264 + }
7.265 +
7.266 + public static Case parseData(String s) {
7.267 + return new Case(toJSON(s));
7.268 + }
7.269 +
7.270 + public String getMethodName() {
7.271 + return value("methodName", data);
7.272 + }
7.273 +
7.274 + public String getClassName() {
7.275 + return value("className", data);
7.276 + }
7.277 +
7.278 + public String getRequestId() {
7.279 + return value("request", data);
7.280 + }
7.281 +
7.282 + public String getHtmlFragment() {
7.283 + return value("html", data);
7.284 + }
7.285 +
7.286 + void again(Object[] arr) {
7.287 + try {
7.288 + textArea = arr[0];
7.289 + statusArea = arr[1];
7.290 + setAttr(textArea, "value", "");
7.291 + runTest();
7.292 + } catch (Exception ex) {
7.293 + log(ex.getClass().getName() + ":" + ex.getMessage());
7.294 + }
7.295 + }
7.296 +
7.297 + private Object runTest() throws IllegalAccessException,
7.298 + IllegalArgumentException, ClassNotFoundException, UnsupportedEncodingException,
7.299 + InvocationTargetException, InstantiationException, InterruptedException {
7.300 + if (this.getHtmlFragment() != null) {
7.301 + setAttr("bck2brwsr.fragment", "innerHTML", this.getHtmlFragment());
7.302 + }
7.303 + log("Invoking " + this.getClassName() + '.' + this.getMethodName() + " as request: " + this.getRequestId());
7.304 + Object result = invokeMethod(this.getClassName(), this.getMethodName());
7.305 + setAttr("bck2brwsr.fragment", "innerHTML", "");
7.306 + log("Result: " + result);
7.307 + result = encodeURL("" + result);
7.308 + log("Sending back: ...?request=" + this.getRequestId() + "&result=" + result);
7.309 + return result;
7.310 + }
7.311 +
7.312 + private Object invokeMethod(String clazz, String method)
7.313 + throws ClassNotFoundException, InvocationTargetException,
7.314 + InterruptedException, IllegalAccessException, IllegalArgumentException,
7.315 + InstantiationException {
7.316 + Method found = null;
7.317 + Class<?> c = Class.forName(clazz);
7.318 + for (Method m : c.getMethods()) {
7.319 + if (m.getName().equals(method)) {
7.320 + found = m;
7.321 + }
7.322 + }
7.323 + Object res;
7.324 + if (found != null) {
7.325 + try {
7.326 + if ((found.getModifiers() & Modifier.STATIC) != 0) {
7.327 + res = found.invoke(null);
7.328 + } else {
7.329 + if (inst == null) {
7.330 + inst = c.newInstance();
7.331 + }
7.332 + res = found.invoke(inst);
7.333 + }
7.334 + } catch (Throwable ex) {
7.335 + if (ex instanceof InvocationTargetException) {
7.336 + ex = ((InvocationTargetException) ex).getTargetException();
7.337 + }
7.338 + if (ex instanceof InterruptedException) {
7.339 + throw (InterruptedException)ex;
7.340 + }
7.341 + res = ex.getClass().getName() + ":" + ex.getMessage();
7.342 + }
7.343 + } else {
7.344 + res = "Can't find method " + method + " in " + clazz;
7.345 + }
7.346 + return res;
7.347 + }
7.348 +
7.349 + @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');")
7.350 + private static native Object toJSON(String s);
7.351 +
7.352 + @JavaScriptBody(args = {"p", "d"}, body =
7.353 + "var v = d[p];\n"
7.354 + + "if (typeof v === 'undefined') return null;\n"
7.355 + + "return v.toString();"
7.356 + )
7.357 + private static native String value(String p, Object d);
7.358 + }
7.359 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/launcher/http/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Sun Apr 28 10:14:31 2013 +0200
8.3 @@ -0,0 +1,43 @@
8.4 +<?xml version="1.0" encoding="UTF-8"?>
8.5 +<!--
8.6 +
8.7 + Back 2 Browser Bytecode Translator
8.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
8.9 +
8.10 + This program is free software: you can redistribute it and/or modify
8.11 + it under the terms of the GNU General Public License as published by
8.12 + the Free Software Foundation, version 2 of the License.
8.13 +
8.14 + This program is distributed in the hope that it will be useful,
8.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
8.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8.17 + GNU General Public License for more details.
8.18 +
8.19 + You should have received a copy of the GNU General Public License
8.20 + along with this program. Look for COPYING file in the top folder.
8.21 + If not, see http://opensource.org/licenses/GPL-2.0.
8.22 +
8.23 +-->
8.24 +<!DOCTYPE html>
8.25 +<html xmlns="http://www.w3.org/1999/xhtml">
8.26 + <head>
8.27 + <title>Bck2Brwsr Harness</title>
8.28 + </head>
8.29 + <body>
8.30 + <script src="/bck2brwsr.js"></script>
8.31 + <script>
8.32 + var vm = bck2brwsr();
8.33 + </script>
8.34 +
8.35 + <h1>Bck2Brwsr Execution Harness</h1>
8.36 +
8.37 + <ul id="bck2brwsr.result" style="width: 100%;" >
8.38 + </ul>
8.39 +
8.40 + <div id="bck2brwsr.fragment"/>
8.41 +
8.42 + <script type="text/javascript">
8.43 + vm.loadClass('org.apidesign.bck2brwsr.launcher.impl.Console').harness__VLjava_lang_String_2('$U/../data');
8.44 + </script>
8.45 + </body>
8.46 +</html>
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/launcher/pom.xml Sun Apr 28 10:14:31 2013 +0200
9.3 @@ -0,0 +1,18 @@
9.4 +<?xml version="1.0" encoding="UTF-8"?>
9.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
9.6 + <modelVersion>4.0.0</modelVersion>
9.7 + <parent>
9.8 + <artifactId>bck2brwsr</artifactId>
9.9 + <groupId>org.apidesign</groupId>
9.10 + <version>0.7-SNAPSHOT</version>
9.11 + </parent>
9.12 + <groupId>org.apidesign.bck2brwsr</groupId>
9.13 + <artifactId>launcher-pom</artifactId>
9.14 + <version>0.7-SNAPSHOT</version>
9.15 + <packaging>pom</packaging>
9.16 + <name>Launchers</name>
9.17 + <modules>
9.18 + <module>api</module>
9.19 + <module>http</module>
9.20 + </modules>
9.21 +</project>
9.22 \ No newline at end of file
10.1 --- a/rt/launcher/pom.xml Sun Apr 28 09:46:23 2013 +0200
10.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
10.3 @@ -1,56 +0,0 @@
10.4 -<?xml version="1.0"?>
10.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
10.6 - <modelVersion>4.0.0</modelVersion>
10.7 - <parent>
10.8 - <groupId>org.apidesign.bck2brwsr</groupId>
10.9 - <artifactId>rt</artifactId>
10.10 - <version>0.7-SNAPSHOT</version>
10.11 - </parent>
10.12 - <groupId>org.apidesign.bck2brwsr</groupId>
10.13 - <artifactId>launcher</artifactId>
10.14 - <version>0.7-SNAPSHOT</version>
10.15 - <name>Bck2Brwsr Launcher</name>
10.16 - <url>http://maven.apache.org</url>
10.17 - <build>
10.18 - <plugins>
10.19 - <plugin>
10.20 - <groupId>org.apache.maven.plugins</groupId>
10.21 - <artifactId>maven-compiler-plugin</artifactId>
10.22 - <version>2.3.2</version>
10.23 - <configuration>
10.24 - <source>1.7</source>
10.25 - <target>1.7</target>
10.26 - </configuration>
10.27 - </plugin>
10.28 - <plugin>
10.29 - <groupId>org.apache.maven.plugins</groupId>
10.30 - <artifactId>maven-javadoc-plugin</artifactId>
10.31 - <configuration>
10.32 - <excludePackageNames>org.apidesign.bck2brwsr.launcher.impl</excludePackageNames>
10.33 - <skip>false</skip>
10.34 - </configuration>
10.35 - </plugin>
10.36 - </plugins>
10.37 - </build>
10.38 - <properties>
10.39 - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
10.40 - </properties>
10.41 - <dependencies>
10.42 - <dependency>
10.43 - <groupId>junit</groupId>
10.44 - <artifactId>junit</artifactId>
10.45 - <version>3.8.1</version>
10.46 - <scope>test</scope>
10.47 - </dependency>
10.48 - <dependency>
10.49 - <groupId>org.glassfish.grizzly</groupId>
10.50 - <artifactId>grizzly-http-server</artifactId>
10.51 - <version>2.2.19</version>
10.52 - </dependency>
10.53 - <dependency>
10.54 - <groupId>${project.groupId}</groupId>
10.55 - <artifactId>vm4brwsr</artifactId>
10.56 - <version>${project.version}</version>
10.57 - </dependency>
10.58 - </dependencies>
10.59 -</project>
11.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Sun Apr 28 09:46:23 2013 +0200
11.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
11.3 @@ -1,602 +0,0 @@
11.4 -/**
11.5 - * Back 2 Browser Bytecode Translator
11.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
11.7 - *
11.8 - * This program is free software: you can redistribute it and/or modify
11.9 - * it under the terms of the GNU General Public License as published by
11.10 - * the Free Software Foundation, version 2 of the License.
11.11 - *
11.12 - * This program is distributed in the hope that it will be useful,
11.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
11.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11.15 - * GNU General Public License for more details.
11.16 - *
11.17 - * You should have received a copy of the GNU General Public License
11.18 - * along with this program. Look for COPYING file in the top folder.
11.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
11.20 - */
11.21 -package org.apidesign.bck2brwsr.launcher;
11.22 -
11.23 -import java.io.Closeable;
11.24 -import java.io.File;
11.25 -import java.io.IOException;
11.26 -import java.io.InputStream;
11.27 -import java.io.InterruptedIOException;
11.28 -import java.io.OutputStream;
11.29 -import java.io.UnsupportedEncodingException;
11.30 -import java.io.Writer;
11.31 -import java.net.URI;
11.32 -import java.net.URISyntaxException;
11.33 -import java.net.URL;
11.34 -import java.util.ArrayList;
11.35 -import java.util.Arrays;
11.36 -import java.util.Enumeration;
11.37 -import java.util.LinkedHashSet;
11.38 -import java.util.List;
11.39 -import java.util.Set;
11.40 -import java.util.concurrent.BlockingQueue;
11.41 -import java.util.concurrent.CountDownLatch;
11.42 -import java.util.concurrent.LinkedBlockingQueue;
11.43 -import java.util.concurrent.TimeUnit;
11.44 -import java.util.logging.Level;
11.45 -import java.util.logging.Logger;
11.46 -import org.apidesign.bck2brwsr.launcher.InvocationContext.Resource;
11.47 -import org.apidesign.vm4brwsr.Bck2Brwsr;
11.48 -import org.glassfish.grizzly.PortRange;
11.49 -import org.glassfish.grizzly.http.server.HttpHandler;
11.50 -import org.glassfish.grizzly.http.server.HttpServer;
11.51 -import org.glassfish.grizzly.http.server.NetworkListener;
11.52 -import org.glassfish.grizzly.http.server.Request;
11.53 -import org.glassfish.grizzly.http.server.Response;
11.54 -import org.glassfish.grizzly.http.server.ServerConfiguration;
11.55 -import org.glassfish.grizzly.http.util.HttpStatus;
11.56 -
11.57 -/**
11.58 - * Lightweight server to launch Bck2Brwsr applications and tests.
11.59 - * Supports execution in native browser as well as Java's internal
11.60 - * execution engine.
11.61 - */
11.62 -final class Bck2BrwsrLauncher extends Launcher implements Closeable {
11.63 - private static final Logger LOG = Logger.getLogger(Bck2BrwsrLauncher.class.getName());
11.64 - private static final InvocationContext END = new InvocationContext(null, null, null);
11.65 - private final Set<ClassLoader> loaders = new LinkedHashSet<>();
11.66 - private final BlockingQueue<InvocationContext> methods = new LinkedBlockingQueue<>();
11.67 - private long timeOut;
11.68 - private final Res resources = new Res();
11.69 - private final String cmd;
11.70 - private Object[] brwsr;
11.71 - private HttpServer server;
11.72 - private CountDownLatch wait;
11.73 -
11.74 - public Bck2BrwsrLauncher(String cmd) {
11.75 - this.cmd = cmd;
11.76 - }
11.77 -
11.78 - @Override
11.79 - InvocationContext runMethod(InvocationContext c) throws IOException {
11.80 - loaders.add(c.clazz.getClassLoader());
11.81 - methods.add(c);
11.82 - try {
11.83 - c.await(timeOut);
11.84 - } catch (InterruptedException ex) {
11.85 - throw new IOException(ex);
11.86 - }
11.87 - return c;
11.88 - }
11.89 -
11.90 - public void setTimeout(long ms) {
11.91 - timeOut = ms;
11.92 - }
11.93 -
11.94 - public void addClassLoader(ClassLoader url) {
11.95 - this.loaders.add(url);
11.96 - }
11.97 -
11.98 - public void showURL(String startpage) throws IOException {
11.99 - if (!startpage.startsWith("/")) {
11.100 - startpage = "/" + startpage;
11.101 - }
11.102 - HttpServer s = initServer(".", true);
11.103 - int last = startpage.lastIndexOf('/');
11.104 - String prefix = startpage.substring(0, last);
11.105 - String simpleName = startpage.substring(last);
11.106 - s.getServerConfiguration().addHttpHandler(new SubTree(resources, prefix), "/");
11.107 - try {
11.108 - launchServerAndBrwsr(s, simpleName);
11.109 - } catch (URISyntaxException | InterruptedException ex) {
11.110 - throw new IOException(ex);
11.111 - }
11.112 - }
11.113 -
11.114 - void showDirectory(File dir, String startpage) throws IOException {
11.115 - if (!startpage.startsWith("/")) {
11.116 - startpage = "/" + startpage;
11.117 - }
11.118 - HttpServer s = initServer(dir.getPath(), false);
11.119 - try {
11.120 - launchServerAndBrwsr(s, startpage);
11.121 - } catch (URISyntaxException | InterruptedException ex) {
11.122 - throw new IOException(ex);
11.123 - }
11.124 - }
11.125 -
11.126 - @Override
11.127 - public void initialize() throws IOException {
11.128 - try {
11.129 - executeInBrowser();
11.130 - } catch (InterruptedException ex) {
11.131 - final InterruptedIOException iio = new InterruptedIOException(ex.getMessage());
11.132 - iio.initCause(ex);
11.133 - throw iio;
11.134 - } catch (Exception ex) {
11.135 - if (ex instanceof IOException) {
11.136 - throw (IOException)ex;
11.137 - }
11.138 - if (ex instanceof RuntimeException) {
11.139 - throw (RuntimeException)ex;
11.140 - }
11.141 - throw new IOException(ex);
11.142 - }
11.143 - }
11.144 -
11.145 - private HttpServer initServer(String path, boolean addClasses) throws IOException {
11.146 - HttpServer s = HttpServer.createSimpleServer(path, new PortRange(8080, 65535));
11.147 -
11.148 - final ServerConfiguration conf = s.getServerConfiguration();
11.149 - if (addClasses) {
11.150 - conf.addHttpHandler(new VM(resources), "/bck2brwsr.js");
11.151 - conf.addHttpHandler(new Classes(resources), "/classes/");
11.152 - }
11.153 - return s;
11.154 - }
11.155 -
11.156 - private void executeInBrowser() throws InterruptedException, URISyntaxException, IOException {
11.157 - wait = new CountDownLatch(1);
11.158 - server = initServer(".", true);
11.159 - final ServerConfiguration conf = server.getServerConfiguration();
11.160 -
11.161 - class DynamicResourceHandler extends HttpHandler {
11.162 - private final InvocationContext ic;
11.163 - public DynamicResourceHandler(InvocationContext ic) {
11.164 - if (ic == null || ic.resources.isEmpty()) {
11.165 - throw new NullPointerException();
11.166 - }
11.167 - this.ic = ic;
11.168 - for (Resource r : ic.resources) {
11.169 - conf.addHttpHandler(this, r.httpPath);
11.170 - }
11.171 - }
11.172 -
11.173 - public void close() {
11.174 - conf.removeHttpHandler(this);
11.175 - }
11.176 -
11.177 - @Override
11.178 - public void service(Request request, Response response) throws Exception {
11.179 - for (Resource r : ic.resources) {
11.180 - if (r.httpPath.equals(request.getRequestURI())) {
11.181 - LOG.log(Level.INFO, "Serving HttpResource for {0}", request.getRequestURI());
11.182 - response.setContentType(r.httpType);
11.183 - r.httpContent.reset();
11.184 - String[] params = null;
11.185 - if (r.parameters.length != 0) {
11.186 - params = new String[r.parameters.length];
11.187 - for (int i = 0; i < r.parameters.length; i++) {
11.188 - params[i] = request.getParameter(r.parameters[i]);
11.189 - }
11.190 - }
11.191 -
11.192 - copyStream(r.httpContent, response.getOutputStream(), null, params);
11.193 - }
11.194 - }
11.195 - }
11.196 - }
11.197 -
11.198 - conf.addHttpHandler(new Page(resources,
11.199 - "org/apidesign/bck2brwsr/launcher/harness.xhtml"
11.200 - ), "/execute");
11.201 -
11.202 - conf.addHttpHandler(new HttpHandler() {
11.203 - int cnt;
11.204 - List<InvocationContext> cases = new ArrayList<>();
11.205 - DynamicResourceHandler prev;
11.206 - @Override
11.207 - public void service(Request request, Response response) throws Exception {
11.208 - String id = request.getParameter("request");
11.209 - String value = request.getParameter("result");
11.210 - if (value != null && value.indexOf((char)0xC5) != -1) {
11.211 - value = toUTF8(value);
11.212 - }
11.213 -
11.214 -
11.215 - InvocationContext mi = null;
11.216 - int caseNmbr = -1;
11.217 -
11.218 - if (id != null && value != null) {
11.219 - LOG.log(Level.INFO, "Received result for case {0} = {1}", new Object[]{id, value});
11.220 - value = decodeURL(value);
11.221 - int indx = Integer.parseInt(id);
11.222 - cases.get(indx).result(value, null);
11.223 - if (++indx < cases.size()) {
11.224 - mi = cases.get(indx);
11.225 - LOG.log(Level.INFO, "Re-executing case {0}", indx);
11.226 - caseNmbr = indx;
11.227 - }
11.228 - } else {
11.229 - if (!cases.isEmpty()) {
11.230 - LOG.info("Re-executing test cases");
11.231 - mi = cases.get(0);
11.232 - caseNmbr = 0;
11.233 - }
11.234 - }
11.235 -
11.236 - if (prev != null) {
11.237 - prev.close();
11.238 - prev = null;
11.239 - }
11.240 -
11.241 - if (mi == null) {
11.242 - mi = methods.take();
11.243 - caseNmbr = cnt++;
11.244 - }
11.245 - if (mi == END) {
11.246 - response.getWriter().write("");
11.247 - wait.countDown();
11.248 - cnt = 0;
11.249 - LOG.log(Level.INFO, "End of data reached. Exiting.");
11.250 - return;
11.251 - }
11.252 -
11.253 - if (!mi.resources.isEmpty()) {
11.254 - prev = new DynamicResourceHandler(mi);
11.255 - }
11.256 -
11.257 - cases.add(mi);
11.258 - final String cn = mi.clazz.getName();
11.259 - final String mn = mi.methodName;
11.260 - LOG.log(Level.INFO, "Request for {0} case. Sending {1}.{2}", new Object[]{caseNmbr, cn, mn});
11.261 - response.getWriter().write("{"
11.262 - + "className: '" + cn + "', "
11.263 - + "methodName: '" + mn + "', "
11.264 - + "request: " + caseNmbr
11.265 - );
11.266 - if (mi.html != null) {
11.267 - response.getWriter().write(", html: '");
11.268 - response.getWriter().write(encodeJSON(mi.html));
11.269 - response.getWriter().write("'");
11.270 - }
11.271 - response.getWriter().write("}");
11.272 - }
11.273 - }, "/data");
11.274 -
11.275 - this.brwsr = launchServerAndBrwsr(server, "/execute");
11.276 - }
11.277 -
11.278 - private static String encodeJSON(String in) {
11.279 - StringBuilder sb = new StringBuilder();
11.280 - for (int i = 0; i < in.length(); i++) {
11.281 - char ch = in.charAt(i);
11.282 - if (ch < 32 || ch == '\'' || ch == '"') {
11.283 - sb.append("\\u");
11.284 - String hs = "0000" + Integer.toHexString(ch);
11.285 - hs = hs.substring(hs.length() - 4);
11.286 - sb.append(hs);
11.287 - } else {
11.288 - sb.append(ch);
11.289 - }
11.290 - }
11.291 - return sb.toString();
11.292 - }
11.293 -
11.294 - @Override
11.295 - public void shutdown() throws IOException {
11.296 - methods.offer(END);
11.297 - for (;;) {
11.298 - int prev = methods.size();
11.299 - try {
11.300 - if (wait != null && wait.await(timeOut, TimeUnit.MILLISECONDS)) {
11.301 - break;
11.302 - }
11.303 - } catch (InterruptedException ex) {
11.304 - throw new IOException(ex);
11.305 - }
11.306 - if (prev == methods.size()) {
11.307 - LOG.log(
11.308 - Level.WARNING,
11.309 - "Timeout and no test has been executed meanwhile (at {0}). Giving up.",
11.310 - methods.size()
11.311 - );
11.312 - break;
11.313 - }
11.314 - LOG.log(Level.INFO,
11.315 - "Timeout, but tests got from {0} to {1}. Trying again.",
11.316 - new Object[]{prev, methods.size()}
11.317 - );
11.318 - }
11.319 - stopServerAndBrwsr(server, brwsr);
11.320 - }
11.321 -
11.322 - static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
11.323 - for (;;) {
11.324 - int ch = is.read();
11.325 - if (ch == -1) {
11.326 - break;
11.327 - }
11.328 - if (ch == '$' && params.length > 0) {
11.329 - int cnt = is.read() - '0';
11.330 - if (baseURL != null && cnt == 'U' - '0') {
11.331 - os.write(baseURL.getBytes("UTF-8"));
11.332 - } else {
11.333 - if (cnt >= 0 && cnt < params.length) {
11.334 - os.write(params[cnt].getBytes("UTF-8"));
11.335 - } else {
11.336 - os.write('$');
11.337 - os.write(cnt + '0');
11.338 - }
11.339 - }
11.340 - } else {
11.341 - os.write(ch);
11.342 - }
11.343 - }
11.344 - }
11.345 -
11.346 - private Object[] launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException {
11.347 - server.start();
11.348 - NetworkListener listener = server.getListeners().iterator().next();
11.349 - int port = listener.getPort();
11.350 -
11.351 - URI uri = new URI("http://localhost:" + port + page);
11.352 - LOG.log(Level.INFO, "Showing {0}", uri);
11.353 - if (cmd == null) {
11.354 - try {
11.355 - LOG.log(Level.INFO, "Trying Desktop.browse on {0} {2} by {1}", new Object[] {
11.356 - System.getProperty("java.vm.name"),
11.357 - System.getProperty("java.vm.vendor"),
11.358 - System.getProperty("java.vm.version"),
11.359 - });
11.360 - java.awt.Desktop.getDesktop().browse(uri);
11.361 - LOG.log(Level.INFO, "Desktop.browse successfully finished");
11.362 - return null;
11.363 - } catch (UnsupportedOperationException ex) {
11.364 - LOG.log(Level.INFO, "Desktop.browse not supported: {0}", ex.getMessage());
11.365 - LOG.log(Level.FINE, null, ex);
11.366 - }
11.367 - }
11.368 - {
11.369 - String cmdName = cmd == null ? "xdg-open" : cmd;
11.370 - String[] cmdArr = {
11.371 - cmdName, uri.toString()
11.372 - };
11.373 - LOG.log(Level.INFO, "Launching {0}", Arrays.toString(cmdArr));
11.374 - final Process process = Runtime.getRuntime().exec(cmdArr);
11.375 - return new Object[] { process, null };
11.376 - }
11.377 - }
11.378 - private static String toUTF8(String value) throws UnsupportedEncodingException {
11.379 - byte[] arr = new byte[value.length()];
11.380 - for (int i = 0; i < arr.length; i++) {
11.381 - arr[i] = (byte)value.charAt(i);
11.382 - }
11.383 - return new String(arr, "UTF-8");
11.384 - }
11.385 -
11.386 - private static String decodeURL(String s) {
11.387 - for (;;) {
11.388 - int pos = s.indexOf('%');
11.389 - if (pos == -1) {
11.390 - return s;
11.391 - }
11.392 - int i = Integer.parseInt(s.substring(pos + 1, pos + 2), 16);
11.393 - s = s.substring(0, pos) + (char)i + s.substring(pos + 2);
11.394 - }
11.395 - }
11.396 -
11.397 - private void stopServerAndBrwsr(HttpServer server, Object[] brwsr) throws IOException {
11.398 - if (brwsr == null) {
11.399 - return;
11.400 - }
11.401 - Process process = (Process)brwsr[0];
11.402 -
11.403 - server.stop();
11.404 - InputStream stdout = process.getInputStream();
11.405 - InputStream stderr = process.getErrorStream();
11.406 - drain("StdOut", stdout);
11.407 - drain("StdErr", stderr);
11.408 - process.destroy();
11.409 - int res;
11.410 - try {
11.411 - res = process.waitFor();
11.412 - } catch (InterruptedException ex) {
11.413 - throw new IOException(ex);
11.414 - }
11.415 - LOG.log(Level.INFO, "Exit code: {0}", res);
11.416 -
11.417 - deleteTree((File)brwsr[1]);
11.418 - }
11.419 -
11.420 - private static void drain(String name, InputStream is) throws IOException {
11.421 - int av = is.available();
11.422 - if (av > 0) {
11.423 - StringBuilder sb = new StringBuilder();
11.424 - sb.append("v== ").append(name).append(" ==v\n");
11.425 - while (av-- > 0) {
11.426 - sb.append((char)is.read());
11.427 - }
11.428 - sb.append("\n^== ").append(name).append(" ==^");
11.429 - LOG.log(Level.INFO, sb.toString());
11.430 - }
11.431 - }
11.432 -
11.433 - private void deleteTree(File file) {
11.434 - if (file == null) {
11.435 - return;
11.436 - }
11.437 - File[] arr = file.listFiles();
11.438 - if (arr != null) {
11.439 - for (File s : arr) {
11.440 - deleteTree(s);
11.441 - }
11.442 - }
11.443 - file.delete();
11.444 - }
11.445 -
11.446 - @Override
11.447 - public void close() throws IOException {
11.448 - shutdown();
11.449 - }
11.450 -
11.451 - private class Res implements Bck2Brwsr.Resources {
11.452 - @Override
11.453 - public InputStream get(String resource) throws IOException {
11.454 - for (ClassLoader l : loaders) {
11.455 - URL u = null;
11.456 - Enumeration<URL> en = l.getResources(resource);
11.457 - while (en.hasMoreElements()) {
11.458 - u = en.nextElement();
11.459 - }
11.460 - if (u != null) {
11.461 - return u.openStream();
11.462 - }
11.463 - }
11.464 - throw new IOException("Can't find " + resource);
11.465 - }
11.466 - }
11.467 -
11.468 - private static class Page extends HttpHandler {
11.469 - final String resource;
11.470 - private final String[] args;
11.471 - private final Res res;
11.472 -
11.473 - public Page(Res res, String resource, String... args) {
11.474 - this.res = res;
11.475 - this.resource = resource;
11.476 - this.args = args.length == 0 ? new String[] { "$0" } : args;
11.477 - }
11.478 -
11.479 - @Override
11.480 - public void service(Request request, Response response) throws Exception {
11.481 - String r = computePage(request);
11.482 - if (r.startsWith("/")) {
11.483 - r = r.substring(1);
11.484 - }
11.485 - String[] replace = {};
11.486 - if (r.endsWith(".html")) {
11.487 - response.setContentType("text/html");
11.488 - LOG.info("Content type text/html");
11.489 - replace = args;
11.490 - }
11.491 - if (r.endsWith(".xhtml")) {
11.492 - response.setContentType("application/xhtml+xml");
11.493 - LOG.info("Content type application/xhtml+xml");
11.494 - replace = args;
11.495 - }
11.496 - OutputStream os = response.getOutputStream();
11.497 - try (InputStream is = res.get(r)) {
11.498 - copyStream(is, os, request.getRequestURL().toString(), replace);
11.499 - } catch (IOException ex) {
11.500 - response.setDetailMessage(ex.getLocalizedMessage());
11.501 - response.setError();
11.502 - response.setStatus(404);
11.503 - }
11.504 - }
11.505 -
11.506 - protected String computePage(Request request) {
11.507 - String r = resource;
11.508 - if (r == null) {
11.509 - r = request.getHttpHandlerPath();
11.510 - }
11.511 - return r;
11.512 - }
11.513 - }
11.514 -
11.515 - private static class SubTree extends Page {
11.516 -
11.517 - public SubTree(Res res, String resource, String... args) {
11.518 - super(res, resource, args);
11.519 - }
11.520 -
11.521 - @Override
11.522 - protected String computePage(Request request) {
11.523 - return resource + request.getHttpHandlerPath();
11.524 - }
11.525 -
11.526 -
11.527 - }
11.528 -
11.529 - private static class VM extends HttpHandler {
11.530 - private final String bck2brwsr;
11.531 -
11.532 - public VM(Res loader) throws IOException {
11.533 - StringBuilder sb = new StringBuilder();
11.534 - Bck2Brwsr.generate(sb, loader);
11.535 - sb.append(
11.536 - "(function WrapperVM(global) {"
11.537 - + " function ldCls(res) {\n"
11.538 - + " var request = new XMLHttpRequest();\n"
11.539 - + " request.open('GET', '/classes/' + res, false);\n"
11.540 - + " request.send();\n"
11.541 - + " if (request.status !== 200) return null;\n"
11.542 - + " var arr = eval('(' + request.responseText + ')');\n"
11.543 - + " return arr;\n"
11.544 - + " }\n"
11.545 - + " var prevvm = global.bck2brwsr;\n"
11.546 - + " global.bck2brwsr = function() {\n"
11.547 - + " var args = Array.prototype.slice.apply(arguments);\n"
11.548 - + " args.unshift(ldCls);\n"
11.549 - + " return prevvm.apply(null, args);\n"
11.550 - + " };\n"
11.551 - + "})(this);\n"
11.552 - );
11.553 - this.bck2brwsr = sb.toString();
11.554 - }
11.555 -
11.556 - @Override
11.557 - public void service(Request request, Response response) throws Exception {
11.558 - response.setCharacterEncoding("UTF-8");
11.559 - response.setContentType("text/javascript");
11.560 - response.getWriter().write(bck2brwsr);
11.561 - }
11.562 - }
11.563 -
11.564 - private static class Classes extends HttpHandler {
11.565 - private final Res loader;
11.566 -
11.567 - public Classes(Res loader) {
11.568 - this.loader = loader;
11.569 - }
11.570 -
11.571 - @Override
11.572 - public void service(Request request, Response response) throws Exception {
11.573 - String res = request.getHttpHandlerPath();
11.574 - if (res.startsWith("/")) {
11.575 - res = res.substring(1);
11.576 - }
11.577 - try (InputStream is = loader.get(res)) {
11.578 - response.setContentType("text/javascript");
11.579 - Writer w = response.getWriter();
11.580 - w.append("[");
11.581 - for (int i = 0;; i++) {
11.582 - int b = is.read();
11.583 - if (b == -1) {
11.584 - break;
11.585 - }
11.586 - if (i > 0) {
11.587 - w.append(", ");
11.588 - }
11.589 - if (i % 20 == 0) {
11.590 - w.write("\n");
11.591 - }
11.592 - if (b > 127) {
11.593 - b = b - 256;
11.594 - }
11.595 - w.append(Integer.toString(b));
11.596 - }
11.597 - w.append("\n]");
11.598 - } catch (IOException ex) {
11.599 - response.setStatus(HttpStatus.NOT_FOUND_404);
11.600 - response.setError();
11.601 - response.setDetailMessage(ex.getMessage());
11.602 - }
11.603 - }
11.604 - }
11.605 -}
12.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java Sun Apr 28 09:46:23 2013 +0200
12.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
12.3 @@ -1,115 +0,0 @@
12.4 -/**
12.5 - * Back 2 Browser Bytecode Translator
12.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
12.7 - *
12.8 - * This program is free software: you can redistribute it and/or modify
12.9 - * it under the terms of the GNU General Public License as published by
12.10 - * the Free Software Foundation, version 2 of the License.
12.11 - *
12.12 - * This program is distributed in the hope that it will be useful,
12.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
12.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12.15 - * GNU General Public License for more details.
12.16 - *
12.17 - * You should have received a copy of the GNU General Public License
12.18 - * along with this program. Look for COPYING file in the top folder.
12.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
12.20 - */
12.21 -package org.apidesign.bck2brwsr.launcher;
12.22 -
12.23 -import java.io.IOException;
12.24 -import java.io.InputStream;
12.25 -import java.util.ArrayList;
12.26 -import java.util.List;
12.27 -import java.util.concurrent.CountDownLatch;
12.28 -import java.util.concurrent.TimeUnit;
12.29 -
12.30 -/** Represents individual method invocation, its context and its result.
12.31 - *
12.32 - * @author Jaroslav Tulach <jtulach@netbeans.org>
12.33 - */
12.34 -public final class InvocationContext {
12.35 - final CountDownLatch wait = new CountDownLatch(1);
12.36 - final Class<?> clazz;
12.37 - final String methodName;
12.38 - private final Launcher launcher;
12.39 - private String result;
12.40 - private Throwable exception;
12.41 - String html;
12.42 - final List<Resource> resources = new ArrayList<>();
12.43 -
12.44 - InvocationContext(Launcher launcher, Class<?> clazz, String methodName) {
12.45 - this.launcher = launcher;
12.46 - this.clazz = clazz;
12.47 - this.methodName = methodName;
12.48 - }
12.49 -
12.50 - /** An HTML fragment to be available for the execution. Useful primarily when
12.51 - * executing in a browser via {@link Launcher#createBrowser(java.lang.String)}.
12.52 - * @param html the html fragment
12.53 - */
12.54 - public void setHtmlFragment(String html) {
12.55 - this.html = html;
12.56 - }
12.57 -
12.58 - /** HTTP resource to be available during execution. An invocation may
12.59 - * perform an HTTP query and obtain a resource relative to the page.
12.60 - */
12.61 - public void addHttpResource(String relativePath, String mimeType, String[] parameters, InputStream content) {
12.62 - if (relativePath == null || mimeType == null || content == null || parameters == null) {
12.63 - throw new NullPointerException();
12.64 - }
12.65 - resources.add(new Resource(content, mimeType, relativePath, parameters));
12.66 - }
12.67 -
12.68 - /** Invokes the associated method.
12.69 - * @return the textual result of the invocation
12.70 - */
12.71 - public String invoke() throws IOException {
12.72 - launcher.runMethod(this);
12.73 - return toString();
12.74 - }
12.75 -
12.76 - /** Obtains textual result of the invocation.
12.77 - * @return text representing the exception or result value
12.78 - */
12.79 - @Override
12.80 - public String toString() {
12.81 - if (exception != null) {
12.82 - return exception.toString();
12.83 - }
12.84 - return result;
12.85 - }
12.86 -
12.87 - /**
12.88 - * @param timeOut
12.89 - * @throws InterruptedException
12.90 - */
12.91 - void await(long timeOut) throws InterruptedException {
12.92 - wait.await(timeOut, TimeUnit.MILLISECONDS);
12.93 - }
12.94 -
12.95 - void result(String r, Throwable e) {
12.96 - this.result = r;
12.97 - this.exception = e;
12.98 - wait.countDown();
12.99 - }
12.100 -
12.101 -
12.102 - static final class Resource {
12.103 - final InputStream httpContent;
12.104 - final String httpType;
12.105 - final String httpPath;
12.106 - final String[] parameters;
12.107 -
12.108 - Resource(InputStream httpContent, String httpType, String httpPath,
12.109 - String[] parameters
12.110 - ) {
12.111 - httpContent.mark(Integer.MAX_VALUE);
12.112 - this.httpContent = httpContent;
12.113 - this.httpType = httpType;
12.114 - this.httpPath = httpPath;
12.115 - this.parameters = parameters;
12.116 - }
12.117 - }
12.118 -}
13.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Sun Apr 28 09:46:23 2013 +0200
13.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
13.3 @@ -1,132 +0,0 @@
13.4 -/**
13.5 - * Back 2 Browser Bytecode Translator
13.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
13.7 - *
13.8 - * This program is free software: you can redistribute it and/or modify
13.9 - * it under the terms of the GNU General Public License as published by
13.10 - * the Free Software Foundation, version 2 of the License.
13.11 - *
13.12 - * This program is distributed in the hope that it will be useful,
13.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
13.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13.15 - * GNU General Public License for more details.
13.16 - *
13.17 - * You should have received a copy of the GNU General Public License
13.18 - * along with this program. Look for COPYING file in the top folder.
13.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
13.20 - */
13.21 -package org.apidesign.bck2brwsr.launcher;
13.22 -
13.23 -import org.apidesign.bck2brwsr.launcher.impl.Console;
13.24 -import java.io.IOException;
13.25 -import java.io.InputStream;
13.26 -import java.net.URL;
13.27 -import java.util.Enumeration;
13.28 -import java.util.LinkedHashSet;
13.29 -import java.util.Set;
13.30 -import java.util.logging.Level;
13.31 -import java.util.logging.Logger;
13.32 -import javax.script.Invocable;
13.33 -import javax.script.ScriptEngine;
13.34 -import javax.script.ScriptEngineManager;
13.35 -import javax.script.ScriptException;
13.36 -import org.apidesign.vm4brwsr.Bck2Brwsr;
13.37 -
13.38 -/**
13.39 - * Tests execution in Java's internal scripting engine.
13.40 - */
13.41 -final class JSLauncher extends Launcher {
13.42 - private static final Logger LOG = Logger.getLogger(JSLauncher.class.getName());
13.43 - private Set<ClassLoader> loaders = new LinkedHashSet<>();
13.44 - private final Res resources = new Res();
13.45 - private Invocable code;
13.46 - private StringBuilder codeSeq;
13.47 - private Object console;
13.48 -
13.49 -
13.50 - @Override InvocationContext runMethod(InvocationContext mi) {
13.51 - loaders.add(mi.clazz.getClassLoader());
13.52 - try {
13.53 - long time = System.currentTimeMillis();
13.54 - LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.clazz.getName(), mi.methodName});
13.55 - String res = code.invokeMethod(
13.56 - console,
13.57 - "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2",
13.58 - mi.clazz.getName(), mi.methodName).toString();
13.59 - time = System.currentTimeMillis() - time;
13.60 - LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.clazz.getName(), mi.methodName, res, time});
13.61 - mi.result(res, null);
13.62 - } catch (ScriptException | NoSuchMethodException ex) {
13.63 - mi.result(null, ex);
13.64 - }
13.65 - return mi;
13.66 - }
13.67 -
13.68 - public void addClassLoader(ClassLoader url) {
13.69 - this.loaders.add(url);
13.70 - }
13.71 -
13.72 - @Override
13.73 - public void initialize() throws IOException {
13.74 - try {
13.75 - initRhino();
13.76 - } catch (Exception ex) {
13.77 - if (ex instanceof IOException) {
13.78 - throw (IOException)ex;
13.79 - }
13.80 - if (ex instanceof RuntimeException) {
13.81 - throw (RuntimeException)ex;
13.82 - }
13.83 - throw new IOException(ex);
13.84 - }
13.85 - }
13.86 -
13.87 - private void initRhino() throws IOException, ScriptException, NoSuchMethodException {
13.88 - StringBuilder sb = new StringBuilder();
13.89 - Bck2Brwsr.generate(sb, new Res());
13.90 -
13.91 - ScriptEngineManager sem = new ScriptEngineManager();
13.92 - ScriptEngine mach = sem.getEngineByExtension("js");
13.93 -
13.94 - sb.append(
13.95 - "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.impl.Console.read);"
13.96 - + "\nfunction initVM() { return vm; };"
13.97 - + "\n");
13.98 -
13.99 - Object res = mach.eval(sb.toString());
13.100 - if (!(mach instanceof Invocable)) {
13.101 - throw new IOException("It is invocable object: " + res);
13.102 - }
13.103 - code = (Invocable) mach;
13.104 - codeSeq = sb;
13.105 -
13.106 - Object vm = code.invokeFunction("initVM");
13.107 - console = code.invokeMethod(vm, "loadClass", Console.class.getName());
13.108 - }
13.109 -
13.110 - @Override
13.111 - public void shutdown() throws IOException {
13.112 - }
13.113 -
13.114 - @Override
13.115 - public String toString() {
13.116 - return codeSeq.toString();
13.117 - }
13.118 -
13.119 - private class Res implements Bck2Brwsr.Resources {
13.120 - @Override
13.121 - public InputStream get(String resource) throws IOException {
13.122 - for (ClassLoader l : loaders) {
13.123 - URL u = null;
13.124 - Enumeration<URL> en = l.getResources(resource);
13.125 - while (en.hasMoreElements()) {
13.126 - u = en.nextElement();
13.127 - }
13.128 - if (u != null) {
13.129 - return u.openStream();
13.130 - }
13.131 - }
13.132 - throw new IOException("Can't find " + resource);
13.133 - }
13.134 - }
13.135 -}
14.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Sun Apr 28 09:46:23 2013 +0200
14.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
14.3 @@ -1,116 +0,0 @@
14.4 -/**
14.5 - * Back 2 Browser Bytecode Translator
14.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
14.7 - *
14.8 - * This program is free software: you can redistribute it and/or modify
14.9 - * it under the terms of the GNU General Public License as published by
14.10 - * the Free Software Foundation, version 2 of the License.
14.11 - *
14.12 - * This program is distributed in the hope that it will be useful,
14.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
14.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14.15 - * GNU General Public License for more details.
14.16 - *
14.17 - * You should have received a copy of the GNU General Public License
14.18 - * along with this program. Look for COPYING file in the top folder.
14.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
14.20 - */
14.21 -package org.apidesign.bck2brwsr.launcher;
14.22 -
14.23 -import java.io.Closeable;
14.24 -import java.io.File;
14.25 -import java.io.IOException;
14.26 -import org.apidesign.vm4brwsr.Bck2Brwsr;
14.27 -
14.28 -/** An abstraction for executing tests in a Bck2Brwsr virtual machine.
14.29 - * Either in {@linkm Launcher#createJavaScript JavaScript engine},
14.30 - * or in {@linkm Launcher#createBrowser external browser}.
14.31 - * <p>
14.32 - * There also are methods to {@link #showDir(java.io.File, java.lang.String) display pages}
14.33 - * in an external browser served by internal HTTP server.
14.34 - *
14.35 - * @author Jaroslav Tulach <jtulach@netbeans.org>
14.36 - */
14.37 -public abstract class Launcher {
14.38 -
14.39 - Launcher() {
14.40 - }
14.41 -
14.42 - /** Initializes the launcher. This may mean starting a web browser or
14.43 - * initializing execution engine.
14.44 - * @throws IOException if something goes wrong
14.45 - */
14.46 - public abstract void initialize() throws IOException;
14.47 -
14.48 - /** Shuts down the launcher.
14.49 - * @throws IOException if something goes wrong
14.50 - */
14.51 - public abstract void shutdown() throws IOException;
14.52 -
14.53 -
14.54 - /** Builds an invocation context. The context can later be customized
14.55 - * and {@link InvocationContext#invoke() invoked}.
14.56 - *
14.57 - * @param clazz the class to execute method from
14.58 - * @param method the method to execute
14.59 - * @return the context pointing to the selected method
14.60 - */
14.61 - public InvocationContext createInvocation(Class<?> clazz, String method) {
14.62 - return new InvocationContext(this, clazz, method);
14.63 - }
14.64 -
14.65 -
14.66 - /** Creates launcher that uses internal JavaScript engine (Rhino).
14.67 - * @return the launcher
14.68 - */
14.69 - public static Launcher createJavaScript() {
14.70 - final JSLauncher l = new JSLauncher();
14.71 - l.addClassLoader(Bck2Brwsr.class.getClassLoader());
14.72 - return l;
14.73 - }
14.74 -
14.75 - /** Creates launcher that is using external browser.
14.76 - *
14.77 - * @param cmd <code>null</code> to use <code>java.awt.Desktop</code> to show the launcher
14.78 - * or a string to execute in an external process (with a parameter to the URL)
14.79 - * @return launcher executing in external browser.
14.80 - */
14.81 - public static Launcher createBrowser(String cmd) {
14.82 - final Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(cmd);
14.83 - l.addClassLoader(Bck2Brwsr.class.getClassLoader());
14.84 - l.setTimeout(180000);
14.85 - return l;
14.86 - }
14.87 -
14.88 - /** Starts an HTTP server which provides access to classes and resources
14.89 - * available in the <code>classes</code> URL and shows a start page
14.90 - * available as {@link ClassLoader#getResource(java.lang.String)} from the
14.91 - * provide classloader. Opens a browser with URL showing the start page.
14.92 - *
14.93 - * @param classes classloader offering access to classes and resources
14.94 - * @param startpage page to show in the browser
14.95 - * @return interface that allows one to stop the server
14.96 - * @throws IOException if something goes wrong
14.97 - */
14.98 - public static Closeable showURL(ClassLoader classes, String startpage) throws IOException {
14.99 - Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(null);
14.100 - l.addClassLoader(classes);
14.101 - l.showURL(startpage);
14.102 - return l;
14.103 - }
14.104 - /** Starts an HTTP server which provides access to certain directory.
14.105 - * The <code>startpage</code> should be relative location inside the root
14.106 - * directory. Opens a browser with URL showing the start page.
14.107 - *
14.108 - * @param directory the root directory on disk
14.109 - * @param startpage relative path from the root to the page
14.110 - * @exception IOException if something goes wrong.
14.111 - */
14.112 - public static Closeable showDir(File directory, String startpage) throws IOException {
14.113 - Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(null);
14.114 - l.showDirectory(directory, startpage);
14.115 - return l;
14.116 - }
14.117 -
14.118 - abstract InvocationContext runMethod(InvocationContext c) throws IOException;
14.119 -}
15.1 --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java Sun Apr 28 09:46:23 2013 +0200
15.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
15.3 @@ -1,356 +0,0 @@
15.4 -/**
15.5 - * Back 2 Browser Bytecode Translator
15.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
15.7 - *
15.8 - * This program is free software: you can redistribute it and/or modify
15.9 - * it under the terms of the GNU General Public License as published by
15.10 - * the Free Software Foundation, version 2 of the License.
15.11 - *
15.12 - * This program is distributed in the hope that it will be useful,
15.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
15.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15.15 - * GNU General Public License for more details.
15.16 - *
15.17 - * You should have received a copy of the GNU General Public License
15.18 - * along with this program. Look for COPYING file in the top folder.
15.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
15.20 - */
15.21 -package org.apidesign.bck2brwsr.launcher.impl;
15.22 -
15.23 -import java.io.IOException;
15.24 -import java.io.InputStream;
15.25 -import java.io.UnsupportedEncodingException;
15.26 -import java.lang.reflect.InvocationTargetException;
15.27 -import java.lang.reflect.Method;
15.28 -import java.lang.reflect.Modifier;
15.29 -import java.net.URL;
15.30 -import java.util.Enumeration;
15.31 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
15.32 -
15.33 -/**
15.34 - *
15.35 - * @author Jaroslav Tulach <jtulach@netbeans.org>
15.36 - */
15.37 -public class Console {
15.38 - private Console() {
15.39 - }
15.40 - static {
15.41 - turnAssetionStatusOn();
15.42 - }
15.43 -
15.44 - @JavaScriptBody(args = {"id", "attr"}, body =
15.45 - "return window.document.getElementById(id)[attr].toString();")
15.46 - private static native Object getAttr(String id, String attr);
15.47 - @JavaScriptBody(args = {"elem", "attr"}, body =
15.48 - "return elem[attr].toString();")
15.49 - private static native Object getAttr(Object elem, String attr);
15.50 -
15.51 - @JavaScriptBody(args = {"id", "attr", "value"}, body =
15.52 - "window.document.getElementById(id)[attr] = value;")
15.53 - private static native void setAttr(String id, String attr, Object value);
15.54 - @JavaScriptBody(args = {"elem", "attr", "value"}, body =
15.55 - "elem[attr] = value;")
15.56 - private static native void setAttr(Object id, String attr, Object value);
15.57 -
15.58 - @JavaScriptBody(args = {}, body = "return; window.close();")
15.59 - private static native void closeWindow();
15.60 -
15.61 - private static Object textArea;
15.62 - private static Object statusArea;
15.63 -
15.64 - private static void log(String newText) {
15.65 - if (textArea == null) {
15.66 - return;
15.67 - }
15.68 - String attr = "value";
15.69 - setAttr(textArea, attr, getAttr(textArea, attr) + "\n" + newText);
15.70 - setAttr(textArea, "scrollTop", getAttr(textArea, "scrollHeight"));
15.71 - }
15.72 -
15.73 - private static void beginTest(Case c) {
15.74 - Object[] arr = new Object[2];
15.75 - beginTest(c.getClassName() + "." + c.getMethodName(), c, arr);
15.76 - textArea = arr[0];
15.77 - statusArea = arr[1];
15.78 - }
15.79 -
15.80 - private static void finishTest(Case c, Object res) {
15.81 - if ("null".equals(res)) {
15.82 - setAttr(statusArea, "innerHTML", "Success");
15.83 - } else {
15.84 - setAttr(statusArea, "innerHTML", "Result " + res);
15.85 - }
15.86 - statusArea = null;
15.87 - textArea = null;
15.88 - }
15.89 -
15.90 - @JavaScriptBody(args = { "test", "c", "arr" }, body =
15.91 - "var ul = window.document.getElementById('bck2brwsr.result');\n"
15.92 - + "var li = window.document.createElement('li');\n"
15.93 - + "var span = window.document.createElement('span');"
15.94 - + "span.innerHTML = test + ' - ';\n"
15.95 - + "var details = window.document.createElement('a');\n"
15.96 - + "details.innerHTML = 'Details';\n"
15.97 - + "details.href = '#';\n"
15.98 - + "var p = window.document.createElement('p');\n"
15.99 - + "var status = window.document.createElement('a');\n"
15.100 - + "status.innerHTML = 'running';"
15.101 - + "details.onclick = function() { li.appendChild(p); li.removeChild(details); status.innerHTML = 'Run Again'; status.href = '#'; };\n"
15.102 - + "status.onclick = function() { c.again__V_3Ljava_lang_Object_2(arr); }\n"
15.103 - + "var pre = window.document.createElement('textarea');\n"
15.104 - + "pre.cols = 100;"
15.105 - + "pre.rows = 10;"
15.106 - + "li.appendChild(span);\n"
15.107 - + "li.appendChild(status);\n"
15.108 - + "var span = window.document.createElement('span');"
15.109 - + "span.innerHTML = ' ';\n"
15.110 - + "li.appendChild(span);\n"
15.111 - + "li.appendChild(details);\n"
15.112 - + "p.appendChild(pre);\n"
15.113 - + "ul.appendChild(li);\n"
15.114 - + "arr[0] = pre;\n"
15.115 - + "arr[1] = status;\n"
15.116 - )
15.117 - private static native void beginTest(String test, Case c, Object[] arr);
15.118 -
15.119 - @JavaScriptBody(args = { "url", "callback", "arr" }, body = ""
15.120 - + "var request = new XMLHttpRequest();\n"
15.121 - + "request.open('GET', url, true);\n"
15.122 - + "request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n"
15.123 - + "request.onreadystatechange = function() {\n"
15.124 - + " if (this.readyState!==4) return;\n"
15.125 - + " arr[0] = this.responseText;\n"
15.126 - + " callback.run__V();\n"
15.127 - + "};"
15.128 - + "request.send();"
15.129 - )
15.130 - private static native void loadText(String url, Runnable callback, String[] arr) throws IOException;
15.131 -
15.132 - public static void harness(String url) throws IOException {
15.133 - log("Connecting to " + url);
15.134 - Request r = new Request(url);
15.135 - }
15.136 -
15.137 - private static class Request implements Runnable {
15.138 - private final String[] arr = { null };
15.139 - private final String url;
15.140 - private Case c;
15.141 - private int retries;
15.142 -
15.143 - private Request(String url) throws IOException {
15.144 - this.url = url;
15.145 - loadText(url, this, arr);
15.146 - }
15.147 - private Request(String url, String u) throws IOException {
15.148 - this.url = url;
15.149 - loadText(u, this, arr);
15.150 - }
15.151 -
15.152 - @Override
15.153 - public void run() {
15.154 - try {
15.155 - if (c == null) {
15.156 - String data = arr[0];
15.157 -
15.158 - if (data == null) {
15.159 - log("Some error exiting");
15.160 - closeWindow();
15.161 - return;
15.162 - }
15.163 -
15.164 - if (data.isEmpty()) {
15.165 - log("No data, exiting");
15.166 - closeWindow();
15.167 - return;
15.168 - }
15.169 -
15.170 - c = Case.parseData(data);
15.171 - beginTest(c);
15.172 - log("Got \"" + data + "\"");
15.173 - } else {
15.174 - log("Processing \"" + arr[0] + "\" for " + retries + " time");
15.175 - }
15.176 - Object result = retries++ >= 10 ? "java.lang.InterruptedException:timeout" : c.runTest();
15.177 - finishTest(c, result);
15.178 -
15.179 - String u = url + "?request=" + c.getRequestId() + "&result=" + result;
15.180 - new Request(url, u);
15.181 - } catch (Exception ex) {
15.182 - if (ex instanceof InterruptedException) {
15.183 - log("Re-scheduling in 100ms");
15.184 - schedule(this, 100);
15.185 - return;
15.186 - }
15.187 - log(ex.getClass().getName() + ":" + ex.getMessage());
15.188 - }
15.189 - }
15.190 - }
15.191 -
15.192 - private static String encodeURL(String r) throws UnsupportedEncodingException {
15.193 - final String SPECIAL = "%$&+,/:;=?@";
15.194 - StringBuilder sb = new StringBuilder();
15.195 - byte[] utf8 = r.getBytes("UTF-8");
15.196 - for (int i = 0; i < utf8.length; i++) {
15.197 - int ch = utf8[i] & 0xff;
15.198 - if (ch < 32 || ch > 127 || SPECIAL.indexOf(ch) >= 0) {
15.199 - final String numbers = "0" + Integer.toHexString(ch);
15.200 - sb.append("%").append(numbers.substring(numbers.length() - 2));
15.201 - } else {
15.202 - if (ch == 32) {
15.203 - sb.append("+");
15.204 - } else {
15.205 - sb.append((char)ch);
15.206 - }
15.207 - }
15.208 - }
15.209 - return sb.toString();
15.210 - }
15.211 -
15.212 - static String invoke(String clazz, String method) throws
15.213 - ClassNotFoundException, InvocationTargetException, IllegalAccessException,
15.214 - InstantiationException, InterruptedException {
15.215 - final Object r = new Case(null).invokeMethod(clazz, method);
15.216 - return r == null ? "null" : r.toString().toString();
15.217 - }
15.218 -
15.219 - /** Helper method that inspects the classpath and loads given resource
15.220 - * (usually a class file). Used while running tests in Rhino.
15.221 - *
15.222 - * @param name resource name to find
15.223 - * @return the array of bytes in the given resource
15.224 - * @throws IOException I/O in case something goes wrong
15.225 - */
15.226 - public static byte[] read(String name) throws IOException {
15.227 - URL u = null;
15.228 - Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
15.229 - while (en.hasMoreElements()) {
15.230 - u = en.nextElement();
15.231 - }
15.232 - if (u == null) {
15.233 - throw new IOException("Can't find " + name);
15.234 - }
15.235 - try (InputStream is = u.openStream()) {
15.236 - byte[] arr;
15.237 - arr = new byte[is.available()];
15.238 - int offset = 0;
15.239 - while (offset < arr.length) {
15.240 - int len = is.read(arr, offset, arr.length - offset);
15.241 - if (len == -1) {
15.242 - throw new IOException("Can't read " + name);
15.243 - }
15.244 - offset += len;
15.245 - }
15.246 - return arr;
15.247 - }
15.248 - }
15.249 -
15.250 - @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
15.251 - private static void turnAssetionStatusOn() {
15.252 - }
15.253 -
15.254 - @JavaScriptBody(args = {"r", "time"}, body =
15.255 - "return window.setTimeout(function() { r.run__V(); }, time);")
15.256 - private static native Object schedule(Runnable r, int time);
15.257 -
15.258 - private static final class Case {
15.259 - private final Object data;
15.260 - private Object inst;
15.261 -
15.262 - private Case(Object data) {
15.263 - this.data = data;
15.264 - }
15.265 -
15.266 - public static Case parseData(String s) {
15.267 - return new Case(toJSON(s));
15.268 - }
15.269 -
15.270 - public String getMethodName() {
15.271 - return value("methodName", data);
15.272 - }
15.273 -
15.274 - public String getClassName() {
15.275 - return value("className", data);
15.276 - }
15.277 -
15.278 - public String getRequestId() {
15.279 - return value("request", data);
15.280 - }
15.281 -
15.282 - public String getHtmlFragment() {
15.283 - return value("html", data);
15.284 - }
15.285 -
15.286 - void again(Object[] arr) {
15.287 - try {
15.288 - textArea = arr[0];
15.289 - statusArea = arr[1];
15.290 - setAttr(textArea, "value", "");
15.291 - runTest();
15.292 - } catch (Exception ex) {
15.293 - log(ex.getClass().getName() + ":" + ex.getMessage());
15.294 - }
15.295 - }
15.296 -
15.297 - private Object runTest() throws IllegalAccessException,
15.298 - IllegalArgumentException, ClassNotFoundException, UnsupportedEncodingException,
15.299 - InvocationTargetException, InstantiationException, InterruptedException {
15.300 - if (this.getHtmlFragment() != null) {
15.301 - setAttr("bck2brwsr.fragment", "innerHTML", this.getHtmlFragment());
15.302 - }
15.303 - log("Invoking " + this.getClassName() + '.' + this.getMethodName() + " as request: " + this.getRequestId());
15.304 - Object result = invokeMethod(this.getClassName(), this.getMethodName());
15.305 - setAttr("bck2brwsr.fragment", "innerHTML", "");
15.306 - log("Result: " + result);
15.307 - result = encodeURL("" + result);
15.308 - log("Sending back: ...?request=" + this.getRequestId() + "&result=" + result);
15.309 - return result;
15.310 - }
15.311 -
15.312 - private Object invokeMethod(String clazz, String method)
15.313 - throws ClassNotFoundException, InvocationTargetException,
15.314 - InterruptedException, IllegalAccessException, IllegalArgumentException,
15.315 - InstantiationException {
15.316 - Method found = null;
15.317 - Class<?> c = Class.forName(clazz);
15.318 - for (Method m : c.getMethods()) {
15.319 - if (m.getName().equals(method)) {
15.320 - found = m;
15.321 - }
15.322 - }
15.323 - Object res;
15.324 - if (found != null) {
15.325 - try {
15.326 - if ((found.getModifiers() & Modifier.STATIC) != 0) {
15.327 - res = found.invoke(null);
15.328 - } else {
15.329 - if (inst == null) {
15.330 - inst = c.newInstance();
15.331 - }
15.332 - res = found.invoke(inst);
15.333 - }
15.334 - } catch (Throwable ex) {
15.335 - if (ex instanceof InvocationTargetException) {
15.336 - ex = ((InvocationTargetException) ex).getTargetException();
15.337 - }
15.338 - if (ex instanceof InterruptedException) {
15.339 - throw (InterruptedException)ex;
15.340 - }
15.341 - res = ex.getClass().getName() + ":" + ex.getMessage();
15.342 - }
15.343 - } else {
15.344 - res = "Can't find method " + method + " in " + clazz;
15.345 - }
15.346 - return res;
15.347 - }
15.348 -
15.349 - @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');")
15.350 - private static native Object toJSON(String s);
15.351 -
15.352 - @JavaScriptBody(args = {"p", "d"}, body =
15.353 - "var v = d[p];\n"
15.354 - + "if (typeof v === 'undefined') return null;\n"
15.355 - + "return v.toString();"
15.356 - )
15.357 - private static native String value(String p, Object d);
15.358 - }
15.359 -}
16.1 --- a/rt/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Sun Apr 28 09:46:23 2013 +0200
16.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
16.3 @@ -1,43 +0,0 @@
16.4 -<?xml version="1.0" encoding="UTF-8"?>
16.5 -<!--
16.6 -
16.7 - Back 2 Browser Bytecode Translator
16.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
16.9 -
16.10 - This program is free software: you can redistribute it and/or modify
16.11 - it under the terms of the GNU General Public License as published by
16.12 - the Free Software Foundation, version 2 of the License.
16.13 -
16.14 - This program is distributed in the hope that it will be useful,
16.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
16.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16.17 - GNU General Public License for more details.
16.18 -
16.19 - You should have received a copy of the GNU General Public License
16.20 - along with this program. Look for COPYING file in the top folder.
16.21 - If not, see http://opensource.org/licenses/GPL-2.0.
16.22 -
16.23 --->
16.24 -<!DOCTYPE html>
16.25 -<html xmlns="http://www.w3.org/1999/xhtml">
16.26 - <head>
16.27 - <title>Bck2Brwsr Harness</title>
16.28 - </head>
16.29 - <body>
16.30 - <script src="/bck2brwsr.js"></script>
16.31 - <script>
16.32 - var vm = bck2brwsr();
16.33 - </script>
16.34 -
16.35 - <h1>Bck2Brwsr Execution Harness</h1>
16.36 -
16.37 - <ul id="bck2brwsr.result" style="width: 100%;" >
16.38 - </ul>
16.39 -
16.40 - <div id="bck2brwsr.fragment"/>
16.41 -
16.42 - <script type="text/javascript">
16.43 - vm.loadClass('org.apidesign.bck2brwsr.launcher.impl.Console').harness__VLjava_lang_String_2('$U/../data');
16.44 - </script>
16.45 - </body>
16.46 -</html>
17.1 --- a/rt/pom.xml Sun Apr 28 09:46:23 2013 +0200
17.2 +++ b/rt/pom.xml Sun Apr 28 10:14:31 2013 +0200
17.3 @@ -14,7 +14,6 @@
17.4 <modules>
17.5 <module>core</module>
17.6 <module>emul</module>
17.7 - <module>launcher</module>
17.8 <module>archetype</module>
17.9 <module>mojo</module>
17.10 <module>vm</module>