/tags/v-2007-08-07/src/utils/ClassPathInfo.java
Java | 325 lines | 185 code | 28 blank | 112 comment | 32 complexity | 336382f4495d3123e1858d991a493cf3 MD5 | raw file
- package utils;
- import java.io.File;
- import java.io.IOException;
- import java.net.URI;
- import java.net.URISyntaxException;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.util.ArrayList;
- import java.util.Enumeration;
- import java.util.Iterator;
- import java.util.List;
- import java.util.StringTokenizer;
- import java.util.zip.ZipEntry;
- import java.util.zip.ZipFile;
- import utils.testing.TestedBy;
- /**
- * A data structure representing a Java-like CLASSPATH, i.e., a collection of
- * names of folders and archive files. Tacit is the convention that Java class
- * files are found in these, by replacing each package name by a folder name.
- * <p>
- * This class also makes it possible to enumerate all classes in the class path,
- * where the enumerated classes are represented as a collection of
- * {@link String}, where each string is the fully-qualified Java name of a
- * class, in the same format as in java.lang.class#forName(String);
- *
- * @author Itay Maman
- * @date Jul 6, 2006
- */
- @TestedBy(Test_ClassPathInfo.class)//
- public class ClassPathInfo implements Iterable<String> {
- /**
- * This is where the collection of elements of the class path are stored.
- */
- public final File[] files;
- @Override public String toString() {
- return Separator.separateBy(files, File.pathSeparator);
- }
- /**
- * Intitalize a new instance
- *
- * @param fs
- * Array of Files
- */
- public ClassPathInfo(File... fs) {
- files = new File[fs.length];
- int i = 0;
- for (File f : fs)
- files[i++] = f.getAbsoluteFile();
- }
- /**
- * Intitalize a new instance
- *
- */
- public ClassPathInfo() {
- files = new File[0];
- }
- /**
- * Intitalize a new instance
- *
- * @param fs
- * List of Files
- */
- public ClassPathInfo(Iterable<File> fs) {
- this(Iterables.toArray(fs, File.class));
- }
- /**
- * Intitalize a new instance
- *
- * @param paths
- * Array of strings. Each element is a path to a single file
- * system location
- */
- public ClassPathInfo(String... paths) {
- this(toFile(paths));
- }
- public ClassPathInfo(URI uri) {
- this(new File(uri));
- }
- private static File[] toFile(String[] paths) {
- File[] $ = new File[paths.length];
- int i = 0;
- for (String path : paths)
- $[i++] = new File(path);
- return $;
- }
- /**
- * Equivalent to <code>return new ClassPathInfo(fromJre(ignore));</code>
- *
- * @param ignore
- * List of paths to ignore
- * @return A new ClassPathInfo object
- */
- public static ClassPathInfo makeJREClassPath(File... ignore) {
- return new ClassPathInfo(fromJre(ignore));
- }
- /**
- * Obtain a ClassPathInfo object that is initialized with the location of
- * the JRE on the local machine.
- *
- * Note that Java does not have an API that provides this information so we
- * have to make an intelligent guess as to its whereabouts, follows:
- * <ul>
- * <li>If the default class loader is an instance of {@link URLClassLoader},
- * then use its getURLs() method.
- * <li>Use the system property "sun.boot.class.path" which points to the
- * JRE location, but only in JVMs by Sun.
- * </ul>
- *
- * @param ignore
- * An array of file objects. Class path entries that are located
- * below one of the array's entires will be excluded.
- * @return A new ClassPathInfo object
- */
- public static List<File> fromJre(File... ignore) {
- try {
- List<File> fs = fromClass(Object.class);
- return fs;
- } catch (Throwable t) {
- // Abosrb, let's try the other option...
- }
- List<File> fs = new ArrayList<File>();
- String cp = System.getProperty("sun.boot.class.path");
- for (StringTokenizer st = new StringTokenizer(cp, File.pathSeparator); st.hasMoreTokens();) {
- String entry = st.nextToken();
- // System.out.printf("TOKEN = %s/n", entry);
- fs.add(new File(entry));
- }
- return filter(fs, ignore);
- }
- /**
- * Obtain the class (as a list of files) from the class loaders of the given
- * classes.
- *
- * @param cs
- * An array of classes return A new ClassPathInfo object
- * @return A list of files
- * @throws IllegalArgumentException
- * If the class loader of <code>c</code> is not a
- * URLClassLoader
- */
- public static List<File> fromClass(Class<?>... cs) throws IllegalArgumentException {
- List<File> fs = new ArrayList<File>();
- for (Class<?> c : cs) {
- ClassLoader cl = c.getClassLoader();
- if (!(cl instanceof URLClassLoader))
- throw new IllegalArgumentException("Class loader is not a URLClassLoader. class=" + c.getName());
- URL[] urls = ((URLClassLoader) cl).getURLs();
- for (URL url : urls)
- try {
- fs.add(new File(url.toURI()));
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException("I cannot obtain a file from url " + url);
- }
- }
- return fs;
- }
- /**
- * Obtain an iterator over all class names found in the class path
- *
- * @return a new iterator object
- */
- public Iterator<String> iterator() {
- try {
- return getClasses().iterator();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- /**
- * Find all classes on the classpath represented by the receiver
- *
- * @return List of fully qualified names of all such classes
- */
- public ArrayList<String> getClasses() {
- ArrayList<String> $ = new ArrayList<String>();
- for (File f : files)
- addFromDirectory(0, f, f.getAbsolutePath(), $, "");
- return $;
- }
- private static final String DOT_CLASS = ".class";
- private static final String DOT_JAR = ".jar";
- private static final String DOT_ZIP = ".zip";
- /**
- * Recursively adding all classes residing in specified directory into
- * cache.
- *
- * @param depth
- * 0-based depth inside the directory tree
- * @param dirOrFile
- * file or directory
- * @param root
- * the root directory
- * @param result
- * List where results are stored
- * @param path
- * Relative path (dot-separated) from the starting point
- * @throws Exception
- */
- private void addFromDirectory(int depth, File dirOrFile, String root, ArrayList<String> result, String path) {
- if (dirOrFile.isDirectory()) {
- String[] children = dirOrFile.list();
- for (String s : children) {
- String newPath = concat(path, dirOrFile.getName());
- if (depth == 0)
- newPath = "";
- addFromDirectory(depth + 1, new File(dirOrFile, s), root, result, newPath);
- }
- return;
- }
- NameDotSuffix nds = new NameDotSuffix(dirOrFile);
- if (nds.suffixIs(DOT_JAR) || nds.suffixIs(DOT_ZIP))
- addFromArchive(dirOrFile.getPath(), result);
- else if (nds.suffixIs(DOT_CLASS))
- result.add(concat(path, nds.name));
- }
- private static class NameDotSuffix {
- public final String name;
- public final String suffix;
- public NameDotSuffix(ZipEntry ze) {
- this(ze.getName().replace('/', '.'));
- }
- public NameDotSuffix(File f) {
- this(f.getName());
- }
- public NameDotSuffix(String s) {
- int dot = s.lastIndexOf('.');
- if (dot < 0) {
- name = s;
- suffix = "";
- return;
- }
- name = s.substring(0, dot);
- suffix = s.substring(dot);
- }
- public boolean suffixIs(String s) {
- return suffix.equalsIgnoreCase(s);
- }
- }
- /**
- * Adding all classes residing in archive to cache
- *
- * @param jarFile
- * fill path to a jar file
- * @param result
- * List where scanned files are stored
- * @throws Exception
- */
- private void addFromArchive(String jarFile, ArrayList<String> result) {
- try {
- if(!new File(jarFile).exists())
- return;
-
- ZipFile f = new ZipFile(jarFile);
- Enumeration<? extends ZipEntry> entries = f.entries();
- while (entries.hasMoreElements()) {
- ZipEntry ze = entries.nextElement();
- NameDotSuffix nds = new NameDotSuffix(ze);
- if (!nds.suffixIs(DOT_CLASS))
- continue;
- result.add(nds.name);
- }
- } catch (IOException e) {
- throw new RuntimeException("Damaged zip file: " + jarFile, e);
- }
- }
- private static String concat(String path, String name) {
- if (path == null || path.length() == 0)
- return name;
- return path + "." + name;
- }
- private static List<File> filter(Iterable<File> fs, File... ignore) {
- final List<File> $ = new ArrayList<File>();
- for (File f : fs) {
- f = f.getAbsoluteFile();
- if (f.exists() && !onDirs(f, ignore))
- $.add(f);
- }
- return $;
- }
- private static boolean onDirs(File f, File... dirs) {
- for (File d : dirs)
- if (onDir(f, d.getAbsoluteFile()))
- return true;
- return false;
- }
- private static boolean onDir(File f, File d) {
- for (File parent = f; parent != null; parent = parent.getParentFile())
- if (parent.equals(d))
- return true;
- return false;
- }
- public static void main(String[] args) {
- ClassPathInfo cpi = new ClassPathInfo(new File("D:/tools/jdk-1-6-0/jre/lib/rt.jar"));
- List<String> list = cpi.getClasses();
- for (int i = 0; i < list.size(); ++i)
- System.out.println(i + " " + list.get(i));
- }
- }