/tags/v-2007-09-11-b/src/il/ac/technion/cs/ssdl/utils/ClassPathInfo.java
Java | 332 lines | 194 code | 28 blank | 110 comment | 32 complexity | 3b62c7c585ddaabddb7b5511a2ba8126 MD5 | raw file
- package il.ac.technion.cs.ssdl.utils;
- import static il.ac.technion.cs.ssdl.utils.DBC.sure;
- import il.ac.technion.cs.ssdl.testing.TestedBy;
- 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;
- /**
- * 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 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(File.pathSeparator, files);
- }
- /**
- * Intitalize a new instance
- *
- * @param fs
- * Array of Files
- */
- public ClassPathInfo(File... fs) {
- files = new File[fs.length];
- int i = 0;
- for (final 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));
- }
- public ClassPathInfo(Class<?> me) {
- this(fromClass(me));
- sure(files.length > 0);
- sure(Iterables.size(this) > 0);
- }
- private static File[] toFile(String[] paths) {
- final File[] $ = new File[paths.length];
- int i = 0;
- for (final String path : paths)
- $[i++] = new File(path).getAbsoluteFile();
- 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 {
- final List<File> fs = fromClass(Object.class);
- return fs;
- } catch (final Throwable t) {
- // Abosrb, let's try the other option...
- }
- final List<File> fs = new ArrayList<File>();
- final String cp = System.getProperty("sun.boot.class.path");
- for (final StringTokenizer st = new StringTokenizer(cp, File.pathSeparator); st.hasMoreTokens();) {
- final String entry = st.nextToken();
- // System.out.printf("TOKEN = %s/n", entry);
- fs.add(new File(entry));
- }
- return filter(fs, ignore);
- }
- /**
- * Obtain the classpath (as a list of files) from the class loaders of the
- * given classes.
- *
- * @param cs
- * An array of classes return
- * @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 {
- final List<File> $ = new ArrayList<File>();
- for (final Class<?> c : cs) {
- final ClassLoader cl = c.getClassLoader();
- if (!(cl instanceof URLClassLoader))
- throw new IllegalArgumentException("Class loader is not a URLClassLoader. class=" + c.getName());
- sure(((URLClassLoader) cl).getURLs().length > 0);
- for (final URL url : ((URLClassLoader) cl).getURLs()) {
- $.add(new File(url.getFile().substring(1)));
- try {
- $.add(new File(url.toURI()));
- } catch (URISyntaxException e) {
- continue;
- }
- }
- }
- sure($.size() > 0);
- return $;
- }
- /**
- * 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 (final 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() {
- final ArrayList<String> $ = new ArrayList<String>();
- for (final 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()) {
- final String[] children = dirOrFile.list();
- for (final String s : children) {
- String newPath = concat(path, dirOrFile.getName());
- if (depth == 0)
- newPath = "";
- addFromDirectory(depth + 1, new File(dirOrFile, s), root, result, newPath);
- }
- return;
- }
- final 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) {
- final 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;
- final ZipFile f = new ZipFile(jarFile);
- final Enumeration<? extends ZipEntry> entries = f.entries();
- while (entries.hasMoreElements()) {
- final ZipEntry ze = entries.nextElement();
- final NameDotSuffix nds = new NameDotSuffix(ze);
- if (!nds.suffixIs(DOT_CLASS))
- continue;
- result.add(nds.name);
- }
- } catch (final 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 (final 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) {
- final ClassPathInfo cpi = new ClassPathInfo(new File("D:/tools/jdk-1-6-0/jre/lib/rt.jar"));
- final List<String> list = cpi.getClasses();
- for (int i = 0; i < list.size(); ++i)
- System.out.println(i + " " + list.get(i));
- }
- }