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@1033: import org.apidesign.bck2brwsr.launcher.impl.Console; jaroslav@1033: import java.io.IOException; jaroslav@1033: import java.io.InputStream; jaroslav@1033: import java.net.URL; jaroslav@1033: import java.util.Enumeration; jaroslav@1033: import java.util.LinkedHashSet; jaroslav@1033: import java.util.Set; jaroslav@1033: import java.util.logging.Level; jaroslav@1033: import java.util.logging.Logger; jaroslav@1033: import javax.script.Invocable; jaroslav@1033: import javax.script.ScriptEngine; jaroslav@1033: import javax.script.ScriptEngineManager; jaroslav@1033: import javax.script.ScriptException; jaroslav@1033: import org.apidesign.vm4brwsr.Bck2Brwsr; jaroslav@1033: jaroslav@1033: /** jaroslav@1033: * Tests execution in Java's internal scripting engine. jaroslav@1033: */ jaroslav@1033: final class JSLauncher extends Launcher { jaroslav@1033: private static final Logger LOG = Logger.getLogger(JSLauncher.class.getName()); jaroslav@1033: private Set loaders = new LinkedHashSet<>(); jaroslav@1033: private final Res resources = new Res(); jaroslav@1033: private Invocable code; jaroslav@1033: private StringBuilder codeSeq; jaroslav@1033: private Object console; jaroslav@1033: jaroslav@1033: JSLauncher() { jaroslav@1033: addClassLoader(Bck2Brwsr.class.getClassLoader()); jaroslav@1033: } jaroslav@1033: jaroslav@1033: @Override InvocationContext runMethod(InvocationContext mi) { jaroslav@1033: loaders.add(mi.clazz.getClassLoader()); jaroslav@1033: try { jaroslav@1033: long time = System.currentTimeMillis(); jaroslav@1033: LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.clazz.getName(), mi.methodName}); jaroslav@1033: String res = code.invokeMethod( jaroslav@1033: console, jaroslav@1033: "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2", jaroslav@1033: mi.clazz.getName(), mi.methodName).toString(); jaroslav@1033: time = System.currentTimeMillis() - time; jaroslav@1033: LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.clazz.getName(), mi.methodName, res, time}); jaroslav@1033: mi.result(res, null); jaroslav@1033: } catch (ScriptException | NoSuchMethodException ex) { jaroslav@1033: mi.result(null, ex); jaroslav@1033: } jaroslav@1033: return mi; jaroslav@1033: } jaroslav@1033: jaroslav@1033: public void addClassLoader(ClassLoader url) { jaroslav@1033: this.loaders.add(url); jaroslav@1033: } jaroslav@1033: jaroslav@1033: @Override jaroslav@1033: public void initialize() throws IOException { jaroslav@1033: try { jaroslav@1033: initRhino(); jaroslav@1033: } catch (Exception ex) { jaroslav@1033: if (ex instanceof IOException) { jaroslav@1033: throw (IOException)ex; jaroslav@1033: } jaroslav@1033: if (ex instanceof RuntimeException) { jaroslav@1033: throw (RuntimeException)ex; jaroslav@1033: } jaroslav@1033: throw new IOException(ex); jaroslav@1033: } jaroslav@1033: } jaroslav@1033: jaroslav@1033: private void initRhino() throws IOException, ScriptException, NoSuchMethodException { jaroslav@1033: StringBuilder sb = new StringBuilder(); jaroslav@1033: Bck2Brwsr.generate(sb, new Res()); jaroslav@1033: jaroslav@1033: ScriptEngineManager sem = new ScriptEngineManager(); jaroslav@1033: ScriptEngine mach = sem.getEngineByExtension("js"); jaroslav@1033: jaroslav@1033: sb.append( jaroslav@1033: "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.impl.Console.read);" jaroslav@1033: + "\nfunction initVM() { return vm; };" jaroslav@1033: + "\n"); jaroslav@1033: jaroslav@1033: Object res = mach.eval(sb.toString()); jaroslav@1033: if (!(mach instanceof Invocable)) { jaroslav@1033: throw new IOException("It is invocable object: " + res); jaroslav@1033: } jaroslav@1033: code = (Invocable) mach; jaroslav@1033: codeSeq = sb; jaroslav@1033: jaroslav@1033: Object vm = code.invokeFunction("initVM"); jaroslav@1033: console = code.invokeMethod(vm, "loadClass", Console.class.getName()); jaroslav@1033: } jaroslav@1033: jaroslav@1033: @Override jaroslav@1033: public void shutdown() throws IOException { jaroslav@1033: } jaroslav@1033: jaroslav@1033: @Override jaroslav@1033: public String toString() { jaroslav@1033: return codeSeq.toString(); jaroslav@1033: } jaroslav@1033: jaroslav@1033: private class Res implements Bck2Brwsr.Resources { jaroslav@1033: @Override jaroslav@1033: public InputStream get(String resource) throws IOException { jaroslav@1033: for (ClassLoader l : loaders) { jaroslav@1033: URL u = null; jaroslav@1033: Enumeration en = l.getResources(resource); jaroslav@1033: while (en.hasMoreElements()) { jaroslav@1033: u = en.nextElement(); jaroslav@1033: } jaroslav@1033: if (u != null) { jaroslav@1703: if (u.toExternalForm().contains("/rt.jar")) { jaroslav@1347: LOG.log(Level.WARNING, "No fallback to bootclasspath for {0}", u); jaroslav@1347: return null; jaroslav@1347: } jaroslav@1033: return u.openStream(); jaroslav@1033: } jaroslav@1033: } jaroslav@1033: throw new IOException("Can't find " + resource); jaroslav@1033: } jaroslav@1033: } jaroslav@1033: }