Static compilator demo is capable to load itself from individual extension files
1.1 --- a/javaquery/demo-calculator/pom.xml Wed May 21 23:42:24 2014 +0200
1.2 +++ b/javaquery/demo-calculator/pom.xml Thu May 22 10:48:09 2014 +0200
1.3 @@ -24,6 +24,7 @@
1.4 <execution>
1.5 <goals>
1.6 <goal>j2js</goal>
1.7 + <goal>aot</goal>
1.8 <goal>brwsr</goal>
1.9 </goals>
1.10 </execution>
1.11 @@ -31,7 +32,8 @@
1.12 <configuration>
1.13 <directory>${project.build.directory}/${project.build.finalName}-bck2brwsr/public_html/</directory>
1.14 <startpage>index.xhtml</startpage>
1.15 - <javascript>${project.build.directory}/bck2brwsr.js</javascript>
1.16 + <javascript>${project.build.directory}/app.js</javascript>
1.17 + <library>true</library>
1.18 <obfuscation>${bck2brwsr.obfuscationlevel}</obfuscation>
1.19 </configuration>
1.20 </plugin>
2.1 --- a/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Wed May 21 23:42:24 2014 +0200
2.2 +++ b/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Thu May 22 10:48:09 2014 +0200
2.3 @@ -38,16 +38,23 @@
2.4 </includes>
2.5 </dependencySet>
2.6 </dependencySets>
2.7 + <fileSets>
2.8 + <fileSet>
2.9 + <directory>${project.build.directory}</directory>
2.10 + <outputDirectory>/</outputDirectory>
2.11 + <includes>
2.12 + <include>bck2brwsr.js</include>
2.13 + <include>app.js</include>
2.14 + <include>lib/*.js</include>
2.15 + </includes>
2.16 + </fileSet>
2.17 + </fileSets>
2.18 <files>
2.19 <file>
2.20 <source>${project.build.directory}/${project.build.finalName}.jar</source>
2.21 <outputDirectory>/</outputDirectory>
2.22 </file>
2.23 <file>
2.24 - <source>${project.build.directory}/bck2brwsr.js</source>
2.25 - <outputDirectory>/</outputDirectory>
2.26 - </file>
2.27 - <file>
2.28 <source>${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml</source>
2.29 <outputDirectory>/</outputDirectory>
2.30 <destName>index.xhtml</destName>
3.1 --- a/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Wed May 21 23:42:24 2014 +0200
3.2 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Thu May 22 10:48:09 2014 +0200
3.3 @@ -90,8 +90,11 @@
3.4
3.5 <div data-bind="text: displayPreview"></div>
3.6 <script src="bck2brwsr.js"></script>
3.7 + <script src="lib/emul-0.9-SNAPSHOT-rt.js"></script>
3.8 + <script src="lib/javaquery.api-0.9-SNAPSHOT.js"></script>
3.9 + <script src="app.js"></script>
3.10 <script>
3.11 - var vm = bck2brwsr('demo.static.calculator-0.6.jar');
3.12 + var vm = bck2brwsr();
3.13 vm.loadClass('org.apidesign.bck2brwsr.demo.calc.staticcompilation.Calc');
3.14 </script>
3.15 </body>
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AheadOfTime.java Thu May 22 10:48:09 2014 +0200
4.3 @@ -0,0 +1,199 @@
4.4 +/**
4.5 + * Back 2 Browser Bytecode Translator
4.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
4.7 + *
4.8 + * This program is free software: you can redistribute it and/or modify
4.9 + * it under the terms of the GNU General Public License as published by
4.10 + * the Free Software Foundation, version 2 of the License.
4.11 + *
4.12 + * This program is distributed in the hope that it will be useful,
4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.15 + * GNU General Public License for more details.
4.16 + *
4.17 + * You should have received a copy of the GNU General Public License
4.18 + * along with this program. Look for COPYING file in the top folder.
4.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
4.20 + */
4.21 +
4.22 +package org.apidesign.bck2brwsr.mojo;
4.23 +
4.24 +import java.io.BufferedReader;
4.25 +import java.io.File;
4.26 +import java.io.FileWriter;
4.27 +import java.io.IOException;
4.28 +import java.io.InputStream;
4.29 +import java.io.InputStreamReader;
4.30 +import java.net.MalformedURLException;
4.31 +import java.net.URL;
4.32 +import java.net.URLClassLoader;
4.33 +import java.util.ArrayList;
4.34 +import java.util.Collection;
4.35 +import java.util.Enumeration;
4.36 +import java.util.HashSet;
4.37 +import java.util.List;
4.38 +import java.util.Set;
4.39 +import java.util.jar.JarEntry;
4.40 +import java.util.jar.JarFile;
4.41 +import org.apache.maven.artifact.Artifact;
4.42 +import org.apache.maven.plugin.AbstractMojo;
4.43 +import org.apache.maven.plugin.MojoExecutionException;
4.44 +import org.apache.maven.plugin.MojoFailureException;
4.45 +import org.apache.maven.plugins.annotations.LifecyclePhase;
4.46 +import org.apache.maven.plugins.annotations.Mojo;
4.47 +import org.apache.maven.plugins.annotations.Parameter;
4.48 +import org.apache.maven.plugins.annotations.ResolutionScope;
4.49 +import org.apache.maven.project.MavenProject;
4.50 +import org.apidesign.vm4brwsr.Bck2Brwsr;
4.51 +import org.apidesign.vm4brwsr.ObfuscationLevel;
4.52 +
4.53 +/**
4.54 + *
4.55 + * @author Jaroslav Tulach
4.56 + * @since 0.9
4.57 + */
4.58 +@Mojo(name = "aot",
4.59 + requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
4.60 + defaultPhase = LifecyclePhase.PACKAGE
4.61 +)
4.62 +public class AheadOfTime extends AbstractMojo {
4.63 + @Parameter(defaultValue = "${project}")
4.64 + private MavenProject prj;
4.65 +
4.66 + /**
4.67 + * Directory where to generate ahead-of-time JavaScript files for
4.68 + * required libraries.
4.69 + */
4.70 + @Parameter(defaultValue = "${project.build.directory}/lib")
4.71 + private File aot;
4.72 +
4.73 + /** Root JavaScript file to generate */
4.74 + @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js")
4.75 + private File vm;
4.76 +
4.77 + /**
4.78 + * The obfuscation level for the generated JavaScript file.
4.79 + *
4.80 + * @since 0.5
4.81 + */
4.82 + @Parameter(defaultValue = "NONE")
4.83 + private ObfuscationLevel obfuscation;
4.84 +
4.85 + @Override
4.86 + public void execute() throws MojoExecutionException, MojoFailureException {
4.87 + try {
4.88 + URLClassLoader loader = buildClassLoader(null, prj.getArtifacts());
4.89 + for (Artifact a : prj.getArtifacts()) {
4.90 + if (a.getFile() == null) {
4.91 + continue;
4.92 + }
4.93 + String n = a.getFile().getName();
4.94 + if (!n.endsWith(".jar")) {
4.95 + continue;
4.96 + }
4.97 + aot.mkdirs();
4.98 + File js = new File(aot, n.substring(0, n.length() - 4) + ".js");
4.99 + aotLibrary(a, js , loader);
4.100 + }
4.101 +
4.102 + FileWriter w = new FileWriter(vm);
4.103 + Bck2Brwsr.newCompiler().
4.104 + obfuscation(obfuscation).
4.105 + standalone(false).
4.106 + resources(new Bck2Brwsr.Resources() {
4.107 +
4.108 + @Override
4.109 + public InputStream get(String resource) throws IOException {
4.110 + return null;
4.111 + }
4.112 + }).
4.113 + generate(w);
4.114 + w.close();
4.115 +
4.116 + } catch (IOException ex) {
4.117 + throw new MojoExecutionException("Can't compile", ex);
4.118 + }
4.119 + }
4.120 +
4.121 + private void aotLibrary(Artifact a, File js, URLClassLoader loader) throws IOException {
4.122 + List<String> classes = new ArrayList<String>();
4.123 + List<String> resources = new ArrayList<String>();
4.124 + Set<String> exported = new HashSet<String>();
4.125 +
4.126 + JarFile jf = new JarFile(a.getFile());
4.127 + listJAR(jf, classes , resources, exported);
4.128 +
4.129 + FileWriter w = new FileWriter(js);
4.130 + Bck2Brwsr.newCompiler().
4.131 + obfuscation(obfuscation).
4.132 + library(true).
4.133 + resources(loader).
4.134 + addResources(resources.toArray(new String[0])).
4.135 + addClasses(classes.toArray(new String[0])).
4.136 + addExported(exported.toArray(new String[0])).
4.137 + generate(w);
4.138 + w.close();
4.139 + }
4.140 + private static URLClassLoader buildClassLoader(File root, Collection<Artifact> deps) throws MalformedURLException {
4.141 + List<URL> arr = new ArrayList<URL>();
4.142 + if (root != null) {
4.143 + arr.add(root.toURI().toURL());
4.144 + }
4.145 + for (Artifact a : deps) {
4.146 + if (a.getFile() != null) {
4.147 + arr.add(a.getFile().toURI().toURL());
4.148 + }
4.149 + }
4.150 + return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader());
4.151 + }
4.152 +
4.153 + private static void listJAR(
4.154 + JarFile j, List<String> classes,
4.155 + List<String> resources, Set<String> exported
4.156 + ) throws IOException {
4.157 + Enumeration<JarEntry> en = j.entries();
4.158 + while (en.hasMoreElements()) {
4.159 + JarEntry e = en.nextElement();
4.160 + final String n = e.getName();
4.161 + if (n.endsWith("/")) {
4.162 + continue;
4.163 + }
4.164 + int last = n.lastIndexOf('/');
4.165 + String pkg = n.substring(0, last + 1);
4.166 + if (n.endsWith(".class")) {
4.167 + classes.add(n.substring(0, n.length() - 6));
4.168 + } else {
4.169 + resources.add(n);
4.170 + if (n.startsWith("META-INF/services/") && exported != null) {
4.171 + final InputStream is = j.getInputStream(e);
4.172 + exportedServices(is, exported);
4.173 + is.close();
4.174 + }
4.175 + }
4.176 + }
4.177 + String exp = j.getManifest().getMainAttributes().getValue("Export-Package");
4.178 + if (exp != null && exported != null) {
4.179 + for (String def : exp.split(",")) {
4.180 + for (String sep : def.split(";")) {
4.181 + exported.add(sep.replace('.', '/') + "/");
4.182 + break;
4.183 + }
4.184 + }
4.185 + }
4.186 + }
4.187 +
4.188 + static void exportedServices(final InputStream is, Set<String> exported) throws IOException {
4.189 + BufferedReader r = new BufferedReader(new InputStreamReader(is));
4.190 + for (;;) {
4.191 + String l = r.readLine();
4.192 + if (l == null) {
4.193 + break;
4.194 + }
4.195 + if (l.startsWith("#")) {
4.196 + continue;
4.197 + }
4.198 + exported.add(l.replace('.', '/'));
4.199 + }
4.200 + }
4.201 +
4.202 +}
5.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Wed May 21 23:42:24 2014 +0200
5.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Thu May 22 10:48:09 2014 +0200
5.3 @@ -57,9 +57,13 @@
5.4 private final StringArray classes;
5.5 private final StringArray resources;
5.6 private final Resources res;
5.7 - private final boolean extension;
5.8 + private final Boolean extension;
5.9
5.10 - private Bck2Brwsr(ObfuscationLevel level, StringArray exported, StringArray classes, StringArray resources, Resources res, boolean extension) {
5.11 + private Bck2Brwsr(
5.12 + ObfuscationLevel level,
5.13 + StringArray exported, StringArray classes, StringArray resources,
5.14 + Resources res, Boolean extension
5.15 + ) {
5.16 this.level = level;
5.17 this.exported = exported;
5.18 this.classes = classes;
5.19 @@ -226,6 +230,19 @@
5.20 public Bck2Brwsr library(boolean library) {
5.21 return new Bck2Brwsr(level, exported, classes, resources, res, library);
5.22 }
5.23 +
5.24 + /** Turns on the standalone mode. E.g. acts like {@link #library(boolean) library(false)},
5.25 + * but also allows to specify whether the <em>Bck2Brwsr VM</em> should
5.26 + * be included at all. If not, only the skeleton of the launcher is
5.27 + * generated without any additional VM classes referenced.
5.28 + *
5.29 + * @param includeVM should the VM be compiled in, or left out
5.30 + * @return new instance of the compiler with standalone mode on
5.31 + * @since 0.9
5.32 + */
5.33 + public Bck2Brwsr standalone(boolean includeVM) {
5.34 + return new Bck2Brwsr(level, exported, classes, resources, res, includeVM ? false : null);
5.35 + }
5.36
5.37 /** A way to change the provider of additional resources (classes) for the
5.38 * compiler by specifying classloader to use for loading them.
5.39 @@ -296,7 +313,11 @@
5.40 }
5.41
5.42 boolean isExtension() {
5.43 - return extension;
5.44 + return Boolean.TRUE.equals(extension);
5.45 + }
5.46 +
5.47 + boolean includeVM() {
5.48 + return extension != null;
5.49 }
5.50
5.51 /** Provider of resources (classes and other files). The
6.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Wed May 21 23:42:24 2014 +0200
6.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Thu May 22 10:48:09 2014 +0200
6.3 @@ -35,12 +35,6 @@
6.4 private final ExportedSymbols exportedSymbols;
6.5 private final StringArray invokerMethods;
6.6
6.7 - private static final Class<?> FIXED_DEPENDENCIES[] = {
6.8 - Class.class,
6.9 - ArithmeticException.class,
6.10 - VM.class
6.11 - };
6.12 -
6.13 private VM(Appendable out, Bck2Brwsr.Resources resources, StringArray explicitlyExported) {
6.14 super(out);
6.15 this.resources = resources;
6.16 @@ -69,17 +63,20 @@
6.17 ) throws IOException {
6.18 String[] both = config.classes().toArray();
6.19
6.20 - VM vm = config.isExtension() ?
6.21 - new Extension(out, config.getResources(), both, config.exported())
6.22 - :
6.23 - new Standalone(out, config.getResources(), config.exported());
6.24 -
6.25 final StringArray fixedNames = new StringArray();
6.26 -
6.27 - for (final Class<?> fixedClass: FIXED_DEPENDENCIES) {
6.28 - fixedNames.add(fixedClass.getName().replace('.', '/'));
6.29 - }
6.30 -
6.31 + fixedNames.add(Class.class.getName().replace('.', '/'));
6.32 + fixedNames.add(ArithmeticException.class.getName().replace('.', '/'));
6.33 +
6.34 + VM vm;
6.35 + if (config.isExtension()) {
6.36 + fixedNames.add(VM.class.getName().replace('.', '/'));
6.37 + vm = new Extension(out, config.getResources(), both, config.exported());
6.38 + } else {
6.39 + if (config.includeVM()) {
6.40 + fixedNames.add(VM.class.getName().replace('.', '/'));
6.41 + }
6.42 + vm = new Standalone(out, config.getResources(), config.exported());
6.43 + }
6.44 vm.doCompile(fixedNames.addAndNew(both), config.allResources());
6.45 }
6.46
6.47 @@ -490,6 +487,10 @@
6.48 + " else resources[n].push(arr);\n"
6.49 + " }\n"
6.50 + " var vm = fillInVMSkeleton({ 'registerResource' : registerResource });\n"
6.51 + + " function initVM() {\n"
6.52 + + " var clsArray = vm['java_lang_reflect_Array'];\n"
6.53 + + " if (clsArray) clsArray(false);\n"
6.54 + + " }\n"
6.55 + " for (var i = 0; i < extensions.length; ++i) {\n"
6.56 + " extensions[i](vm);\n"
6.57 + " }\n"
6.58 @@ -518,6 +519,7 @@
6.59 + " vm['registerResource'] = registerResource;\n"
6.60 + " extensions[knownExtensions++](vm);\n"
6.61 + " vm['registerResource'] = null;\n"
6.62 + + " initVM();\n"
6.63 + " }\n"
6.64 + " var arr = resources[name];\n"
6.65 + " return (arr && arr.length > arrSize) ? arr[arrSize] : null;\n"
6.66 @@ -536,7 +538,7 @@
6.67 + " var fn = vm[attr];\n"
6.68 + " if (fn) return fn(false);\n"
6.69 + " try {\n"
6.70 - + " var arr = loadBytes(name.replace__Ljava_lang_String_2CC('.', '/') + '.class');\n"
6.71 + + " var arr = loadBytes(replaceAll(name, '.', '/') + '.class');\n"
6.72 + " return reload(name, arr, true);\n"
6.73 + " } catch (err) {\n"
6.74 + " fn = vm[attr];\n"
6.75 @@ -550,7 +552,7 @@
6.76 + " vm['loadClass'] = loader.loadClass;\n"
6.77 + " vm['_reload'] = reload;\n"
6.78 + " vm['loadBytes'] = loadBytes;\n"
6.79 - + " vm['java_lang_reflect_Array'](false);\n"
6.80 + + " initVM();\n"
6.81 + " return loader;\n"
6.82 + " };\n");
6.83 append(