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.

Sandbox.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * Xerox/PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.testing.harness.bridge;
  13. import org.aspectj.bridge.ICommand;
  14. import org.aspectj.bridge.IMessage;
  15. import org.aspectj.bridge.IMessageHandler;
  16. import org.aspectj.testing.util.Diffs;
  17. import org.aspectj.util.FileUtil;
  18. import org.aspectj.util.LangUtil;
  19. import java.io.File;
  20. import java.util.ArrayList;
  21. /**
  22. * A sandbox holds state shared by AjcTest sub-runs,
  23. * mostly directories relevant to testing.
  24. * It permits a limited amount of coordination and
  25. * setup/cleanup operations (todo XXX).
  26. * <p>
  27. * AjcTest creates the Sandbox and initializes the final fields.
  28. * To coordinate with each other, run components may set and get values,
  29. * with the sources running first and the sinks second.
  30. * To make the interactions clear
  31. * (and to avoid accidentally violating these semantics),
  32. * setters/getters for a coordinated property are constrained two ways:
  33. * <li>Both have an extra (typed) "caller" parameter which must not
  34. * be null, authenticating that the caller is known & valid.</li>
  35. * <li>A getter throws IllegalStateException if called before the setter</li>
  36. * <li>A setter throws IllegalStateException if called after the getter<li>
  37. * XXX subclass more general sandbox?
  38. */
  39. public class Sandbox {
  40. /** classes directory token for DirChanges.Spec */
  41. public static final String RUN_DIR = "run";
  42. /** run directory token for DirChanges.Spec */
  43. public static final String CLASSES_DIR = "classes";
  44. private static boolean canRead(File dir) {
  45. return ((null != dir) && dir.isDirectory() && dir.canRead());
  46. }
  47. private static boolean canWrite(File dir) {
  48. return ((null != dir) && dir.isDirectory() && dir.canWrite());
  49. }
  50. private static void iaxWrite(File dir, String label) {
  51. if (!canWrite(dir)) {
  52. throw new IllegalArgumentException(label + " - " + dir);
  53. }
  54. }
  55. private static void iaxRead(File dir, String label) {
  56. if (!canRead(dir)) {
  57. throw new IllegalArgumentException(label + " - " + dir);
  58. }
  59. }
  60. /** @throws IllegalStateException(message) if test */
  61. private static void assertState(boolean test, String message) {
  62. if (!test) {
  63. throw new IllegalStateException(message);
  64. }
  65. }
  66. /**
  67. * The (read-only) base of the test sources (which may or may not
  68. * be the base of the java sources)
  69. */
  70. public final File testBaseDir;
  71. /** the parent of a temporary workspace, probably includes some others */
  72. public final File sandboxDir;
  73. /** a shared working dir */
  74. public final File workingDir;
  75. /** a shared classes dir */
  76. public final File classesDir;
  77. /** a run dir (which will be ignored in non-forking runs) */
  78. public final File runDir;
  79. /** staging directory for IAjcRun requiring files be copied, deleted, etc. */
  80. public final File stagingDir;
  81. /**
  82. * This manages creation and deletion of temporary directories.
  83. * We hold a reference so that our clients can signal whether
  84. * this should be deleted.
  85. */
  86. private final Validator validator; // XXX required after completing tests?
  87. /** original base of the original java sources, set by CompileRun.setup(..) */
  88. private File testBaseSrcDir;
  89. /** directories and libraries on the classpath, set by CompileRun.setup(..) */
  90. private File[] compileClasspath;
  91. /** aspectpath entries, set by CompileRun.setup(..) */
  92. private File[] aspectpath;
  93. /** track whether classpath getter ran */
  94. private boolean gotClasspath;
  95. /** command shared between runs using sandbox - i.e., compiler */
  96. private ICommand command;
  97. /** track whether command getter ran */
  98. private boolean gotCommand;
  99. /** cache results of rendering final fields */
  100. private transient String toStringLeader;
  101. /** @throws IllegalArgumentException unless validator validates
  102. * testBaseDir as readable
  103. */
  104. public Sandbox(File testBaseDir, Validator validator) {
  105. LangUtil.throwIaxIfNull(validator, "validator");
  106. this.validator = validator;
  107. Sandbox.iaxRead(testBaseDir, "testBaseDir");
  108. this.testBaseDir = testBaseDir;
  109. sandboxDir = FileUtil.getTempDir("Sandbox");
  110. Sandbox.iaxWrite(sandboxDir, "sandboxDir"); // XXX not really iax
  111. workingDir = FileUtil.makeNewChildDir(sandboxDir, "workingDir");
  112. Sandbox.iaxWrite(workingDir, "workingDir");
  113. classesDir = FileUtil.makeNewChildDir(sandboxDir, "classes");
  114. Sandbox.iaxWrite(classesDir, "classesDir");
  115. runDir = FileUtil.makeNewChildDir(sandboxDir, "run");
  116. Sandbox.iaxWrite(runDir, "runDir");
  117. stagingDir = FileUtil.makeNewChildDir(sandboxDir, "staging");
  118. Sandbox.iaxWrite(stagingDir, "stagingDir");
  119. validator.registerSandbox(this);
  120. }
  121. private String getToStringLeader() {
  122. if (null == toStringLeader) {
  123. toStringLeader = "Sandbox(" + sandboxDir.getName()
  124. + ", " + testBaseSrcDir.getName();
  125. }
  126. return toStringLeader;
  127. }
  128. /** @return "Sandbox(sandbox, src, classes)" with names only */
  129. public String toString() {
  130. return getToStringLeader() + ", " + classesDir.getName() + ")";
  131. }
  132. /** @return "Sandbox(sandbox, src, classes)" with paths */
  133. public String toLongString() {
  134. return getToStringLeader() + ", " + classesDir.getPath()
  135. + (null == command ? ", (null command)" : ", " + command) + ")";
  136. }
  137. void setCommand(ICommand command, CompilerRun caller) {
  138. LangUtil.throwIaxIfNull(caller, "caller");
  139. LangUtil.throwIaxIfNull(command, "command");
  140. LangUtil.throwIaxIfFalse(!gotCommand, "no command");
  141. this.command = command;
  142. }
  143. /** When test is completed, clear the compiler to avoid memory leaks */
  144. void clearCommand(AjcTest caller) {
  145. LangUtil.throwIaxIfNull(caller, "caller");
  146. if (null != command) {
  147. command = null;
  148. }
  149. }
  150. // /**
  151. // * Populate the staging directory by copying any files in the
  152. // * source directory ending with fromSuffix
  153. // * to the staging directory, after renaming them with toSuffix.
  154. // * If the source file name starts with "delete", then the
  155. // * corresponding file in the staging directory is deleting.
  156. // * @return a String[] of the files copied or deleted
  157. // * (path after suffix changes and relative to staging dir)
  158. // * @throws Error if no File using fromSuffix are found
  159. // */
  160. // String[] populateStagingDir(String fromSuffix, String toSuffix, IAjcRun caller) {
  161. // LangUtil.throwIaxIfNull(fromSuffix, "fromSuffix");
  162. // LangUtil.throwIaxIfNull(toSuffix, "toSuffix");
  163. // LangUtil.throwIaxIfNull(caller, "caller");
  164. //
  165. // ArrayList result = new ArrayList();
  166. // FileUtil.copyDir(
  167. // srcBase,
  168. // targetSrc,
  169. // fromSuffix,
  170. // toSuffix,
  171. // collector);
  172. //
  173. // final String canonicalFrom = srcBase.getCanonicalPath();
  174. // final Definition[] defs = getDefinitions(srcBase);
  175. // if ((null == defs) || (defs.length < 9)) {
  176. // throw new Error("did not get definitions");
  177. // }
  178. // MessageHandler compilerMessages = new MessageHandler();
  179. // StringBuffer commandLine = new StringBuffer();
  180. // for (int i = 1; result && (i < 10); i++) {
  181. // String fromSuffix = "." + i + "0.java";
  182. // // copy files, collecting as we go...
  183. // files.clear();
  184. // if (0 == files.size()) { // XXX detect incomplete?
  185. // break;
  186. // }
  187. //
  188. //
  189. // return (String[]) result.toArray(new String[0]);
  190. // }
  191. // XXX move to more general in FileUtil
  192. void reportClassDiffs(
  193. final IMessageHandler handler,
  194. IncCompilerRun caller,
  195. long classesDirStartTime,
  196. String[] expectedSources) {
  197. LangUtil.throwIaxIfFalse(0 < classesDirStartTime, "0 >= " + classesDirStartTime);
  198. boolean acceptPrefixes = true;
  199. Diffs diffs = org.aspectj.testing.util.FileUtil.dirDiffs(
  200. "classes",
  201. classesDir,
  202. classesDirStartTime,
  203. ".class",
  204. expectedSources,
  205. acceptPrefixes);
  206. diffs.report(handler, IMessage.ERROR);
  207. }
  208. // // XXX replace with IMessage-based implementation
  209. // // XXX move to more general in FileUtil
  210. // void reportClassesDirDiffs(final IMessageHandler handler, IncCompilerRun caller,
  211. // String[] expectedSources) {
  212. // // normalize sources to ignore
  213. // final ArrayList sources = new ArrayList();
  214. // if (!LangUtil.isEmpty(expectedSources)) {
  215. // for (int i = 0; i < expectedSources.length; i++) {
  216. // String srcPath = expectedSources[i];
  217. // int clip = FileUtil.sourceSuffixLength(srcPath);
  218. // if (0 != clip) {
  219. // srcPath = srcPath.substring(0, srcPath.length() - clip);
  220. // sources.add(FileUtil.weakNormalize(srcPath));
  221. // } else if (srcPath.endsWith(".class")) {
  222. // srcPath = srcPath.substring(0, srcPath.length() - 6);
  223. // sources.add(FileUtil.weakNormalize(srcPath));
  224. // } else {
  225. // MessageUtil.info(handler, "not source file: " + srcPath);
  226. // }
  227. // }
  228. // }
  229. //
  230. // // gather, normalize paths changed
  231. // final ArrayList changed = new ArrayList();
  232. // FileFilter touchedCollector = new FileFilter() {
  233. // public boolean accept(File file) {
  234. // if (file.lastModified() > classesDirTime) {
  235. // String path = file.getPath();
  236. // if (!path.endsWith(".class")) {
  237. // MessageUtil.info(handler, "changed file not a class: " + file);
  238. // } else {
  239. // String classPath = path.substring(0, path.length() - 6);
  240. // classPath = FileUtil.weakNormalize(classPath);
  241. // if (sources.contains(classPath)) {
  242. // sources.remove(classPath);
  243. // } else {
  244. // changed.add(classPath);
  245. // }
  246. // }
  247. // }
  248. // return false;
  249. // }
  250. // };
  251. // classesDir.listFiles(touchedCollector);
  252. //
  253. // // report any unexpected changes
  254. // Diffs diffs = new Diffs("classes", sources, changed, String.CASE_INSENSITIVE_ORDER);
  255. // diffs.report(handler, IMessage.ERROR);
  256. // }
  257. ICommand getCommand(IncCompilerRun caller) {
  258. LangUtil.throwIaxIfNull(caller, "caller");
  259. assertState(null != command, "command never set");
  260. return command;
  261. }
  262. File getTestBaseSrcDir(IncCompilerRun caller) {
  263. LangUtil.throwIaxIfNull(caller, "caller");
  264. return testBaseSrcDir;
  265. }
  266. File getTestBaseSrcDir(JavaRun caller) {
  267. LangUtil.throwIaxIfNull(caller, "caller");
  268. return testBaseSrcDir;
  269. }
  270. /** @throws IllegalArgumentException unless a readable directory */
  271. void setTestBaseSrcDir(File dir, CompilerRun caller) {
  272. LangUtil.throwIaxIfNull(caller, "caller");
  273. if ((null == dir) || !dir.isDirectory() || !dir.canRead()) {
  274. throw new IllegalArgumentException("bad test base src dir: " + dir);
  275. }
  276. testBaseSrcDir = dir;
  277. }
  278. /**
  279. * Set aspectpath.
  280. * @param readable if true, then throw IllegalArgumentException if not readable
  281. */
  282. void setAspectpath(File[] files, boolean readable, CompilerRun caller) {
  283. LangUtil.throwIaxIfNull(files, "files");
  284. LangUtil.throwIaxIfNull(caller, "caller");
  285. assertState(null == aspectpath, "aspectpath already written");
  286. aspectpath = new File[files.length];
  287. for (int i = 0; i < files.length; i++) {
  288. LangUtil.throwIaxIfNull(files[i], "files[i]");
  289. if (readable && !files[i].canRead()) {
  290. throw new IllegalArgumentException("bad aspectpath entry: " + files[i]);
  291. }
  292. aspectpath[i] = files[i];
  293. }
  294. }
  295. /**
  296. * Set compile classpath.
  297. * @param readable if true, then throw IllegalArgumentException if not readable
  298. */
  299. void setClasspath(File[] files, boolean readable, CompilerRun caller) {
  300. LangUtil.throwIaxIfNull(files, "files");
  301. LangUtil.throwIaxIfNull(caller, "caller");
  302. assertState(!gotClasspath, "classpath already read");
  303. compileClasspath = new File[files.length];
  304. for (int i = 0; i < files.length; i++) {
  305. LangUtil.throwIaxIfNull(files[i], "files[i]");
  306. if (readable && !files[i].canRead()) {
  307. throw new IllegalArgumentException("bad classpath entry: " + files[i]);
  308. }
  309. compileClasspath[i] = files[i];
  310. }
  311. }
  312. // /**
  313. // * Get run classpath
  314. // * @param caller unused except to restrict usage to non-null JavaRun.
  315. // * @throws IllegalStateException if compileClasspath was not set.
  316. // * @throws IllegalArgumentException if caller is null
  317. // */
  318. // File[] getRunClasspath(JavaRun caller) {
  319. // LangUtil.throwIaxIfNull(caller, "caller");
  320. // assertState(null != compileClasspath, "classpath not set");
  321. // int compilePathLength = compileClasspath.length;
  322. // int aspectPathLength = (null == aspectpath ? 0 : aspectpath.length);
  323. // File[] result = new File[aspectPathLength + compilePathLength];
  324. // System.arraycopy(compileClasspath, 0, result, 0, compilePathLength);
  325. // if (0 < aspectPathLength) {
  326. // System.arraycopy(aspectpath, 0, result, compilePathLength, aspectPathLength);
  327. // }
  328. // return result;
  329. // }
  330. /**
  331. * Get directories for the run classpath by selecting them
  332. * from the compile classpath.
  333. * This ignores aspectpath since it may contain only jar files.
  334. * @param readable if true, omit non-readable directories
  335. */
  336. File[] getClasspathDirectories(boolean readable, JavaRun caller) {
  337. LangUtil.throwIaxIfNull(caller, "caller");
  338. assertState(null != compileClasspath, "classpath not set");
  339. ArrayList result = new ArrayList();
  340. File[] src = compileClasspath;
  341. for (int i = 0; i < src.length; i++) {
  342. File f = src[i];
  343. if ((null != f) && (f.isDirectory()) && (!readable || f.canRead())) {
  344. result.add(f);
  345. }
  346. }
  347. return (File[]) result.toArray(new File[0]);
  348. }
  349. /**
  350. * Get the jars belonging on the run classpath, including classpath
  351. * and aspectpath entries.
  352. * @param readable if true, omit non-readable directories
  353. */
  354. File[] getClasspathJars(boolean readable, JavaRun caller) {
  355. LangUtil.throwIaxIfNull(caller, "caller");
  356. assertState(null != compileClasspath, "classpath not set");
  357. ArrayList result = new ArrayList();
  358. File[][] src = new File[][] { compileClasspath, aspectpath };
  359. for (int i = 0; i < src.length; i++) {
  360. File[] paths = src[i];
  361. int len = (null == paths ? 0 : paths.length);
  362. for (int j = 0; j < len; j++) {
  363. File f = paths[j];
  364. if (FileUtil.hasZipSuffix(f) && (!readable || f.canRead())) {
  365. result.add(f);
  366. }
  367. }
  368. }
  369. return (File[]) result.toArray(new File[0]);
  370. }
  371. /**
  372. * Get the list of aspect jars as a String.
  373. * @return String of classpath entries delimited internally by File.pathSeparator
  374. */
  375. String aspectpathToString(CompilerRun caller) {
  376. LangUtil.throwIaxIfNull(caller, "caller");
  377. return FileUtil.flatten(aspectpath, null);
  378. }
  379. /**
  380. * Get the compile classpath as a String.
  381. * @return String of classpath entries delimited internally by File.pathSeparator
  382. */
  383. String classpathToString(CompilerRun caller) {
  384. LangUtil.throwIaxIfNull(caller, "caller");
  385. return FileUtil.flatten(compileClasspath, null);
  386. }
  387. }