2 * Back 2 Browser Bytecode Translator
3 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
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.
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.
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.
19 package org.apidesign.bck2brwsr.dew;
22 import java.io.IOException;
23 import java.io.InputStream;
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;
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;
43 * @author Tomas Zezula
45 public class ClassLoaderFileManager implements JavaFileManager {
47 private static final Location[] READ_LOCATIONS = {
48 StandardLocation.PLATFORM_CLASS_PATH,
49 StandardLocation.CLASS_PATH,
50 StandardLocation.SOURCE_PATH
53 private static final Location[] WRITE_LOCATIONS = {
54 StandardLocation.CLASS_OUTPUT,
55 StandardLocation.SOURCE_OUTPUT
58 private static final Location[] CLASS_LOADER_LOCATIONS = {
59 StandardLocation.ANNOTATION_PROCESSOR_PATH
62 private Map<Location, Map<String,List<MemoryFileObject>>> generated;
65 ClassLoaderFileManager() {
66 generated = new HashMap<>();
67 for (Location l : WRITE_LOCATIONS) {
68 generated.put(l, new HashMap<String, List<MemoryFileObject>>());
74 public ClassLoader getClassLoader(Location location) {
75 if (canClassLoad(location)) {
76 return new SafeClassLoader(getClass().getClassLoader());
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())) {
93 } else if (canWrite(location)) {
94 Map<String,List<MemoryFileObject>> folders = generated.get(location);
95 List<MemoryFileObject> files = folders.get(convertFQNToResource(packageName));
97 final List<JavaFileObject> res = new ArrayList<JavaFileObject>();
98 for (JavaFileObject file : files) {
99 if (kinds.contains(file.getKind()) && file.getLastModified() >= 0) {
106 return Collections.<JavaFileObject>emptyList();
110 public String inferBinaryName(Location location, JavaFileObject file) {
111 return ((InferableJavaFileObject)file).infer();
115 public boolean isSameFile(FileObject a, FileObject b) {
116 return a.toUri().equals(b.toUri());
120 public boolean handleOption(String current, Iterator<String> remaining) {
125 public boolean hasLocation(Location location) {
126 for (Location l : StandardLocation.values()) {
127 if (l.equals(location)) {
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);
139 throw new UnsupportedOperationException("Unsupported location for reading: " + location); //NOI18N
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);
151 throw new UnsupportedOperationException("Unsupported location for reading: " + location); //NOI18N
156 public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
157 if (canRead(location)) {
158 return new ClassLoaderJavaFileObject(convertFQNToResource(packageName) + '/' + relativeName); //NOI18N
160 throw new UnsupportedOperationException("Unsupported location for reading: " + location); //NOI18N
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);
172 throw new UnsupportedOperationException("Unsupported location for reading: " + location); //NOI18N
177 public void flush() throws IOException {
181 public void close() throws IOException {
185 public int isSupportedOption(String option) {
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
196 // while ((line = in.readLine()) != null) {
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);
215 ZipFile zf = new ZipFile(f);
217 Enumeration<? extends ZipEntry> entries = zf.entries();
218 while (entries.hasMoreElements()) {
219 ZipEntry e = entries.nextElement();
220 if (e.isDirectory()) {
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);
235 } else if (f.isDirectory()) {
236 addFiles(f,"/", classPathContent);
241 List<String> content = classPathContent.get(folder);
242 return content == null ? Collections.<String>emptyList() : content;
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);
251 List<String> content = into.get(path);
252 if (content == null) {
253 content = new ArrayList<>();
254 classPathContent.put(path, content);
261 private Map<String,List<String>> classPathContent;
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);
274 private static String getOwner(String resource) {
275 int lastSlash = resource.lastIndexOf('/');
276 assert lastSlash >= 0;
277 return resource.substring(0, lastSlash);
280 private static boolean canRead(Location loc) {
281 for (Location rl : READ_LOCATIONS) {
282 if (rl.equals(loc)) {
289 private static boolean canWrite(Location loc) {
290 for (Location wl : WRITE_LOCATIONS) {
291 if (wl.equals(loc)) {
298 private static boolean canClassLoad(Location loc) {
299 for (Location cll : CLASS_LOADER_LOCATIONS) {
300 if (cll.equals(loc)) {
307 static String convertFQNToResource(String fqn) {
308 return '/' + fqn.replace('.', '/'); //NOI18N
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 ?
318 return resource.substring(1, stop).replace('/', '.'); //NOI18N
322 JavaFileObject createMemoryFileObject (String resourceName, JavaFileObject.Kind kind, byte[] content) {
323 final InferableJavaFileObject jfo = new MemoryFileObject(resourceName, kind, content);
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) {
343 private static final class SafeClassLoader extends ClassLoader {
344 private final ClassLoader delegate;
346 SafeClassLoader(final ClassLoader delegate) {
347 this.delegate = delegate;
352 public URL getResource(String name) {
353 return delegate.getResource(name);
357 public InputStream getResourceAsStream(String name) {
358 return delegate.getResourceAsStream(name);
362 public Enumeration<URL> getResources(String name) throws IOException {
363 return delegate.getResources(name);
367 public Class<?> loadClass(String name) throws ClassNotFoundException {
368 return delegate.loadClass(name);