jaroslav@1584: /** jaroslav@1584: * Back 2 Browser Bytecode Translator jaroslav@1584: * Copyright (C) 2012 Jaroslav Tulach jaroslav@1584: * jaroslav@1584: * This program is free software: you can redistribute it and/or modify jaroslav@1584: * it under the terms of the GNU General Public License as published by jaroslav@1584: * the Free Software Foundation, version 2 of the License. jaroslav@1584: * jaroslav@1584: * This program is distributed in the hope that it will be useful, jaroslav@1584: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@1584: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@1584: * GNU General Public License for more details. jaroslav@1584: * jaroslav@1584: * You should have received a copy of the GNU General Public License jaroslav@1584: * along with this program. Look for COPYING file in the top folder. jaroslav@1584: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@1584: */ jaroslav@1584: jaroslav@1584: package org.apidesign.bck2brwsr.mojo; jaroslav@1584: jaroslav@1584: import java.io.File; jaroslav@1737: import java.io.FileOutputStream; jaroslav@1584: import java.io.IOException; jaroslav@1737: import java.io.OutputStreamWriter; jaroslav@1737: import java.io.Writer; jaroslav@1584: import java.net.MalformedURLException; jaroslav@1584: import java.net.URL; jaroslav@1584: import java.net.URLClassLoader; jaroslav@1584: import java.util.ArrayList; jaroslav@1584: import java.util.Collection; jaroslav@1584: import java.util.List; jaroslav@1737: import java.util.jar.Attributes; jaroslav@1737: import java.util.jar.JarEntry; jaroslav@1737: import java.util.jar.JarOutputStream; jaroslav@1737: import java.util.jar.Manifest; jaroslav@1584: import org.apache.maven.artifact.Artifact; jaroslav@1584: import org.apache.maven.plugin.AbstractMojo; jaroslav@1584: import org.apache.maven.plugin.MojoExecutionException; jaroslav@1584: import org.apache.maven.plugin.MojoFailureException; jaroslav@1737: import org.apache.maven.plugins.annotations.Component; jaroslav@1584: import org.apache.maven.plugins.annotations.LifecyclePhase; jaroslav@1584: import org.apache.maven.plugins.annotations.Mojo; jaroslav@1584: import org.apache.maven.plugins.annotations.Parameter; jaroslav@1584: import org.apache.maven.plugins.annotations.ResolutionScope; jaroslav@1584: import org.apache.maven.project.MavenProject; jaroslav@1737: import org.apache.maven.project.MavenProjectHelper; jaroslav@1599: import org.apidesign.bck2brwsr.aot.Bck2BrwsrJars; jaroslav@1584: import org.apidesign.vm4brwsr.Bck2Brwsr; jaroslav@1584: import org.apidesign.vm4brwsr.ObfuscationLevel; jaroslav@1584: jaroslav@1584: /** jaroslav@1584: * jaroslav@1584: * @author Jaroslav Tulach jaroslav@1737: * @since 0.12 jaroslav@1584: */ jaroslav@1737: @Mojo(name = "library", jaroslav@1584: requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, jaroslav@1584: defaultPhase = LifecyclePhase.PACKAGE jaroslav@1584: ) jaroslav@1737: public class AOTLibrary extends AbstractMojo { jaroslav@1584: @Parameter(defaultValue = "${project}") jaroslav@1584: private MavenProject prj; jaroslav@1737: jaroslav@1737: @Component jaroslav@1737: private MavenProjectHelper projectHelper; jaroslav@1737: @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.jar") jaroslav@1737: private File mainJar; jaroslav@1737: @Parameter(defaultValue = "${project.build.finalName}-min.js") jaroslav@1737: private String minified; jaroslav@1737: @Parameter(defaultValue = "${project.build.finalName}-debug.js") jaroslav@1737: private String debug; jaroslav@1604: jaroslav@1737: @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}-bck2brwsr.jar") jaroslav@1737: private File aotJar; jaroslav@1604: jaroslav@1604: @Parameter jaroslav@1604: private String[] exports; jaroslav@1604: jaroslav@1739: @Parameter jaroslav@1739: private String[] aotDeps; jaroslav@1739: jaroslav@1584: @Override jaroslav@1584: public void execute() throws MojoExecutionException, MojoFailureException { jaroslav@1594: URLClassLoader loader; jaroslav@1584: try { jaroslav@1604: loader = buildClassLoader(mainJar, prj.getArtifacts()); jaroslav@1594: } catch (MalformedURLException ex) { jaroslav@1594: throw new MojoFailureException("Can't initialize classloader"); jaroslav@1594: } jaroslav@1737: jaroslav@1737: try { jaroslav@1737: Manifest m = new Manifest(); jaroslav@1742: if (!"false".equals(minified)) { jaroslav@1737: Attributes attr = new Attributes(); jaroslav@1737: attr.putValue("Bck2BrwsrArtifactId", prj.getArtifactId()); jaroslav@1737: attr.putValue("Bck2BrwsrGroupId", prj.getGroupId()); jaroslav@1737: attr.putValue("Bck2BrwsrVersion", prj.getVersion()); jaroslav@1737: attr.putValue("Bck2BrwsrMinified", "true"); jaroslav@1737: m.getEntries().put(minified, attr); jaroslav@1594: } jaroslav@1742: if (!"false".equals(debug)) { jaroslav@1737: Attributes attr = new Attributes(); jaroslav@1737: attr.putValue("Bck2BrwsrArtifactId", prj.getArtifactId()); jaroslav@1737: attr.putValue("Bck2BrwsrGroupId", prj.getGroupId()); jaroslav@1737: attr.putValue("Bck2BrwsrVersion", prj.getVersion()); jaroslav@1737: attr.putValue("Bck2BrwsrDebug", "true"); jaroslav@1737: m.getEntries().put(debug, attr); jaroslav@1594: } jaroslav@1737: jaroslav@1739: if (aotDeps != null) { jaroslav@1739: for (Artifact a : prj.getArtifacts()) { jaroslav@1739: if (!matches(aotDeps, a)) { jaroslav@1739: continue; jaroslav@1739: } jaroslav@1739: jaroslav@1739: { jaroslav@1739: Attributes attr = new Attributes(); jaroslav@1739: attr.putValue("Bck2BrwsrArtifactId", a.getArtifactId()); jaroslav@1739: attr.putValue("Bck2BrwsrGroupId", a.getGroupId()); jaroslav@1739: attr.putValue("Bck2BrwsrVersion", a.getVersion()); jaroslav@1748: attr.putValue("Bck2BrwsrDebug", "true"); jaroslav@1739: m.getEntries().put(artifactName(a, true), attr); jaroslav@1739: } jaroslav@1739: { jaroslav@1739: Attributes attr = new Attributes(); jaroslav@1742: attr.putValue("Bck2BrwsrArtifactId", a.getArtifactId()); jaroslav@1742: attr.putValue("Bck2BrwsrGroupId", a.getGroupId()); jaroslav@1742: attr.putValue("Bck2BrwsrVersion", a.getVersion()); jaroslav@1748: attr.putValue("Bck2BrwsrMinified", "true"); jaroslav@1739: m.getEntries().put(artifactName(a, false), attr); jaroslav@1739: } jaroslav@1742: } jaroslav@1739: } jaroslav@1739: jaroslav@1737: FileOutputStream fos = new FileOutputStream(this.aotJar); jaroslav@1737: JarOutputStream os = new JarOutputStream(fos, m); jaroslav@1737: jaroslav@1742: if (!"false".equals(debug)) { jaroslav@1737: os.putNextEntry(new JarEntry(debug)); jaroslav@1765: Writer w = new OutputStreamWriter(os, "UTF-8"); jaroslav@1742: configureMain(loader). jaroslav@1737: obfuscation(ObfuscationLevel.NONE). jaroslav@1737: generate(w); jaroslav@1737: w.flush(); jaroslav@1737: os.closeEntry(); jaroslav@1618: } jaroslav@1742: if (!"false".equals(minified)) { jaroslav@1737: os.putNextEntry(new JarEntry(minified)); jaroslav@1737: jaroslav@1765: Writer w = new OutputStreamWriter(os, "UTF-8"); jaroslav@1742: configureMain(loader). jaroslav@1737: obfuscation(ObfuscationLevel.FULL). jaroslav@1737: generate(w); jaroslav@1737: w.flush(); jaroslav@1737: os.closeEntry(); jaroslav@1584: } jaroslav@1739: jaroslav@1739: if (aotDeps != null) { jaroslav@1739: for (Artifact a : prj.getArtifacts()) { jaroslav@1739: if (!matches(aotDeps, a)) { jaroslav@1739: continue; jaroslav@1739: } jaroslav@1742: getLog().info("Generating bck2brwsr for " + a.getFile()); jaroslav@1742: Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, a.getFile(), loader); jaroslav@1742: if (exports != null) { jaroslav@1742: for (String e : exports) { jaroslav@1742: c = c.addExported(e.replace('.', '/')); jaroslav@1742: } jaroslav@1742: } jaroslav@1739: { jaroslav@1739: os.putNextEntry(new JarEntry(artifactName(a, true))); jaroslav@1765: Writer w = new OutputStreamWriter(os, "UTF-8"); jaroslav@1739: c. jaroslav@1739: obfuscation(ObfuscationLevel.NONE). jaroslav@1739: generate(w); jaroslav@1739: w.flush(); jaroslav@1739: os.closeEntry(); jaroslav@1739: } jaroslav@1739: { jaroslav@1739: os.putNextEntry(new JarEntry(artifactName(a, false))); jaroslav@1739: jaroslav@1765: Writer w = new OutputStreamWriter(os, "UTF-8"); jaroslav@1739: c. jaroslav@1739: obfuscation(ObfuscationLevel.FULL). jaroslav@1739: generate(w); jaroslav@1739: w.flush(); jaroslav@1739: os.closeEntry(); jaroslav@1739: } jaroslav@1739: } jaroslav@1739: } jaroslav@1737: os.close(); jaroslav@1737: jaroslav@1737: projectHelper.attachArtifact(prj, "jar", "bck2brwsr", aotJar); jaroslav@1604: } catch (IOException ex) { jaroslav@1604: throw new MojoFailureException("Cannot generate script for " + mainJar, ex); jaroslav@1604: } jaroslav@1584: } jaroslav@1584: jaroslav@1742: private Bck2Brwsr configureMain(URLClassLoader loader) throws IOException { jaroslav@1742: Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, mainJar, loader); jaroslav@1742: if (exports != null) { jaroslav@1742: for (String e : exports) { jaroslav@1742: c = c.addExported(e.replace('.', '/')); jaroslav@1742: } jaroslav@1742: } jaroslav@1742: return c; jaroslav@1742: } jaroslav@1742: jaroslav@1739: private static String artifactName(Artifact a, boolean debug) { jaroslav@1739: return a.getGroupId() + "-" + a.getArtifactId() + (debug ? "-debug.js" : "-min.js"); jaroslav@1739: } jaroslav@1739: jaroslav@1584: private static URLClassLoader buildClassLoader(File root, Collection deps) throws MalformedURLException { jaroslav@1584: List arr = new ArrayList(); jaroslav@1584: if (root != null) { jaroslav@1584: arr.add(root.toURI().toURL()); jaroslav@1584: } jaroslav@1584: for (Artifact a : deps) { jaroslav@1584: if (a.getFile() != null) { jaroslav@1584: arr.add(a.getFile().toURI().toURL()); jaroslav@1584: } jaroslav@1584: } jaroslav@1584: return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader()); jaroslav@1584: } jaroslav@1739: jaroslav@1739: private static boolean matches(String[] aotDeps, Artifact a) { jaroslav@1739: for (String d : aotDeps) { jaroslav@1739: String[] parts = d.split(":"); jaroslav@1739: for (int i = 0; i < parts.length; i++) { jaroslav@1739: if ("*".equals(parts[i])) { jaroslav@1739: parts[i] = null; jaroslav@1739: } jaroslav@1739: } jaroslav@1739: jaroslav@1739: if (parts[0] != null && !parts[0].equals(a.getGroupId())) { jaroslav@1739: continue; jaroslav@1739: } jaroslav@1739: if (parts[1] != null && !parts[1].equals(a.getArtifactId())) { jaroslav@1739: continue; jaroslav@1739: } jaroslav@1739: if (parts.length > 2 && parts[2] != null && !parts[2].equals(a.getClassifier())) { jaroslav@1739: continue; jaroslav@1739: } jaroslav@1739: return true; jaroslav@1739: } jaroslav@1739: return false; jaroslav@1739: } jaroslav@1584: }