rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AheadOfTime.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 26 May 2014 10:19:43 +0200
branchclosure
changeset 1594 d7c375541fb7
parent 1584 7b6295731c30
child 1599 36746c46716a
permissions -rw-r--r--
Don't include provided dependencies
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 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 
    19 package org.apidesign.bck2brwsr.mojo;
    20 
    21 import java.io.BufferedReader;
    22 import java.io.File;
    23 import java.io.FileWriter;
    24 import java.io.IOException;
    25 import java.io.InputStream;
    26 import java.io.InputStreamReader;
    27 import java.net.MalformedURLException;
    28 import java.net.URL;
    29 import java.net.URLClassLoader;
    30 import java.util.ArrayList;
    31 import java.util.Collection;
    32 import java.util.Enumeration;
    33 import java.util.HashSet;
    34 import java.util.List;
    35 import java.util.Set;
    36 import java.util.jar.JarEntry;
    37 import java.util.jar.JarFile;
    38 import java.util.logging.Level;
    39 import java.util.logging.Logger;
    40 import org.apache.maven.artifact.Artifact;
    41 import org.apache.maven.plugin.AbstractMojo;
    42 import org.apache.maven.plugin.MojoExecutionException;
    43 import org.apache.maven.plugin.MojoFailureException;
    44 import org.apache.maven.plugins.annotations.LifecyclePhase;
    45 import org.apache.maven.plugins.annotations.Mojo;
    46 import org.apache.maven.plugins.annotations.Parameter;
    47 import org.apache.maven.plugins.annotations.ResolutionScope;
    48 import org.apache.maven.project.MavenProject;
    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     /**
    66      * Directory where to generate ahead-of-time JavaScript files for
    67      * required libraries.
    68      */
    69     @Parameter(defaultValue = "${project.build.directory}/lib")
    70     private File aot;
    71 
    72     /** Root JavaScript file to generate */
    73     @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js")
    74     private File vm;
    75     
    76     /**
    77      * The obfuscation level for the generated JavaScript file.
    78      *
    79      * @since 0.5
    80      */
    81     @Parameter(defaultValue = "NONE")
    82     private ObfuscationLevel obfuscation;
    83     
    84     @Override
    85     public void execute() throws MojoExecutionException, MojoFailureException {
    86         URLClassLoader loader;
    87         try {
    88             loader = buildClassLoader(null, prj.getArtifacts());
    89         } catch (MalformedURLException ex) {
    90             throw new MojoFailureException("Can't initialize classloader");
    91         }
    92         for (Artifact a : prj.getArtifacts()) {
    93             if (a.getFile() == null) {
    94                 continue;
    95             }
    96             String n = a.getFile().getName();
    97             if (!n.endsWith(".jar")) {
    98                 continue;
    99             }
   100             if ("provided".equals(a.getScope())) {
   101                 continue;
   102             }
   103             aot.mkdirs();
   104             File js = new File(aot, n.substring(0, n.length() - 4) + ".js");
   105             try {
   106                 aotLibrary(a, js , loader);
   107             } catch (IOException ex) {
   108                 throw new MojoFailureException("Can't compile" + a.getFile(), ex);
   109             }
   110         }
   111             
   112         try {
   113             FileWriter w = new FileWriter(vm);
   114             Bck2Brwsr.newCompiler().
   115                     obfuscation(obfuscation).
   116                     standalone(false).
   117                     resources(new Bck2Brwsr.Resources() {
   118 
   119                 @Override
   120                 public InputStream get(String resource) throws IOException {
   121                     return null;
   122                 }
   123             }).
   124                     generate(w);
   125             w.close();
   126             
   127         } catch (IOException ex) {
   128             throw new MojoExecutionException("Can't compile", ex);
   129         }
   130     }
   131 
   132     private void aotLibrary(Artifact a, File js, URLClassLoader loader) throws IOException {
   133         List<String> classes = new ArrayList<String>();
   134         List<String> resources = new ArrayList<String>();
   135         Set<String> exported = new HashSet<String>();
   136         
   137         JarFile jf = new JarFile(a.getFile());
   138         listJAR(jf, classes , resources, exported);
   139         
   140         FileWriter w = new FileWriter(js);
   141         Bck2Brwsr.newCompiler().
   142                 obfuscation(obfuscation).
   143                 library(true).
   144                 resources(loader).
   145                 addResources(resources.toArray(new String[0])).
   146                 addClasses(classes.toArray(new String[0])).
   147                 addExported(exported.toArray(new String[0])).
   148                 generate(w);
   149         w.close();
   150     }
   151     private static URLClassLoader buildClassLoader(File root, Collection<Artifact> deps) throws MalformedURLException {
   152         List<URL> arr = new ArrayList<URL>();
   153         if (root != null) {
   154             arr.add(root.toURI().toURL());
   155         }
   156         for (Artifact a : deps) {
   157             if (a.getFile() != null) {
   158                 arr.add(a.getFile().toURI().toURL());
   159             }
   160         }
   161         return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader());
   162     }
   163     
   164     private static void listJAR(
   165             JarFile j, List<String> classes,
   166             List<String> resources, Set<String> exported
   167     ) throws IOException {
   168         Enumeration<JarEntry> en = j.entries();
   169         while (en.hasMoreElements()) {
   170             JarEntry e = en.nextElement();
   171             final String n = e.getName();
   172             if (n.endsWith("/")) {
   173                 continue;
   174             }
   175             int last = n.lastIndexOf('/');
   176             String pkg = n.substring(0, last + 1);
   177             if (n.endsWith(".class")) {
   178                 classes.add(n.substring(0, n.length() - 6));
   179             } else {
   180                 resources.add(n);
   181                 if (n.startsWith("META-INF/services/") && exported != null) {
   182                     final InputStream is = j.getInputStream(e);
   183                     exportedServices(is, exported);
   184                     is.close();
   185                 }
   186             }
   187         }
   188         String exp = j.getManifest().getMainAttributes().getValue("Export-Package");
   189         if (exp != null && exported != null) {
   190             for (String def : exp.split(",")) {
   191                 for (String sep : def.split(";")) {
   192                     exported.add(sep.replace('.', '/') + "/");
   193                     break;
   194                 }
   195             }
   196         }
   197     }
   198 
   199     static void exportedServices(final InputStream is, Set<String> exported) throws IOException {
   200         BufferedReader r = new BufferedReader(new InputStreamReader(is));
   201         for (;;) {
   202             String l = r.readLine();
   203             if (l == null) {
   204                 break;
   205             }
   206             if (l.startsWith("#")) {
   207                 continue;
   208             }
   209             exported.add(l.replace('.', '/'));
   210         }
   211     }
   212     
   213 }