rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AheadOfTime.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 17 Jan 2017 07:04:06 +0100
changeset 1985 cd1cc103a03c
parent 1826 511463a1733d
permissions -rw-r--r--
Implementation of ClassValue for bck2brwsr
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012-2015 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.bck2brwsr.mojo;
    19 
    20 import java.io.File;
    21 import java.io.FileOutputStream;
    22 import java.io.IOException;
    23 import java.io.InputStream;
    24 import java.io.OutputStreamWriter;
    25 import java.io.Writer;
    26 import java.net.MalformedURLException;
    27 import java.net.URL;
    28 import java.net.URLClassLoader;
    29 import java.nio.file.Files;
    30 import java.nio.file.StandardCopyOption;
    31 import java.util.ArrayList;
    32 import java.util.Collection;
    33 import java.util.List;
    34 import java.util.Map;
    35 import java.util.jar.Attributes;
    36 import java.util.jar.JarFile;
    37 import java.util.jar.Manifest;
    38 import java.util.zip.ZipEntry;
    39 import org.apache.maven.artifact.Artifact;
    40 import org.apache.maven.plugin.AbstractMojo;
    41 import org.apache.maven.plugin.MojoExecutionException;
    42 import org.apache.maven.plugin.MojoFailureException;
    43 import org.apache.maven.plugins.annotations.LifecyclePhase;
    44 import org.apache.maven.plugins.annotations.Mojo;
    45 import org.apache.maven.plugins.annotations.Parameter;
    46 import org.apache.maven.plugins.annotations.ResolutionScope;
    47 import org.apache.maven.project.MavenProject;
    48 import org.apidesign.bck2brwsr.aot.Bck2BrwsrJars;
    49 import org.apidesign.vm4brwsr.Bck2Brwsr;
    50 import org.apidesign.vm4brwsr.ObfuscationLevel;
    51 
    52 /**
    53  *
    54  * @author Jaroslav Tulach
    55  * @since 0.9
    56  */
    57 @Mojo(name = "aot",
    58     requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
    59     defaultPhase = LifecyclePhase.PACKAGE
    60 )
    61 public class AheadOfTime extends AbstractMojo {
    62     @Parameter(defaultValue = "${project}")
    63     private MavenProject prj;
    64     
    65     @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.jar")
    66     private File mainJar;
    67 
    68     @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.js")
    69     private File mainJavaScript;
    70     
    71     @Parameter
    72     private String[] exports;
    73     
    74     /**
    75      * Directory where to generate ahead-of-time JavaScript files for
    76      * required libraries.
    77      */
    78     @Parameter(defaultValue = "lib")
    79     private String classPathPrefix;
    80 
    81     /** Root JavaScript file to generate */
    82     @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js")
    83     private File vm;
    84     
    85     @Parameter(defaultValue = "true")
    86     private boolean generateAotLibraries;
    87     
    88     @Parameter(defaultValue = "true")
    89     private boolean ignoreBootClassPath;
    90     
    91     /**
    92      * The obfuscation level for the generated JavaScript file.
    93      *
    94      * @since 0.5
    95      */
    96     @Parameter(defaultValue = "NONE")
    97     private ObfuscationLevel obfuscation;
    98     
    99     @Override
   100     public void execute() throws MojoExecutionException, MojoFailureException {
   101         URLClassLoader loader;
   102         try {
   103             loader = buildClassLoader(mainJar, prj.getArtifacts());
   104         } catch (MalformedURLException ex) {
   105             throw new MojoFailureException("Can't initialize classloader");
   106         }
   107         for (Artifact a : prj.getArtifacts()) {
   108             if (a.getFile() == null) {
   109                 continue;
   110             }
   111             String n = a.getFile().getName();
   112             if (!n.endsWith(".jar")) {
   113                 continue;
   114             }
   115             if ("provided".equals(a.getScope())) {
   116                 continue;
   117             }
   118             File aot = new File(mainJavaScript.getParent(), classPathPrefix);
   119             aot.mkdirs();
   120             File js = new File(aot, n.substring(0, n.length() - 4) + ".js");
   121             if (js.lastModified() > a.getFile().lastModified()) {
   122                 getLog().info("Skipping " + js + " as it already exists.");
   123                 continue;
   124             }
   125             try {
   126                 aotLibrary(a, js , loader);
   127             } catch (IOException ex) {
   128                 throw new MojoFailureException("Can't compile " + a.getFile(), ex);
   129             }
   130         }
   131         
   132         try {
   133             if (mainJavaScript.lastModified() > mainJar.lastModified()) {
   134                 getLog().info("Skipping " + mainJavaScript + " as it already exists.");
   135             } else {
   136                 getLog().info("Generating " + mainJavaScript);
   137                 Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, mainJar, loader, ignoreBootClassPath);
   138                 if (exports != null) {
   139                     for (String e : exports) {
   140                         c = c.addExported(e.replace('.', '/'));
   141                     }
   142                 }
   143                 Writer w = new OutputStreamWriter(new FileOutputStream(mainJavaScript), "UTF-8");
   144                 c.
   145                         obfuscation(obfuscation).
   146                         generate(w);
   147                 w.close();
   148             }
   149         } catch (IOException ex) {
   150             throw new MojoFailureException("Cannot generate script for " + mainJar, ex);
   151         }
   152             
   153         try {
   154             Writer w = new OutputStreamWriter(new FileOutputStream(vm), "UTF-8");
   155             Bck2Brwsr.newCompiler().
   156                     obfuscation(obfuscation).
   157                     standalone(false).
   158                     resources(new Bck2Brwsr.Resources() {
   159 
   160                 @Override
   161                 public InputStream get(String resource) throws IOException {
   162                     return null;
   163                 }
   164             }).
   165                     generate(w);
   166             w.close();
   167             
   168         } catch (IOException ex) {
   169             throw new MojoExecutionException("Can't compile", ex);
   170         }
   171     }
   172 
   173     private void aotLibrary(Artifact a, File js, URLClassLoader loader) throws IOException, MojoExecutionException {
   174         for (Artifact b : prj.getArtifacts()) {
   175             if ("bck2brwsr".equals(b.getClassifier())) { // NOI18N
   176                 getLog().debug("Inspecting " + b.getFile());
   177                 JarFile jf = new JarFile(b.getFile());
   178                 Manifest man = jf.getManifest();
   179                 for (Map.Entry<String, Attributes> entrySet : man.getEntries().entrySet()) {
   180                     String entryName = entrySet.getKey();
   181                     Attributes attr = entrySet.getValue();
   182                     
   183                     if (
   184                         a.getArtifactId().equals(attr.getValue("Bck2BrwsrArtifactId")) &&
   185                         a.getGroupId().equals(attr.getValue("Bck2BrwsrGroupId")) &&
   186                         a.getVersion().equals(attr.getValue("Bck2BrwsrVersion")) &&
   187                         (
   188                             obfuscation == ObfuscationLevel.FULL && "true".equals(attr.getValue("Bck2BrwsrMinified"))
   189                             ||
   190                             obfuscation != ObfuscationLevel.FULL && "true".equals(attr.getValue("Bck2BrwsrDebug"))
   191                         )
   192                     ) {
   193                         getLog().info("Extracting " + js + " from " + b.getFile());
   194                         InputStream is = jf.getInputStream(new ZipEntry(entryName));
   195                         Files.copy(is, js.toPath(), StandardCopyOption.REPLACE_EXISTING);
   196                         is.close();
   197                         return;
   198                     }
   199                 }
   200             }
   201         }
   202         if (!generateAotLibraries) {
   203             throw new MojoExecutionException("Not generating " + js + " and no precompiled version found!");
   204         }
   205         getLog().info("Generating " + js);
   206         Writer w = new OutputStreamWriter(new FileOutputStream(js), "UTF-8");
   207         Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, a.getFile(), loader, ignoreBootClassPath);
   208         if (exports != null) {
   209             c = c.addExported(exports);
   210         }
   211         c.
   212             obfuscation(obfuscation).
   213             generate(w);
   214         w.close();
   215     }
   216     private static URLClassLoader buildClassLoader(File root, Collection<Artifact> deps) throws MalformedURLException {
   217         List<URL> arr = new ArrayList<URL>();
   218         if (root != null) {
   219             arr.add(root.toURI().toURL());
   220         }
   221         for (Artifact a : deps) {
   222             if (a.getFile() != null) {
   223                 arr.add(a.getFile().toURI().toURL());
   224             }
   225         }
   226         return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader());
   227     }
   228 }