jaroslav@1599: /** jaroslav@1599: * Back 2 Browser Bytecode Translator jaroslav@1599: * Copyright (C) 2012 Jaroslav Tulach jaroslav@1599: * jaroslav@1599: * This program is free software: you can redistribute it and/or modify jaroslav@1599: * it under the terms of the GNU General Public License as published by jaroslav@1599: * the Free Software Foundation, version 2 of the License. jaroslav@1599: * jaroslav@1599: * This program is distributed in the hope that it will be useful, jaroslav@1599: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@1599: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@1599: * GNU General Public License for more details. jaroslav@1599: * jaroslav@1599: * You should have received a copy of the GNU General Public License jaroslav@1599: * along with this program. Look for COPYING file in the top folder. jaroslav@1599: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@1599: */ jaroslav@1599: package org.apidesign.bck2brwsr.aot; jaroslav@1599: jaroslav@1599: import java.io.BufferedReader; jaroslav@1599: import java.io.File; jaroslav@1599: import java.io.IOException; jaroslav@1599: import java.io.InputStream; jaroslav@1599: import java.io.InputStreamReader; jaroslav@1599: import java.net.URL; jaroslav@1599: import java.util.ArrayList; jaroslav@1599: import java.util.Enumeration; jaroslav@1599: import java.util.HashSet; jaroslav@1599: import java.util.List; jaroslav@1599: import java.util.Set; jaroslav@1599: import java.util.jar.JarEntry; jaroslav@1599: import java.util.jar.JarFile; jaroslav@1599: import java.util.logging.Level; jaroslav@1599: import java.util.logging.Logger; jaroslav@1599: import java.util.zip.ZipEntry; jaroslav@1599: import org.apidesign.vm4brwsr.Bck2Brwsr; jaroslav@1599: jaroslav@1599: /** Utilities to process JAR files and set a compiler jaroslav@1599: * up jaroslav@1599: * jaroslav@1599: * @author Jaroslav Tulach jaroslav@1599: */ jaroslav@1599: public final class Bck2BrwsrJars { jaroslav@1599: private static final Logger LOG = Logger.getLogger(Bck2BrwsrJars.class.getName()); jaroslav@1599: jaroslav@1599: private Bck2BrwsrJars() { jaroslav@1599: } jaroslav@1599: jaroslav@1599: /** Creates new compiler pre-configured from the content of jaroslav@1599: * provided JAR file. The compiler will compile all classes. jaroslav@1599: * The system understands OSGi manifest entries and will export jaroslav@1599: * all packages that are exported in the JAR file. The system jaroslav@1599: * also recognizes META-INF/services and makes sure the file names jaroslav@1599: * are not mangled. jaroslav@1599: * jaroslav@1599: * @param c the compiler to {@link Bck2Brwsr#addClasses(java.lang.String...) add classes}, jaroslav@1599: * {@link Bck2Brwsr#addResources(java.lang.String...) add resources} and jaroslav@1599: * {@link Bck2Brwsr#addExported(java.lang.String...) exported objects} to. jaroslav@1599: * Can be null - in such case an jaroslav@1599: * {@link Bck2Brwsr#newCompiler() empty compiler} is constructed. jaroslav@1599: * @param jar the file to process jaroslav@1599: * @return newly configured compiler jaroslav@1599: * @throws IOException if something goes wrong jaroslav@1599: */ jaroslav@1599: public static Bck2Brwsr configureFrom(Bck2Brwsr c, File jar) throws IOException { jaroslav@1601: final JarFile jf = new JarFile(jar); jaroslav@1601: List classes = new ArrayList<>(); jaroslav@1601: List resources = new ArrayList<>(); jaroslav@1601: Set exported = new HashSet<>(); jaroslav@1599: jaroslav@1601: listJAR(jf, classes, resources, exported); jaroslav@1601: jaroslav@1601: class JarRes extends EmulationResources implements Bck2Brwsr.Resources { jaroslav@1601: jaroslav@1601: @Override jaroslav@1601: public InputStream get(String resource) throws IOException { jaroslav@1601: InputStream is = jf.getInputStream(new ZipEntry(resource)); jaroslav@1601: return is == null ? super.get(resource) : is; jaroslav@1599: } jaroslav@1599: } jaroslav@1601: return Bck2Brwsr.newCompiler() jaroslav@1601: .library(true) jaroslav@1601: .addClasses(classes.toArray(new String[classes.size()])) jaroslav@1601: .addExported(exported.toArray(new String[exported.size()])) jaroslav@1601: .addResources(resources.toArray(new String[resources.size()])) jaroslav@1601: .resources(new JarRes()); jaroslav@1599: } jaroslav@1599: jaroslav@1599: private static void listJAR( jaroslav@1599: JarFile j, List classes, jaroslav@1599: List resources, Set keep jaroslav@1599: ) throws IOException { jaroslav@1599: Enumeration en = j.entries(); jaroslav@1599: while (en.hasMoreElements()) { jaroslav@1599: JarEntry e = en.nextElement(); jaroslav@1599: final String n = e.getName(); jaroslav@1599: if (n.endsWith("/")) { jaroslav@1599: continue; jaroslav@1599: } jaroslav@1599: int last = n.lastIndexOf('/'); jaroslav@1599: String pkg = n.substring(0, last + 1); jaroslav@1599: if (pkg.startsWith("java/")) { jaroslav@1599: keep.add(pkg); jaroslav@1599: } jaroslav@1599: if (n.endsWith(".class")) { jaroslav@1599: classes.add(n.substring(0, n.length() - 6)); jaroslav@1599: } else { jaroslav@1599: resources.add(n); jaroslav@1599: if (n.startsWith("META-INF/services/") && keep != null) { jaroslav@1599: BufferedReader r = new BufferedReader(new InputStreamReader(j.getInputStream(e))); jaroslav@1599: for (;;) { jaroslav@1599: String l = r.readLine(); jaroslav@1599: if (l == null) { jaroslav@1599: break; jaroslav@1599: } jaroslav@1599: if (l.startsWith("#")) { jaroslav@1599: continue; jaroslav@1599: } jaroslav@1599: keep.add(l.replace('.', '/')); jaroslav@1599: } jaroslav@1599: } jaroslav@1599: } jaroslav@1599: } jaroslav@1599: String exp = j.getManifest().getMainAttributes().getValue("Export-Package"); jaroslav@1599: if (exp != null && keep != null) { jaroslav@1599: for (String def : exp.split(",")) { jaroslav@1599: for (String sep : def.split(";")) { jaroslav@1599: keep.add(sep.replace('.', '/') + "/"); jaroslav@1599: break; jaroslav@1599: } jaroslav@1599: } jaroslav@1599: } jaroslav@1599: } jaroslav@1599: jaroslav@1599: static class EmulationResources implements Bck2Brwsr.Resources { jaroslav@1599: jaroslav@1599: @Override jaroslav@1599: public InputStream get(String name) throws IOException { jaroslav@1599: Enumeration en = Bck2BrwsrJars.class.getClassLoader().getResources(name); jaroslav@1599: URL u = null; jaroslav@1599: while (en.hasMoreElements()) { jaroslav@1599: u = en.nextElement(); jaroslav@1599: } jaroslav@1599: if (u == null) { jaroslav@1599: LOG.log(Level.WARNING, "Cannot find {0}", name); jaroslav@1599: return null; jaroslav@1599: } jaroslav@1599: if (u.toExternalForm().contains("/rt.jar!")) { jaroslav@1599: LOG.log(Level.WARNING, "{0}No bootdelegation for ", name); jaroslav@1599: return null; jaroslav@1599: } jaroslav@1599: return u.openStream(); jaroslav@1599: } jaroslav@1599: } jaroslav@1599: jaroslav@1599: }