dew/src/main/java/org/apidesign/bck2brwsr/dew/ClassLoaderFileManager.java
changeset 1324 263482b074e9
child 1325 f7f25ea1bbec
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dew/src/main/java/org/apidesign/bck2brwsr/dew/ClassLoaderFileManager.java	Wed Oct 02 21:00:24 2013 +0200
     1.3 @@ -0,0 +1,331 @@
     1.4 +/*
     1.5 + * To change this license header, choose License Headers in Project Properties.
     1.6 + * To change this template file, choose Tools | Templates
     1.7 + * and open the template in the editor.
     1.8 + */
     1.9 +
    1.10 +package org.apidesign.bck2brwsr.dew;
    1.11 +
    1.12 +import java.io.BufferedReader;
    1.13 +import java.io.File;
    1.14 +import java.io.IOException;
    1.15 +import java.io.InputStreamReader;
    1.16 +import java.util.ArrayList;
    1.17 +import java.util.Collections;
    1.18 +import java.util.EnumSet;
    1.19 +import java.util.Enumeration;
    1.20 +import java.util.HashMap;
    1.21 +import java.util.Iterator;
    1.22 +import java.util.List;
    1.23 +import java.util.Map;
    1.24 +import java.util.Set;
    1.25 +import java.util.zip.ZipEntry;
    1.26 +import java.util.zip.ZipFile;
    1.27 +import javax.tools.FileObject;
    1.28 +import javax.tools.JavaFileManager;
    1.29 +import javax.tools.JavaFileObject;
    1.30 +import javax.tools.StandardLocation;
    1.31 +
    1.32 +/**
    1.33 + *
    1.34 + * @author Tomas Zezula
    1.35 + */
    1.36 +public class ClassLoaderFileManager implements JavaFileManager {
    1.37 +
    1.38 +    private static final Location[] READ_LOCATIONS = {
    1.39 +        StandardLocation.PLATFORM_CLASS_PATH,
    1.40 +        StandardLocation.CLASS_PATH,
    1.41 +        StandardLocation.SOURCE_PATH
    1.42 +    };
    1.43 +
    1.44 +    private static final Location[] WRITE_LOCATIONS = {
    1.45 +        StandardLocation.CLASS_OUTPUT,
    1.46 +        StandardLocation.SOURCE_OUTPUT
    1.47 +    };
    1.48 +
    1.49 +    private static final Location[] CLASS_LOADER_LOCATIONS = {
    1.50 +        StandardLocation.ANNOTATION_PROCESSOR_PATH
    1.51 +    };
    1.52 +
    1.53 +    private Map<Location, Map<String,List<MemoryFileObject>>> generated;
    1.54 +
    1.55 +
    1.56 +    ClassLoaderFileManager() {
    1.57 +        generated = new HashMap<>();
    1.58 +        for (Location l : WRITE_LOCATIONS) {
    1.59 +            generated.put(l, new HashMap<String, List<MemoryFileObject>>());
    1.60 +        }
    1.61 +    }
    1.62 +
    1.63 +
    1.64 +    @Override
    1.65 +    public ClassLoader getClassLoader(Location location) {
    1.66 +        if (canClassLoad(location)) {
    1.67 +            return getClass().getClassLoader();
    1.68 +        } else {
    1.69 +            return null;
    1.70 +        }
    1.71 +    }
    1.72 +
    1.73 +    @Override
    1.74 +    public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
    1.75 +        if (canRead(location)) {
    1.76 +            final List<JavaFileObject> res = new ArrayList<JavaFileObject>();
    1.77 +            for (String resource : getResources(convertFQNToResource(packageName))) {
    1.78 +                final JavaFileObject jfo = new ClassLoaderJavaFileObject(resource);
    1.79 +                if (kinds.contains(jfo.getKind())) {
    1.80 +                    res.add(jfo);
    1.81 +                }
    1.82 +            }
    1.83 +            return res;
    1.84 +        } else if (canWrite(location)) {
    1.85 +            Map<String,List<MemoryFileObject>> folders = generated.get(location);
    1.86 +            List<MemoryFileObject> files = folders.get(convertFQNToResource(packageName));
    1.87 +            if (files != null) {
    1.88 +                final List<JavaFileObject> res = new ArrayList<JavaFileObject>();
    1.89 +                for (JavaFileObject file : files) {
    1.90 +                    if (kinds.contains(file.getKind()) && file.getLastModified() >= 0) {
    1.91 +                        res.add(file);
    1.92 +                    }
    1.93 +                }
    1.94 +                return res;
    1.95 +            }
    1.96 +        }
    1.97 +        return Collections.<JavaFileObject>emptyList();
    1.98 +    }
    1.99 +
   1.100 +    @Override
   1.101 +    public String inferBinaryName(Location location, JavaFileObject file) {
   1.102 +        return ((InferableJavaFileObject)file).infer();
   1.103 +    }
   1.104 +
   1.105 +    @Override
   1.106 +    public boolean isSameFile(FileObject a, FileObject b) {
   1.107 +        return a.toUri().equals(b.toUri());
   1.108 +    }
   1.109 +
   1.110 +    @Override
   1.111 +    public boolean handleOption(String current, Iterator<String> remaining) {
   1.112 +        return false;
   1.113 +    }
   1.114 +
   1.115 +    @Override
   1.116 +    public boolean hasLocation(Location location) {
   1.117 +        for (Location l : StandardLocation.values()) {
   1.118 +            if (l.equals(location)) {
   1.119 +                return true;
   1.120 +            }
   1.121 +        }
   1.122 +        return false;
   1.123 +    }
   1.124 +
   1.125 +    @Override
   1.126 +    public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
   1.127 +        if (canRead(location)) {
   1.128 +            return new ClassLoaderJavaFileObject(convertFQNToResource(className) + kind.extension);
   1.129 +        } else {
   1.130 +            throw new UnsupportedOperationException("Unsupported location for reading: " + location);   //NOI18N
   1.131 +        }
   1.132 +    }
   1.133 +
   1.134 +    @Override
   1.135 +    public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
   1.136 +        if (canWrite(location)) {
   1.137 +            final String resource = convertFQNToResource(className) + kind.extension;
   1.138 +            final MemoryFileObject res = new MemoryFileObject(resource, null);
   1.139 +            register(location, resource, res);
   1.140 +            return res;
   1.141 +        } else {
   1.142 +            throw new UnsupportedOperationException("Unsupported location for reading: " + location);   //NOI18N
   1.143 +        }
   1.144 +    }
   1.145 +
   1.146 +    @Override
   1.147 +    public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
   1.148 +        if (canRead(location)) {
   1.149 +            return new ClassLoaderJavaFileObject(convertFQNToResource(packageName) + '/' + relativeName); //NOI18N
   1.150 +        } else {
   1.151 +            throw new UnsupportedOperationException("Unsupported location for reading: " + location);   //NOI18N
   1.152 +        }
   1.153 +    }
   1.154 +
   1.155 +    @Override
   1.156 +    public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
   1.157 +        if (canWrite(location)) {
   1.158 +            final String resource = convertFQNToResource(packageName) + '/' + relativeName; //NOI18N
   1.159 +            final MemoryFileObject res = new MemoryFileObject(resource, null);
   1.160 +            register(location, resource, res);
   1.161 +            return res;
   1.162 +        } else {
   1.163 +            throw new UnsupportedOperationException("Unsupported location for reading: " + location);   //NOI18N
   1.164 +        }
   1.165 +    }
   1.166 +
   1.167 +    @Override
   1.168 +    public void flush() throws IOException {
   1.169 +    }
   1.170 +
   1.171 +    @Override
   1.172 +    public void close() throws IOException {        
   1.173 +    }
   1.174 +
   1.175 +    @Override
   1.176 +    public int isSupportedOption(String option) {
   1.177 +        return -1;
   1.178 +    }
   1.179 +
   1.180 +//    private List<String> getResources(String folder) throws IOException {
   1.181 +//        final List<String> result = new ArrayList<String>();
   1.182 +//        final BufferedReader in = new BufferedReader(new InputStreamReader(
   1.183 +//                this.getClass().getClassLoader().getResourceAsStream(String.format("%s/pkg-list", folder.substring(0))),    //NOI18N
   1.184 +//                "UTF-8"));  //NOI18N
   1.185 +//        try {
   1.186 +//            String line;
   1.187 +//            while ((line = in.readLine()) != null) {
   1.188 +//                result.add(line);
   1.189 +//            }
   1.190 +//        } finally {
   1.191 +//            in.close();
   1.192 +//        }
   1.193 +//        return result;
   1.194 +//    }
   1.195 +
   1.196 +    //MOCK IMPL
   1.197 +    private List<String> getResources(String folder) throws IOException {
   1.198 +        if (classPathContent == null) {
   1.199 +            classPathContent = new HashMap<>();
   1.200 +//            final String boot = System.getProperty("sun.boot.class.path");  //NOI18N
   1.201 +            final String cp = System.getProperty("java.class.path");
   1.202 +            for (String entry : cp.split(File.pathSeparator)) {
   1.203 +                File f = new File (entry);
   1.204 +                if (f.canRead()) {
   1.205 +                    if (f.isFile()) {
   1.206 +                        ZipFile zf = new ZipFile(f);
   1.207 +                        try {
   1.208 +                            Enumeration<? extends ZipEntry> entries = zf.entries();
   1.209 +                            while (entries.hasMoreElements()) {
   1.210 +                                ZipEntry e = entries.nextElement();
   1.211 +                                if (e.isDirectory()) {
   1.212 +                                    continue;
   1.213 +                                }
   1.214 +                                final String name = String.format("/%s",e.getName());
   1.215 +                                final String owner = getOwner(name);
   1.216 +                                List<String> content = classPathContent.get(owner);
   1.217 +                                if (content == null) {
   1.218 +                                    content = new ArrayList<>();
   1.219 +                                    classPathContent.put(owner, content);
   1.220 +                                }
   1.221 +                                content.add(name);
   1.222 +                            }
   1.223 +                        } finally {
   1.224 +                            zf.close();
   1.225 +                        }
   1.226 +                    } else if (f.isDirectory()) {
   1.227 +                        addFiles(f,"/", classPathContent);
   1.228 +                    }
   1.229 +                }
   1.230 +            }                                    
   1.231 +        }
   1.232 +        List<String> content = classPathContent.get(folder);
   1.233 +        return content == null ? Collections.<String>emptyList() : content;
   1.234 +    }
   1.235 +
   1.236 +    private void addFiles(File folder, String path, Map<String,List<String>> into) {
   1.237 +        for (File f : folder.listFiles()) {
   1.238 +            String fname = path + (path.length() == 1 ? "" : "/") +  f.getName();
   1.239 +            if (f.isDirectory()) {
   1.240 +                addFiles(f, fname, into);
   1.241 +            } else {
   1.242 +                List<String> content = into.get(path);
   1.243 +                if (content == null) {
   1.244 +                    content = new ArrayList<>();
   1.245 +                    classPathContent.put(path, content);
   1.246 +                }
   1.247 +                content.add(fname);
   1.248 +            }
   1.249 +        }
   1.250 +    }
   1.251 +    
   1.252 +    private Map<String,List<String>> classPathContent;
   1.253 +
   1.254 +    private void register(Location loc, String resource, MemoryFileObject jfo) {
   1.255 +        Map<String,List<MemoryFileObject>> folders = generated.get(loc);
   1.256 +        final String folder = getOwner(resource);
   1.257 +        List<MemoryFileObject> content = folders.get(folder);
   1.258 +        if (content == null) {
   1.259 +            content = new ArrayList<>();
   1.260 +            folders.put(folder, content);
   1.261 +        }
   1.262 +        content.add(jfo);
   1.263 +    }
   1.264 +
   1.265 +    private static String getOwner(String resource) {
   1.266 +        int lastSlash = resource.lastIndexOf('/');
   1.267 +        assert lastSlash >= 0;
   1.268 +        return resource.substring(0, lastSlash);
   1.269 +    }
   1.270 +
   1.271 +    private static boolean canRead(Location loc) {
   1.272 +        for (Location rl : READ_LOCATIONS) {
   1.273 +            if (rl.equals(loc)) {
   1.274 +                return true;
   1.275 +            }
   1.276 +        }
   1.277 +        return false;
   1.278 +    }
   1.279 +
   1.280 +    private static boolean canWrite(Location loc) {
   1.281 +        for (Location wl : WRITE_LOCATIONS) {
   1.282 +            if (wl.equals(loc)) {
   1.283 +                return true;
   1.284 +            }
   1.285 +        }
   1.286 +        return false;
   1.287 +    }
   1.288 +
   1.289 +    private static boolean canClassLoad(Location loc) {
   1.290 +        for (Location cll : CLASS_LOADER_LOCATIONS) {
   1.291 +            if (cll.equals(loc)) {
   1.292 +                return true;
   1.293 +            }
   1.294 +        }
   1.295 +        return false;
   1.296 +    }
   1.297 +
   1.298 +    static String convertFQNToResource(String fqn) {
   1.299 +        return '/' + fqn.replace('.', '/');   //NOI18N
   1.300 +    }
   1.301 +
   1.302 +    static String convertResourceToFQN(String resource) {
   1.303 +        assert resource.startsWith("/");    //NOI18N
   1.304 +        int lastSlash = resource.lastIndexOf('/');  //NOI18N
   1.305 +        int lastDot = resource.lastIndexOf('.');    //NOI18N
   1.306 +        int stop = lastSlash < lastDot ?
   1.307 +            lastDot :
   1.308 +            resource.length();
   1.309 +        return resource.substring(1, stop).replace('/', '.');    //NOI18N
   1.310 +    }
   1.311 +
   1.312 +
   1.313 +    JavaFileObject createMemoryFileObject (String resourceName, JavaFileObject.Kind kind, byte[] content) {
   1.314 +        final InferableJavaFileObject jfo  = new MemoryFileObject(resourceName, kind, content);
   1.315 +        return jfo;
   1.316 +    }
   1.317 +
   1.318 +    Iterable<? extends MemoryFileObject> getGeneratedFiles(JavaFileObject.Kind... kinds) {
   1.319 +        final Set<JavaFileObject.Kind> ks = EnumSet.noneOf(JavaFileObject.Kind.class);
   1.320 +        Collections.addAll(ks, kinds);
   1.321 +        final List<MemoryFileObject> res = new ArrayList<>();
   1.322 +        for (Map<String,List<MemoryFileObject>> folders : generated.values()) {
   1.323 +            for (List<MemoryFileObject> content : folders.values()) {
   1.324 +                for (MemoryFileObject fo : content) {
   1.325 +                    if (ks.contains(fo.getKind()) && fo.getLastModified() >= 0) {
   1.326 +                        res.add(fo);
   1.327 +                    }
   1.328 +                }
   1.329 +            }
   1.330 +        }
   1.331 +        return res;
   1.332 +    }
   1.333 +
   1.334 +}