Fixed ClassLoader problems.
2 * To change this license header, choose License Headers in Project Properties.
3 * To change this template file, choose Tools | Templates
4 * and open the template in the editor.
7 package org.apidesign.bck2brwsr.dew;
9 import java.io.BufferedReader;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.InputStreamReader;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.EnumSet;
18 import java.util.Enumeration;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
24 import java.util.zip.ZipEntry;
25 import java.util.zip.ZipFile;
26 import javax.tools.FileObject;
27 import javax.tools.JavaFileManager;
28 import javax.tools.JavaFileObject;
29 import javax.tools.StandardLocation;
33 * @author Tomas Zezula
35 public class ClassLoaderFileManager implements JavaFileManager {
37 private static final Location[] READ_LOCATIONS = {
38 StandardLocation.PLATFORM_CLASS_PATH,
39 StandardLocation.CLASS_PATH,
40 StandardLocation.SOURCE_PATH
43 private static final Location[] WRITE_LOCATIONS = {
44 StandardLocation.CLASS_OUTPUT,
45 StandardLocation.SOURCE_OUTPUT
48 private static final Location[] CLASS_LOADER_LOCATIONS = {
49 StandardLocation.ANNOTATION_PROCESSOR_PATH
52 private Map<Location, Map<String,List<MemoryFileObject>>> generated;
55 ClassLoaderFileManager() {
56 generated = new HashMap<>();
57 for (Location l : WRITE_LOCATIONS) {
58 generated.put(l, new HashMap<String, List<MemoryFileObject>>());
64 public ClassLoader getClassLoader(Location location) {
65 if (canClassLoad(location)) {
66 return new SafeClassLoader(getClass().getClassLoader());
73 public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
74 if (canRead(location)) {
75 final List<JavaFileObject> res = new ArrayList<JavaFileObject>();
76 for (String resource : getResources(convertFQNToResource(packageName))) {
77 final JavaFileObject jfo = new ClassLoaderJavaFileObject(resource);
78 if (kinds.contains(jfo.getKind())) {
83 } else if (canWrite(location)) {
84 Map<String,List<MemoryFileObject>> folders = generated.get(location);
85 List<MemoryFileObject> files = folders.get(convertFQNToResource(packageName));
87 final List<JavaFileObject> res = new ArrayList<JavaFileObject>();
88 for (JavaFileObject file : files) {
89 if (kinds.contains(file.getKind()) && file.getLastModified() >= 0) {
96 return Collections.<JavaFileObject>emptyList();
100 public String inferBinaryName(Location location, JavaFileObject file) {
101 return ((InferableJavaFileObject)file).infer();
105 public boolean isSameFile(FileObject a, FileObject b) {
106 return a.toUri().equals(b.toUri());
110 public boolean handleOption(String current, Iterator<String> remaining) {
115 public boolean hasLocation(Location location) {
116 for (Location l : StandardLocation.values()) {
117 if (l.equals(location)) {
125 public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
126 if (canRead(location)) {
127 return new ClassLoaderJavaFileObject(convertFQNToResource(className) + kind.extension);
129 throw new UnsupportedOperationException("Unsupported location for reading: " + location); //NOI18N
134 public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
135 if (canWrite(location)) {
136 final String resource = convertFQNToResource(className) + kind.extension;
137 final MemoryFileObject res = new MemoryFileObject(resource, null);
138 register(location, resource, res);
141 throw new UnsupportedOperationException("Unsupported location for reading: " + location); //NOI18N
146 public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
147 if (canRead(location)) {
148 return new ClassLoaderJavaFileObject(convertFQNToResource(packageName) + '/' + relativeName); //NOI18N
150 throw new UnsupportedOperationException("Unsupported location for reading: " + location); //NOI18N
155 public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
156 if (canWrite(location)) {
157 final String resource = convertFQNToResource(packageName) + '/' + relativeName; //NOI18N
158 final MemoryFileObject res = new MemoryFileObject(resource, null);
159 register(location, resource, res);
162 throw new UnsupportedOperationException("Unsupported location for reading: " + location); //NOI18N
167 public void flush() throws IOException {
171 public void close() throws IOException {
175 public int isSupportedOption(String option) {
179 // private List<String> getResources(String folder) throws IOException {
180 // final List<String> result = new ArrayList<String>();
181 // final BufferedReader in = new BufferedReader(new InputStreamReader(
182 // this.getClass().getClassLoader().getResourceAsStream(String.format("%s/pkg-list", folder.substring(0))), //NOI18N
183 // "UTF-8")); //NOI18N
186 // while ((line = in.readLine()) != null) {
196 private List<String> getResources(String folder) throws IOException {
197 if (classPathContent == null) {
198 classPathContent = new HashMap<>();
199 // final String boot = System.getProperty("sun.boot.class.path"); //NOI18N
200 final String cp = System.getProperty("java.class.path");
201 for (String entry : cp.split(File.pathSeparator)) {
202 File f = new File (entry);
205 ZipFile zf = new ZipFile(f);
207 Enumeration<? extends ZipEntry> entries = zf.entries();
208 while (entries.hasMoreElements()) {
209 ZipEntry e = entries.nextElement();
210 if (e.isDirectory()) {
213 final String name = String.format("/%s",e.getName());
214 final String owner = getOwner(name);
215 List<String> content = classPathContent.get(owner);
216 if (content == null) {
217 content = new ArrayList<>();
218 classPathContent.put(owner, content);
225 } else if (f.isDirectory()) {
226 addFiles(f,"/", classPathContent);
231 List<String> content = classPathContent.get(folder);
232 return content == null ? Collections.<String>emptyList() : content;
235 private void addFiles(File folder, String path, Map<String,List<String>> into) {
236 for (File f : folder.listFiles()) {
237 String fname = path + (path.length() == 1 ? "" : "/") + f.getName();
238 if (f.isDirectory()) {
239 addFiles(f, fname, into);
241 List<String> content = into.get(path);
242 if (content == null) {
243 content = new ArrayList<>();
244 classPathContent.put(path, content);
251 private Map<String,List<String>> classPathContent;
253 private void register(Location loc, String resource, MemoryFileObject jfo) {
254 Map<String,List<MemoryFileObject>> folders = generated.get(loc);
255 final String folder = getOwner(resource);
256 List<MemoryFileObject> content = folders.get(folder);
257 if (content == null) {
258 content = new ArrayList<>();
259 folders.put(folder, content);
264 private static String getOwner(String resource) {
265 int lastSlash = resource.lastIndexOf('/');
266 assert lastSlash >= 0;
267 return resource.substring(0, lastSlash);
270 private static boolean canRead(Location loc) {
271 for (Location rl : READ_LOCATIONS) {
272 if (rl.equals(loc)) {
279 private static boolean canWrite(Location loc) {
280 for (Location wl : WRITE_LOCATIONS) {
281 if (wl.equals(loc)) {
288 private static boolean canClassLoad(Location loc) {
289 for (Location cll : CLASS_LOADER_LOCATIONS) {
290 if (cll.equals(loc)) {
297 static String convertFQNToResource(String fqn) {
298 return '/' + fqn.replace('.', '/'); //NOI18N
301 static String convertResourceToFQN(String resource) {
302 assert resource.startsWith("/"); //NOI18N
303 int lastSlash = resource.lastIndexOf('/'); //NOI18N
304 int lastDot = resource.lastIndexOf('.'); //NOI18N
305 int stop = lastSlash < lastDot ?
308 return resource.substring(1, stop).replace('/', '.'); //NOI18N
312 JavaFileObject createMemoryFileObject (String resourceName, JavaFileObject.Kind kind, byte[] content) {
313 final InferableJavaFileObject jfo = new MemoryFileObject(resourceName, kind, content);
317 Iterable<? extends MemoryFileObject> getGeneratedFiles(JavaFileObject.Kind... kinds) {
318 final Set<JavaFileObject.Kind> ks = EnumSet.noneOf(JavaFileObject.Kind.class);
319 Collections.addAll(ks, kinds);
320 final List<MemoryFileObject> res = new ArrayList<>();
321 for (Map<String,List<MemoryFileObject>> folders : generated.values()) {
322 for (List<MemoryFileObject> content : folders.values()) {
323 for (MemoryFileObject fo : content) {
324 if (ks.contains(fo.getKind()) && fo.getLastModified() >= 0) {
333 private static final class SafeClassLoader extends ClassLoader {
334 private final ClassLoader delegate;
336 SafeClassLoader(final ClassLoader delegate) {
337 this.delegate = delegate;
342 public URL getResource(String name) {
343 return delegate.getResource(name);
347 public InputStream getResourceAsStream(String name) {
348 return delegate.getResourceAsStream(name);
352 public Enumeration<URL> getResources(String name) throws IOException {
353 return delegate.getResources(name);
357 public Class<?> loadClass(String name) throws ClassNotFoundException {
358 return delegate.loadClass(name);