jaroslav@1489: /** jaroslav@1489: * Back 2 Browser Bytecode Translator jaroslav@1489: * Copyright (C) 2012 Jaroslav Tulach jaroslav@1489: * jaroslav@1489: * This program is free software: you can redistribute it and/or modify jaroslav@1489: * it under the terms of the GNU General Public License as published by jaroslav@1489: * the Free Software Foundation, version 2 of the License. jaroslav@1489: * jaroslav@1489: * This program is distributed in the hope that it will be useful, jaroslav@1489: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@1489: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@1489: * GNU General Public License for more details. jaroslav@1489: * jaroslav@1489: * You should have received a copy of the GNU General Public License jaroslav@1489: * along with this program. Look for COPYING file in the top folder. jaroslav@1489: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@1489: */ jaroslav@1489: package org.apidesign.bck2brwsr.launcher; jaroslav@1489: jaroslav@1525: import java.io.BufferedReader; jaroslav@1489: import java.io.File; jaroslav@1489: import java.io.IOException; jaroslav@1489: import java.io.InputStream; jaroslav@1525: import java.io.InputStreamReader; jaroslav@1489: import java.io.StringWriter; jaroslav@1492: import java.net.JarURLConnection; jaroslav@1489: import java.net.URISyntaxException; jaroslav@1489: import java.net.URL; jaroslav@1489: import java.util.ArrayList; jaroslav@1489: import java.util.Enumeration; jaroslav@1525: import java.util.HashSet; jaroslav@1489: import java.util.List; jaroslav@1525: import java.util.Set; jaroslav@1489: import java.util.jar.JarEntry; jaroslav@1489: import java.util.jar.JarFile; jaroslav@1505: import java.util.logging.Level; jaroslav@1505: import java.util.logging.Logger; jaroslav@1489: import java.util.zip.ZipEntry; jaroslav@1492: import org.apidesign.bck2brwsr.launcher.BaseHTTPLauncher.Res; jaroslav@1489: import org.apidesign.vm4brwsr.Bck2Brwsr; jaroslav@1489: jaroslav@1489: /** jaroslav@1489: * jaroslav@1489: * @author Jaroslav Tulach jaroslav@1489: */ jaroslav@1489: class CompileCP { jaroslav@1523: private static final Logger LOG = Logger.getLogger(CompileCP.class.getName()); jaroslav@1525: static String compileJAR(final JarFile jar, Set testClasses) jaroslav@1525: throws IOException { jaroslav@1489: List arr = new ArrayList<>(); jaroslav@1489: List classes = new ArrayList<>(); jaroslav@1525: Set exported = new HashSet(); jaroslav@1525: Set keep = new HashSet(testClasses); jaroslav@1525: listJAR(jar, classes, arr, exported, keep); jaroslav@1525: List root = new ArrayList<>(); jaroslav@1525: for (String c : classes) { jaroslav@1525: if (keep.contains(c)) { jaroslav@1525: root.add(c); jaroslav@1525: continue; jaroslav@1525: } jaroslav@1525: int slash = c.lastIndexOf('/'); jaroslav@1525: String pkg = c.substring(0, slash + 1); jaroslav@1525: if (exported.contains(pkg)) { jaroslav@1525: root.add(c); jaroslav@1525: } jaroslav@1525: } jaroslav@1525: jaroslav@1489: StringWriter w = new StringWriter(); jaroslav@1489: try { jaroslav@1489: class JarRes extends EmulationResources implements Bck2Brwsr.Resources { jaroslav@1489: @Override jaroslav@1489: public InputStream get(String resource) throws IOException { jaroslav@1489: InputStream is = jar.getInputStream(new ZipEntry(resource)); jaroslav@1489: return is == null ? super.get(resource) : is; jaroslav@1489: } jaroslav@1489: } jaroslav@1489: jaroslav@1489: Bck2Brwsr.newCompiler() jaroslav@1491: .addClasses(classes.toArray(new String[0])) jaroslav@1525: .addRootClasses(root.toArray(new String[0])) jaroslav@1498: .addResources(arr.toArray(new String[0])) jaroslav@1491: .library(true) jaroslav@1489: .resources(new JarRes()) jaroslav@1489: .generate(w); jaroslav@1489: w.flush(); jaroslav@1489: return w.toString(); jaroslav@1523: } catch (IOException ex) { jaroslav@1523: throw ex; jaroslav@1489: } catch (Throwable ex) { jaroslav@1489: throw new IOException("Cannot compile: ", ex); jaroslav@1489: } finally { jaroslav@1489: w.close(); jaroslav@1489: } jaroslav@1489: } jaroslav@1489: jaroslav@1505: static String compileFromClassPath(URL u, final Res r) throws IOException { jaroslav@1505: File f; jaroslav@1505: try { jaroslav@1505: f = new File(u.toURI()); jaroslav@1505: } catch (URISyntaxException ex) { jaroslav@1505: throw new IOException(ex); jaroslav@1505: } jaroslav@1489: for (String s : System.getProperty("java.class.path").split(File.pathSeparator)) { jaroslav@1489: if (!f.getPath().startsWith(s)) { jaroslav@1489: continue; jaroslav@1489: } jaroslav@1489: File root = new File(s); jaroslav@1489: List arr = new ArrayList<>(); jaroslav@1489: List classes = new ArrayList<>(); jaroslav@1489: listDir(root, null, classes, arr); jaroslav@1489: StringWriter w = new StringWriter(); jaroslav@1489: try { jaroslav@1489: Bck2Brwsr.newCompiler() jaroslav@1489: .addRootClasses(classes.toArray(new String[0])) jaroslav@1498: .addResources(arr.toArray(new String[0])) jaroslav@1491: .library(true) jaroslav@1504: .resources(new EmulationResources() { jaroslav@1504: @Override jaroslav@1504: public InputStream get(String resource) throws IOException { jaroslav@1517: if (r != null) { jaroslav@1517: final URL url = r.get(resource, 0); jaroslav@1517: return url == null ? null : url.openStream(); jaroslav@1517: } jaroslav@1517: return super.get(resource); jaroslav@1504: } jaroslav@1504: }) jaroslav@1489: .generate(w); jaroslav@1489: w.flush(); jaroslav@1489: return w.toString(); jaroslav@1489: } catch (ClassFormatError ex) { jaroslav@1489: throw new IOException(ex); jaroslav@1489: } finally { jaroslav@1489: w.close(); jaroslav@1489: } jaroslav@1489: } jaroslav@1489: return null; jaroslav@1489: } jaroslav@1489: jaroslav@1525: private static void listJAR( jaroslav@1525: JarFile j, List classes, jaroslav@1525: List resources, Set exported, Set keep jaroslav@1525: ) throws IOException { jaroslav@1489: Enumeration en = j.entries(); jaroslav@1489: while (en.hasMoreElements()) { jaroslav@1489: JarEntry e = en.nextElement(); jaroslav@1489: final String n = e.getName(); jaroslav@1492: if (n.contains("package-info")) { jaroslav@1492: continue; jaroslav@1492: } jaroslav@1489: if (n.endsWith("/")) { jaroslav@1489: continue; jaroslav@1489: } jaroslav@1489: int last = n.lastIndexOf('/'); jaroslav@1489: String pkg = n.substring(0, last + 1); jaroslav@1489: if (skipPkg(pkg)) { jaroslav@1489: continue; jaroslav@1489: } jaroslav@1489: if (n.endsWith(".class")) { jaroslav@1489: classes.add(n.substring(0, n.length() - 6)); jaroslav@1489: } else { jaroslav@1489: resources.add(n); jaroslav@1525: if (n.startsWith("META-INF/services/") && keep != null) { jaroslav@1525: BufferedReader r = new BufferedReader(new InputStreamReader(j.getInputStream(e))); jaroslav@1525: for (;;) { jaroslav@1525: String l = r.readLine(); jaroslav@1525: if (l == null) { jaroslav@1525: break; jaroslav@1525: } jaroslav@1525: if (l.startsWith("#")) { jaroslav@1525: continue; jaroslav@1525: } jaroslav@1525: keep.add(l.replace('.', '/')); jaroslav@1525: } jaroslav@1525: } jaroslav@1525: } jaroslav@1525: } jaroslav@1525: String exp = j.getManifest().getMainAttributes().getValue("Export-Package"); jaroslav@1525: if (exp != null && exported != null) { jaroslav@1525: for (String def : exp.split(",")) { jaroslav@1525: for (String sep : def.split(";")) { jaroslav@1525: exported.add(sep.replace('.', '/') + "/"); jaroslav@1525: break; jaroslav@1525: } jaroslav@1489: } jaroslav@1489: } jaroslav@1489: } jaroslav@1489: jaroslav@1489: private static boolean skipPkg(String pkg) { jaroslav@1489: return pkg.equals("org/apidesign/bck2brwsr/launcher/"); jaroslav@1489: } jaroslav@1489: jaroslav@1489: private static void listDir(File f, String pref, List classes, List resources) throws IOException { jaroslav@1489: File[] arr = f.listFiles(); jaroslav@1489: if (arr == null) { jaroslav@1504: if (f.getName().equals("package-info.class")) { jaroslav@1504: return; jaroslav@1504: } jaroslav@1489: if (f.getName().endsWith(".class")) { jaroslav@1489: classes.add(pref + f.getName().substring(0, f.getName().length() - 6)); jaroslav@1489: } else { jaroslav@1489: resources.add(pref + f.getName()); jaroslav@1489: } jaroslav@1489: } else { jaroslav@1489: for (File ch : arr) { jaroslav@1489: jaroslav@1489: listDir(ch, pref == null ? "" : pref + f.getName() + "/", classes, resources); jaroslav@1489: } jaroslav@1489: } jaroslav@1489: } jaroslav@1489: jaroslav@1504: static void compileVM(StringBuilder sb, final Res r) throws IOException { jaroslav@1513: URL u = r.get(InterruptedException.class.getName().replace('.', '/') + ".class", 0); jaroslav@1492: JarURLConnection juc = (JarURLConnection)u.openConnection(); jaroslav@1492: jaroslav@1492: List arr = new ArrayList<>(); jaroslav@1492: List classes = new ArrayList<>(); jaroslav@1525: listJAR(juc.getJarFile(), classes, arr, null, null); jaroslav@1492: jaroslav@1492: Bck2Brwsr.newCompiler().addRootClasses(classes.toArray(new String[0])) jaroslav@1504: .resources(new Bck2Brwsr.Resources() { jaroslav@1504: @Override jaroslav@1504: public InputStream get(String resource) throws IOException { jaroslav@1523: final URL url = r.get(resource, 0); jaroslav@1523: return url == null ? null : url.openStream(); jaroslav@1504: } jaroslav@1504: }).generate(sb); jaroslav@1492: } jaroslav@1492: jaroslav@1489: static class EmulationResources implements Bck2Brwsr.Resources { jaroslav@1489: jaroslav@1489: @Override jaroslav@1489: public InputStream get(String name) throws IOException { jaroslav@1489: Enumeration en = CompileCP.class.getClassLoader().getResources(name); jaroslav@1489: URL u = null; jaroslav@1489: while (en.hasMoreElements()) { jaroslav@1489: u = en.nextElement(); jaroslav@1489: } jaroslav@1489: if (u == null) { jaroslav@1523: LOG.log(Level.WARNING, "Cannot find {0}", name); jaroslav@1523: return null; jaroslav@1489: } jaroslav@1523: if (u.toExternalForm().contains("/rt.jar!")) { jaroslav@1523: LOG.warning(name + "No bootdelegation for "); jaroslav@1523: return null; jaroslav@1489: } jaroslav@1489: return u.openStream(); jaroslav@1489: } jaroslav@1489: } jaroslav@1489: }