Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(279)

Side by Side Diff: third_party/jmake/src/org/pantsbuild/jmake/ClassPath.java

Issue 1373723003: Fix javac --incremental by using jmake for dependency analysis (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@aidl
Patch Set: fix license check Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /* Copyright (c) 2002-2008 Sun Microsystems, Inc. All rights reserved
2 *
3 * This program is distributed under the terms of
4 * the GNU General Public License Version 2. See the LICENSE file
5 * at the top of the source tree.
6 */
7 package org.pantsbuild.jmake;
8
9 import java.io.File;
10 import java.io.FilenameFilter;
11 import java.io.IOException;
12 import java.net.URL;
13 import java.net.URLClassLoader;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.LinkedHashMap;
17 import java.util.List;
18 import java.util.Locale;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.StringTokenizer;
22 import java.util.zip.ZipEntry;
23 import java.util.zip.ZipFile;
24
25 /**
26 * An instance of this class represents a class path, on which binary classes ca n be looked up.
27 * It also provides several static methods to create and utilize several specifi c class paths used
28 * throughout jmake.
29 *
30 * @author Misha Dmitriev
31 * 12 October 2004
32 */
33 public class ClassPath {
34
35 private PathEntry[] paths;
36 private static ClassPath projectClassPath; // Class path (currently it can contain only JARs) containing sourceless project classes.
37 // See also the comment to standardClassPath.
38 private static ClassPath standardClassPath; // Class path that the user spe cifies via the -classpath option. A sum of the
39 // standardClassPath, the projectClassPath, and the virtualPath is passed to the compiler. Each of these
40 // class paths are also used to look up non-project superclasses/superinterf aces of
41 // project classes.
42 private static ClassPath bootClassPath, extClassPath; // Class paths that b y default are sun.boot.class.path and all JARs on
43 // java.ext.class.path, respectively. They are used to look up non-project
44 // superclasses/superinterfaces of project classes. Their values can be chan ged using
45 // setBootClassPath() and setExtDirs().
46 private static ClassPath virtualPath; // Class path that the user specifies via the -vpath option.
47 private static String compilerUserClassPath; // Class path to be passed to t he compiler; equals to the sum of values of parameters of
48 // setClassPath() and setProjectClassPath() methods.
49 private static String standardClassPathStr, projectClassPathStr, bootClass PathStr, extDirsStr,
50 virtualPathStr;
51 private static Map<String,ClassInfo> classCache;
52
53
54 static {
55 resetOnFinish();
56 }
57
58 /**
59 * Needed since some environments, e.g. NetBeans, can keep jmake classes in memory
60 * permanently. Thus unchanged class paths from previous, possibly unrelated invocations
61 * of jmake, may interfere with the current settings.
62 */
63 public static void resetOnFinish() {
64 projectClassPath = standardClassPath = bootClassPath = extClassPath = vi rtualPath =
65 null;
66 compilerUserClassPath = null;
67 standardClassPathStr = projectClassPathStr = bootClassPathStr =
68 extDirsStr = virtualPathStr = null;
69 classCache = new LinkedHashMap<String,ClassInfo>();
70 }
71
72 public static void setClassPath(String value) throws PublicExceptions.Invali dCmdOptionException {
73 standardClassPathStr = value;
74 standardClassPath = new ClassPath(value, false);
75 }
76
77 public static void setProjectClassPath(String value) throws PublicExceptions .InvalidCmdOptionException {
78 projectClassPathStr = value;
79 projectClassPath = new ClassPath(value, true);
80 }
81
82 public static void setBootClassPath(String value) throws PublicExceptions.In validCmdOptionException {
83 bootClassPathStr = value;
84 bootClassPath = new ClassPath(value, false);
85 }
86
87 public static void setExtDirs(String value) throws PublicExceptions.InvalidC mdOptionException {
88 extDirsStr = value;
89 // Extension class path needs special handling, since it consists of dir ectories, which contain .jars
90 // So we need to find all these .jars in all these dirs and add them to extClassPathElementList
91 List<String> extClassPathElements = new ArrayList<String>();
92 for (StringTokenizer tok =
93 new StringTokenizer(value, File.pathSeparator); tok.hasMoreToken s();) {
94 File extDir = new File(tok.nextToken());
95 String[] extJars = extDir.list(new FilenameFilter() {
96
97 public boolean accept(File dir, String name) {
98 name = name.toLowerCase(Locale.ENGLISH);
99 return name.endsWith(".zip") || name.endsWith(".jar");
100 }
101 });
102 if (extJars == null) {
103 continue;
104 }
105 for (int i = 0; i < extJars.length; i++) {
106 extClassPathElements.add(extDir + File.separator + extJars[i]);
107 }
108 }
109 extClassPath = new ClassPath(extClassPathElements, false);
110 }
111
112 public static void setVirtualPath(String value) throws PublicExceptions.Inva lidCmdOptionException {
113 if (value == null) {
114 throw new PublicExceptions.InvalidCmdOptionException("null argument" );
115 }
116 StringTokenizer st = new StringTokenizer(value, File.pathSeparator);
117 while (st.hasMoreElements()) {
118 String dir = st.nextToken();
119 if ( ! (new File(dir)).isDirectory()) {
120 throw new PublicExceptions.InvalidCmdOptionException("Virtual pa th must contain only directories." +
121 " Entry " + dir + " is not a directory.");
122 }
123 }
124 virtualPathStr = value;
125 virtualPath = new ClassPath(value, false);
126 }
127
128 public static void initializeAllClassPaths() {
129 // First set the compiler class path value
130 if (standardClassPathStr == null && projectClassPathStr == null) {
131 compilerUserClassPath = ".";
132 } else if (standardClassPathStr == null) {
133 compilerUserClassPath = projectClassPathStr;
134 } else if (projectClassPathStr == null) {
135 compilerUserClassPath = standardClassPathStr;
136 } else {
137 compilerUserClassPath =
138 standardClassPathStr + File.pathSeparator + projectClassPath Str;
139 }
140
141 if (virtualPathStr != null) {
142 compilerUserClassPath += File.pathSeparator + virtualPathStr;
143 }
144
145 if (standardClassPathStr == null) {
146 try {
147 String tmp = ".";
148 if (virtualPathStr != null) {
149 tmp += File.pathSeparator + virtualPathStr;
150 }
151 standardClassPath = new ClassPath(tmp, false);
152 } catch (PublicExceptions.InvalidCmdOptionException ex) { /* Should not happen */ }
153 }
154 if (projectClassPathStr == null) {
155 projectClassPath = new ClassPath();
156 }
157
158 // Create the core class path as a combination of sun.boot.class.path an d java.ext.dirs contents
159 if (bootClassPathStr == null) {
160 try {
161 bootClassPath =
162 new ClassPath(System.getProperty("sun.boot.class.path"), false);
163 } catch (PublicExceptions.InvalidCmdOptionException ex) { /* Shouldn 't happen */ }
164 // bootClassPathStr should remain null, so that nothing that the user di dn't specify is passed to the compiler
165 }
166
167 if (extDirsStr == null) {
168 try {
169 setExtDirs(System.getProperty("java.ext.dirs"));
170 } catch (PublicExceptions.InvalidCmdOptionException ex) { /* Shouldn 't happen */ }
171 // extDirsStr should remain null, so that nothing that the user didn 't specify is passed to the compiler
172 extDirsStr = null;
173 }
174 }
175
176 /** Never returns null - if classpath wasn't set explicitly, returns "." */
177 public static String getCompilerUserClassPath() {
178 return compilerUserClassPath;
179 }
180
181 /** Will return null if boot class path wasn't explicitly specified */
182 public static String getCompilerBootClassPath() {
183 return bootClassPathStr;
184 }
185
186 /** Will return null if extdirs weren't explicitly specified */
187 public static String getCompilerExtDirs() {
188 return extDirsStr;
189 }
190
191 /** Will return null if virtualPath wasn't explicitly specified */
192 public static String getVirtualPath() {
193 return virtualPathStr;
194 }
195
196 /**
197 * For the given class return the list of all of its superclasses (excluding Object), that can be loaded from
198 * projectClassPath or standardClassPath, plus the first superclass that can be loaded from coreClassPath.
199 * The latter is an optimization based on the assumption that core classes n ever change, or rather the programmer
200 * will recompile everything when they switch to a new JDK version. The opti mization prevents us from wasting time
201 * repeatedly loading the same sets of core classes.
202 */
203 public static void getSuperclasses(String className,
204 Collection<String> res, PCDManager pcdm) {
205 int iterNo = 0;
206 while (!"java/lang/Object".equals(className)) {
207 ClassInfo ci = getClassInfoForName(className, pcdm);
208 if (ci == null) {
209 return;
210 }
211 if (iterNo++ > 0) {
212 res.add(ci.name);
213 }
214 className = ci.superName;
215 }
216 }
217
218 /**
219 * Add to the given set the names of all interfaces implemented by the given class, that can be loaded from
220 * projectClassPath or standardClassPath, plus the first interface on each b ranch that can be loaded from
221 * coreClassPath. It's the same optimization as in getSuperclasses().
222 */
223 public static void addAllImplementedInterfaceNames(String className,
224 Set<String> intfSet, PCDManager pcdm) {
225 if ("java/lang/Object".equals(className)) {
226 return;
227 }
228 ClassInfo ci = getClassInfoForName(className, pcdm);
229 if (ci == null) {
230 return;
231 }
232 String[] interfaces = ci.interfaces;
233 if (interfaces != null) {
234 for (int i = 0; i < interfaces.length; i++) {
235 intfSet.add(interfaces[i]);
236 addAllImplementedInterfaceNames(interfaces[i], intfSet, pcdm);
237 }
238 }
239
240 String superName = ci.superName;
241 if (superName != null) {
242 addAllImplementedInterfaceNames(superName, intfSet, pcdm);
243 }
244 }
245
246 public static String[] getProjectJars() {
247 if (projectClassPath == null || projectClassPath.isEmpty()) {
248 return null;
249 }
250 PathEntry paths[] = projectClassPath.paths;
251 String[] ret = new String[paths.length];
252 for (int i = 0; i < paths.length; i++) {
253 ret[i] = paths[i].toString();
254 }
255 return ret;
256 }
257
258 public static ClassInfo getClassInfoForName(String className, PCDManager pcd m) {
259 ClassInfo info = classCache.get(className);
260 if (info != null) {
261 return info;
262 }
263
264 byte buf[] = bootClassPath.getBytesForClass(className);
265 if (buf == null) {
266 buf = extClassPath.getBytesForClass(className);
267 }
268 if (buf == null) {
269 buf = standardClassPath.getBytesForClass(className);
270 }
271 if (buf == null) {
272 buf = projectClassPath.getBytesForClass(className);
273 }
274 if (buf == null) {
275 return null;
276 }
277
278 info = new ClassInfo(buf, pcdm, className);
279 classCache.put(className, info);
280 return info;
281 }
282
283 /** Returns the class loader that would load classes from the given class pa th. */
284 public static ClassLoader getClassLoaderForPath(String classPath) throws Exc eption {
285 boolean isWindows = System.getProperty("os.name").startsWith("Win");
286 ClassPath cp = new ClassPath(classPath, false);
287 PathEntry[] paths = cp.paths;
288 URL[] urls = new URL[paths.length];
289 for (int i = 0; i < paths.length; i++) {
290 String dirOrJar = paths[i].toString();
291 if (!(dirOrJar.startsWith("file://") || dirOrJar.startsWith("http:// "))) {
292 // On Windows, if I have path specified as "file://c:\...", (i.e . with the drive name) URLClassLoader works
293 // unbelievably slow. However, if an additional slash is added, like : "file:///c:\...", the speed becomes
294 // normal. To me it looks like a bug, but, anyway, I am taking m easure here.
295 if (isWindows && dirOrJar.charAt(1) == ':') {
296 dirOrJar = "/" + dirOrJar;
297 }
298 dirOrJar = new File(dirOrJar).toURI().toString();
299 }
300 if (!(dirOrJar.endsWith(".jar") || dirOrJar.endsWith(".zip") || dirO rJar.endsWith(File.separator))) {
301 dirOrJar += File.separator; // So that URLClassLoader correctly handles it as a directory
302 }
303 urls[i] = new URL(dirOrJar);
304 }
305
306 return new URLClassLoader(urls);
307 //} catch (java.net.MalformedURLException e) {
308
309 //}
310 }
311
312
313 // ------------------------------------ Private implementation ------------- -------------------------------
314 private ClassPath() {
315 paths = new PathEntry[0];
316 }
317
318 private ClassPath(String classPath, boolean isJarOnly) throws PublicExceptio ns.InvalidCmdOptionException {
319 if (classPath == null) {
320 throw new PublicExceptions.InvalidCmdOptionException("null argument" );
321 }
322 List<String> vec = new ArrayList<String>();
323
324 for (StringTokenizer tok =
325 new StringTokenizer(classPath, File.pathSeparator); tok.hasMoreT okens();) {
326 String path = tok.nextToken();
327 vec.add(path);
328 }
329 init(vec, isJarOnly);
330 }
331
332 private ClassPath(List<String> pathEntries, boolean isJarOnly) throws Public Exceptions.InvalidCmdOptionException {
333 init(pathEntries, isJarOnly);
334 }
335
336 private void init(List<String> pathEntries, boolean isJarOnly) throws Public Exceptions.InvalidCmdOptionException {
337 if (pathEntries == null) {
338 throw new PublicExceptions.InvalidCmdOptionException("null argument" );
339 }
340 List<PathEntry> vec = new ArrayList<PathEntry>(pathEntries.size());
341 for (int i = 0; i < pathEntries.size(); i++) {
342 String path = pathEntries.get(i);
343 if (!path.equals("")) {
344 File file = new File(path);
345 try {
346 if (file.exists() && file.canRead()) {
347 if (file.isDirectory()) {
348 if (isJarOnly) {
349 throw new PublicExceptions.InvalidCmdOptionExcep tion("directories are not allowed on this class path: " + path);
350 }
351 vec.add(new Dir(file));
352 } else {
353 vec.add(new Zip(new ZipFile(file)));
354 }
355 } else if (isJarOnly) {
356 throw new IOException("file does not exist");
357 }
358 } catch (IOException e) {
359 if (isJarOnly) {
360 throw new PublicExceptions.InvalidCmdOptionException("er ror initializing class path component " + path + ": " + e.getMessage());
361 }
362 }
363 }
364 }
365
366 paths = new PathEntry[vec.size()];
367 vec.toArray(paths);
368 }
369
370 private boolean isEmpty() {
371 return paths.length == 0;
372 }
373
374 private byte[] getBytesForClass(String className) {
375 String fileName = className + ".class";
376 for (int i = 0; i < paths.length; i++) {
377 byte buf[] = paths[i].getBytesForClassFile(fileName);
378 if (buf != null) {
379 return buf;
380 }
381 }
382 return null;
383 }
384
385 public String toString() {
386 if (paths == null) {
387 return "NULL";
388 }
389 StringBuilder res = new StringBuilder();
390 for (int i = 0; i < paths.length; i++) {
391 res.append(paths[i].toString());
392 }
393 return res.toString();
394 }
395
396
397 // ------------------------------------ Private helper classes ------------- -------------------------------
398 private static abstract class PathEntry {
399
400 abstract byte[] getBytesForClassFile(String fileName);
401
402 public abstract String toString();
403 }
404
405 private static class Dir extends PathEntry {
406
407 private String dir;
408
409 Dir(File f) throws IOException {
410 dir = f.getCanonicalPath();
411 }
412
413 byte[] getBytesForClassFile(String fileName) {
414 File file = new File(dir + File.separatorChar + fileName);
415 if (file.exists()) {
416 return Utils.readFileIntoBuffer(file);
417 } else {
418 return null;
419 }
420 }
421
422 public String toString() {
423 return dir;
424 }
425 }
426
427 private static class Zip extends PathEntry {
428
429 private ZipFile zip;
430
431 Zip(ZipFile z) {
432 zip = z;
433 }
434
435 byte[] getBytesForClassFile(String fileName) {
436 ZipEntry entry = zip.getEntry(fileName);
437 if (entry != null) {
438 return Utils.readZipEntryIntoBuffer(zip, entry);
439 } else {
440 return null;
441 }
442 }
443
444 public String toString() {
445 return zip.getName();
446 }
447 }
448 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698