# HG changeset patch # User Jaroslav Tulach # Date 1400748489 -7200 # Node ID 7b6295731c30cc31c4af9c3c1da1caa87ce21981 # Parent 89b6b369c13dc74161869f21a6568ec1c43e9dcf Static compilator demo is capable to load itself from individual extension files diff -r 89b6b369c13d -r 7b6295731c30 javaquery/demo-calculator/pom.xml --- a/javaquery/demo-calculator/pom.xml Wed May 21 23:42:24 2014 +0200 +++ b/javaquery/demo-calculator/pom.xml Thu May 22 10:48:09 2014 +0200 @@ -24,6 +24,7 @@ j2js + aot brwsr @@ -31,7 +32,8 @@ ${project.build.directory}/${project.build.finalName}-bck2brwsr/public_html/ index.xhtml - ${project.build.directory}/bck2brwsr.js + ${project.build.directory}/app.js + true ${bck2brwsr.obfuscationlevel} diff -r 89b6b369c13d -r 7b6295731c30 javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml --- a/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Wed May 21 23:42:24 2014 +0200 +++ b/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Thu May 22 10:48:09 2014 +0200 @@ -38,16 +38,23 @@ + + + ${project.build.directory} + / + + bck2brwsr.js + app.js + lib/*.js + + + ${project.build.directory}/${project.build.finalName}.jar / - ${project.build.directory}/bck2brwsr.js - / - - ${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml / index.xhtml diff -r 89b6b369c13d -r 7b6295731c30 javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml --- a/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Wed May 21 23:42:24 2014 +0200 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Thu May 22 10:48:09 2014 +0200 @@ -90,8 +90,11 @@
+ + + diff -r 89b6b369c13d -r 7b6295731c30 rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AheadOfTime.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AheadOfTime.java Thu May 22 10:48:09 2014 +0200 @@ -0,0 +1,199 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ + +package org.apidesign.bck2brwsr.mojo; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; +import org.apidesign.vm4brwsr.Bck2Brwsr; +import org.apidesign.vm4brwsr.ObfuscationLevel; + +/** + * + * @author Jaroslav Tulach + * @since 0.9 + */ +@Mojo(name = "aot", + requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, + defaultPhase = LifecyclePhase.PACKAGE +) +public class AheadOfTime extends AbstractMojo { + @Parameter(defaultValue = "${project}") + private MavenProject prj; + + /** + * Directory where to generate ahead-of-time JavaScript files for + * required libraries. + */ + @Parameter(defaultValue = "${project.build.directory}/lib") + private File aot; + + /** Root JavaScript file to generate */ + @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js") + private File vm; + + /** + * The obfuscation level for the generated JavaScript file. + * + * @since 0.5 + */ + @Parameter(defaultValue = "NONE") + private ObfuscationLevel obfuscation; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + try { + URLClassLoader loader = buildClassLoader(null, prj.getArtifacts()); + for (Artifact a : prj.getArtifacts()) { + if (a.getFile() == null) { + continue; + } + String n = a.getFile().getName(); + if (!n.endsWith(".jar")) { + continue; + } + aot.mkdirs(); + File js = new File(aot, n.substring(0, n.length() - 4) + ".js"); + aotLibrary(a, js , loader); + } + + FileWriter w = new FileWriter(vm); + Bck2Brwsr.newCompiler(). + obfuscation(obfuscation). + standalone(false). + resources(new Bck2Brwsr.Resources() { + + @Override + public InputStream get(String resource) throws IOException { + return null; + } + }). + generate(w); + w.close(); + + } catch (IOException ex) { + throw new MojoExecutionException("Can't compile", ex); + } + } + + private void aotLibrary(Artifact a, File js, URLClassLoader loader) throws IOException { + List classes = new ArrayList(); + List resources = new ArrayList(); + Set exported = new HashSet(); + + JarFile jf = new JarFile(a.getFile()); + listJAR(jf, classes , resources, exported); + + FileWriter w = new FileWriter(js); + Bck2Brwsr.newCompiler(). + obfuscation(obfuscation). + library(true). + resources(loader). + addResources(resources.toArray(new String[0])). + addClasses(classes.toArray(new String[0])). + addExported(exported.toArray(new String[0])). + generate(w); + w.close(); + } + private static URLClassLoader buildClassLoader(File root, Collection deps) throws MalformedURLException { + List arr = new ArrayList(); + if (root != null) { + arr.add(root.toURI().toURL()); + } + for (Artifact a : deps) { + if (a.getFile() != null) { + arr.add(a.getFile().toURI().toURL()); + } + } + return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader()); + } + + private static void listJAR( + JarFile j, List classes, + List resources, Set exported + ) throws IOException { + Enumeration en = j.entries(); + while (en.hasMoreElements()) { + JarEntry e = en.nextElement(); + final String n = e.getName(); + if (n.endsWith("/")) { + continue; + } + int last = n.lastIndexOf('/'); + String pkg = n.substring(0, last + 1); + if (n.endsWith(".class")) { + classes.add(n.substring(0, n.length() - 6)); + } else { + resources.add(n); + if (n.startsWith("META-INF/services/") && exported != null) { + final InputStream is = j.getInputStream(e); + exportedServices(is, exported); + is.close(); + } + } + } + String exp = j.getManifest().getMainAttributes().getValue("Export-Package"); + if (exp != null && exported != null) { + for (String def : exp.split(",")) { + for (String sep : def.split(";")) { + exported.add(sep.replace('.', '/') + "/"); + break; + } + } + } + } + + static void exportedServices(final InputStream is, Set exported) throws IOException { + BufferedReader r = new BufferedReader(new InputStreamReader(is)); + for (;;) { + String l = r.readLine(); + if (l == null) { + break; + } + if (l.startsWith("#")) { + continue; + } + exported.add(l.replace('.', '/')); + } + } + +} diff -r 89b6b369c13d -r 7b6295731c30 rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Wed May 21 23:42:24 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Thu May 22 10:48:09 2014 +0200 @@ -57,9 +57,13 @@ private final StringArray classes; private final StringArray resources; private final Resources res; - private final boolean extension; + private final Boolean extension; - private Bck2Brwsr(ObfuscationLevel level, StringArray exported, StringArray classes, StringArray resources, Resources res, boolean extension) { + private Bck2Brwsr( + ObfuscationLevel level, + StringArray exported, StringArray classes, StringArray resources, + Resources res, Boolean extension + ) { this.level = level; this.exported = exported; this.classes = classes; @@ -226,6 +230,19 @@ public Bck2Brwsr library(boolean library) { return new Bck2Brwsr(level, exported, classes, resources, res, library); } + + /** Turns on the standalone mode. E.g. acts like {@link #library(boolean) library(false)}, + * but also allows to specify whether the Bck2Brwsr VM should + * be included at all. If not, only the skeleton of the launcher is + * generated without any additional VM classes referenced. + * + * @param includeVM should the VM be compiled in, or left out + * @return new instance of the compiler with standalone mode on + * @since 0.9 + */ + public Bck2Brwsr standalone(boolean includeVM) { + return new Bck2Brwsr(level, exported, classes, resources, res, includeVM ? false : null); + } /** A way to change the provider of additional resources (classes) for the * compiler by specifying classloader to use for loading them. @@ -296,7 +313,11 @@ } boolean isExtension() { - return extension; + return Boolean.TRUE.equals(extension); + } + + boolean includeVM() { + return extension != null; } /** Provider of resources (classes and other files). The diff -r 89b6b369c13d -r 7b6295731c30 rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Wed May 21 23:42:24 2014 +0200 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Thu May 22 10:48:09 2014 +0200 @@ -35,12 +35,6 @@ private final ExportedSymbols exportedSymbols; private final StringArray invokerMethods; - private static final Class FIXED_DEPENDENCIES[] = { - Class.class, - ArithmeticException.class, - VM.class - }; - private VM(Appendable out, Bck2Brwsr.Resources resources, StringArray explicitlyExported) { super(out); this.resources = resources; @@ -69,17 +63,20 @@ ) throws IOException { String[] both = config.classes().toArray(); - VM vm = config.isExtension() ? - new Extension(out, config.getResources(), both, config.exported()) - : - new Standalone(out, config.getResources(), config.exported()); - final StringArray fixedNames = new StringArray(); - - for (final Class fixedClass: FIXED_DEPENDENCIES) { - fixedNames.add(fixedClass.getName().replace('.', '/')); - } - + fixedNames.add(Class.class.getName().replace('.', '/')); + fixedNames.add(ArithmeticException.class.getName().replace('.', '/')); + + VM vm; + if (config.isExtension()) { + fixedNames.add(VM.class.getName().replace('.', '/')); + vm = new Extension(out, config.getResources(), both, config.exported()); + } else { + if (config.includeVM()) { + fixedNames.add(VM.class.getName().replace('.', '/')); + } + vm = new Standalone(out, config.getResources(), config.exported()); + } vm.doCompile(fixedNames.addAndNew(both), config.allResources()); } @@ -490,6 +487,10 @@ + " else resources[n].push(arr);\n" + " }\n" + " var vm = fillInVMSkeleton({ 'registerResource' : registerResource });\n" + + " function initVM() {\n" + + " var clsArray = vm['java_lang_reflect_Array'];\n" + + " if (clsArray) clsArray(false);\n" + + " }\n" + " for (var i = 0; i < extensions.length; ++i) {\n" + " extensions[i](vm);\n" + " }\n" @@ -518,6 +519,7 @@ + " vm['registerResource'] = registerResource;\n" + " extensions[knownExtensions++](vm);\n" + " vm['registerResource'] = null;\n" + + " initVM();\n" + " }\n" + " var arr = resources[name];\n" + " return (arr && arr.length > arrSize) ? arr[arrSize] : null;\n" @@ -536,7 +538,7 @@ + " var fn = vm[attr];\n" + " if (fn) return fn(false);\n" + " try {\n" - + " var arr = loadBytes(name.replace__Ljava_lang_String_2CC('.', '/') + '.class');\n" + + " var arr = loadBytes(replaceAll(name, '.', '/') + '.class');\n" + " return reload(name, arr, true);\n" + " } catch (err) {\n" + " fn = vm[attr];\n" @@ -550,7 +552,7 @@ + " vm['loadClass'] = loader.loadClass;\n" + " vm['_reload'] = reload;\n" + " vm['loadBytes'] = loadBytes;\n" - + " vm['java_lang_reflect_Array'](false);\n" + + " initVM();\n" + " return loader;\n" + " };\n"); append(