rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AOTLibrary.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 28 Mar 2016 06:34:38 +0200
changeset 1916 a9d37af23a00
parent 1914 88b00e03fc8f
child 1956 442c7f2d54ea
permissions -rw-r--r--
Record name of an OSGi bundle to be used when Maven coordinates are missing
     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 
   152             JarOutputStream os = null;
   153             if (!"false".equals(debug)) {
   154                 if (os == null) {
   155                     os = aotJar(m);
   156                 }
   157                 os.putNextEntry(new JarEntry(debug));
   158                 Writer w = new OutputStreamWriter(os, "UTF-8");
   159                 configureMain(loader).
   160                     obfuscation(ObfuscationLevel.NONE).
   161                     generate(w);
   162                 w.flush();
   163                 os.closeEntry();
   164             }
   165             if (!"false".equals(minified)) {
   166                 if (os == null) {
   167                     os = aotJar(m);
   168                 }
   169                 os.putNextEntry(new JarEntry(minified));
   170             
   171                 Writer w = new OutputStreamWriter(os, "UTF-8");
   172                 configureMain(loader).
   173                     obfuscation(obfuscation).
   174                     generate(w);
   175                 w.flush();
   176                 os.closeEntry();
   177             }
   178             
   179             if (aotDeps != null) {
   180                 for (Artifact a : prj.getArtifacts()) {
   181                     if (!matches(aotDeps, a)) {
   182                         continue;
   183                     }
   184                     getLog().info("Generating bck2brwsr for " + a.getFile());
   185                     Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, a.getFile(), loader, ignoreBootClassPath);
   186                     if (exports != null) {
   187                         for (String e : exports) {
   188                             c = c.addExported(e.replace('.', '/'));
   189                         }
   190                     }
   191                     {
   192                         if (os == null) {
   193                             os = aotJar(m);
   194                         }
   195                         os.putNextEntry(new JarEntry(artifactName(a, true)));
   196                         Writer w = new OutputStreamWriter(os, "UTF-8");
   197                         c.
   198                             obfuscation(ObfuscationLevel.NONE).
   199                             generate(w);
   200                         w.flush();
   201                         os.closeEntry();
   202                     }
   203                     {
   204                         os.putNextEntry(new JarEntry(artifactName(a, false)));
   205 
   206                         Writer w = new OutputStreamWriter(os, "UTF-8");
   207                         c.
   208                             obfuscation(ObfuscationLevel.FULL).
   209                             generate(w);
   210                         w.flush();
   211                         os.closeEntry();
   212                     }                    
   213                 }
   214             }
   215             if (os != null) {
   216                 os.close();
   217             }
   218             
   219             projectHelper.attachArtifact(prj, "jar", "bck2brwsr", aotJar);
   220         } catch (IOException ex) {
   221             throw new MojoFailureException("Cannot generate script for " + mainJar, ex);
   222         }
   223     }
   224 
   225     private JarOutputStream aotJar(Manifest m) throws IOException, FileNotFoundException {
   226         this.aotJar.getParentFile().mkdirs();
   227         FileOutputStream fos = new FileOutputStream(this.aotJar);
   228         JarOutputStream os = new JarOutputStream(fos, m);
   229         return os;
   230     }
   231 
   232     private Bck2Brwsr configureMain(URLClassLoader loader) throws IOException {
   233         Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, mainJar, loader, ignoreBootClassPath);
   234         if (exports != null) {
   235             for (String e : exports) {
   236                 c = c.addExported(e.replace('.', '/'));
   237             }
   238         }
   239         return c;
   240     }
   241 
   242     private static String artifactName(Artifact a, boolean debug) {
   243         return a.getGroupId() + "-" + a.getArtifactId() + (debug ? "-debug.js" : "-min.js");
   244     }
   245 
   246     private static void bundleName(Attributes attr, File file) throws IOException {
   247         try (JarFile jf = new JarFile(file)) {
   248             Attributes main = jf.getManifest().getMainAttributes();
   249             String version = main.getValue("Bundle-SymbolicName");
   250             if (version == null) {
   251                 version = main.getValue("OpenIDE-Module-Name");
   252             }
   253             if (version != null) {
   254                 attr.putValue("Bck2BrwsrName", version);
   255             }
   256         }
   257     }
   258 
   259     private static URLClassLoader buildClassLoader(File root, Collection<Artifact> deps) throws MalformedURLException {
   260         List<URL> arr = new ArrayList<URL>();
   261         if (root != null) {
   262             arr.add(root.toURI().toURL());
   263         }
   264         for (Artifact a : deps) {
   265             if (a.getFile() != null) {
   266                 arr.add(a.getFile().toURI().toURL());
   267             }
   268         }
   269         return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader());
   270     }
   271 
   272     private static boolean matches(String[] aotDeps, Artifact a) {
   273         for (String d : aotDeps) {
   274             String[] parts = d.split(":");
   275             for (int i = 0; i < parts.length; i++) {
   276                 if ("*".equals(parts[i])) {
   277                     parts[i] = null;
   278                 }
   279             }
   280             
   281             if (parts[0] != null && !parts[0].equals(a.getGroupId())) {
   282                 continue;
   283             }
   284             if (parts[1] != null && !parts[1].equals(a.getArtifactId())) {
   285                 continue;
   286             }
   287             if (parts.length > 2 && parts[2] != null && !parts[2].equals(a.getClassifier())) {
   288                 continue;
   289             }
   290             return true;
   291         }
   292         return false;
   293     }
   294 }