rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AOTLibrary.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 17 Jan 2017 07:04:06 +0100
changeset 1985 cd1cc103a03c
parent 1916 a9d37af23a00
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.FileNotFoundException;
    22 import java.io.FileOutputStream;
    23 import java.io.IOException;
    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.util.ArrayList;
    30 import java.util.Collection;
    31 import java.util.List;
    32 import java.util.jar.Attributes;
    33 import java.util.jar.JarEntry;
    34 import java.util.jar.JarFile;
    35 import java.util.jar.JarOutputStream;
    36 import java.util.jar.Manifest;
    37 import org.apache.maven.artifact.Artifact;
    38 import org.apache.maven.plugin.AbstractMojo;
    39 import org.apache.maven.plugin.MojoExecutionException;
    40 import org.apache.maven.plugin.MojoFailureException;
    41 import org.apache.maven.plugins.annotations.Component;
    42 import org.apache.maven.plugins.annotations.LifecyclePhase;
    43 import org.apache.maven.plugins.annotations.Mojo;
    44 import org.apache.maven.plugins.annotations.Parameter;
    45 import org.apache.maven.plugins.annotations.ResolutionScope;
    46 import org.apache.maven.project.MavenProject;
    47 import org.apache.maven.project.MavenProjectHelper;
    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.12
    56  */
    57 @Mojo(name = "library",
    58     requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
    59     defaultPhase = LifecyclePhase.PACKAGE
    60 )
    61 public class AOTLibrary extends AbstractMojo {
    62     @Parameter(defaultValue = "${project}")
    63     private MavenProject prj;
    64 
    65     @Component
    66     private MavenProjectHelper projectHelper;
    67     @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.jar")
    68     private File mainJar;    
    69     @Parameter(defaultValue = "${project.build.finalName}-min.js")
    70     private String minified;
    71     @Parameter(defaultValue = "${project.build.finalName}-debug.js")
    72     private String debug;
    73     
    74     @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}-bck2brwsr.jar")
    75     private File aotJar;
    76     
    77     @Parameter
    78     private String[] exports;
    79     
    80     @Parameter
    81     private String[] aotDeps;
    82 
    83     @Parameter(defaultValue = "true")
    84     private boolean ignoreBootClassPath;
    85     
    86     /**
    87      * The obfuscation level for the generated minified JavaScript file.
    88      * @since 0.5
    89      */
    90     @Parameter(defaultValue = "FULL")
    91     private ObfuscationLevel obfuscation;
    92     
    93     @Override
    94     public void execute() throws MojoExecutionException, MojoFailureException {
    95         URLClassLoader loader;
    96         try {
    97             loader = buildClassLoader(mainJar, prj.getArtifacts());
    98         } catch (MalformedURLException ex) {
    99             throw new MojoFailureException("Can't initialize classloader");
   100         }
   101 
   102         try {
   103             Manifest m = new Manifest();
   104             if (!"false".equals(minified)) {
   105                 Attributes attr = new Attributes();
   106                 attr.putValue("Bck2BrwsrArtifactId", prj.getArtifactId());
   107                 attr.putValue("Bck2BrwsrGroupId", prj.getGroupId());
   108                 attr.putValue("Bck2BrwsrVersion", prj.getVersion());
   109                 attr.putValue("Bck2BrwsrMinified", "true");
   110                 bundleName(attr, mainJar);
   111                 m.getEntries().put(minified, attr);
   112             }
   113             if (!"false".equals(debug)) {
   114                 Attributes attr = new Attributes();
   115                 attr.putValue("Bck2BrwsrArtifactId", prj.getArtifactId());
   116                 attr.putValue("Bck2BrwsrGroupId", prj.getGroupId());
   117                 attr.putValue("Bck2BrwsrVersion", prj.getVersion());
   118                 attr.putValue("Bck2BrwsrDebug", "true");
   119                 bundleName(attr, mainJar);
   120                 m.getEntries().put(debug, attr);
   121             }
   122             
   123             if (aotDeps != null) {
   124                 for (Artifact a : prj.getArtifacts()) {
   125                     if (!matches(aotDeps, a)) {
   126                         continue;
   127                     }
   128                     
   129                     {
   130                         Attributes attr = new Attributes();
   131                         attr.putValue("Bck2BrwsrArtifactId", a.getArtifactId());
   132                         attr.putValue("Bck2BrwsrGroupId", a.getGroupId());
   133                         attr.putValue("Bck2BrwsrVersion", a.getVersion());
   134                         attr.putValue("Bck2BrwsrDebug", "true");
   135                         bundleName(attr, a.getFile());
   136 
   137                         m.getEntries().put(artifactName(a, true), attr);
   138                     }
   139                     {
   140                         Attributes attr = new Attributes();
   141                         attr.putValue("Bck2BrwsrArtifactId", a.getArtifactId());
   142                         attr.putValue("Bck2BrwsrGroupId", a.getGroupId());
   143                         attr.putValue("Bck2BrwsrVersion", a.getVersion());
   144                         attr.putValue("Bck2BrwsrMinified", "true");
   145                         bundleName(attr, a.getFile());
   146                         m.getEntries().put(artifactName(a, false), attr);
   147                     }
   148                 }
   149             }
   150 
   151             boolean notified = false;
   152 
   153             JarOutputStream os = null;
   154             if (!"false".equals(debug)) {
   155                 if (os == null) {
   156                     os = aotJar(m);
   157                 }
   158                 os.putNextEntry(new JarEntry(debug));
   159                 getLog().info("Generating bck2brwsr for " + mainJar);
   160                 notified = true;
   161                 Writer w = new OutputStreamWriter(os, "UTF-8");
   162                 configureMain(loader).
   163                     obfuscation(ObfuscationLevel.NONE).
   164                     generate(w);
   165                 w.flush();
   166                 os.closeEntry();
   167             }
   168             if (!"false".equals(minified)) {
   169                 if (os == null) {
   170                     os = aotJar(m);
   171                 }
   172                 os.putNextEntry(new JarEntry(minified));
   173 
   174                 if (!notified) {
   175                     getLog().info("Generating bck2brwsr for " + mainJar);
   176                 }
   177                 Writer w = new OutputStreamWriter(os, "UTF-8");
   178                 configureMain(loader).
   179                     obfuscation(obfuscation).
   180                     generate(w);
   181                 w.flush();
   182                 os.closeEntry();
   183             }
   184             
   185             if (aotDeps != null) {
   186                 for (Artifact a : prj.getArtifacts()) {
   187                     if (!matches(aotDeps, a)) {
   188                         continue;
   189                     }
   190                     getLog().info("Generating bck2brwsr for " + a.getFile());
   191                     Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, a.getFile(), loader, ignoreBootClassPath);
   192                     if (exports != null) {
   193                         for (String e : exports) {
   194                             c = c.addExported(e.replace('.', '/'));
   195                         }
   196                     }
   197                     {
   198                         if (os == null) {
   199                             os = aotJar(m);
   200                         }
   201                         os.putNextEntry(new JarEntry(artifactName(a, true)));
   202                         Writer w = new OutputStreamWriter(os, "UTF-8");
   203                         c.
   204                             obfuscation(ObfuscationLevel.NONE).
   205                             generate(w);
   206                         w.flush();
   207                         os.closeEntry();
   208                     }
   209                     {
   210                         os.putNextEntry(new JarEntry(artifactName(a, false)));
   211 
   212                         Writer w = new OutputStreamWriter(os, "UTF-8");
   213                         c.
   214                             obfuscation(ObfuscationLevel.FULL).
   215                             generate(w);
   216                         w.flush();
   217                         os.closeEntry();
   218                     }                    
   219                 }
   220             }
   221             if (os != null) {
   222                 os.close();
   223             }
   224             
   225             projectHelper.attachArtifact(prj, "jar", "bck2brwsr", aotJar);
   226         } catch (IOException ex) {
   227             throw new MojoFailureException("Cannot generate script for " + mainJar, ex);
   228         }
   229     }
   230 
   231     private JarOutputStream aotJar(Manifest m) throws IOException, FileNotFoundException {
   232         this.aotJar.getParentFile().mkdirs();
   233         FileOutputStream fos = new FileOutputStream(this.aotJar);
   234         JarOutputStream os = new JarOutputStream(fos, m);
   235         return os;
   236     }
   237 
   238     private Bck2Brwsr configureMain(URLClassLoader loader) throws IOException {
   239         Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, mainJar, loader, ignoreBootClassPath);
   240         if (exports != null) {
   241             for (String e : exports) {
   242                 c = c.addExported(e.replace('.', '/'));
   243             }
   244         }
   245         return c;
   246     }
   247 
   248     private static String artifactName(Artifact a, boolean debug) {
   249         return a.getGroupId() + "-" + a.getArtifactId() + (debug ? "-debug.js" : "-min.js");
   250     }
   251 
   252     private static void bundleName(Attributes attr, File file) throws IOException {
   253         try (JarFile jf = new JarFile(file)) {
   254             Attributes main = jf.getManifest().getMainAttributes();
   255             String version = main.getValue("Bundle-SymbolicName");
   256             if (version == null) {
   257                 version = main.getValue("OpenIDE-Module-Name");
   258             }
   259             if (version != null) {
   260                 attr.putValue("Bck2BrwsrName", version);
   261             }
   262         }
   263     }
   264 
   265     private static URLClassLoader buildClassLoader(File root, Collection<Artifact> deps) throws MalformedURLException {
   266         List<URL> arr = new ArrayList<URL>();
   267         if (root != null) {
   268             arr.add(root.toURI().toURL());
   269         }
   270         for (Artifact a : deps) {
   271             if (a.getFile() != null) {
   272                 arr.add(a.getFile().toURI().toURL());
   273             }
   274         }
   275         return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader());
   276     }
   277 
   278     private static boolean matches(String[] aotDeps, Artifact a) {
   279         for (String d : aotDeps) {
   280             String[] parts = d.split(":");
   281             for (int i = 0; i < parts.length; i++) {
   282                 if ("*".equals(parts[i])) {
   283                     parts[i] = null;
   284                 }
   285             }
   286             
   287             if (parts[0] != null && !parts[0].equals(a.getGroupId())) {
   288                 continue;
   289             }
   290             if (parts[1] != null && !parts[1].equals(a.getArtifactId())) {
   291                 continue;
   292             }
   293             if (parts.length > 2 && parts[2] != null && !parts[2].equals(a.getClassifier())) {
   294                 continue;
   295             }
   296             return true;
   297         }
   298         return false;
   299     }
   300 }