dew/src/main/java/org/apidesign/bck2brwsr/dew/ClassLoaderFileManager.java
author Jaroslav Tulach <jtulach@netbeans.org>
Thu, 03 Oct 2013 10:02:13 +0200
changeset 1326 8ae6a6c42b5f
parent 1325 f7f25ea1bbec
permissions -rw-r--r--
Fixing license
     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 
    19 package org.apidesign.bck2brwsr.dew;
    20 
    21 import java.io.File;
    22 import java.io.IOException;
    23 import java.io.InputStream;
    24 import java.net.URL;
    25 import java.util.ArrayList;
    26 import java.util.Collections;
    27 import java.util.EnumSet;
    28 import java.util.Enumeration;
    29 import java.util.HashMap;
    30 import java.util.Iterator;
    31 import java.util.List;
    32 import java.util.Map;
    33 import java.util.Set;
    34 import java.util.zip.ZipEntry;
    35 import java.util.zip.ZipFile;
    36 import javax.tools.FileObject;
    37 import javax.tools.JavaFileManager;
    38 import javax.tools.JavaFileObject;
    39 import javax.tools.StandardLocation;
    40 
    41 /**
    42  *
    43  * @author Tomas Zezula
    44  */
    45 public class ClassLoaderFileManager implements JavaFileManager {
    46 
    47     private static final Location[] READ_LOCATIONS = {
    48         StandardLocation.PLATFORM_CLASS_PATH,
    49         StandardLocation.CLASS_PATH,
    50         StandardLocation.SOURCE_PATH
    51     };
    52 
    53     private static final Location[] WRITE_LOCATIONS = {
    54         StandardLocation.CLASS_OUTPUT,
    55         StandardLocation.SOURCE_OUTPUT
    56     };
    57 
    58     private static final Location[] CLASS_LOADER_LOCATIONS = {
    59         StandardLocation.ANNOTATION_PROCESSOR_PATH
    60     };
    61 
    62     private Map<Location, Map<String,List<MemoryFileObject>>> generated;
    63 
    64 
    65     ClassLoaderFileManager() {
    66         generated = new HashMap<>();
    67         for (Location l : WRITE_LOCATIONS) {
    68             generated.put(l, new HashMap<String, List<MemoryFileObject>>());
    69         }
    70     }
    71 
    72 
    73     @Override
    74     public ClassLoader getClassLoader(Location location) {
    75         if (canClassLoad(location)) {
    76             return new SafeClassLoader(getClass().getClassLoader());
    77         } else {
    78             return null;
    79         }
    80     }
    81 
    82     @Override
    83     public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
    84         if (canRead(location)) {
    85             final List<JavaFileObject> res = new ArrayList<JavaFileObject>();
    86             for (String resource : getResources(convertFQNToResource(packageName))) {
    87                 final JavaFileObject jfo = new ClassLoaderJavaFileObject(resource);
    88                 if (kinds.contains(jfo.getKind())) {
    89                     res.add(jfo);
    90                 }
    91             }
    92             return res;
    93         } else if (canWrite(location)) {
    94             Map<String,List<MemoryFileObject>> folders = generated.get(location);
    95             List<MemoryFileObject> files = folders.get(convertFQNToResource(packageName));
    96             if (files != null) {
    97                 final List<JavaFileObject> res = new ArrayList<JavaFileObject>();
    98                 for (JavaFileObject file : files) {
    99                     if (kinds.contains(file.getKind()) && file.getLastModified() >= 0) {
   100                         res.add(file);
   101                     }
   102                 }
   103                 return res;
   104             }
   105         }
   106         return Collections.<JavaFileObject>emptyList();
   107     }
   108 
   109     @Override
   110     public String inferBinaryName(Location location, JavaFileObject file) {
   111         return ((InferableJavaFileObject)file).infer();
   112     }
   113 
   114     @Override
   115     public boolean isSameFile(FileObject a, FileObject b) {
   116         return a.toUri().equals(b.toUri());
   117     }
   118 
   119     @Override
   120     public boolean handleOption(String current, Iterator<String> remaining) {
   121         return false;
   122     }
   123 
   124     @Override
   125     public boolean hasLocation(Location location) {
   126         for (Location l : StandardLocation.values()) {
   127             if (l.equals(location)) {
   128                 return true;
   129             }
   130         }
   131         return false;
   132     }
   133 
   134     @Override
   135     public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
   136         if (canRead(location)) {
   137             return new ClassLoaderJavaFileObject(convertFQNToResource(className) + kind.extension);
   138         } else {
   139             throw new UnsupportedOperationException("Unsupported location for reading: " + location);   //NOI18N
   140         }
   141     }
   142 
   143     @Override
   144     public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
   145         if (canWrite(location)) {
   146             final String resource = convertFQNToResource(className) + kind.extension;
   147             final MemoryFileObject res = new MemoryFileObject(resource, null);
   148             register(location, resource, res);
   149             return res;
   150         } else {
   151             throw new UnsupportedOperationException("Unsupported location for reading: " + location);   //NOI18N
   152         }
   153     }
   154 
   155     @Override
   156     public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
   157         if (canRead(location)) {
   158             return new ClassLoaderJavaFileObject(convertFQNToResource(packageName) + '/' + relativeName); //NOI18N
   159         } else {
   160             throw new UnsupportedOperationException("Unsupported location for reading: " + location);   //NOI18N
   161         }
   162     }
   163 
   164     @Override
   165     public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
   166         if (canWrite(location)) {
   167             final String resource = convertFQNToResource(packageName) + '/' + relativeName; //NOI18N
   168             final MemoryFileObject res = new MemoryFileObject(resource, null);
   169             register(location, resource, res);
   170             return res;
   171         } else {
   172             throw new UnsupportedOperationException("Unsupported location for reading: " + location);   //NOI18N
   173         }
   174     }
   175 
   176     @Override
   177     public void flush() throws IOException {
   178     }
   179 
   180     @Override
   181     public void close() throws IOException {        
   182     }
   183 
   184     @Override
   185     public int isSupportedOption(String option) {
   186         return -1;
   187     }
   188 
   189 //    private List<String> getResources(String folder) throws IOException {
   190 //        final List<String> result = new ArrayList<String>();
   191 //        final BufferedReader in = new BufferedReader(new InputStreamReader(
   192 //                this.getClass().getClassLoader().getResourceAsStream(String.format("%s/pkg-list", folder.substring(0))),    //NOI18N
   193 //                "UTF-8"));  //NOI18N
   194 //        try {
   195 //            String line;
   196 //            while ((line = in.readLine()) != null) {
   197 //                result.add(line);
   198 //            }
   199 //        } finally {
   200 //            in.close();
   201 //        }
   202 //        return result;
   203 //    }
   204 
   205     //MOCK IMPL
   206     private List<String> getResources(String folder) throws IOException {
   207         if (classPathContent == null) {
   208             classPathContent = new HashMap<>();
   209 //            final String boot = System.getProperty("sun.boot.class.path");  //NOI18N
   210             final String cp = System.getProperty("java.class.path");
   211             for (String entry : cp.split(File.pathSeparator)) {
   212                 File f = new File (entry);
   213                 if (f.canRead()) {
   214                     if (f.isFile()) {
   215                         ZipFile zf = new ZipFile(f);
   216                         try {
   217                             Enumeration<? extends ZipEntry> entries = zf.entries();
   218                             while (entries.hasMoreElements()) {
   219                                 ZipEntry e = entries.nextElement();
   220                                 if (e.isDirectory()) {
   221                                     continue;
   222                                 }
   223                                 final String name = String.format("/%s",e.getName());
   224                                 final String owner = getOwner(name);
   225                                 List<String> content = classPathContent.get(owner);
   226                                 if (content == null) {
   227                                     content = new ArrayList<>();
   228                                     classPathContent.put(owner, content);
   229                                 }
   230                                 content.add(name);
   231                             }
   232                         } finally {
   233                             zf.close();
   234                         }
   235                     } else if (f.isDirectory()) {
   236                         addFiles(f,"/", classPathContent);
   237                     }
   238                 }
   239             }                                    
   240         }
   241         List<String> content = classPathContent.get(folder);
   242         return content == null ? Collections.<String>emptyList() : content;
   243     }
   244 
   245     private void addFiles(File folder, String path, Map<String,List<String>> into) {
   246         for (File f : folder.listFiles()) {
   247             String fname = path + (path.length() == 1 ? "" : "/") +  f.getName();
   248             if (f.isDirectory()) {
   249                 addFiles(f, fname, into);
   250             } else {
   251                 List<String> content = into.get(path);
   252                 if (content == null) {
   253                     content = new ArrayList<>();
   254                     classPathContent.put(path, content);
   255                 }
   256                 content.add(fname);
   257             }
   258         }
   259     }
   260     
   261     private Map<String,List<String>> classPathContent;
   262 
   263     private void register(Location loc, String resource, MemoryFileObject jfo) {
   264         Map<String,List<MemoryFileObject>> folders = generated.get(loc);
   265         final String folder = getOwner(resource);
   266         List<MemoryFileObject> content = folders.get(folder);
   267         if (content == null) {
   268             content = new ArrayList<>();
   269             folders.put(folder, content);
   270         }
   271         content.add(jfo);
   272     }
   273 
   274     private static String getOwner(String resource) {
   275         int lastSlash = resource.lastIndexOf('/');
   276         assert lastSlash >= 0;
   277         return resource.substring(0, lastSlash);
   278     }
   279 
   280     private static boolean canRead(Location loc) {
   281         for (Location rl : READ_LOCATIONS) {
   282             if (rl.equals(loc)) {
   283                 return true;
   284             }
   285         }
   286         return false;
   287     }
   288 
   289     private static boolean canWrite(Location loc) {
   290         for (Location wl : WRITE_LOCATIONS) {
   291             if (wl.equals(loc)) {
   292                 return true;
   293             }
   294         }
   295         return false;
   296     }
   297 
   298     private static boolean canClassLoad(Location loc) {
   299         for (Location cll : CLASS_LOADER_LOCATIONS) {
   300             if (cll.equals(loc)) {
   301                 return true;
   302             }
   303         }
   304         return false;
   305     }
   306 
   307     static String convertFQNToResource(String fqn) {
   308         return '/' + fqn.replace('.', '/');   //NOI18N
   309     }
   310 
   311     static String convertResourceToFQN(String resource) {
   312         assert resource.startsWith("/");    //NOI18N
   313         int lastSlash = resource.lastIndexOf('/');  //NOI18N
   314         int lastDot = resource.lastIndexOf('.');    //NOI18N
   315         int stop = lastSlash < lastDot ?
   316             lastDot :
   317             resource.length();
   318         return resource.substring(1, stop).replace('/', '.');    //NOI18N
   319     }
   320 
   321 
   322     JavaFileObject createMemoryFileObject (String resourceName, JavaFileObject.Kind kind, byte[] content) {
   323         final InferableJavaFileObject jfo  = new MemoryFileObject(resourceName, kind, content);
   324         return jfo;
   325     }
   326 
   327     Iterable<? extends MemoryFileObject> getGeneratedFiles(JavaFileObject.Kind... kinds) {
   328         final Set<JavaFileObject.Kind> ks = EnumSet.noneOf(JavaFileObject.Kind.class);
   329         Collections.addAll(ks, kinds);
   330         final List<MemoryFileObject> res = new ArrayList<>();
   331         for (Map<String,List<MemoryFileObject>> folders : generated.values()) {
   332             for (List<MemoryFileObject> content : folders.values()) {
   333                 for (MemoryFileObject fo : content) {
   334                     if (ks.contains(fo.getKind()) && fo.getLastModified() >= 0) {
   335                         res.add(fo);
   336                     }
   337                 }
   338             }
   339         }
   340         return res;
   341     }
   342 
   343     private static final class SafeClassLoader extends ClassLoader {
   344         private final ClassLoader delegate;
   345 
   346         SafeClassLoader(final ClassLoader delegate) {
   347             this.delegate = delegate;
   348 
   349         }
   350 
   351         @Override
   352         public URL getResource(String name) {
   353             return delegate.getResource(name);
   354         }
   355 
   356         @Override
   357         public InputStream getResourceAsStream(String name) {
   358             return delegate.getResourceAsStream(name);
   359         }
   360 
   361         @Override
   362         public Enumeration<URL> getResources(String name) throws IOException {
   363             return delegate.getResources(name);
   364         }
   365 
   366         @Override
   367         public Class<?> loadClass(String name) throws ClassNotFoundException {
   368             return delegate.loadClass(name);
   369         }
   370     }
   371 
   372 }