All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apidesign.bck2brwsr.mojo.AheadOfTimeBase Maven / Gradle / Ivy

The newest version!
/**
 * Back 2 Browser Bytecode Translator
 * Copyright (C) 2012-2018 Jaroslav Tulach 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. Look for COPYING file in the top folder.
 * If not, see http://opensource.org/licenses/GPL-2.0.
 */
package org.apidesign.bck2brwsr.mojo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import org.apidesign.bck2brwsr.aot.Bck2BrwsrJars;
import org.apidesign.vm4brwsr.Bck2Brwsr;
import org.apidesign.vm4brwsr.ObfuscationLevel;

abstract class AheadOfTimeBase {
    protected abstract File mainJavaScript();
    protected abstract File libraryPath(String fileNameJs);
    protected abstract ObfuscationLevel obfuscation();
    protected abstract String[] exports();
    protected abstract boolean ignoreBootClassPath();
    protected abstract boolean generateAotLibraries();
    protected abstract File mainJar();
    protected abstract File vm();
    protected abstract Iterable artifacts();
    protected abstract void logInfo(String msg);
    protected abstract Exception failure(String msg, Throwable cause);

    protected abstract File file(Art a);
    protected abstract Scope scope(Art a);
    protected abstract String classifier(Art a);
     protected abstract String artifactId(Art a);
    protected abstract String groupId(Art a);
    protected abstract String version(Art a);

    protected final void work() {
        URLClassLoader loader;
        final Iterable artifacts = artifacts();
        try {
            loader = buildClassLoader(mainJar(), artifacts);
        } catch (MalformedURLException ex) {
            throw raise("Can't initialize classloader", ex);
        }
        List libsCp = new ArrayList<>();
        for (Art a : artifacts) {
            final File aFile = file(a);
            if (aFile == null) {
                continue;
            }
            String n = aFile.getName();
            if (!n.endsWith(".jar")) {
                continue;
            }
            if (Scope.PROVIDED == scope(a)) {
                continue;
            }
            if ("bck2brwsr".equals(classifier(a))) {
                continue;
            }
            final String libNameJs = n.substring(0, n.length() - 4) + ".js";
            File js = libraryPath(libNameJs);
            try {
                js.getParentFile().mkdirs();
                aotLibrary(a, artifacts, js, loader, libsCp);
            } catch (IOException ex) {
                throw raise("Can't compile " + aFile, ex);
            }
        }

        try {
            if (mainJavaScript().lastModified() > mainJar().lastModified()) {
                logInfo("Skipping " + mainJavaScript() + " as it already exists.");
            } else {
                logInfo("Generating " + mainJavaScript());
                Bck2Brwsr withLibsCp = Bck2Brwsr.newCompiler().library(libsCp.toArray(new String[0]));
                Bck2Brwsr c = Bck2BrwsrJars.configureFrom(withLibsCp, mainJar(), loader, ignoreBootClassPath());
                if (exports() != null) {
                    for (String e : exports()) {
                        if (e != null) {
                            c = c.addExported(e.replace('.', '/'));
                        }
                    }
                }
                try (Writer w = new OutputStreamWriter(new FileOutputStream(mainJavaScript()), "UTF-8")) {
                    c.
                            obfuscation(obfuscation()).
                            generate(w);
                }
            }
        } catch (IOException ex) {
            throw raise("Cannot generate script for " + mainJar(), ex);
        }

        try (Writer w = new OutputStreamWriter(new FileOutputStream(vm()), "UTF-8")) {
            Bck2Brwsr.newCompiler().
                    obfuscation(obfuscation()).
                    standalone(false).
                    resources(new Bck2Brwsr.Resources() {

                @Override
                public InputStream get(String resource) throws IOException {
                    return null;
                }
            }).
                    generate(w);
            w.close();
        } catch (IOException ex) {
            throw raise("Can't compile", ex);
        }
    }

    private void aotLibrary(Art a, Iterable allArtifacts, File js, URLClassLoader loader, List libsCp) throws IOException {
        File aFile = file(a);
        if (js.lastModified() > aFile.lastModified()) {
            logInfo("Skipping " + js + " as it already exists.");
            libsCp.add(js.getParentFile().getName() + '/' + js.getName());
            return;
        }
        for (Art b : allArtifacts) {
            final File file = file(b);
            if ("bck2brwsr".equals(classifier(b))) { // NOI18N
                JarFile jf = new JarFile(file);
                Manifest man = jf.getManifest();
                for (Map.Entry entrySet : man.getEntries().entrySet()) {
                    String entryName = entrySet.getKey();
                    Attributes attr = entrySet.getValue();

                    if (
                        artifactId(a).equals(attr.getValue("Bck2BrwsrArtifactId")) &&
                        groupId(a).equals(attr.getValue("Bck2BrwsrGroupId")) &&
                        version(a).equals(attr.getValue("Bck2BrwsrVersion")) &&
                        "melta".equals(attr.getValue("Bck2BrwsrMagic")) &&
                        (
                            obfuscation() == ObfuscationLevel.FULL && "true".equals(attr.getValue("Bck2BrwsrMinified"))
                            ||
                            obfuscation() != ObfuscationLevel.FULL && "true".equals(attr.getValue("Bck2BrwsrDebug"))
                        )
                    ) {
                        logInfo("Extracting " + js + " from " + file);
                        libsCp.add(js.getParentFile().getName() + '/' + js.getName());
                        try (InputStream is = jf.getInputStream(new ZipEntry(entryName))) {
                            Files.copy(is, js.toPath(), StandardCopyOption.REPLACE_EXISTING);
                        }
                        return;
                    }
                }
            }
        }
        if (!generateAotLibraries()) {
            throw raise("Not generating " + js + " and no precompiled version found!", null);
        }
        logInfo("Generating " + js);
        libsCp.add(js.getParentFile().getName() + '/' + js.getName());
        try (Writer w = new OutputStreamWriter(new FileOutputStream(js), "UTF-8")) {
            Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, file(a), loader, ignoreBootClassPath());
            if (exports() != null) {
                c = c.addExported(exports());
            }
            c.
                    obfuscation(obfuscation()).
                    generate(w);
        }
    }
    private URLClassLoader buildClassLoader(File root, Iterable deps) throws MalformedURLException {
        List arr = new ArrayList<>();
        if (root != null) {
            arr.add(root.toURI().toURL());
        }
        for (Art a : deps) {
            if (file(a) != null) {
                arr.add(file(a).toURI().toURL());
            }
        }
        return new URLClassLoader(arr.toArray(new URL[0]), AheadOfTimeBase.class.getClassLoader());
    }

    private RuntimeException raise(String msg, Throwable cause) throws RuntimeException {
        return raise(RuntimeException.class, failure(msg, cause));
    }

    private static  E raise(Class type, Throwable ex) throws E {
        throw (E)ex;
    }

    enum Scope {
        PROVIDED, RUNTIME;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy