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

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. }