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
jaroslav@1584
     1
/**
jaroslav@1584
     2
 * Back 2 Browser Bytecode Translator
jaroslav@1584
     3
 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@1584
     4
 *
jaroslav@1584
     5
 * This program is free software: you can redistribute it and/or modify
jaroslav@1584
     6
 * it under the terms of the GNU General Public License as published by
jaroslav@1584
     7
 * the Free Software Foundation, version 2 of the License.
jaroslav@1584
     8
 *
jaroslav@1584
     9
 * This program is distributed in the hope that it will be useful,
jaroslav@1584
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@1584
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@1584
    12
 * GNU General Public License for more details.
jaroslav@1584
    13
 *
jaroslav@1584
    14
 * You should have received a copy of the GNU General Public License
jaroslav@1584
    15
 * along with this program. Look for COPYING file in the top folder.
jaroslav@1584
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
jaroslav@1584
    17
 */
jaroslav@1584
    18
jaroslav@1584
    19
package org.apidesign.bck2brwsr.mojo;
jaroslav@1584
    20
jaroslav@1584
    21
import java.io.BufferedReader;
jaroslav@1584
    22
import java.io.File;
jaroslav@1584
    23
import java.io.FileWriter;
jaroslav@1584
    24
import java.io.IOException;
jaroslav@1584
    25
import java.io.InputStream;
jaroslav@1584
    26
import java.io.InputStreamReader;
jaroslav@1584
    27
import java.net.MalformedURLException;
jaroslav@1584
    28
import java.net.URL;
jaroslav@1584
    29
import java.net.URLClassLoader;
jaroslav@1584
    30
import java.util.ArrayList;
jaroslav@1584
    31
import java.util.Collection;
jaroslav@1584
    32
import java.util.Enumeration;
jaroslav@1584
    33
import java.util.HashSet;
jaroslav@1584
    34
import java.util.List;
jaroslav@1584
    35
import java.util.Set;
jaroslav@1584
    36
import java.util.jar.JarEntry;
jaroslav@1584
    37
import java.util.jar.JarFile;
jaroslav@1594
    38
import java.util.logging.Level;
jaroslav@1594
    39
import java.util.logging.Logger;
jaroslav@1584
    40
import org.apache.maven.artifact.Artifact;
jaroslav@1584
    41
import org.apache.maven.plugin.AbstractMojo;
jaroslav@1584
    42
import org.apache.maven.plugin.MojoExecutionException;
jaroslav@1584
    43
import org.apache.maven.plugin.MojoFailureException;
jaroslav@1584
    44
import org.apache.maven.plugins.annotations.LifecyclePhase;
jaroslav@1584
    45
import org.apache.maven.plugins.annotations.Mojo;
jaroslav@1584
    46
import org.apache.maven.plugins.annotations.Parameter;
jaroslav@1584
    47
import org.apache.maven.plugins.annotations.ResolutionScope;
jaroslav@1584
    48
import org.apache.maven.project.MavenProject;
jaroslav@1584
    49
import org.apidesign.vm4brwsr.Bck2Brwsr;
jaroslav@1584
    50
import org.apidesign.vm4brwsr.ObfuscationLevel;
jaroslav@1584
    51
jaroslav@1584
    52
/**
jaroslav@1584
    53
 *
jaroslav@1584
    54
 * @author Jaroslav Tulach
jaroslav@1584
    55
 * @since 0.9
jaroslav@1584
    56
 */
jaroslav@1584
    57
@Mojo(name = "aot",
jaroslav@1584
    58
    requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
jaroslav@1584
    59
    defaultPhase = LifecyclePhase.PACKAGE
jaroslav@1584
    60
)
jaroslav@1584
    61
public class AheadOfTime extends AbstractMojo {
jaroslav@1584
    62
    @Parameter(defaultValue = "${project}")
jaroslav@1584
    63
    private MavenProject prj;
jaroslav@1584
    64
jaroslav@1584
    65
    /**
jaroslav@1584
    66
     * Directory where to generate ahead-of-time JavaScript files for
jaroslav@1584
    67
     * required libraries.
jaroslav@1584
    68
     */
jaroslav@1584
    69
    @Parameter(defaultValue = "${project.build.directory}/lib")
jaroslav@1584
    70
    private File aot;
jaroslav@1584
    71
jaroslav@1584
    72
    /** Root JavaScript file to generate */
jaroslav@1584
    73
    @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js")
jaroslav@1584
    74
    private File vm;
jaroslav@1584
    75
    
jaroslav@1584
    76
    /**
jaroslav@1584
    77
     * The obfuscation level for the generated JavaScript file.
jaroslav@1584
    78
     *
jaroslav@1584
    79
     * @since 0.5
jaroslav@1584
    80
     */
jaroslav@1584
    81
    @Parameter(defaultValue = "NONE")
jaroslav@1584
    82
    private ObfuscationLevel obfuscation;
jaroslav@1584
    83
    
jaroslav@1584
    84
    @Override
jaroslav@1584
    85
    public void execute() throws MojoExecutionException, MojoFailureException {
jaroslav@1594
    86
        URLClassLoader loader;
jaroslav@1584
    87
        try {
jaroslav@1594
    88
            loader = buildClassLoader(null, prj.getArtifacts());
jaroslav@1594
    89
        } catch (MalformedURLException ex) {
jaroslav@1594
    90
            throw new MojoFailureException("Can't initialize classloader");
jaroslav@1594
    91
        }
jaroslav@1594
    92
        for (Artifact a : prj.getArtifacts()) {
jaroslav@1594
    93
            if (a.getFile() == null) {
jaroslav@1594
    94
                continue;
jaroslav@1594
    95
            }
jaroslav@1594
    96
            String n = a.getFile().getName();
jaroslav@1594
    97
            if (!n.endsWith(".jar")) {
jaroslav@1594
    98
                continue;
jaroslav@1594
    99
            }
jaroslav@1594
   100
            if ("provided".equals(a.getScope())) {
jaroslav@1594
   101
                continue;
jaroslav@1594
   102
            }
jaroslav@1594
   103
            aot.mkdirs();
jaroslav@1594
   104
            File js = new File(aot, n.substring(0, n.length() - 4) + ".js");
jaroslav@1594
   105
            try {
jaroslav@1584
   106
                aotLibrary(a, js , loader);
jaroslav@1594
   107
            } catch (IOException ex) {
jaroslav@1594
   108
                throw new MojoFailureException("Can't compile" + a.getFile(), ex);
jaroslav@1584
   109
            }
jaroslav@1594
   110
        }
jaroslav@1584
   111
            
jaroslav@1594
   112
        try {
jaroslav@1584
   113
            FileWriter w = new FileWriter(vm);
jaroslav@1584
   114
            Bck2Brwsr.newCompiler().
jaroslav@1584
   115
                    obfuscation(obfuscation).
jaroslav@1584
   116
                    standalone(false).
jaroslav@1584
   117
                    resources(new Bck2Brwsr.Resources() {
jaroslav@1584
   118
jaroslav@1584
   119
                @Override
jaroslav@1584
   120
                public InputStream get(String resource) throws IOException {
jaroslav@1584
   121
                    return null;
jaroslav@1584
   122
                }
jaroslav@1584
   123
            }).
jaroslav@1584
   124
                    generate(w);
jaroslav@1584
   125
            w.close();
jaroslav@1584
   126
            
jaroslav@1584
   127
        } catch (IOException ex) {
jaroslav@1584
   128
            throw new MojoExecutionException("Can't compile", ex);
jaroslav@1584
   129
        }
jaroslav@1584
   130
    }
jaroslav@1584
   131
jaroslav@1584
   132
    private void aotLibrary(Artifact a, File js, URLClassLoader loader) throws IOException {
jaroslav@1584
   133
        List<String> classes = new ArrayList<String>();
jaroslav@1584
   134
        List<String> resources = new ArrayList<String>();
jaroslav@1584
   135
        Set<String> exported = new HashSet<String>();
jaroslav@1584
   136
        
jaroslav@1584
   137
        JarFile jf = new JarFile(a.getFile());
jaroslav@1584
   138
        listJAR(jf, classes , resources, exported);
jaroslav@1584
   139
        
jaroslav@1584
   140
        FileWriter w = new FileWriter(js);
jaroslav@1584
   141
        Bck2Brwsr.newCompiler().
jaroslav@1584
   142
                obfuscation(obfuscation).
jaroslav@1584
   143
                library(true).
jaroslav@1584
   144
                resources(loader).
jaroslav@1584
   145
                addResources(resources.toArray(new String[0])).
jaroslav@1584
   146
                addClasses(classes.toArray(new String[0])).
jaroslav@1584
   147
                addExported(exported.toArray(new String[0])).
jaroslav@1584
   148
                generate(w);
jaroslav@1584
   149
        w.close();
jaroslav@1584
   150
    }
jaroslav@1584
   151
    private static URLClassLoader buildClassLoader(File root, Collection<Artifact> deps) throws MalformedURLException {
jaroslav@1584
   152
        List<URL> arr = new ArrayList<URL>();
jaroslav@1584
   153
        if (root != null) {
jaroslav@1584
   154
            arr.add(root.toURI().toURL());
jaroslav@1584
   155
        }
jaroslav@1584
   156
        for (Artifact a : deps) {
jaroslav@1584
   157
            if (a.getFile() != null) {
jaroslav@1584
   158
                arr.add(a.getFile().toURI().toURL());
jaroslav@1584
   159
            }
jaroslav@1584
   160
        }
jaroslav@1584
   161
        return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader());
jaroslav@1584
   162
    }
jaroslav@1584
   163
    
jaroslav@1584
   164
    private static void listJAR(
jaroslav@1584
   165
            JarFile j, List<String> classes,
jaroslav@1584
   166
            List<String> resources, Set<String> exported
jaroslav@1584
   167
    ) throws IOException {
jaroslav@1584
   168
        Enumeration<JarEntry> en = j.entries();
jaroslav@1584
   169
        while (en.hasMoreElements()) {
jaroslav@1584
   170
            JarEntry e = en.nextElement();
jaroslav@1584
   171
            final String n = e.getName();
jaroslav@1584
   172
            if (n.endsWith("/")) {
jaroslav@1584
   173
                continue;
jaroslav@1584
   174
            }
jaroslav@1584
   175
            int last = n.lastIndexOf('/');
jaroslav@1584
   176
            String pkg = n.substring(0, last + 1);
jaroslav@1584
   177
            if (n.endsWith(".class")) {
jaroslav@1584
   178
                classes.add(n.substring(0, n.length() - 6));
jaroslav@1584
   179
            } else {
jaroslav@1584
   180
                resources.add(n);
jaroslav@1584
   181
                if (n.startsWith("META-INF/services/") && exported != null) {
jaroslav@1584
   182
                    final InputStream is = j.getInputStream(e);
jaroslav@1584
   183
                    exportedServices(is, exported);
jaroslav@1584
   184
                    is.close();
jaroslav@1584
   185
                }
jaroslav@1584
   186
            }
jaroslav@1584
   187
        }
jaroslav@1584
   188
        String exp = j.getManifest().getMainAttributes().getValue("Export-Package");
jaroslav@1584
   189
        if (exp != null && exported != null) {
jaroslav@1584
   190
            for (String def : exp.split(",")) {
jaroslav@1584
   191
                for (String sep : def.split(";")) {
jaroslav@1584
   192
                    exported.add(sep.replace('.', '/') + "/");
jaroslav@1584
   193
                    break;
jaroslav@1584
   194
                }
jaroslav@1584
   195
            }
jaroslav@1584
   196
        }
jaroslav@1584
   197
    }
jaroslav@1584
   198
jaroslav@1584
   199
    static void exportedServices(final InputStream is, Set<String> exported) throws IOException {
jaroslav@1584
   200
        BufferedReader r = new BufferedReader(new InputStreamReader(is));
jaroslav@1584
   201
        for (;;) {
jaroslav@1584
   202
            String l = r.readLine();
jaroslav@1584
   203
            if (l == null) {
jaroslav@1584
   204
                break;
jaroslav@1584
   205
            }
jaroslav@1584
   206
            if (l.startsWith("#")) {
jaroslav@1584
   207
                continue;
jaroslav@1584
   208
            }
jaroslav@1584
   209
            exported.add(l.replace('.', '/'));
jaroslav@1584
   210
        }
jaroslav@1584
   211
    }
jaroslav@1584
   212
    
jaroslav@1584
   213
}