123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Common Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
- * Contributors:
- * Xerox/PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.testing.harness.bridge;
-
- import org.aspectj.bridge.ICommand;
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.IMessageHandler;
- import org.aspectj.testing.util.Diffs;
- import org.aspectj.util.FileUtil;
- import org.aspectj.util.LangUtil;
-
- import java.io.File;
- import java.util.ArrayList;
-
- /**
- * A sandbox holds state shared by AjcTest sub-runs,
- * mostly directories relevant to testing.
- * It permits a limited amount of coordination and
- * setup/cleanup operations (todo XXX).
- * <p>
- * AjcTest creates the Sandbox and initializes the final fields.
- * To coordinate with each other, run components may set and get values,
- * with the sources running first and the sinks second.
- * To make the interactions clear
- * (and to avoid accidentally violating these semantics),
- * setters/getters for a coordinated property are constrained two ways:
- * <li>Both have an extra (typed) "caller" parameter which must not
- * be null, authenticating that the caller is known & valid.</li>
- * <li>A getter throws IllegalStateException if called before the setter</li>
- * <li>A setter throws IllegalStateException if called after the getter<li>
- * XXX subclass more general sandbox?
- */
- public class Sandbox {
- /** classes directory token for DirChanges.Spec */
- public static final String RUN_DIR = "run";
-
- /** run directory token for DirChanges.Spec */
- public static final String CLASSES_DIR = "classes";
-
- private static boolean canRead(File dir) {
- return ((null != dir) && dir.isDirectory() && dir.canRead());
- }
-
- private static boolean canWrite(File dir) {
- return ((null != dir) && dir.isDirectory() && dir.canWrite());
- }
-
- private static void iaxWrite(File dir, String label) {
- if (!canWrite(dir)) {
- throw new IllegalArgumentException(label + " - " + dir);
- }
- }
-
- private static void iaxRead(File dir, String label) {
- if (!canRead(dir)) {
- throw new IllegalArgumentException(label + " - " + dir);
- }
- }
-
- /** @throws IllegalStateException(message) if test */
- private static void assertState(boolean test, String message) {
- if (!test) {
- throw new IllegalStateException(message);
- }
- }
-
- /**
- * The (read-only) base of the test sources (which may or may not
- * be the base of the java sources)
- */
- public final File testBaseDir;
-
- /** the parent of a temporary workspace, probably includes some others */
- public final File sandboxDir;
-
- /** a shared working dir */
- public final File workingDir;
-
- /** a shared classes dir */
- public final File classesDir;
-
- /** a run dir (which will be ignored in non-forking runs) */
- public final File runDir;
-
- /** staging directory for IAjcRun requiring files be copied, deleted, etc. */
- public final File stagingDir;
-
- /**
- * This manages creation and deletion of temporary directories.
- * We hold a reference so that our clients can signal whether
- * this should be deleted.
- */
- private final Validator validator; // XXX required after completing tests?
-
- /** original base of the original java sources, set by CompileRun.setup(..) */
- private File testBaseSrcDir;
-
- /** directories and libraries on the classpath, set by CompileRun.setup(..) */
- private File[] compileClasspath;
-
- /** aspectpath entries, set by CompileRun.setup(..) */
- private File[] aspectpath;
-
- /** track whether classpath getter ran */
- private boolean gotClasspath;
-
- /** command shared between runs using sandbox - i.e., compiler */
- private ICommand command;
-
- /** track whether command getter ran */
- private boolean gotCommand;
-
- /** cache results of rendering final fields */
- private transient String toStringLeader;
-
- /** @throws IllegalArgumentException unless validator validates
- * testBaseDir as readable
- */
- public Sandbox(File testBaseDir, Validator validator) {
- LangUtil.throwIaxIfNull(validator, "validator");
- this.validator = validator;
- Sandbox.iaxRead(testBaseDir, "testBaseDir");
- this.testBaseDir = testBaseDir;
-
- sandboxDir = FileUtil.getTempDir("Sandbox");
- Sandbox.iaxWrite(sandboxDir, "sandboxDir"); // XXX not really iax
-
- workingDir = FileUtil.makeNewChildDir(sandboxDir, "workingDir");
- Sandbox.iaxWrite(workingDir, "workingDir");
-
- classesDir = FileUtil.makeNewChildDir(sandboxDir, "classes");
- Sandbox.iaxWrite(classesDir, "classesDir");
-
- runDir = FileUtil.makeNewChildDir(sandboxDir, "run");
- Sandbox.iaxWrite(runDir, "runDir");
-
- stagingDir = FileUtil.makeNewChildDir(sandboxDir, "staging");
- Sandbox.iaxWrite(stagingDir, "stagingDir");
-
- validator.registerSandbox(this);
- }
-
- private String getToStringLeader() {
- if (null == toStringLeader) {
- toStringLeader = "Sandbox(" + sandboxDir.getName()
- + ", " + testBaseSrcDir.getName();
- }
- return toStringLeader;
- }
-
- /** @return "Sandbox(sandbox, src, classes)" with names only */
- public String toString() {
- return getToStringLeader() + ", " + classesDir.getName() + ")";
- }
-
- /** @return "Sandbox(sandbox, src, classes)" with paths */
- public String toLongString() {
- return getToStringLeader() + ", " + classesDir.getPath()
- + (null == command ? ", (null command)" : ", " + command) + ")";
- }
-
- void setCommand(ICommand command, CompilerRun caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- LangUtil.throwIaxIfNull(command, "command");
- LangUtil.throwIaxIfFalse(!gotCommand, "no command");
- this.command = command;
- }
-
- /** When test is completed, clear the compiler to avoid memory leaks */
- void clearCommand(AjcTest caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- if (null != command) {
- command = null;
- }
- }
-
- // /**
- // * Populate the staging directory by copying any files in the
- // * source directory ending with fromSuffix
- // * to the staging directory, after renaming them with toSuffix.
- // * If the source file name starts with "delete", then the
- // * corresponding file in the staging directory is deleting.
- // * @return a String[] of the files copied or deleted
- // * (path after suffix changes and relative to staging dir)
- // * @throws Error if no File using fromSuffix are found
- // */
- // String[] populateStagingDir(String fromSuffix, String toSuffix, IAjcRun caller) {
- // LangUtil.throwIaxIfNull(fromSuffix, "fromSuffix");
- // LangUtil.throwIaxIfNull(toSuffix, "toSuffix");
- // LangUtil.throwIaxIfNull(caller, "caller");
- //
- // ArrayList result = new ArrayList();
- // FileUtil.copyDir(
- // srcBase,
- // targetSrc,
- // fromSuffix,
- // toSuffix,
- // collector);
- //
- // final String canonicalFrom = srcBase.getCanonicalPath();
- // final Definition[] defs = getDefinitions(srcBase);
- // if ((null == defs) || (defs.length < 9)) {
- // throw new Error("did not get definitions");
- // }
- // MessageHandler compilerMessages = new MessageHandler();
- // StringBuffer commandLine = new StringBuffer();
- // for (int i = 1; result && (i < 10); i++) {
- // String fromSuffix = "." + i + "0.java";
- // // copy files, collecting as we go...
- // files.clear();
- // if (0 == files.size()) { // XXX detect incomplete?
- // break;
- // }
- //
- //
- // return (String[]) result.toArray(new String[0]);
- // }
-
- // XXX move to more general in FileUtil
- void reportClassDiffs(
- final IMessageHandler handler,
- IncCompilerRun caller,
- long classesDirStartTime,
- String[] expectedSources) {
- LangUtil.throwIaxIfFalse(0 < classesDirStartTime, "0 >= " + classesDirStartTime);
- boolean acceptPrefixes = true;
- Diffs diffs = org.aspectj.testing.util.FileUtil.dirDiffs(
- "classes",
- classesDir,
- classesDirStartTime,
- ".class",
- expectedSources,
- acceptPrefixes);
- diffs.report(handler, IMessage.ERROR);
- }
-
- // // XXX replace with IMessage-based implementation
- // // XXX move to more general in FileUtil
- // void reportClassesDirDiffs(final IMessageHandler handler, IncCompilerRun caller,
- // String[] expectedSources) {
- // // normalize sources to ignore
- // final ArrayList sources = new ArrayList();
- // if (!LangUtil.isEmpty(expectedSources)) {
- // for (int i = 0; i < expectedSources.length; i++) {
- // String srcPath = expectedSources[i];
- // int clip = FileUtil.sourceSuffixLength(srcPath);
- // if (0 != clip) {
- // srcPath = srcPath.substring(0, srcPath.length() - clip);
- // sources.add(FileUtil.weakNormalize(srcPath));
- // } else if (srcPath.endsWith(".class")) {
- // srcPath = srcPath.substring(0, srcPath.length() - 6);
- // sources.add(FileUtil.weakNormalize(srcPath));
- // } else {
- // MessageUtil.info(handler, "not source file: " + srcPath);
- // }
- // }
- // }
- //
- // // gather, normalize paths changed
- // final ArrayList changed = new ArrayList();
- // FileFilter touchedCollector = new FileFilter() {
- // public boolean accept(File file) {
- // if (file.lastModified() > classesDirTime) {
- // String path = file.getPath();
- // if (!path.endsWith(".class")) {
- // MessageUtil.info(handler, "changed file not a class: " + file);
- // } else {
- // String classPath = path.substring(0, path.length() - 6);
- // classPath = FileUtil.weakNormalize(classPath);
- // if (sources.contains(classPath)) {
- // sources.remove(classPath);
- // } else {
- // changed.add(classPath);
- // }
- // }
- // }
- // return false;
- // }
- // };
- // classesDir.listFiles(touchedCollector);
- //
- // // report any unexpected changes
- // Diffs diffs = new Diffs("classes", sources, changed, String.CASE_INSENSITIVE_ORDER);
- // diffs.report(handler, IMessage.ERROR);
- // }
-
- ICommand getCommand(IncCompilerRun caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- assertState(null != command, "command never set");
- return command;
- }
-
- File getTestBaseSrcDir(IncCompilerRun caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- return testBaseSrcDir;
- }
-
- File getTestBaseSrcDir(JavaRun caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- return testBaseSrcDir;
- }
-
- /** @throws IllegalArgumentException unless a readable directory */
- void setTestBaseSrcDir(File dir, CompilerRun caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- if ((null == dir) || !dir.isDirectory() || !dir.canRead()) {
- throw new IllegalArgumentException("bad test base src dir: " + dir);
- }
- testBaseSrcDir = dir;
- }
-
- /**
- * Set aspectpath.
- * @param readable if true, then throw IllegalArgumentException if not readable
- */
- void setAspectpath(File[] files, boolean readable, CompilerRun caller) {
- LangUtil.throwIaxIfNull(files, "files");
- LangUtil.throwIaxIfNull(caller, "caller");
- assertState(null == aspectpath, "aspectpath already written");
- aspectpath = new File[files.length];
- for (int i = 0; i < files.length; i++) {
- LangUtil.throwIaxIfNull(files[i], "files[i]");
- if (readable && !files[i].canRead()) {
- throw new IllegalArgumentException("bad aspectpath entry: " + files[i]);
- }
- aspectpath[i] = files[i];
- }
- }
-
- /**
- * Set compile classpath.
- * @param readable if true, then throw IllegalArgumentException if not readable
- */
- void setClasspath(File[] files, boolean readable, CompilerRun caller) {
- LangUtil.throwIaxIfNull(files, "files");
- LangUtil.throwIaxIfNull(caller, "caller");
- assertState(!gotClasspath, "classpath already read");
- compileClasspath = new File[files.length];
- for (int i = 0; i < files.length; i++) {
- LangUtil.throwIaxIfNull(files[i], "files[i]");
- if (readable && !files[i].canRead()) {
- throw new IllegalArgumentException("bad classpath entry: " + files[i]);
- }
- compileClasspath[i] = files[i];
- }
- }
-
- // /**
- // * Get run classpath
- // * @param caller unused except to restrict usage to non-null JavaRun.
- // * @throws IllegalStateException if compileClasspath was not set.
- // * @throws IllegalArgumentException if caller is null
- // */
- // File[] getRunClasspath(JavaRun caller) {
- // LangUtil.throwIaxIfNull(caller, "caller");
- // assertState(null != compileClasspath, "classpath not set");
- // int compilePathLength = compileClasspath.length;
- // int aspectPathLength = (null == aspectpath ? 0 : aspectpath.length);
- // File[] result = new File[aspectPathLength + compilePathLength];
- // System.arraycopy(compileClasspath, 0, result, 0, compilePathLength);
- // if (0 < aspectPathLength) {
- // System.arraycopy(aspectpath, 0, result, compilePathLength, aspectPathLength);
- // }
- // return result;
- // }
-
- /**
- * Get directories for the run classpath by selecting them
- * from the compile classpath.
- * This ignores aspectpath since it may contain only jar files.
- * @param readable if true, omit non-readable directories
- */
- File[] getClasspathDirectories(boolean readable, JavaRun caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- assertState(null != compileClasspath, "classpath not set");
- ArrayList result = new ArrayList();
- File[] src = compileClasspath;
- for (int i = 0; i < src.length; i++) {
- File f = src[i];
- if ((null != f) && (f.isDirectory()) && (!readable || f.canRead())) {
- result.add(f);
- }
- }
- return (File[]) result.toArray(new File[0]);
- }
-
- /**
- * Get the jars belonging on the run classpath, including classpath
- * and aspectpath entries.
- * @param readable if true, omit non-readable directories
- */
- File[] getClasspathJars(boolean readable, JavaRun caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- assertState(null != compileClasspath, "classpath not set");
- ArrayList result = new ArrayList();
- File[][] src = new File[][] { compileClasspath, aspectpath };
- for (int i = 0; i < src.length; i++) {
- File[] paths = src[i];
- int len = (null == paths ? 0 : paths.length);
- for (int j = 0; j < len; j++) {
- File f = paths[j];
- if (FileUtil.hasZipSuffix(f) && (!readable || f.canRead())) {
- result.add(f);
- }
- }
- }
- return (File[]) result.toArray(new File[0]);
- }
-
- /**
- * Get the list of aspect jars as a String.
- * @return String of classpath entries delimited internally by File.pathSeparator
- */
- String aspectpathToString(CompilerRun caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- return FileUtil.flatten(aspectpath, null);
- }
-
- /**
- * Get the compile classpath as a String.
- * @return String of classpath entries delimited internally by File.pathSeparator
- */
- String classpathToString(CompilerRun caller) {
- LangUtil.throwIaxIfNull(caller, "caller");
- return FileUtil.flatten(compileClasspath, null);
- }
- }
|