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