jaroslav@1033: /** jaroslav@1033: * Back 2 Browser Bytecode Translator jaroslav@1033: * Copyright (C) 2012 Jaroslav Tulach jaroslav@1033: * jaroslav@1033: * This program is free software: you can redistribute it and/or modify jaroslav@1033: * it under the terms of the GNU General Public License as published by jaroslav@1033: * the Free Software Foundation, version 2 of the License. jaroslav@1033: * jaroslav@1033: * This program is distributed in the hope that it will be useful, jaroslav@1033: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@1033: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@1033: * GNU General Public License for more details. jaroslav@1033: * jaroslav@1033: * You should have received a copy of the GNU General Public License jaroslav@1033: * along with this program. Look for COPYING file in the top folder. jaroslav@1033: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@1033: */ jaroslav@1033: package org.apidesign.bck2brwsr.launcher; jaroslav@1033: jaroslav@1371: import java.io.File; jaroslav@1033: import java.io.IOException; jaroslav@1371: import java.io.InputStreamReader; jaroslav@1371: import java.io.Reader; jaroslav@1389: import java.net.MalformedURLException; jaroslav@1599: import java.net.URISyntaxException; jaroslav@1371: import java.net.URL; jaroslav@1525: import java.util.HashSet; jaroslav@1525: import java.util.Set; jaroslav@1371: import java.util.logging.Level; jaroslav@1033: jaroslav@1033: /** jaroslav@1033: * Lightweight server to launch Bck2Brwsr applications and tests. jaroslav@1033: * Supports execution in native browser as well as Java's internal jaroslav@1033: * execution engine. jaroslav@1033: */ jaroslav@1088: final class Bck2BrwsrLauncher extends BaseHTTPLauncher { jaroslav@1525: private Set testClasses = new HashSet(); jaroslav@1033: jaroslav@1033: public Bck2BrwsrLauncher(String cmd) { jaroslav@1088: super(cmd); jaroslav@1033: } jaroslav@1033: jaroslav@1033: @Override jaroslav@1088: String harnessResource() { jaroslav@1088: return "org/apidesign/bck2brwsr/launcher/harness.xhtml"; jaroslav@1033: } jaroslav@1489: jaroslav@1489: @Override jaroslav@1599: String compileJar(URL jar) throws IOException { jaroslav@1599: File f; jaroslav@1599: try { jaroslav@1599: f = new File(jar.toURI()); jaroslav@1599: } catch (URISyntaxException ex) { jaroslav@1599: throw new IOException(ex); jaroslav@1599: } jaroslav@1599: return CompileCP.compileJAR(f, testClasses); jaroslav@1525: } jaroslav@1525: jaroslav@1525: @Override jaroslav@1525: public InvocationContext createInvocation(Class clazz, String method) { jaroslav@1525: testClasses.add(clazz.getName().replace('.', '/')); jaroslav@1525: return super.createInvocation(clazz, method); jaroslav@1489: } jaroslav@1489: jaroslav@1505: @Override String compileFromClassPath(URL f, Res loader) throws IOException { jaroslav@1505: return CompileCP.compileFromClassPath(f, loader); jaroslav@1489: } jaroslav@1033: jaroslav@1033: @Override jaroslav@1088: void generateBck2BrwsrJS(StringBuilder sb, final Res loader) throws IOException { jaroslav@1371: String b2b = System.getProperty("bck2brwsr.js"); jaroslav@1371: if (b2b != null) { jaroslav@1371: LOG.log(Level.INFO, "Serving bck2brwsr.js from {0}", b2b); jaroslav@1389: URL bu; jaroslav@1389: try { jaroslav@1389: bu = new URL(b2b); jaroslav@1389: } catch (MalformedURLException ex) { jaroslav@1389: File f = new File(b2b); jaroslav@1389: if (f.exists()) { jaroslav@1389: bu = f.toURI().toURL(); jaroslav@1389: } else { jaroslav@1389: throw ex; jaroslav@1389: } jaroslav@1389: } jaroslav@1389: try (Reader r = new InputStreamReader(bu.openStream())) { jaroslav@1371: char[] arr = new char[4096]; jaroslav@1371: for (;;) { jaroslav@1371: int len = r.read(arr); jaroslav@1371: if (len == -1) { jaroslav@1371: break; jaroslav@1371: } jaroslav@1371: sb.append(arr, 0, len); jaroslav@1371: } jaroslav@1371: } jaroslav@1371: } else { jaroslav@1371: LOG.log(Level.INFO, "Generating bck2brwsr.js from scratch", b2b); jaroslav@1513: CompileCP.compileVM(sb, loader); jaroslav@1371: } jaroslav@1088: sb.append( jaroslav@1390: "(function WrapperVM(global) {\n" jaroslav@1390: + " var cache = {};\n" jaroslav@1530: + " var empty = {};\n" jaroslav@1375: + " function ldCls(res, skip) {\n" jaroslav@1390: + " var c = cache[res];\n" jaroslav@1390: + " if (c) {\n" jaroslav@1530: + " if (c[skip] === empty) return null;\n" jaroslav@1390: + " if (c[skip]) return c[skip];\n" jaroslav@1390: + " } else {\n" jaroslav@1390: + " cache[res] = c = new Array();\n" jaroslav@1390: + " }\n" jaroslav@1088: + " var request = new XMLHttpRequest();\n" jaroslav@1375: + " request.open('GET', '/classes/' + res + '?skip=' + skip, false);\n" jaroslav@1088: + " request.send();\n" jaroslav@1390: + " if (request.status !== 200) {\n" jaroslav@1390: + " c[skip] = null;\n" jaroslav@1390: + " return null;\n" jaroslav@1390: + " }\n" jaroslav@1489: + " var arr = eval(request.responseText);\n" jaroslav@1531: + " if (arr === null) c[skip] = empty;\n" jaroslav@1531: + " else c[skip] = arr;\n" jaroslav@1088: + " return arr;\n" jaroslav@1088: + " }\n" jaroslav@1088: + " var prevvm = global.bck2brwsr;\n" jaroslav@1088: + " global.bck2brwsr = function() {\n" jaroslav@1088: + " var args = Array.prototype.slice.apply(arguments);\n" jaroslav@1088: + " args.unshift(ldCls);\n" jaroslav@1088: + " return prevvm.apply(null, args);\n" jaroslav@1088: + " };\n" jaroslav@1598: + " global.bck2brwsr.register = prevvm.register;\n" jaroslav@1088: + "})(this);\n" jaroslav@1088: ); jaroslav@1371: LOG.log(Level.INFO, "Serving bck2brwsr.js", b2b); jaroslav@1033: } jaroslav@1033: jaroslav@1033: }