PageRenderTime 128ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/v-2007-09-11-b/src/il/ac/technion/cs/ssdl/utils/ClassPathInfo.java

https://bitbucket.org/yossi_gil/services
Java | 332 lines | 194 code | 28 blank | 110 comment | 32 complexity | 3b62c7c585ddaabddb7b5511a2ba8126 MD5 | raw file
  1. package il.ac.technion.cs.ssdl.utils;
  2. import static il.ac.technion.cs.ssdl.utils.DBC.sure;
  3. import il.ac.technion.cs.ssdl.testing.TestedBy;
  4. import java.io.File;
  5. import java.io.IOException;
  6. import java.net.URI;
  7. import java.net.URISyntaxException;
  8. import java.net.URL;
  9. import java.net.URLClassLoader;
  10. import java.util.ArrayList;
  11. import java.util.Enumeration;
  12. import java.util.Iterator;
  13. import java.util.List;
  14. import java.util.StringTokenizer;
  15. import java.util.zip.ZipEntry;
  16. import java.util.zip.ZipFile;
  17. /**
  18. * A data structure representing a Java-like CLASSPATH, i.e., a collection of
  19. * names of folders and archive files. Tacit is the convention that Java class
  20. * files are found in these, by replacing each package name by a folder name.
  21. * <p>
  22. * This class also makes it possible to enumerate all classes in the class path,
  23. * where the enumerated classes are represented as a collection of
  24. * {@link String}, where each string is the fully-qualified Java name of a
  25. * class, in the same format as in java.lang.class#forName(String);
  26. *
  27. * @author Itay Maman Jul 6, 2006
  28. */
  29. @TestedBy(Test_ClassPathInfo.class)//
  30. public class ClassPathInfo implements Iterable<String> {
  31. /**
  32. * This is where the collection of elements of the class path are stored.
  33. */
  34. public final File[] files;
  35. @Override public String toString() {
  36. return Separator.separateBy(File.pathSeparator, files);
  37. }
  38. /**
  39. * Intitalize a new instance
  40. *
  41. * @param fs
  42. * Array of Files
  43. */
  44. public ClassPathInfo(File... fs) {
  45. files = new File[fs.length];
  46. int i = 0;
  47. for (final File f : fs)
  48. files[i++] = f.getAbsoluteFile();
  49. }
  50. /**
  51. * Intitalize a new instance
  52. *
  53. */
  54. public ClassPathInfo() {
  55. files = new File[0];
  56. }
  57. /**
  58. * Intitalize a new instance
  59. *
  60. * @param fs
  61. * List of Files
  62. */
  63. public ClassPathInfo(Iterable<File> fs) {
  64. this(Iterables.toArray(fs, File.class));
  65. }
  66. /**
  67. * Intitalize a new instance
  68. *
  69. * @param paths
  70. * Array of strings. Each element is a path to a single file system
  71. * location
  72. */
  73. public ClassPathInfo(String... paths) {
  74. this(toFile(paths));
  75. }
  76. public ClassPathInfo(URI uri) {
  77. this(new File(uri));
  78. }
  79. public ClassPathInfo(Class<?> me) {
  80. this(fromClass(me));
  81. sure(files.length > 0);
  82. sure(Iterables.size(this) > 0);
  83. }
  84. private static File[] toFile(String[] paths) {
  85. final File[] $ = new File[paths.length];
  86. int i = 0;
  87. for (final String path : paths)
  88. $[i++] = new File(path).getAbsoluteFile();
  89. return $;
  90. }
  91. /**
  92. * Equivalent to <code>return new ClassPathInfo(fromJre(ignore));</code>
  93. *
  94. * @param ignore
  95. * List of paths to ignore
  96. * @return A new ClassPathInfo object
  97. */
  98. public static ClassPathInfo makeJREClassPath(File... ignore) {
  99. return new ClassPathInfo(fromJre(ignore));
  100. }
  101. /**
  102. * Obtain a ClassPathInfo object that is initialized with the location of
  103. * the JRE on the local machine.
  104. *
  105. * Note that Java does not have an API that provides this information so we
  106. * have to make an intelligent guess as to its whereabouts, follows:
  107. * <ul>
  108. * <li>If the default class loader is an instance of {@link URLClassLoader},
  109. * then use its getURLs() method.
  110. * <li>Use the system property "sun.boot.class.path" which points to the
  111. * JRE location, but only in JVMs by Sun.
  112. * </ul>
  113. *
  114. * @param ignore
  115. * An array of file objects. Class path entries that are located
  116. * below one of the array's entires will be excluded.
  117. * @return A new ClassPathInfo object
  118. */
  119. public static List<File> fromJre(File... ignore) {
  120. try {
  121. final List<File> fs = fromClass(Object.class);
  122. return fs;
  123. } catch (final Throwable t) {
  124. // Abosrb, let's try the other option...
  125. }
  126. final List<File> fs = new ArrayList<File>();
  127. final String cp = System.getProperty("sun.boot.class.path");
  128. for (final StringTokenizer st = new StringTokenizer(cp, File.pathSeparator); st.hasMoreTokens();) {
  129. final String entry = st.nextToken();
  130. // System.out.printf("TOKEN = %s/n", entry);
  131. fs.add(new File(entry));
  132. }
  133. return filter(fs, ignore);
  134. }
  135. /**
  136. * Obtain the classpath (as a list of files) from the class loaders of the
  137. * given classes.
  138. *
  139. * @param cs
  140. * An array of classes return
  141. * @return A list of files
  142. * @throws IllegalArgumentException
  143. * If the class loader of <code>c</code> is not a URLClassLoader
  144. */
  145. public static List<File> fromClass(Class<?>... cs) throws IllegalArgumentException {
  146. final List<File> $ = new ArrayList<File>();
  147. for (final Class<?> c : cs) {
  148. final ClassLoader cl = c.getClassLoader();
  149. if (!(cl instanceof URLClassLoader))
  150. throw new IllegalArgumentException("Class loader is not a URLClassLoader. class=" + c.getName());
  151. sure(((URLClassLoader) cl).getURLs().length > 0);
  152. for (final URL url : ((URLClassLoader) cl).getURLs()) {
  153. $.add(new File(url.getFile().substring(1)));
  154. try {
  155. $.add(new File(url.toURI()));
  156. } catch (URISyntaxException e) {
  157. continue;
  158. }
  159. }
  160. }
  161. sure($.size() > 0);
  162. return $;
  163. }
  164. /**
  165. * Obtain an iterator over all class names found in the class path
  166. *
  167. * @return a new iterator object
  168. */
  169. public Iterator<String> iterator() {
  170. try {
  171. return getClasses().iterator();
  172. } catch (final Exception e) {
  173. throw new RuntimeException(e);
  174. }
  175. }
  176. /**
  177. * Find all classes on the classpath represented by the receiver
  178. *
  179. * @return List of fully qualified names of all such classes
  180. */
  181. public ArrayList<String> getClasses() {
  182. final ArrayList<String> $ = new ArrayList<String>();
  183. for (final File f : files)
  184. addFromDirectory(0, f, f.getAbsolutePath(), $, "");
  185. return $;
  186. }
  187. private static final String DOT_CLASS = ".class";
  188. private static final String DOT_JAR = ".jar";
  189. private static final String DOT_ZIP = ".zip";
  190. /**
  191. * Recursively adding all classes residing in specified directory into
  192. * cache.
  193. *
  194. * @param depth
  195. * 0-based depth inside the directory tree
  196. * @param dirOrFile
  197. * file or directory
  198. * @param root
  199. * the root directory
  200. * @param result
  201. * List where results are stored
  202. * @param path
  203. * Relative path (dot-separated) from the starting point
  204. * @throws Exception
  205. */
  206. private void addFromDirectory(int depth, File dirOrFile, String root, ArrayList<String> result, String path) {
  207. if (dirOrFile.isDirectory()) {
  208. final String[] children = dirOrFile.list();
  209. for (final String s : children) {
  210. String newPath = concat(path, dirOrFile.getName());
  211. if (depth == 0)
  212. newPath = "";
  213. addFromDirectory(depth + 1, new File(dirOrFile, s), root, result, newPath);
  214. }
  215. return;
  216. }
  217. final NameDotSuffix nds = new NameDotSuffix(dirOrFile);
  218. if (nds.suffixIs(DOT_JAR) || nds.suffixIs(DOT_ZIP))
  219. addFromArchive(dirOrFile.getPath(), result);
  220. else if (nds.suffixIs(DOT_CLASS))
  221. result.add(concat(path, nds.name));
  222. }
  223. private static class NameDotSuffix {
  224. public final String name;
  225. public final String suffix;
  226. public NameDotSuffix(ZipEntry ze) {
  227. this(ze.getName().replace('/', '.'));
  228. }
  229. public NameDotSuffix(File f) {
  230. this(f.getName());
  231. }
  232. public NameDotSuffix(String s) {
  233. final int dot = s.lastIndexOf('.');
  234. if (dot < 0) {
  235. name = s;
  236. suffix = "";
  237. return;
  238. }
  239. name = s.substring(0, dot);
  240. suffix = s.substring(dot);
  241. }
  242. public boolean suffixIs(String s) {
  243. return suffix.equalsIgnoreCase(s);
  244. }
  245. }
  246. /**
  247. * Adding all classes residing in archive to cache
  248. *
  249. * @param jarFile
  250. * fill path to a jar file
  251. * @param result
  252. * List where scanned files are stored
  253. * @throws Exception
  254. */
  255. private void addFromArchive(String jarFile, ArrayList<String> result) {
  256. try {
  257. if (!new File(jarFile).exists())
  258. return;
  259. final ZipFile f = new ZipFile(jarFile);
  260. final Enumeration<? extends ZipEntry> entries = f.entries();
  261. while (entries.hasMoreElements()) {
  262. final ZipEntry ze = entries.nextElement();
  263. final NameDotSuffix nds = new NameDotSuffix(ze);
  264. if (!nds.suffixIs(DOT_CLASS))
  265. continue;
  266. result.add(nds.name);
  267. }
  268. } catch (final IOException e) {
  269. throw new RuntimeException("Damaged zip file: " + jarFile, e);
  270. }
  271. }
  272. private static String concat(String path, String name) {
  273. if (path == null || path.length() == 0)
  274. return name;
  275. return path + "." + name;
  276. }
  277. private static List<File> filter(Iterable<File> fs, File... ignore) {
  278. final List<File> $ = new ArrayList<File>();
  279. for (File f : fs) {
  280. f = f.getAbsoluteFile();
  281. if (f.exists() && !onDirs(f, ignore))
  282. $.add(f);
  283. }
  284. return $;
  285. }
  286. private static boolean onDirs(File f, File... dirs) {
  287. for (final File d : dirs)
  288. if (onDir(f, d.getAbsoluteFile()))
  289. return true;
  290. return false;
  291. }
  292. private static boolean onDir(File f, File d) {
  293. for (File parent = f; parent != null; parent = parent.getParentFile())
  294. if (parent.equals(d))
  295. return true;
  296. return false;
  297. }
  298. public static void main(String[] args) {
  299. final ClassPathInfo cpi = new ClassPathInfo(new File("D:/tools/jdk-1-6-0/jre/lib/rt.jar"));
  300. final List<String> list = cpi.getClasses();
  301. for (int i = 0; i < list.size(); ++i)
  302. System.out.println(i + " " + list.get(i));
  303. }
  304. }