jaroslav@323: /** jaroslav@323: * Back 2 Browser Bytecode Translator jaroslav@323: * Copyright (C) 2012 Jaroslav Tulach jaroslav@323: * jaroslav@323: * This program is free software: you can redistribute it and/or modify jaroslav@323: * it under the terms of the GNU General Public License as published by jaroslav@323: * the Free Software Foundation, version 2 of the License. jaroslav@323: * jaroslav@323: * This program is distributed in the hope that it will be useful, jaroslav@323: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@323: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@323: * GNU General Public License for more details. jaroslav@323: * jaroslav@323: * You should have received a copy of the GNU General Public License jaroslav@323: * along with this program. Look for COPYING file in the top folder. jaroslav@323: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@323: */ jaroslav@323: package org.apidesign.bck2brwsr.launcher; jaroslav@323: jaroslav@622: import org.apidesign.bck2brwsr.launcher.impl.Console; jaroslav@331: import java.io.IOException; jaroslav@323: import java.io.InputStream; jaroslav@323: import java.net.URL; jaroslav@323: import java.util.Enumeration; jaroslav@348: import java.util.LinkedHashSet; jaroslav@348: import java.util.Set; jaroslav@595: import java.util.logging.Level; jaroslav@362: import java.util.logging.Logger; jaroslav@356: import javax.script.Invocable; jaroslav@356: import javax.script.ScriptEngine; jaroslav@356: import javax.script.ScriptEngineManager; jaroslav@356: import javax.script.ScriptException; jaroslav@323: import org.apidesign.vm4brwsr.Bck2Brwsr; jaroslav@323: jaroslav@323: /** jaroslav@370: * Tests execution in Java's internal scripting engine. jaroslav@323: */ jaroslav@382: final class JSLauncher extends Launcher { jaroslav@370: private static final Logger LOG = Logger.getLogger(JSLauncher.class.getName()); jaroslav@348: private Set loaders = new LinkedHashSet<>(); jaroslav@357: private final Res resources = new Res(); jaroslav@370: private Invocable code; jaroslav@396: private StringBuilder codeSeq; jaroslav@370: private Object console; jaroslav@348: jaroslav@348: jaroslav@622: @Override InvocationContext runMethod(InvocationContext mi) { jaroslav@622: loaders.add(mi.clazz.getClassLoader()); jaroslav@370: try { jaroslav@595: long time = System.currentTimeMillis(); jaroslav@622: LOG.log(Level.FINE, "Invoking {0}.{1}", new Object[]{mi.clazz.getName(), mi.methodName}); jaroslav@595: String res = code.invokeMethod( jaroslav@370: console, jaroslav@370: "invoke__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2", jaroslav@622: mi.clazz.getName(), mi.methodName).toString(); jaroslav@595: time = System.currentTimeMillis() - time; jaroslav@622: LOG.log(Level.FINE, "Resut of {0}.{1} = {2} in {3} ms", new Object[]{mi.clazz.getName(), mi.methodName, res, time}); jaroslav@595: mi.result(res, null); jaroslav@371: } catch (ScriptException | NoSuchMethodException ex) { jaroslav@371: mi.result(null, ex); jaroslav@370: } jaroslav@370: return mi; jaroslav@348: } jaroslav@348: jaroslav@357: public void addClassLoader(ClassLoader url) { jaroslav@357: this.loaders.add(url); jaroslav@357: } jaroslav@348: jaroslav@382: @Override jaroslav@370: public void initialize() throws IOException { jaroslav@356: try { jaroslav@370: initRhino(); jaroslav@356: } catch (Exception ex) { jaroslav@356: if (ex instanceof IOException) { jaroslav@356: throw (IOException)ex; jaroslav@356: } jaroslav@356: if (ex instanceof RuntimeException) { jaroslav@356: throw (RuntimeException)ex; jaroslav@356: } jaroslav@356: throw new IOException(ex); jaroslav@356: } jaroslav@356: } jaroslav@356: jaroslav@370: private void initRhino() throws IOException, ScriptException, NoSuchMethodException { jaroslav@356: StringBuilder sb = new StringBuilder(); jaroslav@356: Bck2Brwsr.generate(sb, new Res()); jaroslav@356: jaroslav@356: ScriptEngineManager sem = new ScriptEngineManager(); jaroslav@370: ScriptEngine mach = sem.getEngineByExtension("js"); jaroslav@356: jaroslav@356: sb.append( jaroslav@622: "\nvar vm = new bck2brwsr(org.apidesign.bck2brwsr.launcher.impl.Console.read);" jaroslav@356: + "\nfunction initVM() { return vm; };" jaroslav@356: + "\n"); jaroslav@356: jaroslav@356: Object res = mach.eval(sb.toString()); jaroslav@356: if (!(mach instanceof Invocable)) { jaroslav@356: throw new IOException("It is invocable object: " + res); jaroslav@356: } jaroslav@370: code = (Invocable) mach; jaroslav@396: codeSeq = sb; jaroslav@356: jaroslav@356: Object vm = code.invokeFunction("initVM"); jaroslav@370: console = code.invokeMethod(vm, "loadClass", Console.class.getName()); jaroslav@356: } jaroslav@382: jaroslav@382: @Override jaroslav@382: public void shutdown() throws IOException { jaroslav@382: } jaroslav@396: jaroslav@396: @Override jaroslav@396: public String toString() { jaroslav@396: return codeSeq.toString(); jaroslav@396: } jaroslav@356: jaroslav@348: private class Res implements Bck2Brwsr.Resources { jaroslav@348: @Override jaroslav@348: public InputStream get(String resource) throws IOException { jaroslav@348: for (ClassLoader l : loaders) { jaroslav@348: URL u = null; jaroslav@348: Enumeration en = l.getResources(resource); jaroslav@348: while (en.hasMoreElements()) { jaroslav@348: u = en.nextElement(); jaroslav@348: } jaroslav@348: if (u != null) { jaroslav@348: return u.openStream(); jaroslav@348: } jaroslav@348: } jaroslav@348: throw new IOException("Can't find " + resource); jaroslav@348: } jaroslav@348: } jaroslav@323: }