Static compilator demo is capable to load itself from individual extension files closure
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 22 May 2014 10:48:09 +0200
branchclosure
changeset 15847b6295731c30
parent 1583 89b6b369c13d
child 1585 60dcb3d7a687
Static compilator demo is capable to load itself from individual extension files
javaquery/demo-calculator/pom.xml
javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml
javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml
rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AheadOfTime.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java
     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(