PageRenderTime 65ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/v-2007-08-07-b/src/utils/ClassPathInfo.java

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