/plugins/JavaSideKick/tags/javasidekick-2-3-1/src/sidekick/java/util/Locator.java

# · Java · 596 lines · 410 code · 53 blank · 133 comment · 111 complexity · b8ad30816902443f99d3f35e4010724a MD5 · raw file

  1. package sidekick.java.util;
  2. import java.io.File;
  3. import java.io.FileFilter;
  4. import java.io.FilenameFilter;
  5. import java.util.*;
  6. import java.util.jar.*;
  7. import java.net.URL;
  8. import java.net.MalformedURLException;
  9. import java.io.File;
  10. import java.io.FilenameFilter;
  11. import java.text.CharacterIterator;
  12. import java.text.StringCharacterIterator;
  13. import java.util.Locale;
  14. /**
  15. * The Locator is a utility class which is used to find classes loaded
  16. * in the runtime environment.
  17. *
  18. */
  19. public final class Locator {
  20. private static File[] classpathJars = getClassPathJars();
  21. private static List classpathClassNames = getClassPathClassNames();
  22. private static File[] runtimeJars = getRuntimeJars();
  23. private static List runtimeClassNames = getRuntimeClassNames();
  24. /**
  25. * Not instantiable
  26. */
  27. private Locator() {}
  28. public static File[] getClassPathJars() {
  29. if ( classpathJars != null )
  30. return classpathJars;
  31. String classpath = System.getProperty( "java.class.path" );
  32. if ( classpath == null || classpath.length() == 0 )
  33. return null;
  34. String path_sep = System.getProperty( "path.separator" );
  35. String[] path_jars = classpath.split( path_sep );
  36. File[] jars = new File[ path_jars.length ];
  37. for ( int i = 0; i < path_jars.length; i++ ) {
  38. jars[ i ] = new File( path_jars[ i ] );
  39. }
  40. return jars;
  41. }
  42. /**
  43. * @return a list of class names of all classes in all jars in the classpath.
  44. */
  45. public static List getClassPathClassNames() {
  46. File[] jars = getClassPathJars();
  47. List allnames = new ArrayList();
  48. for ( int i = 0; i < jars.length; i++ ) {
  49. File jar = jars[ i ];
  50. List names = getJarClassNames( jar );
  51. if ( names != null ) {
  52. allnames.addAll( names );
  53. }
  54. }
  55. return allnames;
  56. }
  57. /**
  58. * @return a list of classnames contained in the given jar.
  59. */
  60. private static List getJarClassNames( File jar ) {
  61. List names = new ArrayList();
  62. try {
  63. JarFile jar_file = new JarFile( jar );
  64. Enumeration entries = jar_file.entries();
  65. while ( entries.hasMoreElements() ) {
  66. JarEntry entry = ( JarEntry ) entries.nextElement();
  67. String classname = entry.getName();
  68. if ( classname.endsWith( ".class" ) )
  69. classname = classname.substring( 0, classname.lastIndexOf( "." ) );
  70. names.add( classname );
  71. }
  72. }
  73. catch ( Exception e ) {
  74. e.printStackTrace();
  75. }
  76. return names;
  77. }
  78. /**
  79. * Returns a list of all jar files in the classpath, java.home/lib,
  80. * java.ext.dirs and java.endorsed.dirs
  81. */
  82. public static File[] getRuntimeJars() {
  83. if ( runtimeJars != null )
  84. return runtimeJars;
  85. // get runtime jars based on java.home setting
  86. File java_lib = null; // location of $JAVA_HOME/lib
  87. File[] libs = null; // actual files from lib dir
  88. File[] java_ext = null; // location of ext dirs
  89. List<File> exts = null; // actual files from ext dirs
  90. File[] java_endorsed = null; // location of endorsed dirs
  91. List<File> endorsed = null; // actual files from endorsed dirs
  92. String javaHome = System.getProperty( "java.home" );
  93. if ( javaHome != null ) {
  94. java_lib = new File( javaHome = "/lib" );
  95. }
  96. FileFilter ff = new FileFilter() {
  97. public boolean accept( File pathname ) {
  98. return pathname.getName().endsWith( ".jar" );
  99. }
  100. };
  101. String ps = System.getProperty("path.separator");
  102. libs = java_lib.listFiles( new FileFilter() {
  103. public boolean accept( File pathname ) {
  104. return pathname.getName().endsWith( ".jar" );
  105. }
  106. }
  107. );
  108. String extDirs = System.getProperty( "java.ext.dirs" );
  109. if ( extDirs != null ) {
  110. String[] filenames = extDirs.split( ps );
  111. exts = new ArrayList();
  112. for (String filename : filenames) {
  113. File dir = new File(filename);
  114. if (dir.exists()) {
  115. File[] filelist = dir.listFiles(ff);
  116. exts.addAll(Arrays.asList(filelist));
  117. }
  118. }
  119. }
  120. String endorsedDirs = System.getProperty( "java.endorsed.dirs" );
  121. if ( endorsedDirs != null ) {
  122. String[] filenames = endorsedDirs.split( ps );
  123. endorsed = new ArrayList();
  124. for (String filename : filenames) {
  125. File dir = new File(filename);
  126. if (dir.exists()) {
  127. File[] filelist = dir.listFiles(ff);
  128. endorsed.addAll(Arrays.asList(filelist));
  129. }
  130. }
  131. }
  132. // add endorsed jars first, they should override standard jars
  133. List<File> list = new ArrayList();
  134. if ( endorsed != null && !endorsed.isEmpty() )
  135. list.addAll( endorsed );
  136. if ( libs != null && libs.length > 0 )
  137. list.addAll( Arrays.asList( libs ) );
  138. if ( exts != null && !exts.isEmpty() )
  139. list.addAll( exts );
  140. runtimeJars = ( File[] ) list.toArray( new File[] {} );
  141. return runtimeJars;
  142. }
  143. /**
  144. * @return a list of class names of public classes provided by the java runtime.
  145. */
  146. public static List getRuntimeClassNames() {
  147. File[] jars = getRuntimeJars();
  148. List names = new ArrayList();
  149. for ( int i = 0; i < jars.length; i++ ) {
  150. File jar = jars[ i ];
  151. try {
  152. JarFile jar_file = new JarFile( jar );
  153. Enumeration entries = jar_file.entries();
  154. while ( entries.hasMoreElements() ) {
  155. JarEntry entry = ( JarEntry ) entries.nextElement();
  156. String classname = entry.getName();
  157. if ( classname.startsWith( "java/" ) ||
  158. classname.startsWith( "javax/" ) ||
  159. classname.startsWith( "org/omg/" ) ||
  160. classname.startsWith( "org/ietf/" ) ||
  161. classname.startsWith( "org/w3c/" ) ||
  162. classname.startsWith( "org/xml/" ) ) {
  163. if ( classname.endsWith( ".class" ) )
  164. classname = classname.substring( 0, classname.lastIndexOf( "." ) );
  165. names.add( classname );
  166. }
  167. }
  168. }
  169. catch ( Exception e ) {
  170. e.printStackTrace();
  171. }
  172. }
  173. return names;
  174. }
  175. /**
  176. * @param name class name minus the package part, e.g. "String" in "java.lang.String".
  177. */
  178. public static String getRuntimeClassName( String name ) {
  179. for ( Iterator it = runtimeClassNames.iterator(); it.hasNext(); ) {
  180. String fullClassName = ( String ) it.next();
  181. int index = fullClassName.lastIndexOf( "/" ) + 1;
  182. String className = fullClassName.substring( index );
  183. if ( className.equals( name ) ) {
  184. fullClassName = fullClassName.replaceAll( "/", "." );
  185. return fullClassName;
  186. }
  187. }
  188. return null;
  189. }
  190. /**
  191. * @param packageName package name with possibly a part of a classname, e.g.
  192. * "javax.swing.tree.DefaultMut"
  193. * @return a list of all class names that match. The list may be empty, but
  194. * won't be null.
  195. */
  196. public static List getRuntimeClasses( String packageName ) {
  197. List list = new ArrayList();
  198. if ( packageName == null || packageName.length() == 0 )
  199. return list;
  200. String name = packageName.replaceAll( "[.]", "/" );
  201. for ( Iterator it = runtimeClassNames.iterator(); it.hasNext(); ) {
  202. String fullClassName = ( String ) it.next();
  203. if ( fullClassName.startsWith( name ) && fullClassName.indexOf( "$" ) < 0 ) {
  204. list.add( fullClassName.substring( fullClassName.lastIndexOf( "/" ) + 1 ) );
  205. }
  206. }
  207. return list;
  208. }
  209. /**
  210. * @param name class name minus the package part, e.g. "String" in "java.lang.String".
  211. */
  212. public static String getClassPathClassName( String name ) {
  213. for ( Iterator it = runtimeClassNames.iterator(); it.hasNext(); ) {
  214. String fullClassName = ( String ) it.next();
  215. int index = fullClassName.lastIndexOf( "/" ) + 1;
  216. String className = fullClassName.substring( index );
  217. if ( className.equals( name ) ) {
  218. fullClassName = fullClassName.replaceAll( "/", "." );
  219. return fullClassName;
  220. }
  221. }
  222. return null;
  223. }
  224. /**
  225. * @param packageName package name with possibly a part of a classname, e.g.
  226. * "javax.swing.tree.DefaultMut"
  227. * @return a list of all class names that match. The list may be empty, but
  228. * won't be null.
  229. */
  230. public static List getClassPathClasses( String packageName ) {
  231. List list = new ArrayList();
  232. if ( packageName == null || packageName.length() == 0 )
  233. return list;
  234. String name = packageName.replaceAll( "[.]", "/" );
  235. for ( Iterator it = runtimeClassNames.iterator(); it.hasNext(); ) {
  236. String fullClassName = ( String ) it.next();
  237. if ( fullClassName.startsWith( name ) && fullClassName.indexOf( "$" ) < 0 ) {
  238. list.add( fullClassName.substring( fullClassName.lastIndexOf( "/" ) + 1 ) );
  239. }
  240. }
  241. return list;
  242. }
  243. /**
  244. * Get a list of class files from the given paths.
  245. * @param path a list of file paths separated by the platform path separator,
  246. * that is, a path that could be used as a classpath.
  247. * @return a consolidated List<String> of classes found in the given paths.
  248. */
  249. public static List getClassesForPath( String path ) {
  250. String pathSep = System.getProperty( "path.separator" );
  251. String[] paths = path.split( pathSep );
  252. // paths can be either jars, zips, directories, or individual classes
  253. // directories can contain individual classes.
  254. List allnames = new ArrayList();
  255. for ( int i = 0; i < paths.length; i++ ) {
  256. path = paths[ i ];
  257. File f = new File( path );
  258. // check for jar or zip
  259. if ( path.toLowerCase().endsWith( ".jar" ) || path.toLowerCase().endsWith( ".zip" ) ) {
  260. List names = getJarClassNames( f );
  261. if ( names != null ) {
  262. allnames.addAll( names );
  263. }
  264. }
  265. // check for individual class
  266. else if ( path.toLowerCase().endsWith( ".class" ) ) {
  267. allnames.add( f.getName().substring( 0, f.getName().lastIndexOf( "." ) ) );
  268. }
  269. // check for directories
  270. else if ( f.isDirectory() ) {
  271. allnames.addAll( getDirClassNames( f, path ) );
  272. }
  273. }
  274. return allnames;
  275. }
  276. private static List getDirClassNames( File directory, String base ) {
  277. List allclasses = new ArrayList();
  278. File[] classes = directory.listFiles( new FileFilter() {
  279. public boolean accept( File pathname ) {
  280. return pathname.getName().endsWith( ".class" );
  281. }
  282. }
  283. );
  284. if ( classes != null ) {
  285. for ( int i = 0; i < classes.length; i++ ) {
  286. String name = classes[ i ].getAbsolutePath();
  287. name = name.substring( base.length(), name.lastIndexOf( "." ) );
  288. name = name.replaceAll( "/", "." );
  289. allclasses.add( name );
  290. }
  291. }
  292. File[] directories = directory.listFiles( new FileFilter() {
  293. public boolean accept( File pathname ) {
  294. return pathname.isDirectory();
  295. }
  296. }
  297. );
  298. for ( int i = 0; i < directories.length; i++ ) {
  299. allclasses.addAll( getDirClassNames( directories[ i ], base ) );
  300. }
  301. return allclasses;
  302. }
  303. public static String getPathClassName( String path, String name ) {
  304. List classes = getClassesForPath( path );
  305. for ( Iterator it = classes.iterator(); it.hasNext(); ) {
  306. String className = ( String ) it.next();
  307. if ( className.substring( className.lastIndexOf( "." ) ).equals( name ) ) {
  308. return className;
  309. }
  310. }
  311. return null;
  312. }
  313. /***********
  314. The following methods were borrowed from Ant from a class with the same
  315. name.
  316. ***********/
  317. /**
  318. * Find the directory or jar file the class has been loaded from.
  319. *
  320. * @param c the class whose location is required.
  321. * @return the file or jar with the class or null if we cannot
  322. * determine the location.
  323. *
  324. * @since Ant 1.6
  325. */
  326. public static File getClassSource( Class c ) {
  327. String classResource = c.getName().replace( '.', '/' ) + ".class";
  328. return getResourceSource( c.getClassLoader(), classResource );
  329. }
  330. /**
  331. * Find the directory or jar a give resource has been loaded from.
  332. *
  333. * @param c the classloader to be consulted for the source
  334. * @param resource the resource whose location is required.
  335. *
  336. * @return the file with the resource source or null if
  337. * we cannot determine the location.
  338. *
  339. * @since Ant 1.6
  340. */
  341. public static File getResourceSource( ClassLoader c, String resource ) {
  342. if ( c == null ) {
  343. c = Locator.class.getClassLoader();
  344. }
  345. URL url = null;
  346. if ( c == null ) {
  347. url = ClassLoader.getSystemResource( resource );
  348. }
  349. else {
  350. url = c.getResource( resource );
  351. }
  352. if ( url != null ) {
  353. String u = url.toString();
  354. if ( u.startsWith( "jar:file:" ) ) {
  355. int pling = u.indexOf( "!" );
  356. String jarName = u.substring( 4, pling );
  357. return new File( fromURI( jarName ) );
  358. }
  359. else if ( u.startsWith( "file:" ) ) {
  360. int tail = u.indexOf( resource );
  361. String dirName = u.substring( 0, tail );
  362. return new File( fromURI( dirName ) );
  363. }
  364. }
  365. return null;
  366. }
  367. /**
  368. * Constructs a file path from a <code>file:</code> URI.
  369. *
  370. * <p>Will be an absolute path if the given URI is absolute.</p>
  371. *
  372. * <p>Swallows '%' that are not followed by two characters,
  373. * doesn't deal with non-ASCII characters.</p>
  374. *
  375. * @param uri the URI designating a file in the local filesystem.
  376. * @return the local file system path for the file.
  377. * @since Ant 1.6
  378. */
  379. public static String fromURI( String uri ) {
  380. URL url = null;
  381. try {
  382. url = new URL( uri );
  383. }
  384. catch ( MalformedURLException emYouEarlEx ) {}
  385. if ( url == null || !( "file".equals( url.getProtocol() ) ) ) {
  386. throw new IllegalArgumentException( "Can only handle valid file: URIs" );
  387. }
  388. StringBuffer buf = new StringBuffer( url.getHost() );
  389. if ( buf.length() > 0 ) {
  390. buf.insert( 0, File.separatorChar ).insert( 0, File.separatorChar );
  391. }
  392. String file = url.getFile();
  393. int queryPos = file.indexOf( '?' );
  394. buf.append( ( queryPos < 0 ) ? file : file.substring( 0, queryPos ) );
  395. uri = buf.toString().replace( '/', File.separatorChar );
  396. if ( File.pathSeparatorChar == ';' && uri.startsWith( "\\" ) && uri.length() > 2
  397. && Character.isLetter( uri.charAt( 1 ) ) && uri.lastIndexOf( ':' ) > -1 ) {
  398. uri = uri.substring( 1 );
  399. }
  400. String path = decodeUri( uri );
  401. return path;
  402. }
  403. /**
  404. * Decodes an Uri with % characters.
  405. * @param uri String with the uri possibly containing % characters.
  406. * @return The decoded Uri
  407. */
  408. private static String decodeUri( String uri ) {
  409. if ( uri.indexOf( '%' ) == -1 ) {
  410. return uri;
  411. }
  412. StringBuffer sb = new StringBuffer();
  413. CharacterIterator iter = new StringCharacterIterator( uri );
  414. for ( char c = iter.first(); c != CharacterIterator.DONE;
  415. c = iter.next() ) {
  416. if ( c == '%' ) {
  417. char c1 = iter.next();
  418. if ( c1 != CharacterIterator.DONE ) {
  419. int i1 = Character.digit( c1, 16 );
  420. char c2 = iter.next();
  421. if ( c2 != CharacterIterator.DONE ) {
  422. int i2 = Character.digit( c2, 16 );
  423. sb.append( ( char ) ( ( i1 << 4 ) + i2 ) );
  424. }
  425. }
  426. }
  427. else {
  428. sb.append( c );
  429. }
  430. }
  431. String path = sb.toString();
  432. return path;
  433. }
  434. /**
  435. * Get the File necessary to load the Sun compiler tools. If the classes
  436. * are available to this class, then no additional URL is required and
  437. * null is returned. This may be because the classes are explicitly in the
  438. * class path or provided by the JVM directly
  439. *
  440. * @return the tools jar as a File if required, null otherwise
  441. */
  442. public static File getToolsJar() {
  443. // firstly check if the tools jar is already in the classpath
  444. boolean toolsJarAvailable = false;
  445. try {
  446. // just check whether this throws an exception
  447. Class.forName( "com.sun.tools.javac.Main" );
  448. toolsJarAvailable = true;
  449. }
  450. catch ( Exception e ) {
  451. try {
  452. Class.forName( "sun.tools.javac.Main" );
  453. toolsJarAvailable = true;
  454. }
  455. catch ( Exception e2 ) {
  456. // ignore
  457. }
  458. }
  459. if ( toolsJarAvailable ) {
  460. return null;
  461. }
  462. // couldn't find compiler - try to find tools.jar
  463. // based on java.home setting
  464. String javaHome = System.getProperty( "java.home" );
  465. if ( javaHome.toLowerCase( Locale.US ).endsWith( "jre" ) ) {
  466. javaHome = javaHome.substring( 0, javaHome.length() - 4 );
  467. }
  468. File toolsJar = new File( javaHome + "/lib/tools.jar" );
  469. if ( !toolsJar.exists() ) {
  470. System.out.println( "Unable to locate tools.jar. "
  471. + "Expected to find it in " + toolsJar.getPath() );
  472. return null;
  473. }
  474. return toolsJar;
  475. }
  476. /**
  477. * Get an array or URLs representing all of the jar files in the
  478. * given location. If the location is a file, it is returned as the only
  479. * element of the array. If the location is a directory, it is scanned for
  480. * jar files
  481. *
  482. * @param location the location to scan for Jars
  483. *
  484. * @return an array of URLs for all jars in the given location.
  485. *
  486. * @exception MalformedURLException if the URLs for the jars cannot be
  487. * formed
  488. */
  489. public static URL[] getLocationURLs( File location )
  490. throws MalformedURLException {
  491. return getLocationURLs( location, new String[] {".jar"} );
  492. }
  493. /**
  494. * Get an array or URLs representing all of the files of a given set of
  495. * extensions in the given location. If the location is a file, it is
  496. * returned as the only element of the array. If the location is a
  497. * directory, it is scanned for matching files
  498. *
  499. * @param location the location to scan for files
  500. * @param extensions an array of extension that are to match in the
  501. * directory search
  502. *
  503. * @return an array of URLs of matching files
  504. * @exception MalformedURLException if the URLs for the files cannot be
  505. * formed
  506. */
  507. public static URL[] getLocationURLs( File location,
  508. final String[] extensions )
  509. throws MalformedURLException {
  510. URL[] urls = new URL[ 0 ];
  511. if ( !location.exists() ) {
  512. return urls;
  513. }
  514. if ( !location.isDirectory() ) {
  515. urls = new URL[ 1 ];
  516. String path = location.getPath();
  517. for ( int i = 0; i < extensions.length; ++i ) {
  518. if ( path.toLowerCase().endsWith( extensions[ i ] ) ) {
  519. urls[ 0 ] = location.toURL();
  520. break;
  521. }
  522. }
  523. return urls;
  524. }
  525. File[] matches = location.listFiles(
  526. new FilenameFilter() {
  527. public boolean accept( File dir, String name ) {
  528. for ( int i = 0; i < extensions.length; ++i ) {
  529. if ( name.toLowerCase().endsWith( extensions[ i ] ) ) {
  530. return true;
  531. }
  532. }
  533. return false;
  534. }
  535. }
  536. );
  537. urls = new URL[ matches.length ];
  538. for ( int i = 0; i < matches.length; ++i ) {
  539. urls[ i ] = matches[ i ].toURL();
  540. }
  541. return urls;
  542. }
  543. }