launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 22 May 2014 15:29:40 +0200
branchclosure
changeset 1586 d4ee65642d8d
parent 1583 89b6b369c13d
child 1599 36746c46716a
permissions -rw-r--r--
Tests pass OK in full obfuscation mode
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.bck2brwsr.launcher;
    19 
    20 import java.io.BufferedReader;
    21 import java.io.File;
    22 import java.io.IOException;
    23 import java.io.InputStream;
    24 import java.io.InputStreamReader;
    25 import java.io.StringWriter;
    26 import java.net.JarURLConnection;
    27 import java.net.URISyntaxException;
    28 import java.net.URL;
    29 import java.util.ArrayList;
    30 import java.util.Enumeration;
    31 import java.util.HashSet;
    32 import java.util.List;
    33 import java.util.Set;
    34 import java.util.jar.JarEntry;
    35 import java.util.jar.JarFile;
    36 import java.util.logging.Level;
    37 import java.util.logging.Logger;
    38 import java.util.zip.ZipEntry;
    39 import org.apidesign.bck2brwsr.launcher.BaseHTTPLauncher.Res;
    40 import org.apidesign.vm4brwsr.Bck2Brwsr;
    41 import org.apidesign.vm4brwsr.ObfuscationLevel;
    42 
    43 /**
    44  *
    45  * @author Jaroslav Tulach
    46  */
    47 class CompileCP {
    48     private static final Logger LOG = Logger.getLogger(CompileCP.class.getName());
    49     static String compileJAR(final JarFile jar, Set<String> testClasses) 
    50     throws IOException {
    51         List<String> arr = new ArrayList<>();
    52         List<String> classes = new ArrayList<>();
    53         Set<String> keep = new HashSet<String>(testClasses);
    54         listJAR(jar, classes, arr, keep);
    55         
    56         StringWriter w = new StringWriter();
    57         try {
    58             class JarRes extends EmulationResources implements Bck2Brwsr.Resources {
    59                 @Override
    60                 public InputStream get(String resource) throws IOException {
    61                     InputStream is = jar.getInputStream(new ZipEntry(resource));
    62                     return is == null ? super.get(resource) : is;
    63                 }
    64             }
    65             
    66             Bck2Brwsr.newCompiler()
    67                 .addClasses(classes.toArray(new String[0]))
    68                 .addExported(keep.toArray(new String[0]))
    69                 .addResources(arr.toArray(new String[0]))
    70                 //.obfuscation(ObfuscationLevel.FULL)
    71                 .library(true)
    72                 .resources(new JarRes())
    73                 .generate(w);
    74             w.flush();
    75             return w.toString();
    76         } catch (IOException ex) {
    77             throw ex;
    78         } catch (Throwable ex) {
    79             throw new IOException("Cannot compile: ", ex);
    80         } finally {
    81             w.close();
    82         }
    83     }
    84     
    85     static String compileFromClassPath(URL u, final Res r) throws IOException {
    86         File f;
    87         try {
    88             f = new File(u.toURI());
    89         } catch (URISyntaxException ex) {
    90             throw new IOException(ex);
    91         }
    92         for (String s : System.getProperty("java.class.path").split(File.pathSeparator)) {
    93             if (!f.getPath().startsWith(s)) {
    94                 continue;
    95             }
    96             File root = new File(s);
    97             List<String> arr = new ArrayList<>();
    98             List<String> classes = new ArrayList<>();
    99             listDir(root, null, classes, arr);
   100             StringWriter w = new StringWriter();
   101             try {
   102                 Bck2Brwsr.newCompiler()
   103                     .addRootClasses(classes.toArray(new String[0]))
   104                     .addResources(arr.toArray(new String[0]))
   105                     .library(true)
   106                     //.obfuscation(ObfuscationLevel.FULL)
   107                     .resources(new EmulationResources() {
   108                         @Override
   109                         public InputStream get(String resource) throws IOException {
   110                             if (r != null) {
   111                                 final URL url = r.get(resource, 0);
   112                                 return url == null ? null : url.openStream();
   113                             }
   114                             return super.get(resource);
   115                         }
   116                     })
   117                     .generate(w);
   118                 w.flush();
   119                 return w.toString();
   120             } catch (ClassFormatError ex) {
   121                 throw new IOException(ex);
   122             } finally {
   123                 w.close();
   124             }
   125         }
   126         return null;
   127     }
   128     
   129     private static void listJAR(
   130         JarFile j, List<String> classes,
   131         List<String> resources, Set<String> keep
   132     ) throws IOException {
   133         Enumeration<JarEntry> en = j.entries();
   134         while (en.hasMoreElements()) {
   135             JarEntry e = en.nextElement();
   136             final String n = e.getName();
   137             if (n.endsWith("/")) {
   138                 continue;
   139             }
   140             int last = n.lastIndexOf('/');
   141             String pkg = n.substring(0, last + 1);
   142             if (skipPkg(pkg)) {
   143                 continue;
   144             }
   145             if (n.endsWith(".class")) {
   146                 classes.add(n.substring(0, n.length() - 6));
   147             } else {
   148                 resources.add(n);
   149                 if (n.startsWith("META-INF/services/") && keep != null) {
   150                     BufferedReader r = new BufferedReader(new InputStreamReader(j.getInputStream(e)));
   151                     for (;;) {
   152                         String l = r.readLine();
   153                         if (l == null) {
   154                             break;
   155                         }
   156                         if (l.startsWith("#")) {
   157                             continue;
   158                         }
   159                         keep.add(l.replace('.', '/'));
   160                     }
   161                 }
   162             }
   163         }
   164         String exp = j.getManifest().getMainAttributes().getValue("Export-Package");
   165         if (exp != null && keep != null) {
   166             for (String def : exp.split(",")) {
   167                 for (String sep : def.split(";")) {
   168                     keep.add(sep.replace('.', '/') + "/");
   169                     break;
   170                 }
   171             }
   172         }
   173     }
   174 
   175     private static boolean skipPkg(String pkg) {
   176         return pkg.equals("org/apidesign/bck2brwsr/launcher/");
   177     }
   178     
   179     private static void listDir(File f, String pref, List<String> classes, List<String> resources) throws IOException {
   180         File[] arr = f.listFiles();
   181         if (arr == null) {
   182             if (f.getName().endsWith(".class")) {
   183                 classes.add(pref + f.getName().substring(0, f.getName().length() - 6));
   184             } else {
   185                 resources.add(pref + f.getName());
   186             }
   187         } else {
   188             for (File ch : arr) {
   189                 
   190                 listDir(ch, pref == null ? "" : pref + f.getName() + "/", classes, resources);
   191             }
   192         }
   193     }
   194 
   195     static void compileVM(StringBuilder sb, final Res r) throws IOException {
   196         List<String> arr = new ArrayList<>();
   197         List<String> classes = new ArrayList<>();
   198 
   199         {
   200             URL u = r.get(InterruptedException.class.getName().replace('.', '/') + ".class", 0);
   201             JarURLConnection juc = (JarURLConnection)u.openConnection();
   202             listJAR(juc.getJarFile(), classes, arr, null);
   203         }
   204         {
   205             URL u = r.get(Bck2Brwsr.class.getName().replace('.', '/') + ".class", 0);
   206             JarURLConnection juc = (JarURLConnection)u.openConnection();
   207             listJAR(juc.getJarFile(), classes, arr, null);
   208         }
   209 
   210         Bck2Brwsr.newCompiler().addRootClasses(classes.toArray(new String[0]))
   211             //.obfuscation(ObfuscationLevel.FULL)
   212             .resources(new Bck2Brwsr.Resources() {
   213                 @Override
   214                 public InputStream get(String resource) throws IOException {
   215                     final URL url = r.get(resource, 0);
   216                     return url == null ? null : url.openStream();
   217                 }
   218             }).generate(sb);
   219     }
   220 
   221     static class EmulationResources implements Bck2Brwsr.Resources {
   222 
   223         @Override
   224         public InputStream get(String name) throws IOException {
   225             Enumeration<URL> en = CompileCP.class.getClassLoader().getResources(name);
   226             URL u = null;
   227             while (en.hasMoreElements()) {
   228                 u = en.nextElement();
   229             }
   230             if (u == null) {
   231                 LOG.log(Level.WARNING, "Cannot find {0}", name);
   232                 return null;
   233             }
   234             if (u.toExternalForm().contains("/rt.jar!")) {
   235                 LOG.warning(name + "No bootdelegation for ");
   236                 return null;
   237             }
   238             return u.openStream();
   239         }
   240     }
   241 }