You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Util.java 16KB

21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
19 years ago
19 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC).
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Public License v 2.0
  7. * which accompanies this distribution and is available at
  8. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * ******************************************************************/
  13. package org.aspectj.internal.tools.build;
  14. import java.io.File;
  15. import java.io.FileFilter;
  16. import java.io.IOException;
  17. import java.io.InputStream;
  18. import java.io.PrintWriter;
  19. import java.io.Reader;
  20. import java.io.StringWriter;
  21. import java.io.Writer;
  22. import java.util.ArrayList;
  23. import java.util.Collections;
  24. import java.util.List;
  25. import java.util.StringTokenizer;
  26. import java.util.jar.Attributes;
  27. import java.util.jar.Attributes.Name;
  28. import java.util.jar.Manifest;
  29. /**
  30. * Build-only utilities.
  31. * Many mirror utils module APIs.
  32. */
  33. public class Util {
  34. public static class Constants {
  35. public static final String TESTSRC = "testsrc";
  36. public static final String JAVA5_SRC = "java5-src";
  37. public static final String JAVA5_TESTSRC = "java5-testsrc";
  38. }
  39. // XXX quick hack for Java 5 support
  40. public static final boolean JAVA5_VM;
  41. static {
  42. boolean java5VM = false;
  43. try {
  44. java5VM = (null != Class.forName("java.lang.annotation.Annotation"));
  45. } catch (Throwable t) {
  46. // ignore
  47. }
  48. JAVA5_VM = java5VM;
  49. }
  50. /**
  51. * Map version in long form to short,
  52. * e.g., replacing "alpha" with "a"
  53. */
  54. public static String shortVersion(String version) {
  55. version = Util.replace(version, "alpha", "a");
  56. version = Util.replace(version, "beta", "b");
  57. version = Util.replace(version, "candidate", "rc");
  58. version = Util.replace(version, "development", "d");
  59. version = Util.replace(version, "dev", "d");
  60. return version;
  61. }
  62. /**
  63. * Replace any instances of {replace} in {input} with {with}.
  64. * @param input the String to search/replace
  65. * @param replace the String to search for in input
  66. * @param with the String to replace with in input
  67. * @return input if it has no replace, otherwise a new String
  68. */
  69. public static String replace(String input, String replace, String with) {
  70. int loc = input.indexOf(replace);
  71. if (-1 != loc) {
  72. String result = input.substring(0, loc);
  73. result += with;
  74. int start = loc + replace.length();
  75. if (start < input.length()) {
  76. result += input.substring(start);
  77. }
  78. input = result;
  79. }
  80. return input;
  81. }
  82. /** @return false if filter returned false for any file in baseDir subtree */
  83. public static boolean visitFiles(File baseDir, FileFilter filter) {
  84. Util.iaxIfNotCanReadDir(baseDir, "baseDir");
  85. Util.iaxIfNull(filter, "filter");
  86. File[] files = baseDir.listFiles();
  87. boolean passed = true;
  88. for (int i = 0; passed && (i < files.length); i++) {
  89. passed = files[i].isDirectory()
  90. ? visitFiles(files[i], filter)
  91. : filter.accept(files[i]);
  92. }
  93. return passed;
  94. }
  95. /** @throws IllegalArgumentException if cannot read dir */
  96. public static void iaxIfNotCanReadDir(File dir, String name) {
  97. if (!canReadDir(dir)) {
  98. throw new IllegalArgumentException(name + " dir not readable: " + dir);
  99. }
  100. }
  101. /** @throws IllegalArgumentException if cannot read file */
  102. public static void iaxIfNotCanReadFile(File file, String name) {
  103. if (!canReadFile(file)) {
  104. throw new IllegalArgumentException(name + " file not readable: " + file);
  105. }
  106. }
  107. /** @throws IllegalArgumentException if cannot write dir */
  108. public static void iaxIfNotCanWriteDir(File dir, String name) {
  109. if (!canWriteDir(dir)) {
  110. throw new IllegalArgumentException(name + " dir not writeable: " + dir);
  111. }
  112. }
  113. /** @throws IllegalArgumentException if input is null */
  114. public static void iaxIfNull(Object input, String name) {
  115. if (null == input) {
  116. throw new IllegalArgumentException("null " + name);
  117. }
  118. }
  119. /** render exception to String */
  120. public static String renderException(Throwable thrown) {
  121. if (null == thrown) {
  122. return "(Throwable) null";
  123. }
  124. StringWriter sw = new StringWriter();
  125. PrintWriter pw = new PrintWriter(sw, true);
  126. pw.println(thrown.getMessage());
  127. thrown.printStackTrace(pw);
  128. pw.flush();
  129. return sw.getBuffer().toString();
  130. }
  131. /** @return true if dir is a writable directory */
  132. public static boolean canWriteDir(File dir) {
  133. return (null != dir) && dir.canWrite() && dir.isDirectory();
  134. }
  135. public static String path(String first, String second) {
  136. return first + File.separator + second;
  137. }
  138. public static String path(String[] segments) {
  139. StringBuilder sb = new StringBuilder();
  140. if ((null != segments)) {
  141. for (int i = 0; i < segments.length; i++) {
  142. if (0 < i) {
  143. sb.append(File.separator);
  144. }
  145. sb.append(segments[i]);
  146. }
  147. }
  148. return sb.toString();
  149. }
  150. /** @return true if dir is a readable directory */
  151. public static boolean canReadDir(File dir) {
  152. return (null != dir) && dir.canRead() && dir.isDirectory();
  153. }
  154. /** @return true if dir is a readable file */
  155. public static boolean canReadFile(File file) {
  156. return (null != file) && file.canRead() && file.isFile();
  157. }
  158. /**
  159. * Delete file or directory.
  160. * @param dir the File file or directory to delete.
  161. * @return true if all contents of dir were deleted
  162. */
  163. public static boolean delete(File dir) {
  164. return deleteContents(dir) && dir.delete();
  165. }
  166. /**
  167. * Delete contents of directory.
  168. * The directory itself is not deleted.
  169. * @param dir the File directory whose contents should be deleted.
  170. * @return true if all contents of dir were deleted
  171. */
  172. public static boolean deleteContents(File dir) {
  173. if ((null == dir) || !dir.canWrite()) {
  174. return false;
  175. } else if (dir.isDirectory()) {
  176. File[] files = dir.listFiles();
  177. for (File file : files) {
  178. if (!deleteContents(file) || !file.delete()) {
  179. return false;
  180. }
  181. }
  182. }
  183. return true;
  184. }
  185. /** @return File temporary directory with the given prefix */
  186. public static File makeTempDir(String prefix) {
  187. if (null == prefix) {
  188. prefix = "tempDir";
  189. }
  190. File tempFile = null;
  191. for (int i = 0; i < 10; i++) {
  192. try {
  193. tempFile = File.createTempFile(prefix,"tmp");
  194. tempFile.delete();
  195. if (tempFile.mkdirs()) {
  196. break;
  197. }
  198. tempFile = null;
  199. } catch (IOException e) {
  200. }
  201. }
  202. return tempFile;
  203. }
  204. /**
  205. * Close stream with the usual checks.
  206. * @param stream the InputStream to close - ignored if null
  207. * @return null if closed without IOException, message otherwise
  208. */
  209. public static String close(Writer stream) {
  210. String result = null;
  211. if (null != stream) {
  212. try {
  213. stream.close();
  214. } catch(IOException e) {
  215. result = e.getMessage();
  216. }
  217. }
  218. return result;
  219. }
  220. /**
  221. * @param list the Object[] to test
  222. * @return true if list is null or empty
  223. */
  224. public static boolean isEmpty(Object[] list) {
  225. return ((null == list) || (0 == list.length));
  226. }
  227. public static void closeSilently(InputStream in) {
  228. if (null != in) {
  229. try {
  230. in.close();
  231. } catch (IOException e) {
  232. // do nothing
  233. }
  234. }
  235. }
  236. public static void closeSilently(Reader in) {
  237. if (null != in) {
  238. try {
  239. in.close();
  240. } catch (IOException e) {
  241. // do nothing
  242. }
  243. }
  244. }
  245. /**
  246. * Report whether actual has different members than expected
  247. * @param expected the String[] of expected members (none null)
  248. * @param actual the String[] of actual members
  249. * @param sb StringBuffer sink for any differences in membership
  250. * @return true if any diffs found and sink updated
  251. */
  252. public static final boolean reportMemberDiffs(String[] expected, String[] actual, StringBuffer sb) {
  253. expected = copy(expected);
  254. actual = copy(actual);
  255. int hits = 0;
  256. for (int i = 0; i < expected.length; i++) {
  257. int curHit = hits;
  258. for (int j = 0; (curHit == hits) && (j < actual.length); j++) {
  259. if (null == expected[i]) {
  260. throw new IllegalArgumentException("null at " + i);
  261. }
  262. if (expected[i].equals(actual[j])) {
  263. expected[i] = null;
  264. actual[j] = null;
  265. hits++;
  266. }
  267. }
  268. }
  269. if ((hits != expected.length) || (hits != actual.length)) {
  270. sb.append("unexpected [");
  271. String prefix = "";
  272. for (String value : actual) {
  273. if (null != value) {
  274. sb.append(prefix);
  275. prefix = ", ";
  276. sb.append("\"");
  277. sb.append(value);
  278. sb.append("\"");
  279. }
  280. }
  281. sb.append("] missing [");
  282. prefix = "";
  283. for (String s : expected) {
  284. if (null != s) {
  285. sb.append(prefix);
  286. prefix = ", ";
  287. sb.append("\"");
  288. sb.append(s);
  289. sb.append("\"");
  290. }
  291. }
  292. sb.append("]");
  293. return true;
  294. }
  295. return false;
  296. }
  297. private static final String[] copy(String[] ra) {
  298. if (null == ra) {
  299. return new String[0];
  300. }
  301. String[] result = new String[ra.length];
  302. System.arraycopy(ra, 0, result, 0, ra.length);
  303. return result;
  304. }
  305. /**
  306. * Support for OSGI bundles read from manifest files.
  307. * Currently very limited, and will only support the subset of
  308. * features that we use.
  309. * sources:
  310. * http://www-128.ibm.com/developerworks/library/os-ecl-osgi/index.html
  311. * http://help.eclipse.org/help30/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/osgi/org/osgi/framework/Constants.html
  312. */
  313. public static class OSGIBundle {
  314. public static final Name BUNDLE_NAME = new Name("Bundle-Name");
  315. public static final Name BUNDLE_SYMBOLIC_NAME = new Name(
  316. "Bundle-SymbolicName");
  317. public static final Name BUNDLE_VERSION = new Name("Bundle-Version");
  318. public static final Name BUNDLE_ACTIVATOR = new Name("Bundle-Activator");
  319. public static final Name BUNDLE_VENDOR = new Name("Bundle-Vendor");
  320. public static final Name REQUIRE_BUNDLE = new Name("Require-Bundle");
  321. public static final Name IMPORT_PACKAGE = new Name("Import-Package");
  322. public static final Name BUNDLE_CLASSPATH = new Name("Bundle-ClassPath");
  323. /** unmodifiable list of all valid OSGIBundle Name's */
  324. public static final List<Name> NAMES;
  325. static {
  326. List<Name> names = new ArrayList<>();
  327. names.add(BUNDLE_NAME);
  328. names.add(BUNDLE_SYMBOLIC_NAME);
  329. names.add(BUNDLE_VERSION);
  330. names.add(BUNDLE_ACTIVATOR);
  331. names.add(BUNDLE_VENDOR);
  332. names.add(REQUIRE_BUNDLE);
  333. names.add(IMPORT_PACKAGE);
  334. names.add(BUNDLE_CLASSPATH);
  335. NAMES = Collections.unmodifiableList(names);
  336. }
  337. private final Manifest manifest;
  338. private final Attributes attributes;
  339. /**
  340. *
  341. * @param manifestInputStream
  342. * the InputStream of the manifest.mf - will be closed.
  343. * @throws IOException
  344. * if unable to read or close the manifest input stream.
  345. */
  346. public OSGIBundle(InputStream manifestInputStream) throws IOException {
  347. manifest = new Manifest();
  348. manifest.read(manifestInputStream);
  349. manifestInputStream.close();
  350. attributes = manifest.getMainAttributes();
  351. }
  352. public String getAttribute(Name attributeName) {
  353. return attributes.getValue(attributeName);
  354. }
  355. public String[] getClasspath() {
  356. String cp = getAttribute(OSGIBundle.BUNDLE_CLASSPATH);
  357. if (null == cp) {
  358. return new String[0];
  359. }
  360. StringTokenizer st = new StringTokenizer(cp, " ,");
  361. String[] result = new String[st.countTokens()];
  362. int i = 0;
  363. while (st.hasMoreTokens()) {
  364. result[i++] = st.nextToken();
  365. }
  366. return result;
  367. }
  368. /**
  369. * XXX ugly/weak hack only handles a single version comma
  370. * {name};bundle-version="[1.5.0,1.5.5]";resolution:=optional
  371. * @return
  372. */
  373. public RequiredBundle[] getRequiredBundles() {
  374. String value = getAttribute(OSGIBundle.REQUIRE_BUNDLE);
  375. if (null == value) {
  376. return new RequiredBundle[0];
  377. }
  378. StringTokenizer st = new StringTokenizer(value, " ,");
  379. RequiredBundle[] result = new RequiredBundle[st.countTokens()];
  380. int i = 0;
  381. int skips = 0;
  382. while (st.hasMoreTokens()) {
  383. String token = st.nextToken();
  384. int first = token.indexOf("\"");
  385. if (-1 != first) {
  386. if (!st.hasMoreTokens()) {
  387. throw new IllegalArgumentException(token);
  388. }
  389. // just assume only one quoted "," for version?
  390. token += "," + st.nextToken();
  391. skips++;
  392. }
  393. result[i++] = new RequiredBundle(token);
  394. }
  395. if (skips > 0) {
  396. RequiredBundle[] patch = new RequiredBundle[result.length-skips];
  397. System.arraycopy(result, 0, patch, 0, patch.length);
  398. result = patch;
  399. }
  400. return result;
  401. }
  402. /**
  403. * Wrap each dependency on another bundle
  404. */
  405. public static class RequiredBundle {
  406. /** unparsed entry text, for debugging */
  407. final String text;
  408. /** Symbolic name of the required bundle */
  409. final String name;
  410. /** if not null, then start/end versions of required bundle
  411. * in the format of the corresponding manifest entry
  412. */
  413. final String versions;
  414. /** if true, then required bundle is optional */
  415. final boolean optional;
  416. private RequiredBundle(String entry) {
  417. text = entry;
  418. StringTokenizer st = new StringTokenizer(entry, ";");
  419. name = st.nextToken();
  420. String vers = null;
  421. String opt = null;
  422. // bundle-version="[1.5.0,1.5.5]";resolution:=optiona
  423. final String RESOLUTION = "resolution:=";
  424. final String VERSION = "bundle-version=\"";
  425. while (st.hasMoreTokens()) {
  426. String token = st.nextToken();
  427. if (token.startsWith(VERSION)) {
  428. int start = VERSION.length();
  429. int end = token.lastIndexOf("\"");
  430. vers = token.substring(start, end);
  431. // e.g., [1.5.0,1.5.5)
  432. } else if (token.startsWith(RESOLUTION)) {
  433. int start = RESOLUTION.length();
  434. int end = token.length();
  435. opt = token.substring(start, end);
  436. }
  437. }
  438. versions = vers;
  439. optional = "optional".equals(opt);
  440. }
  441. }
  442. }
  443. }