diff options
author | wisberg <wisberg> | 2002-12-16 17:09:36 +0000 |
---|---|---|
committer | wisberg <wisberg> | 2002-12-16 17:09:36 +0000 |
commit | c3300283ecc397d26ad9dfe31d1710ec45db2af0 (patch) | |
tree | e9acb7f3d33c1499975cec9ef3cc7ea151078344 /util | |
parent | 3cde920c3f7eb8241bf569007e25225d80b43c0f (diff) | |
download | aspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.tar.gz aspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.zip |
initial version
Diffstat (limited to 'util')
-rw-r--r-- | util/src/.cvsignore | 1 | ||||
-rw-r--r-- | util/src/org/aspectj/util/CollectionUtil.java | 60 | ||||
-rw-r--r-- | util/src/org/aspectj/util/ConfigParser.java | 290 | ||||
-rw-r--r-- | util/src/org/aspectj/util/FileUtil.java | 1048 | ||||
-rw-r--r-- | util/src/org/aspectj/util/FuzzyBoolean.java | 180 | ||||
-rw-r--r-- | util/src/org/aspectj/util/LangUtil.java | 781 | ||||
-rw-r--r-- | util/src/org/aspectj/util/LineReader.java | 212 | ||||
-rw-r--r-- | util/src/org/aspectj/util/NonLocalExit.java | 39 | ||||
-rw-r--r-- | util/src/org/aspectj/util/PartialOrder.java | 213 | ||||
-rw-r--r-- | util/src/org/aspectj/util/Reflection.java | 106 | ||||
-rw-r--r-- | util/src/org/aspectj/util/StreamPrintWriter.java | 101 | ||||
-rw-r--r-- | util/src/org/aspectj/util/TypeSafeEnum.java | 38 | ||||
-rw-r--r-- | util/testsrc/UtilModuleTests.java | 30 | ||||
-rw-r--r-- | util/testsrc/org/aspectj/util/FileUtilTest.java | 377 | ||||
-rw-r--r-- | util/testsrc/org/aspectj/util/LangUtilTest.java | 266 | ||||
-rw-r--r-- | util/testsrc/org/aspectj/util/UtilTests.java | 32 |
16 files changed, 3774 insertions, 0 deletions
diff --git a/util/src/.cvsignore b/util/src/.cvsignore new file mode 100644 index 000000000..a3f0b1b77 --- /dev/null +++ b/util/src/.cvsignore @@ -0,0 +1 @@ +*.lst diff --git a/util/src/org/aspectj/util/CollectionUtil.java b/util/src/org/aspectj/util/CollectionUtil.java new file mode 100644 index 000000000..637362c1c --- /dev/null +++ b/util/src/org/aspectj/util/CollectionUtil.java @@ -0,0 +1,60 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + + +import java.util.*; + +public class CollectionUtil { + public static final String[] NO_STRINGS = new String[0]; + + + public static List getListInMap(Map map, Object key) { + List list = (List)map.get(key); + if (list == null) { + list = new ArrayList(); + map.put(key, list); + } + return list; + } + + public static SortedSet getSortedSetInMap(Map map, Object key) { + SortedSet list = (SortedSet)map.get(key); + if (list == null) { + list = new TreeSet(); + map.put(key, list); + } + return list; + } + + public static Set getSetInMap(Map map, Object key) { + Set list = (Set)map.get(key); + if (list == null) { + list = new HashSet(); + map.put(key, list); + } + return list; + } + + public static Map getMapInMap(Map map, Object key) { + Map list = (Map)map.get(key); + if (list == null) { + list = new HashMap(); + map.put(key, list); + } + return list; + } + +} diff --git a/util/src/org/aspectj/util/ConfigParser.java b/util/src/org/aspectj/util/ConfigParser.java new file mode 100644 index 000000000..dab133510 --- /dev/null +++ b/util/src/org/aspectj/util/ConfigParser.java @@ -0,0 +1,290 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + +import java.util.*; +import java.io.*; + +public class ConfigParser { + Location location; + protected List files = new LinkedList(); + private boolean fileParsed = false; + + public List getFiles() { return files; } + + public void parseCommandLine(String[] argsArray) throws ParseException { + location = new CommandLineLocation(); + LinkedList args = new LinkedList(); + for (int i = 0; i < argsArray.length; i++) { + args.add(new Arg(argsArray[i], location)); + } + parseArgs(args); + } + + public void parseConfigFile(File configFile) throws ParseException { + if (fileParsed == true) { + throw new ParseException("The file has already been parsed.", null); + } else { + parseConfigFileHelper(configFile); + } + } + + /** + * @throws ParseException if the config file has already been prased. + */ + private void parseConfigFileHelper(File configFile) { + if (!configFile.exists()) { + showError("file does not exist: " + configFile.getPath()); + return; + } + + LinkedList args = new LinkedList(); + int lineNum = 0; + + try { + BufferedReader stream = + new BufferedReader(new FileReader(configFile)); + String line = null; + while ( (line = stream.readLine()) != null) { + lineNum += 1; + line = stripWhitespaceAndComments(line); + if (line.length() == 0) continue; + args.add(new Arg(line, new SourceLocation(configFile, lineNum))); + } + } catch (IOException e) { + location = new SourceLocation(configFile, lineNum); + showError("error reading config file: " + e.toString()); + } + parseArgs(args); + fileParsed = true; + } + + File getCurrentDir() { + return location.getDirectory(); + } + + String stripSingleLineComment(String s, String commentString) { + int commentStart = s.indexOf(commentString); + if (commentStart == -1) return s; + else return s.substring(0, commentStart); + } + + String stripWhitespaceAndComments(String s) { + s = stripSingleLineComment(s, "//"); + s = stripSingleLineComment(s, "#"); + s = s.trim(); + if (s.startsWith("\"") && s.endsWith("\"")) { + s = s.substring(1, s.length()-1); + } + return s; + } + + + /** ??? We would like to call a showNonFatalError method here + * to show all errors in config files before aborting the compilation + */ + protected void addFile(File sourceFile) { + if (!sourceFile.isFile()) { + showError("source file does not exist: " + sourceFile.getPath()); + } + + files.add(sourceFile); + } + + void addFileOrPattern(File sourceFile) { + if (sourceFile.getName().equals("*.java")) { + addFiles(sourceFile.getParentFile(), new FileFilter() { + public boolean accept(File f) { + return f != null && f.getName().endsWith(".java"); + }}); + } else if (sourceFile.getName().equals("*.aj")) { + addFiles(sourceFile.getParentFile(), new FileFilter() { + public boolean accept(File f) { + return f != null && f.getName().endsWith(".aj"); + }}); + } else { + addFile(sourceFile); + } + } + + void addFiles(File dir, FileFilter filter) { + if (dir == null) dir = new File(System.getProperty("user.dir")); + + if (!dir.isDirectory()) { + showError("can't find " + dir.getPath()); + } + + File[] files = dir.listFiles(filter); + if (files.length == 0) { + showWarning("no matching files found in: " + dir); + } + + for (int i = 0; i < files.length; i++) { + addFile(files[i]); + } + } + + protected void parseOption(String arg, LinkedList args) { + showWarning("unrecognized option: " + arg); + } + + protected void showWarning(String message) { + if (location != null) { + message += " at " + location.toString(); + } + System.err.println(message); + } + + protected void showError(String message) { + throw new ParseException(message, location); + } + + void parseArgs(LinkedList args) { + while (args.size() > 0) parseOneArg(args); + } + + protected Arg removeArg(LinkedList args) { + if (args.size() == 0) { + showError("value missing"); + return null; + } else { + return (Arg)args.removeFirst(); + } + } + + protected String removeStringArg(LinkedList args) { + Arg arg = removeArg(args); + if (arg == null) return null; + return arg.getValue(); + } + + boolean isSourceFileName(String s) { + if (s.endsWith(".java")) return true; + if (s.endsWith(".aj")) return true; + if (s.endsWith(".ajava")) { + showWarning(".ajava is deprecated, replace with .aj or .java: " + s); + return true; + } + return false; + } + + void parseOneArg(LinkedList args) { + Arg arg = removeArg(args); + String v = arg.getValue(); + location = arg.getLocation(); + if (v.startsWith("@")) { + parseImportedConfigFile(v.substring(1)); + } else if (v.equals("-argfile")) { + parseConfigFileHelper(makeFile(removeArg(args).getValue())); + } else if (isSourceFileName(v)) { + addFileOrPattern(makeFile(v)); + } else { + parseOption(arg.getValue(), args); + } + } + + protected void parseImportedConfigFile(String relativeFilePath) { + parseConfigFileHelper(makeFile(relativeFilePath)); + } + + public File makeFile(String name) { + return makeFile(getCurrentDir(), name); + } + + File makeFile(File dir, String name) { + name = name.replace('/', File.separatorChar); + File ret = new File(name); + if (dir == null || ret.isAbsolute()) return ret; + return new File(dir, name); + } + + + protected static class Arg { + private Location location; + private String value; + public Arg(String value, Location location) { + this.value = value; + this.location = location; + } + + public void setValue(String value) { + this.value = value; + } + + public void setLocation(Location location) { + this.location = location; + } + + public String getValue() { return value; } + public Location getLocation() { return location; } + } + + static abstract class Location { + public abstract File getFile(); + public abstract File getDirectory(); + public abstract int getLine(); + public abstract String toString(); + } + + static class SourceLocation extends Location { + private int line; + private File file; + public SourceLocation(File file, int line) { + this.line = line; + this.file = file; + } + + public File getFile() { return file; } + public File getDirectory() { return file.getParentFile(); } + public int getLine() { return line; } + + public String toString() { + return file.getPath()+":"+line; + } + } + + static class CommandLineLocation extends Location { + public File getFile() { + return new File(System.getProperty("user.dir")); + } + + public File getDirectory() { + return new File(System.getProperty("user.dir")); + } + public int getLine() { return -1; } + public String toString() { + return "command-line"; + } + } + + public static class ParseException extends RuntimeException { + private Location location; + + public ParseException(String message, Location location) { + super(message); + this.location = location; + } + + public int getLine() { + if (location == null) return -1; + return location.getLine(); + } + public File getFile() { + if (location == null) return null; + return location.getFile(); + } + } +} diff --git a/util/src/org/aspectj/util/FileUtil.java b/util/src/org/aspectj/util/FileUtil.java new file mode 100644 index 000000000..a0d445cfe --- /dev/null +++ b/util/src/org/aspectj/util/FileUtil.java @@ -0,0 +1,1048 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.zip.*; +import java.util.zip.ZipFile; + + +/** + * + */ +public class FileUtil { + /** unmodifiable List of String source file suffixes (including leading ".") */ + public static final List SOURCE_SUFFIXES + = Collections.unmodifiableList(Arrays.asList(new String[] { ".java", ".aj"})); + + final static int[] INT_RA = new int[0]; + + /** accept all files */ + public static final FileFilter ALL = new FileFilter() { + public boolean accept(File f) { return true; } + }; + + /** @return true if file path has a zip/jar suffix */ + public static boolean hasZipSuffix(File file) { + return ((null != file) && hasZipSuffix(file.getPath())); + } + + /** @return true if path ends with .zip or .jar */ + public static boolean hasZipSuffix(String path) { + return ((null != path) && (0 != zipSuffixLength(path))); + } + + /** @return 0 if file has no zip/jar suffix or 4 otherwise */ + public static int zipSuffixLength(File file) { + return (null == file ? 0 : zipSuffixLength(file.getPath())); + } + + /** @return 0 if no zip/jar suffix or 4 otherwise */ + public static int zipSuffixLength(String path) { + return (null == path ? 0 + : path.endsWith(".zip") ? 4 + : path.endsWith(".jar") ? 4 : 0); + } + + /** @return true if file path has a source suffix */ + public static boolean hasSourceSuffix(File file) { + return ((null != file) && hasSourceSuffix(file.getPath())); + } + + /** @return true if path ends with .java or .aj */ + public static boolean hasSourceSuffix(String path) { + return ((null != path) && (0 != sourceSuffixLength(path))); + } + + /** @return 0 if file has no source suffix or the length of the suffix otherwise */ + public static int sourceSuffixLength(File file) { + return (null == file ? 0 : sourceSuffixLength(file.getPath())); + } + + /** @return 0 if no source suffix or the length of the suffix otherwise */ + public static int sourceSuffixLength(String path) { + if (LangUtil.isEmpty(path)) { + return 0; + } + + for (Iterator iter = SOURCE_SUFFIXES.iterator(); iter.hasNext();) { + String suffix = (String) iter.next(); + if (path.endsWith(suffix) + || path.toLowerCase().endsWith(suffix)) { + return suffix.length(); + } + } + return 0; + } + + /** @return true if this is a readable directory */ + public static boolean canReadDir(File dir) { + return ((null != dir) && dir.canRead() && dir.isDirectory()); + } + + /** @return true if this is a readable file */ + public static boolean canReadFile(File file) { + return ((null != file) && file.canRead() && file.isFile()); + } + + /** @return true if dir is a writable directory */ + public static boolean canWriteDir(File dir) { + return ((null != dir) && dir.canWrite() && dir.isDirectory()); + } + + /** @return true if this is a writable file */ + public static boolean canWriteFile(File file) { + return ((null != file) && file.canWrite() && file.isFile()); + } + + /** @throws IllegalArgumentException unless file is readable and not a directory */ + public static void throwIaxUnlessCanReadFile(File file, String label) { + if (!canReadFile(file)) { + throw new IllegalArgumentException(label + " not readable file: " + file); + } + } + + /** @throws IllegalArgumentException unless dir is a readable directory */ + public static void throwIaxUnlessCanReadDir(File dir, String label) { + if (!canReadDir(dir)) { + throw new IllegalArgumentException(label + " not readable dir: " + dir); + } + } + + /** @throws IllegalArgumentException unless file is readable and not a directory */ + public static void throwIaxUnlessCanWriteFile(File file, String label) { + if (!canWriteFile(file)) { + throw new IllegalArgumentException(label + " not writable file: " + file); + } + } + + /** @throws IllegalArgumentException unless dir is a readable directory */ + public static void throwIaxUnlessCanWriteDir(File dir, String label) { + if (!canWriteDir(dir)) { + throw new IllegalArgumentException(label + " not writable dir: " + dir); + } + } + + /** @return array same length as input, with String paths */ + public static String[] getPaths(File[] files) { + if ((null == files) || (0 == files.length)) { + return new String[0]; + } + String[] result = new String[files.length]; + for (int i = 0; i < result.length; i++) { + if (null != files[i]) { + result[i] = files[i].getPath(); + } + } + return result; + } + + /** @return array same length as input, with String paths */ + public static String[] getPaths(List files) { + final int size = (null == files ? 0 : files.size()); + if (0 == size) { + return new String[0]; + } + String[] result = new String[size]; + for (int i = 0; i < size; i++) { + File file = (File) files.get(i); + if (null != file) { + result[i] = file.getPath(); + } + } + return result; + } + + + /** + * Extract the name of a class from the path to its file. + * If the basedir is null, then the class is assumed to be in + * the default package unless the classFile has one of the + * top-level suffixes { com, org, java, javax } as a parent directory. + * @param basedir the File of the base directory (prefix of classFile) + * @param classFile the File of the class to extract the name for + * @throws IllegalArgumentException if classFile is null or does not end with + * ".class" or a non-null basedir is not a prefix of classFile + */ + public static String fileToClassName(File basedir, File classFile) { + LangUtil.throwIaxIfNull(classFile, "classFile"); + String classFilePath = normalizedPath(classFile); + if (!classFilePath.endsWith(".class")) { + String m = classFile + " does not end with .class"; + throw new IllegalArgumentException(m); + } + classFilePath = classFilePath.substring(0, classFilePath.length()-6); + if (null != basedir) { + String basePath = normalizedPath(basedir); + if (!classFilePath.startsWith(basePath)) { + String m = classFile + " does not start with " + basedir; + throw new IllegalArgumentException(m); + } + classFilePath = classFilePath.substring(basePath.length()+1); + } else { + final String[] suffixes = new String[] { "com", "org", "java", "javax"}; + boolean found = false; + for (int i = 0; !found && (i < suffixes.length); i++) { + int loc = classFilePath.indexOf(suffixes[i] + "/"); + if ((0 == loc) + || ((-1 != loc) && ('/' == classFilePath.charAt(loc-1)))) { + classFilePath = classFilePath.substring(loc); + found = true; + } + } + if (!found) { + int loc = classFilePath.lastIndexOf("/"); + if (-1 != loc) { // treat as default package + classFilePath = classFilePath.substring(loc+1); + } + } + } + return classFilePath.replace('/', '.'); + } + + /** + * Normalize path for comparisons by rendering absolute, + * clipping basedir prefix, + * trimming and changing '\\' to '/' + * @param file the File with the path to normalize + * @param basedir the File for the prefix of the file to normalize - ignored if null + * @return "" if null or normalized path otherwise + * @throws IllegalArgumentException if basedir is not a prefix of file + */ + public static String normalizedPath(File file, File basedir) { + String filePath = normalizedPath(file); + if (null != basedir) { + String basePath = normalizedPath(basedir); + if (filePath.startsWith(basePath)) { + filePath = filePath.substring(basePath.length()); + if (filePath.startsWith("/")) { + filePath = filePath.substring(1); + } + } + } + return filePath; + } + + /** + * Flatten File[] to String. + * @param files the File[] of paths to flatten - null ignored + * @param infix the String infix to use - null treated as File.pathSeparator + */ + public static String flatten(File[] files, String infix) { + if (LangUtil.isEmpty(files)) { + return ""; + } + return flatten(getPaths(files), infix); + } + + /** + * Flatten File[] to String. + * @param files the File[] of paths to flatten - null ignored + * @param infix the String infix to use - null treated as File.pathSeparator + */ + public static String flatten(String[] paths, String infix) { + if (null == infix) { + infix = File.pathSeparator; + } + StringBuffer result = new StringBuffer(); + boolean first = true; + for (int i = 0; i < paths.length; i++) { + String path = paths[i]; + if (null == path) { + continue; + } + if (first) { + first = false; + } else { + result.append(infix); + } + result.append(path); + } + return result.toString(); + } + + /** + * Normalize path for comparisons by rendering absolute + * trimming and changing '\\' to '/' + * @return "" if null or normalized path otherwise + */ + public static String normalizedPath(File file) { + return (null == file ? "" : weakNormalize(file.getAbsolutePath())); + } + + /** + * Weakly normalize path for comparisons by + * trimming and changing '\\' to '/' + */ + public static String weakNormalize(String path) { + if (null != path) { + path = path.replace('\\', '/').trim(); + } + return path; + } + + /** @return array same length as input, with String absolute paths */ + public static String[] getAbsolutePaths(File[] files) { + if ((null == files) || (0 == files.length)) { + return new String[0]; + } + String[] result = new String[files.length]; + for (int i = 0; i < result.length; i++) { + if (null != files[i]) { + result[i] = files[i].getAbsolutePath(); + } + } + return result; + } + + /** + * Recursively delete the contents of dir, but not the dir itself + * @return the total number of files deleted + */ + public static int deleteContents(File dir) { + return deleteContents(dir, ALL); + } + + /** + * Recursively delete some contents of dir, but not the dir itself. + * This deletes any subdirectory which is empty after its files + * are deleted. + * @return the total number of files deleted + */ + public static int deleteContents(File dir, FileFilter filter) { + return deleteContents(dir, filter, true); + } + + /** + * Recursively delete some contents of dir, but not the dir itself. + * If deleteEmptyDirs is true, this deletes any subdirectory + * which is empty after its files are deleted. + * @param dir the File directory (if a file, the the file is deleted) + * @return the total number of files deleted + */ + public static int deleteContents(File dir, FileFilter filter, + boolean deleteEmptyDirs) { + if (null == dir) { + throw new IllegalArgumentException("null dir"); + } + if ((!dir.exists()) || (!dir.canWrite())) { + return 0; + } + if (!dir.isDirectory()) { + dir.delete(); + return 1; + } + String[] fromFiles = dir.list(); + int result = 0; + for (int i = 0; i < fromFiles.length; i++) { + String string = fromFiles[i]; + File file = new File(dir, string); + if ((null == filter) || filter.accept(file)) { + if (file.isDirectory()) { + result += deleteContents(file, filter, deleteEmptyDirs); + if (deleteEmptyDirs && (0 == file.list().length)) { + file.delete(); + } + } else { + file.delete(); + result++; + } + } + } + return result; + } + + /** + * Copy contents of fromDir into toDir + * @param fromDir must exist and be readable + * @param toDir must exist or be creatable and be writable + * @return the total number of files copied + */ + public static int copyDir(File fromDir, File toDir) throws IOException { + return copyDir(fromDir, toDir, null, null); + } + + /** + * Recursively copy files in fromDir (with any fromSuffix) to toDir, + * replacing fromSuffix with toSuffix if any. + * This silently ignores dirs and files that are not readable + * but throw IOException for directories that are not writable. + * This does not clean out the original contents of toDir. + * (subdirectories are not renamed per directory rules) + * @param fromSuffix select files with this suffix - select all if null or empty + * @param toSuffix replace fromSuffix with toSuffix in the destination file + * name - ignored if null or empty, + * appended to name if fromSuffix is null or empty + * @return the total number of files copied + */ + public static int copyDir(File fromDir, File toDir, + final String fromSuffix, String toSuffix) throws IOException { + return copyDir(fromDir, toDir, fromSuffix, toSuffix, (FileFilter) null); + } + + /** map name to result, removing any fromSuffix and adding any toSuffix */ + private static String map(String name, String fromSuffix, String toSuffix) { + if (null != name) { + if (null != fromSuffix) { + name = name.substring(0, name.length()-fromSuffix.length()); + } + if (null != toSuffix) { + name = name + toSuffix; + } + } + return name; + } + + /** + * Recursively copy files in fromDir (with any fromSuffix) to toDir, + * replacing fromSuffix with toSuffix if any, + * and adding the destination file to any collector. + * This silently ignores dirs and files that are not readable + * but throw IOException for directories that are not writable. + * This does not clean out the original contents of toDir. + * (subdirectories are not renamed per directory rules) + * This calls any delegate FilenameFilter to collect any selected file. + * @param fromSuffix select files with this suffix - select all if null or empty + * @param toSuffix replace fromSuffix with toSuffix in the destination file + * name - ignored if null or empty, + * appended to name if fromSuffix is null or empty + * @param collector the List sink for destination files - ignored if null + * @return the total number of files copied + */ + public static int copyDir(File fromDir, File toDir, final String fromSuffix, + final String toSuffix, final List collector) throws IOException { + //int before = collector.size(); + if (null == collector) { + return copyDir(fromDir, toDir, fromSuffix, toSuffix); + } else { + FileFilter collect = new FileFilter() { + public boolean accept(File pathname) { + return collector.add(pathname); + } + }; + return copyDir(fromDir, toDir, fromSuffix, toSuffix, collect); + } + } + + /** + * Recursively copy files in fromDir (with any fromSuffix) to toDir, + * replacing fromSuffix with toSuffix if any. + * This silently ignores dirs and files that are not readable + * but throw IOException for directories that are not writable. + * This does not clean out the original contents of toDir. + * (subdirectories are not renamed per directory rules) + * This calls any delegate FilenameFilter to collect any selected file. + * @param fromSuffix select files with this suffix - select all if null or empty + * @param toSuffix replace fromSuffix with toSuffix in the destination file + * name - ignored if null or empty, + * appended to name if fromSuffix is null or empty + * @return the total number of files copied + */ + public static int copyDir(File fromDir, File toDir, final String fromSuffix, + final String toSuffix, final FileFilter delegate) throws IOException { + + if ((null == fromDir) || (!fromDir.canRead())) { + return 0; + } + final boolean haveSuffix = ((null != fromSuffix) && (0 < fromSuffix.length())); + final int slen = (!haveSuffix ? 0 : fromSuffix.length()); + + if (!toDir.exists()) { + toDir.mkdirs(); + } + final String[] fromFiles; + if (!haveSuffix) { + fromFiles = fromDir.list(); + } else { + FilenameFilter filter = new FilenameFilter() { + public boolean accept(File dir, String name) { + return (new File(dir, name).isDirectory() + || (name.endsWith(fromSuffix))); + } + }; + fromFiles = fromDir.list(filter); + } + int result = 0; + final int MAX = (null == fromFiles ? 0 : fromFiles.length); + for (int i = 0; i < MAX; i++) { + String filename = fromFiles[i]; + File fromFile = new File(fromDir, filename); + if (fromFile.canRead()) { + if (fromFile.isDirectory()) { + result += copyDir(fromFile, new File(toDir, filename), fromSuffix, toSuffix, delegate); + } else if (fromFile.isFile()) { + if (haveSuffix) { + filename = filename.substring(0, filename.length()-slen); + } + if (null != toSuffix) { + filename = filename + toSuffix; + } + File targetFile = new File(toDir, filename); + if ((null == delegate) || delegate.accept(targetFile)) { + copyFile(fromFile, targetFile); + } + result++; + } + } + } + return result; + } + + /** + * Recursively list files in srcDir. + * @return ArrayList with String paths of File under srcDir (relative to srcDir) + */ + public static String[] listFiles(File srcDir) { + ArrayList result = new ArrayList(); + if ((null != srcDir) && srcDir.canRead()) { + listFiles(srcDir, null, result); + } + return (String[]) result.toArray(new String[0]); + } + + private static void listFiles(final File baseDir, String dir, ArrayList result) { + final String dirPrefix = (null == dir ? "" : dir + "/"); + final File dirFile = (null == dir ? baseDir : new File(baseDir.getPath() + "/" + dir)); + final String[] files = dirFile.list(); + for (int i = 0; i < files.length; i++) { + File f = new File(dirFile, files[i]); + String path = dirPrefix + files[i]; + if (f.isDirectory()) { + listFiles(baseDir, path, result); + } else { + result.add(path); + } + } + } + + public static final FileFilter aspectjSourceFileFilter = new FileFilter() { + public boolean accept(File pathname) { + String name = pathname.getName().toLowerCase(); + return name.endsWith(".java") || name.endsWith(".aj"); + } + }; + + + /** + * Recursively list files in srcDir. + * @return ArrayList with String paths of File under srcDir (relative to srcDir) + */ + public static File[] listFiles(File srcDir, FileFilter fileFilter) { + ArrayList result = new ArrayList(); + if ((null != srcDir) && srcDir.canRead()) { + listFiles(srcDir, result, fileFilter); + } + return (File[]) result.toArray(new File[result.size()]); + } + + private static void listFiles(final File baseDir, ArrayList result, FileFilter filter) { + File[] files = baseDir.listFiles(); + for (int i = 0; i < files.length; i++) { + File f = files[i]; + if (f.isDirectory()) { + listFiles(f, result, filter); + } else { + if (filter.accept(f)) result.add(f); + } + } + } + + /** + * Convert String[] paths to File[] as offset of base directory + * @param basedir the non-null File base directory for File to create with paths + * @param paths the String[] of paths to create + * @return File[] with same length as paths + */ + public static File[] getBaseDirFiles( + File basedir, + String[] paths) { + return getBaseDirFiles(basedir, paths, (String[]) null); + } + + /** + * Convert String[] paths to File[] as offset of base directory + * @param basedir the non-null File base directory for File to create with paths + * @param paths the String[] of paths to create + * @param suffixes the String[] of suffixes to limit sources to - ignored if null + * @return File[] with same length as paths + */ + public static File[] getBaseDirFiles( + File basedir, + String[] paths, + String[] suffixes) { + LangUtil.throwIaxIfNull(basedir, "basedir"); + LangUtil.throwIaxIfNull(paths, "paths"); + File[] result = null; + if (!LangUtil.isEmpty(suffixes)) { + ArrayList list = new ArrayList(); + for (int i = 0; i < paths.length; i++) { + boolean listed = false; + String path = paths[i]; + for (int j = 0; !listed && (j < suffixes.length); j++) { + String suffix = suffixes[j]; + if (listed = path.endsWith(suffix)) { + list.add(new File(basedir, paths[i])); + } + } + } + result = (File[]) list.toArray(new File[0]); + } else { + result = new File[paths.length]; + for (int i = 0; i < result.length; i++) { + result[i] = new File(basedir, paths[i]); + } + } + return result; + } + + /** + * Copy files from source dir into destination directory, + * creating any needed directories. This differs from copyDir in not + * being recursive; each input with the source dir creates a full path. + * @param srcDir an existing, readable directory containing relativePaths files + * @param relativePaths a set of paths relative to srcDir to readable File to copy + * @param destDir an existing, writable directory to copy files to + * @throws IllegalArgumentException if input invalid, IOException if operations fail + */ + public static File[] copyFiles(File srcDir, String[] relativePaths, File destDir) + throws IllegalArgumentException, IOException { + final String[] paths = relativePaths; + throwIaxUnlessCanReadDir(srcDir, "srcDir"); + throwIaxUnlessCanWriteDir(destDir, "destDir"); + LangUtil.throwIaxIfNull(paths, "relativePaths"); + File[] result = new File[paths.length]; + for (int i = 0; i < paths.length; i++) { + String path = paths[i]; + LangUtil.throwIaxIfNull(path, "relativePaths-entry"); + File src = new File(srcDir, relativePaths[i]); + throwIaxUnlessCanReadFile(src, "src-entry"); + File dest = new File(destDir, path); + File destParent = dest.getParentFile(); + if (!destParent.exists()) { + destParent.mkdirs(); + } + LangUtil.throwIaxIfFalse(canWriteDir(destParent), "dest-entry-parent"); + copyFile(src, dest); + result[i] = dest; + } + return result; + } + + /** copy fromFile to toFile */ + public static void copyFile(File fromFile, File toFile) throws IOException { + FileInputStream in = null; + FileOutputStream out = null; + try { + in = new FileInputStream(fromFile); + out = new FileOutputStream(toFile); + copyStream(in, out); + } finally { + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + } + } + + /** do line-based copying */ + public static void copyStream(DataInputStream in, PrintStream out) throws IOException { + LangUtil.throwIaxIfNull(in, "in"); + LangUtil.throwIaxIfNull(in, "out"); + String s; + while (null != (s = in.readLine())) { + out.println(s); + } + } + + public static void copyStream(InputStream in, OutputStream out) throws IOException { + final int MAX = 4096; + byte[] buf = new byte[MAX]; + for (int bytesRead = in.read(buf, 0, MAX); + bytesRead != -1; + bytesRead = in.read(buf, 0, MAX)) { + out.write(buf, 0, bytesRead); + } + } + + public static void copyStream(Reader in, Writer out) throws IOException { + final int MAX = 4096; + char[] buf = new char[MAX]; + for (int bytesRead = in.read(buf, 0, MAX); + bytesRead != -1; + bytesRead = in.read(buf, 0, MAX)) { + out.write(buf, 0, bytesRead); + } + } + + private static boolean isValidFileName(String input) { + return ((null != input) && (-1 == input.indexOf(File.pathSeparator))); + } + + /** + * Make a new child directory of parent + * @param parent a File for the parent (writable) + * @param child a prefix for the child directory + * @return a File dir that exists with parentDir as the parent file or null + */ + public static File makeNewChildDir(File parent, String child) { + if (null == parent || ! parent.canWrite() || !parent.isDirectory()) { + throw new IllegalArgumentException("bad parent: " + parent); + } else if (null == child) { + child = "makeNewChildDir"; + } else if (!isValidFileName(child)) { + throw new IllegalArgumentException("bad child: " + child); + } + File result = new File(parent, child); + int safety = 1000; + for (String suffix = FileUtil.randomFileString(); + ((0 < --safety) && result.exists()); + suffix = FileUtil.randomFileString()) { + result = new File(parent, child+suffix); + } + if ((null == result) || result.exists()) { + System.err.println("exhausted files for child dir in " + parent); + return null; + } + return ((result.mkdirs() && result.exists()) ? result : null); + } + + /** + * Make a new temporary directory in the same directory + * that the system uses for temporary files, or if + * that files, in the current directory. + * @param name the preferred (simple) name of the directory - may be null. + * @return File of an existing new temp dir, or null if unable to create + */ + public static File getTempDir(String name) { + if (null == name) { + name = "FileUtil_getTempDir"; + } else if (!isValidFileName(name)) { + throw new IllegalArgumentException(" invalid: " + name); + } + File result = null; + File tempFile = null; + try { + tempFile = File.createTempFile("ignoreMe", ".txt"); + File tempParent = tempFile.getParentFile(); + result = makeNewChildDir(tempParent, name); + } catch (IOException t) { + result = makeNewChildDir(new File("."), name); + } finally { + if (null != tempFile) { + tempFile.delete(); + } + } + return result; + } + + public static URL[] getFileURLs(File[] files) { // XXX prints errors to System.err + if ((null == files) || (0 == files.length)) { + return new URL[0]; + } + URL[] result = new URL[files.length]; // XXX dangerous non-copy... + for (int i = 0; i < result.length; i++) { + result[i] = getFileURL(files[i]); + } + return result; + } + + /** + * Get URL for a File. + * This appends "/" for directories. + * prints errors to System.err + * @param file the File to convert to URL (not null) + */ + public static URL getFileURL(File file) { + LangUtil.throwIaxIfNull(file, "file"); + URL result = null; + try { + String url = "file:" + file.getAbsolutePath().replace('\\', '/'); + result = new URL(url + (file.isDirectory() ? "/" : "")); + } catch (MalformedURLException e) { + String m = "Util.makeURL(\"" + file.getPath() + "\" MUE " + e.getMessage(); + System.err.println(m); + } + return result; + } + + + + /** + * Write contents to file, returning null on success or error message otherwise. + * This tries to make any necessary parent directories first. + */ + public static String writeAsString(File file, String contents) { + LangUtil.throwIaxIfNull(file, "file"); + if (null == contents) { + contents = ""; + } + Writer out = null; + try { + File parentDir = file.getParentFile(); + if (!parentDir.exists() && !parentDir.mkdirs()) { + return "unable to make parent dir for " + file; + } + Reader in = new StringReader(contents); + out = new FileWriter(file); + FileUtil.copyStream(in, out); + return null; + } catch (IOException e) { + return LangUtil.unqualifiedClassName(e) + " writing " + file + + ": " + e.getMessage(); + } finally { + if (null != out) { + try { out.close(); } + catch (IOException e) {} // ignored + } + } + } + + + /** + * Reads an int array with our encoding + */ + public static int[] readIntArray(DataInputStream s) throws IOException { + int len = s.readInt(); + int[] ret = new int[len]; + for (int i=0; i < len; i++) ret[i] = s.readInt(); + return ret; + } + + + /** + * Reads an int array with our encoding + */ + public static void writeIntArray(DataOutputStream s, int[] a) throws IOException { + int len = a.length; + s.writeInt(len); + for (int i=0; i < len; i++) s.writeInt(a[i]); + } + + + + + /** + * Returns the contents of this file as a String + */ + public static String readAsString(File file) throws IOException { + BufferedReader r = new BufferedReader(new FileReader(file)); + StringBuffer b = new StringBuffer(); + while (true) { + int ch = r.read(); + if (ch == -1) break; + b.append((char)ch); + } + r.close(); + return b.toString(); + } + + /** + * Returns the contents of this stream as a String + */ + public static String readAsString(InputStream in) throws IOException { + BufferedReader r = new BufferedReader(new InputStreamReader(in)); + StringBuffer b = new StringBuffer(); + while (true) { + int ch = r.read(); + if (ch == -1) break; + b.append((char)ch); + } + in.close(); + r.close(); + return b.toString(); + } + + + /** + * Returns the contents of this file as a byte[] + */ + public static byte[] readAsByteArray(File file) throws IOException { + FileInputStream in = new FileInputStream(file); + byte[] ret = FileUtil.readAsByteArray(in); + in.close(); + return ret; + } + + + /** + * Reads this input stream and returns contents as a byte[] + */ + public static byte[] readAsByteArray(InputStream inStream) throws IOException { + int size = 1024; + byte[] ba = new byte[size]; + int readSoFar = 0; + + while (true) { + int nRead = inStream.read(ba, readSoFar, size-readSoFar); + if (nRead == -1) break; + readSoFar += nRead; + if (readSoFar == size) { + int newSize = size * 2; + byte[] newBa = new byte[newSize]; + System.arraycopy(ba, 0, newBa, 0, size); + ba = newBa; + size = newSize; + } + } + + byte[] newBa = new byte[readSoFar]; + System.arraycopy(ba, 0, newBa, 0, readSoFar); + return newBa; + } + final static String FILECHARS = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + /** @return String usable in a File name which is random */ + + /** @return semi-random String of length 6 usable as filename suffix */ + static String randomFileString() { + final double FILECHARS_length = FILECHARS.length(); + final int LEN = 6; + final char[] result = new char[LEN]; + int index = (int) (Math.random() * 6d); + for (int i = 0; i < LEN; i++) { + if (index >= LEN) { + index = 0; + } + result[index++] = FILECHARS.charAt((int) (Math.random() * FILECHARS_length)); + } + return new String(result); + } + + public static InputStream getStreamFromZip(String zipFile, String name) { + try { + ZipFile zf = new ZipFile(zipFile); + try { + ZipEntry entry = zf.getEntry(name); + return zf.getInputStream(entry); + } finally { + //??? is it safe not to close this zf.close(); + } + } catch (IOException ioe) { + return null; + } + } + + + public static void extractJar(String zipFile, String outDir) throws IOException { + ZipInputStream zs = new ZipInputStream(new FileInputStream(zipFile)); + ZipEntry entry; + while ( (entry = zs.getNextEntry()) != null) { + if (entry.isDirectory()) continue; + byte[] in = readAsByteArray(zs); + + File outFile = new File(outDir + "/" + entry.getName()); + //if (!outFile.getParentFile().exists()) + //System.err.println("parent: " + outFile.getParentFile()); + //System.err.println("parent: " + outFile.getParentFile()); + outFile.getParentFile().mkdirs(); + FileOutputStream os = new FileOutputStream(outFile); + os.write(in); + os.close(); + zs.closeEntry(); + } + zs.close(); + } + + private FileUtil() { throw new Error("utility class"); } + + + + /** + * Do line-based search for literal text in source files, + * returning file:line where found. + * @param sought the String text to seek in the file + * @param sources the List of String paths to the source files + * @param listAll if false, only list first match in file + * @param errorSink the PrintStream to print any errors to (one per line) + * (use null to silently ignore errors) + * @return List of String of the form file:line for each found entry + * (never null, might be empty) + */ + public static List lineSeek(String sought, List sources, boolean listAll, + PrintStream errorSink) { + if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sources)) { + return Collections.EMPTY_LIST; + } + ArrayList result = new ArrayList(); + for (Iterator iter = sources.iterator(); iter.hasNext();) { + String path = (String) iter.next(); + String error = lineSeek(sought, path, listAll, result); + if ((null != error) && (null != errorSink)) { + errorSink.println(error); + } + } + return result; + } + + /** + * Do line-based search for literal text in source file, + * returning line where found as a String + * in the form {sourcePath}:line:column submitted to the + * collecting parameter sink. + * Any error is rendered to String and returned as the result. + * + * @param sought the String text to seek in the file + * @param sources the List of String paths to the source files + * @param listAll if false, only list first match in file + * @param List sink the List for String entries of the form {sourcePath}:line:column + * @return String error if any, or add String entries to sink + */ + public static String lineSeek(String sought, String sourcePath, boolean listAll, + ArrayList sink) { + if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sourcePath)) { + return "nothing sought"; + } + if (LangUtil.isEmpty(sourcePath)) { + return "no sourcePath"; + } + final File file = new File(sourcePath); + if (!file.canRead() || !file.isFile()) { + return "sourcePath not a readable file"; + } + int lineNum = 0; + FileReader fin = null; + try { + fin = new FileReader(file); + BufferedReader reader = new BufferedReader(fin); + String line; + while (null != (line = reader.readLine())) { + lineNum++; + int loc = line.indexOf(sought); + if (-1 != loc) { + sink.add(sourcePath + ":" + lineNum + ":" + loc); + if (!listAll) { + break; + } + } + } + } catch (IOException e) { + return LangUtil.unqualifiedClassName(e) + " reading " + sourcePath + + ":" + lineNum; + } finally { + try { if (null != fin) fin.close(); } + catch (IOException e) {} // ignore + } + return null; + } + + public static BufferedOutputStream makeOutputStream(File file) throws FileNotFoundException { + File parent = file.getParentFile(); + if (parent != null) parent.mkdirs(); + return new BufferedOutputStream(new FileOutputStream(file)); + } + +} diff --git a/util/src/org/aspectj/util/FuzzyBoolean.java b/util/src/org/aspectj/util/FuzzyBoolean.java new file mode 100644 index 000000000..adb66bb41 --- /dev/null +++ b/util/src/org/aspectj/util/FuzzyBoolean.java @@ -0,0 +1,180 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + +import java.util.*; + + +/** This class implements boolean that include a "maybe" + */ + +public abstract class FuzzyBoolean { + public abstract boolean alwaysTrue(); + public abstract boolean alwaysFalse(); + public abstract boolean maybeTrue(); + public abstract boolean maybeFalse(); + + public abstract FuzzyBoolean and(FuzzyBoolean other); + public abstract FuzzyBoolean or(FuzzyBoolean other); + public abstract FuzzyBoolean not(); + + private static class YesFuzzyBoolean extends FuzzyBoolean { + public boolean alwaysFalse() { + return false; + } + + public boolean alwaysTrue() { + return true; + } + + + public boolean maybeFalse() { + return false; + } + + public boolean maybeTrue() { + return true; + } + + public FuzzyBoolean and(FuzzyBoolean other) { + return other; + } + + public FuzzyBoolean not() { + return FuzzyBoolean.NO; + } + + public FuzzyBoolean or(FuzzyBoolean other) { + return this; + } + + public String toString() { + return "YES"; + } + } + private static class NoFuzzyBoolean extends FuzzyBoolean { + public boolean alwaysFalse() { + return true; + } + + public boolean alwaysTrue() { + return false; + } + + + public boolean maybeFalse() { + return true; + } + + public boolean maybeTrue() { + return false; + } + + public FuzzyBoolean and(FuzzyBoolean other) { + return this; + } + + public FuzzyBoolean not() { + return FuzzyBoolean.YES; + } + + public FuzzyBoolean or(FuzzyBoolean other) { + return other; + } + + public String toString() { + return "NO"; + } + } + private static class NeverFuzzyBoolean extends FuzzyBoolean { + public boolean alwaysFalse() { + return true; + } + + public boolean alwaysTrue() { + return false; + } + + + public boolean maybeFalse() { + return true; + } + + public boolean maybeTrue() { + return false; + } + + public FuzzyBoolean and(FuzzyBoolean other) { + return this; + } + + public FuzzyBoolean not() { + return this; + } + + public FuzzyBoolean or(FuzzyBoolean other) { + return this; + } + + public String toString() { + return "NEVER"; + } + } + + private static class MaybeFuzzyBoolean extends FuzzyBoolean { + public boolean alwaysFalse() { + return false; + } + + public boolean alwaysTrue() { + return false; + } + + + public boolean maybeFalse() { + return true; + } + + public boolean maybeTrue() { + return true; + } + + public FuzzyBoolean and(FuzzyBoolean other) { + return other.alwaysFalse() ? other : this; + } + + public FuzzyBoolean not() { + return this; + } + + public FuzzyBoolean or(FuzzyBoolean other) { + return other.alwaysTrue() ? other : this; + } + + public String toString() { + return "MAYBE"; + } + } + + public static final FuzzyBoolean YES = new YesFuzzyBoolean(); + public static final FuzzyBoolean NO = new NoFuzzyBoolean(); + public static final FuzzyBoolean MAYBE = new MaybeFuzzyBoolean(); + public static final FuzzyBoolean NEVER = new NeverFuzzyBoolean(); + + public static final FuzzyBoolean fromBoolean(boolean b) { + return b ? YES : NO; + } + +} diff --git a/util/src/org/aspectj/util/LangUtil.java b/util/src/org/aspectj/util/LangUtil.java new file mode 100644 index 000000000..0a93721f1 --- /dev/null +++ b/util/src/org/aspectj/util/LangUtil.java @@ -0,0 +1,781 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * + */ +public class LangUtil { + /** map from String version to String class implemented in that version or later */ + private static final Map VM_CLASSES; + + public static final String EOL; + static { + StringWriter buf = new StringWriter(); + PrintWriter writer = new PrintWriter(buf); + writer.println(""); + String eol = "\n"; + try { + buf.close(); + StringBuffer sb = buf.getBuffer(); + if ((null != sb) || (0 < sb.length())) { + eol = buf.toString(); + } + } catch (Throwable t) { } + EOL = eol; + + HashMap map = new HashMap(); + map.put("1.2", "java.lang.ref.Reference"); + map.put("1.3", "java.lang.reflect.Proxy"); + map.put("1.4", "java.nio.Buffer"); + + VM_CLASSES = Collections.unmodifiableMap(map); + } + + /** + * Detect whether Java version is supported. + * @param version String "1.2" or "1.3" or "1.4" + * @return true if the currently-running VM supports the version + * @throws IllegalArgumentException if version is not known + */ + public static final boolean supportsJava(String version) { + LangUtil.throwIaxIfNull(version, "version"); + String className = (String) VM_CLASSES.get(version); + if (null == className) { + throw new IllegalArgumentException("unknown version: " + version); + } + try { + Class.forName(className); + return true; + } catch (Throwable t) { + return false; + } + } + + /** + * Shorthand for "if null, throw IllegalArgumentException" + * @throws IllegalArgumentException "null {name}" if o is null + */ + public static final void throwIaxIfNull(final Object o, final String name) { + if (null == o) { + String message = "null " + (null == name ? "input" : name); + throw new IllegalArgumentException(message); + } + } + + /** + * Shorthand for "if not null or not assignable, throw IllegalArgumentException" + * @throws IllegalArgumentException "null {name}" if o is null + */ + public static final void throwIaxIfNotAssignable(final Object o, final Class c, final String name) { + throwIaxIfNull(o, name); + if (null != c) { + Class actualClass = o.getClass(); + if (!c.isAssignableFrom(actualClass)) { + String message = name + " not assignable to " + c.getName(); + throw new IllegalArgumentException(message); + } + } + } + + /** + * Shorthand for "if any not null or not assignable, throw IllegalArgumentException" + * @throws IllegalArgumentException "{name} is not assignable to {c}" + */ + public static final void throwIaxIfNotAllAssignable(final Collection collection, + final Class c, final String name) { + throwIaxIfNull(collection, name); + if (null != c) { + for (Iterator iter = collection.iterator(); iter.hasNext();) { + throwIaxIfNotAssignable(iter.next(), c, name); + + } + } + } + /** + * Shorthand for "if false, throw IllegalArgumentException" + * @throws IllegalArgumentException "{message}" if test is false + */ + public static final void throwIaxIfFalse(final boolean test, final String message) { + if (!test) { + throw new IllegalArgumentException(message); + } + } + + /** @return ((null == s) || (0 == s.trim().length())); */ + public static boolean isEmptyTrimmed(String s) { + return ((null == s) || (0 == s.length()) + || (0 == s.trim().length())); + } + + /** @return ((null == s) || (0 == s.length())); */ + public static boolean isEmpty(String s) { + return ((null == s) || (0 == s.length())); + } + + /** @return ((null == ra) || (0 == ra.length)) */ + public static boolean isEmpty(Object[] ra) { + return ((null == ra) || (0 == ra.length)); + } + + /** @return ((null == collection) || (0 == collection.size())) */ + public static boolean isEmpty(Collection collection) { + return ((null == collection) || (0 == collection.size())); + } + + /** + * Splits <code>text</code> at whitespace. + * + * @param text <code>String</code> to split. + */ + public static String[] split(String text) { + return (String[]) strings(text).toArray(new String[0]); + } + + /** + * Splits <code>input</code> at commas, + * trimming any white space. + * + * @param text <code>String</code> to split. + * @return List of String of elements. + */ + public static List commaSplit(String input) { + if (null == input) { + return Collections.EMPTY_LIST; + } + ArrayList result = new ArrayList(); + + if (-1 == input.indexOf(",")) { + result.add(input.trim()); + } else { + StringTokenizer st = new StringTokenizer(input, ","); + while (st.hasMoreTokens()) { + result.add(st.nextToken().trim()); + } + } + return result; + } + + + /** + * Splits strings into a <code>List</code> using a + * <code>StringTokenizer</code>. + * + * @param text <code>String</code> to split. + */ + public static List strings(String text) { + List strings = new ArrayList(); + StringTokenizer tok = new StringTokenizer(text); + while (tok.hasMoreTokens()) { + strings.add(tok.nextToken()); + } + return strings; + } + + /** @return a non-null unmodifiable List */ + public static List safeList(List list) { + return ( + null == list + ? Collections.EMPTY_LIST + : Collections.unmodifiableList(list)); + } + + /** + * Select from input String[] based on suffix-matching + * @param inputs String[] of input - null ignored + * @param suffixes String[] of suffix selectors - null ignored + * @param ignoreCase if true, ignore case + * @return String[] of input that end with any input + */ + public static String[] endsWith(String[] inputs, String[] suffixes, boolean ignoreCase) { + if (LangUtil.isEmpty(inputs) || LangUtil.isEmpty(suffixes)) { + return new String[0]; + } + if (ignoreCase) { + String[] temp = new String[suffixes.length]; + for (int i = 0; i < temp.length; i++) { + String suff = suffixes[i]; + temp[i] = (null == suff ? null : suff.toLowerCase()); + } + suffixes = temp; + } + ArrayList result = new ArrayList(); + for (int i = 0; i < inputs.length; i++) { + String input = inputs[i]; + if (null == input) { + continue; + } + if (!ignoreCase) { + input = input.toLowerCase(); + } + for (int j = 0; j < suffixes.length; j++) { + String suffix = suffixes[j]; + if (null == suffix) { + continue; + } + if (input.endsWith(suffix)) { + result.add(input); + break; + } + } + } + return (String[]) result.toArray(new String[0]); + } + + /** + * copy non-null two-dimensional String[][] + * @see extractOptions(String[], String[][]) + */ + public static String[][] copyStrings(String[][] in) { + String[][] out = new String[in.length][]; + for (int i = 0; i < out.length; i++) { + out[i] = new String[in[i].length]; + System.arraycopy(in[i], 0, out[i], 0, out[i].length); + } + return out; + } + + /** + * Extract options and arguments to input option list, returning remainder. + * The input options will be nullified if not found. e.g., + * <pre>String[] options = new String[][] { new String[] { "-verbose" }, + * new String[] { "-classpath", null } }; + * String[] args = extractOptions(args, options); + * boolean verbose = null != options[0][0]; + * boolean classpath = options[1][1];</pre> + * @param args the String[] input options + * @param options the String[][]options to find in the input args - not null + * for each String[] component the first subcomponent is the option itself, + * and there is one String subcomponent for each additional argument. + * @return String[] of args remaining after extracting options to extracted + */ + public static String[] extractOptions(String[] args, String[][] options) { + if (LangUtil.isEmpty(args) || LangUtil.isEmpty(options) ) { + return args; + } + BitSet foundSet = new BitSet(); + String[] result = new String[args.length]; + int resultIndex = 0; + for (int j = 0; j < args.length; j++) { + boolean found = false; + for (int i = 0; !found && (i < options.length); i++) { + String[] option = options[i]; + LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(option), "options"); + String sought = option[0]; + if (found = sought.equals(args[j])) { + foundSet.set(i); + int doMore = option.length-1; + if (0 < doMore) { + final int MAX = j + doMore; + if (MAX >= args.length) { + String s = "expecting " + doMore + " args after "; + throw new IllegalArgumentException(s + args[j]); + } + for (int k = 1; k < option.length; k++) { + option[k] = args[++j]; + } + } + } + } + if (!found) { + result[resultIndex++] = args[j]; + } + } + + // unset any not found + for (int i = 0; i < options.length; i++) { + if (!foundSet.get(i)) { + options[i][0] = null; + } + } + // fixup remainder + if (resultIndex < args.length) { + String[] temp = new String[resultIndex]; + System.arraycopy(result, 0, temp, 0, resultIndex); + args = temp; + } + + return args; + } + + /** + * Extract options and arguments to input parameter list, returning remainder. + * @param args the String[] input options + * @param validOptions the String[] options to find in the input args - not null + * @param optionArgs the int[] number of arguments for each option in validOptions + * (if null, then no arguments for any option) + * @param extracted the List for the matched options + * @return String[] of args remaining after extracting options to extracted + */ + public static String[] extractOptions(String[] args, String[] validOptions, + int[] optionArgs, List extracted) { + if (LangUtil.isEmpty(args) + || LangUtil.isEmpty(validOptions) ) { + return args; + } + if (null != optionArgs) { + if (optionArgs.length != validOptions.length) { + throw new IllegalArgumentException("args must match options"); + } + } + String[] result = new String[args.length]; + int resultIndex = 0; + for (int j = 0; j < args.length; j++) { + boolean found = false; + for (int i = 0; !found && (i < validOptions.length); i++) { + String sought = validOptions[i]; + int doMore = (null == optionArgs ? 0 : optionArgs[i]); + if (LangUtil.isEmpty(sought)) { + continue; + } + if (found = sought.equals(args[j])) { + if (null != extracted) { + extracted.add(sought); + } + if (0 < doMore) { + final int MAX = j + doMore; + if (MAX >= args.length) { + String s = "expecting " + doMore + " args after "; + throw new IllegalArgumentException(s + args[j]); + } + if (null != extracted) { + while (j < MAX) { + extracted.add(args[++j]); + } + } else { + j = MAX; + } + } + break; + } + } + if (!found) { + result[resultIndex++] = args[j]; + } + } + if (resultIndex < args.length) { + String[] temp = new String[resultIndex]; + System.arraycopy(result, 0, temp, 0, resultIndex); + args = temp; + } + return args; + } + + /** @return String[] of entries in validOptions found in args */ + public static String[] selectOptions(String[] args, String[] validOptions) { + if (LangUtil.isEmpty(args) || LangUtil.isEmpty(validOptions)) { + return new String[0]; + } + ArrayList result = new ArrayList(); + for (int i = 0; i < validOptions.length; i++) { + String sought = validOptions[i]; + if (LangUtil.isEmpty(sought)) { + continue; + } + for (int j = 0; j < args.length; j++) { + if (sought.equals(args[j])) { + result.add(sought); + break; + } + } + } + return (String[]) result.toArray(new String[0]); + } + + /** @return String[] of entries in validOptions found in args */ + public static String[] selectOptions(List args, String[] validOptions) { + if (LangUtil.isEmpty(args) || LangUtil.isEmpty(validOptions)) { + return new String[0]; + } + ArrayList result = new ArrayList(); + for (int i = 0; i < validOptions.length; i++) { + String sought = validOptions[i]; + if (LangUtil.isEmpty(sought)) { + continue; + } + for (Iterator iter = args.iterator(); iter.hasNext();) { + String arg = (String) iter.next(); + if (sought.equals(arg)) { + result.add(sought); + break; + } + } + } + return (String[]) result.toArray(new String[0]); + } + + /** + * Generate variants of String[] options by creating an extra set for + * each option that ends with "-". If none end with "-", then an + * array equal to <code>new String[][] { options }</code> is returned; + * if one ends with "-", then two sets are returned, + * three causes eight sets, etc. + * @return String[][] with each option set. + * @throws IllegalArgumentException if any option is null or empty. + */ + public static String[][] optionVariants(String[] options) { + if ((null == options) || (0 == options.length)) { + return new String[][] { new String[0]}; + } + // be nice, don't stomp input + String[] temp = new String[options.length]; + System.arraycopy(options, 0, temp, 0, temp.length); + options = temp; + boolean[] dup = new boolean[options.length]; + int numDups = 0; + + for (int i = 0; i < options.length; i++) { + String option = options[i]; + if (LangUtil.isEmpty(option)) { + throw new IllegalArgumentException("empty option at " + i); + } + if (option.endsWith("-")) { + options[i] = option.substring(0, option.length()-1); + dup[i] = true; + numDups++; + } + } + final String[] NONE = new String[0]; + final int variants = exp(2, numDups); + final String[][] result = new String[variants][]; + // variant is a bitmap wrt doing extra value when dup[k]=true + for (int variant = 0; variant < variants; variant++) { + ArrayList next = new ArrayList(); + int nextOption = 0; + for (int k = 0; k < options.length; k++) { + if (!dup[k] || (0 != (variant & (1 << (nextOption++))))) { + next.add(options[k]); + } + } + result[variant] = (String[]) next.toArray(NONE); + } + return result; + } + + private static int exp(int base, int power) { // not in Math? + if (0 > power) { + throw new IllegalArgumentException("negative power: " + power); + } + int result = 1; + while (0 < power--) { + result *= base; + } + return result; + } + + /** + * Make a copy of the array. + * @return an array with the same component type as source + * containing same elements, even if null. + * @throws IllegalArgumentException if source is null + */ + public static final Object[] copy(Object[] source) { + LangUtil.throwIaxIfNull(source, "source"); + final Class c = source.getClass().getComponentType(); + Object[] result = (Object[]) Array.newInstance(c, source.length); + System.arraycopy(source, 0, result, 0, result.length); + return result; + } + + + /** + * Convert arrays safely. The number of elements in the result + * will be 1 smaller for each element that is null or not assignable. + * This will use sink if it has exactly the right size. + * The result will always have the same component type as sink. + * @return an array with the same component type as sink + * containing any assignable elements in source (in the same order). + * @throws IllegalArgumentException if either is null + */ + public static Object[] safeCopy(Object[] source, Object[] sink) { + final Class sinkType = (null == sink + ? Object.class + : sink.getClass().getComponentType()); + final int sourceLength = (null == source ? 0 : source.length); + final int sinkLength = (null == sink ? 0 : sink.length); + + final int resultSize; + ArrayList result = null; + if (0 == sourceLength) { + resultSize = 0; + } else { + result = new ArrayList(sourceLength); + for (int i = 0; i < sourceLength; i++) { + if ((null != source[i]) + && (sinkType.isAssignableFrom(source[i].getClass()))) { + result.add(source[i]); + } + } + resultSize = result.size(); + } + if (resultSize != sinkLength) { + sink = (Object[]) Array.newInstance(sinkType, result.size()); + } + if (0 < resultSize) { + sink = result.toArray(sink); + } + return sink; + } + + /** + * @return a String with the unqualified class name of the class (or "null") + */ + public static String unqualifiedClassName(Class c) { + if (null == c) { + return "null"; + } + String name = c.getName(); + int loc = name.lastIndexOf("."); + if (-1 != loc) { + name = name.substring(1 + loc); + } + return name; + } + + /** + * @return a String with the unqualified class name of the object (or "null") + */ + public static String unqualifiedClassName(Object o) { + return LangUtil.unqualifiedClassName(null == o ? null : o.getClass()); + } + + /** render i right-justified with a given width less than about 40 */ + public static String toSizedString(long i, int width) { + String result = "" + i; + int size = result.length(); + if (width > size) { + final String pad = " "; + final int padLength = pad.length(); + if (width > padLength) { + width = padLength; + } + int topad = width-size; + result = pad.substring(0, topad) + result; + } + return result; + } + + /** clip StringBuffer to maximum number of lines */ + static String clipBuffer(StringBuffer buffer, int maxLines) { + if ((null == buffer) || (1 > buffer.length())) return ""; + StringBuffer result = new StringBuffer(); + int j = 0; + final int MAX = maxLines; + final int N = buffer.length(); + for (int i = 0, srcBegin = 0; i < MAX; srcBegin += j) { + // todo: replace with String variant if/since getting char? + char[] chars = new char[128]; + int srcEnd = srcBegin+chars.length; + if (srcEnd >= N) { + srcEnd = N-1; + } + if (srcBegin == srcEnd) break; + //log("srcBegin:" + srcBegin + ":srcEnd:" + srcEnd); + buffer.getChars(srcBegin, srcEnd, chars, 0); + for (j = 0; j < srcEnd-srcBegin/*chars.length*/; j++) { + char c = chars[j]; + if (c == '\n') { + i++; + j++; + break; + } + } + try { result.append(chars, 0, j); } + catch (Throwable t) { } + } + return result.toString(); + } + + /** + * @return "({UnqualifiedExceptionClass}) {message}" + */ + public static String renderExceptionShort(Throwable e) { + if (null == e) + return "(Throwable) null"; + return "(" + LangUtil.unqualifiedClassName(e) + ") " + e.getMessage(); + } + + /** + * Renders exception <code>t</code> after unwrapping and + * eliding any test packages. + * @param t <code>Throwable</code> to print. + * @see #maxStackTrace + */ + public static String renderException(Throwable t) { + return renderException(t, true); + } + + /** + * Renders exception <code>t</code>, unwrapping, + * optionally eliding and limiting total number of lines. + * @param t <code>Throwable</code> to print. + * @param elide true to limit to 100 lines and elide test packages + * @see StringChecker#TEST_PACKAGES + */ + public static String renderException(Throwable t, boolean elide) { + if (null == t) return "null throwable"; + t = unwrapException(t); + StringBuffer stack = stackToString(t, false); + if (elide) { + elideEndingLines(StringChecker.TEST_PACKAGES, stack, 100); + } + return stack.toString(); + } + + /** + * Trim ending lines from a StringBuffer, + * clipping to maxLines and further removing any number of + * trailing lines accepted by checker. + * @param checker returns true if trailing line should be elided. + * @param stack StringBuffer with lines to elide + * @param maxLines int for maximum number of resulting lines + */ + static void elideEndingLines(StringChecker checker, StringBuffer stack, int maxLines) { + if (null == checker || (null == stack) || (0 == stack.length())) { + return; + } + final LinkedList lines = new LinkedList(); + StringTokenizer st = new StringTokenizer(stack.toString(),"\n\r"); + while (st.hasMoreTokens() && (0 < --maxLines)) { + lines.add(st.nextToken()); + } + st = null; + + String line; + int elided = 0; + while (!lines.isEmpty()) { + line = (String) lines.getLast(); + if (!checker.acceptString(line)) { + break; + } else { + elided++; + lines.removeLast(); + } + } + if ((elided > 0) || (maxLines < 1)) { + final int EOL_LEN = EOL.length(); + int totalLength = 0; + while (!lines.isEmpty()) { + totalLength += EOL_LEN + ((String) lines.getFirst()).length(); + lines.removeFirst(); + } + if (stack.length() > totalLength) { + stack.setLength(totalLength); + if (elided > 0) { + stack.append(" (... " + elided + " lines...)"); + } + } + } + } + + + /** Dump message and stack to StringBuffer. */ + public static StringBuffer stackToString(Throwable throwable, boolean skipMessage) { + if (null == throwable) { + return new StringBuffer(); + } + StringWriter buf = new StringWriter(); + PrintWriter writer = new PrintWriter(buf); + if (!skipMessage) { + writer.println(throwable.getMessage()); + } + throwable.printStackTrace(writer); + try { buf.close(); } + catch (IOException ioe) {} // ignored + return buf.getBuffer(); + } + + + /** @return Throwable input or tail of any wrapped exception chain */ + public static Throwable unwrapException(Throwable t) { + if (t instanceof InvocationTargetException) { + Throwable thrown = ((InvocationTargetException) t).getTargetException(); + if (null != thrown) { + return unwrapException(thrown); + } + } else if (t instanceof ClassNotFoundException) { + Throwable thrown = ((ClassNotFoundException) t).getException(); + if (null != thrown) { + return unwrapException(thrown); + } + } + // ChainedException + // ExceptionInInitializerError + return t; + } + + /** + * Replacement for Arrays.asList(..) which gacks on null + * and returns a List in which remove is an unsupported operation. + * @param array the Object[] to convert (may be null) + * @return the List corresponding to array (never null) + */ + public static List arrayAsList(Object[] array) { + if ((null == array) || (1 > array.length)) { + return Collections.EMPTY_LIST; + } + ArrayList list = new ArrayList(); + list.addAll(Arrays.asList(array)); + return list; + } + + + + + /** check if input contains any packages to elide. */ + public static class StringChecker { + static StringChecker TEST_PACKAGES = new StringChecker( new String[] + { "org.aspectj.testing.", + "org.eclipse.jdt.internal.junit", + "junit.framework.", + "org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" + }); + + String[] infixes; + + /** @param infixes adopted */ + StringChecker(String[] infixes) { + this.infixes = infixes; + } + + /** @return true if input contains infixes */ + public boolean acceptString(String input) { + boolean result = false; + if (!LangUtil.isEmpty(input)) { + for (int i = 0; !result && (i < infixes.length); i++) { + result = (-1 != input.indexOf(infixes[i])); + } + } + return result; + } + } +} diff --git a/util/src/org/aspectj/util/LineReader.java b/util/src/org/aspectj/util/LineReader.java new file mode 100644 index 000000000..622d7b4c9 --- /dev/null +++ b/util/src/org/aspectj/util/LineReader.java @@ -0,0 +1,212 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + +import java.io.*; +import java.util.ArrayList; + +/** + * LineNumberReader which absorbs comments and blank lines + * and renders as file:line + */ +public class LineReader extends LineNumberReader { + /** delimited multi-line output of readToBlankLine */ + public static final String RETURN= "\n\r"; + + private static final String[] NONE = new String[0]; + private static final String cSCRIPT = "#"; + private static final String cJAVA = "//"; + private static final String[] TESTER_LEAD = new String[] {cSCRIPT, cJAVA}; + + /** + * Convenience factory for tester suite files + * @return null if IOException or IllegalArgumentException thrown + */ + public static final LineReader createTester(File file) { + return create(file, TESTER_LEAD, null); + } + + /** + * convenience factory + * @return null if IOException or IllegalArgumentException thrown + */ + public static final LineReader create(File file, + String[] leadComments, String[] eolComments) { + try { + FileReader reader = new FileReader(file); + return new LineReader(reader, file, leadComments, eolComments); + } catch (IllegalArgumentException e) { + } catch (IOException e) { + } + return null; + } + + final private File file; + final private String[] eolComments; + final private String[] leadComments; + transient String lastLine; + + /** + * @param file the File used to open the FileReader + * @param leadComments the String[] to be taken as the start of + * comments when they are the first non-blank text on a line - + * pass null to signal none. + * @param leadComments the String[] to be taken as the start of + * comment anywhere on a line - pass null to signal none. + *@throws IllegalArgumentException if any String in + * leadComments or eolComments is null. + */ + public LineReader(FileReader reader, File file, + String[] leadComments, String[] eolComments) { + super(reader); + this.file = file; + this.eolComments = normalize(eolComments); + this.leadComments = normalize(leadComments); + } + public LineReader(FileReader reader, File file) { + this(reader, file, null, null); + } + + /** @return file:line */ + public String toString() { + return file.getPath() + ":" + getLineNumber(); + } + + /** @return underlying file */ + public File getFile() { return file; } + + /** + * Reader first..last (inclusive) and return in String[]. + * This will return (1+(last-first)) elements only if this + * reader has not read past the first line and there are last lines + * and there are no IOExceptions during reads. + * @param first the first line to read - if negative, use 0 + * @param last the last line to read (inclusive) + * - if less than first, use first + * @return String[] of first..last (inclusive) lines read or + */ + public String[] readLines(int first, int last) { + if (0 > first) first = 0; + if (first > last) last = first; + ArrayList list = new ArrayList(); + try { + String line = null; + while (getLineNumber() < first) { + line = readLine(); + if (null == line) { + break; + } + } + if (getLineNumber() > first) { + // XXX warn? something else read past line + } + if ((null != line) && (first == getLineNumber())) { + list.add(line); + while (last >= getLineNumber()) { + line = readLine(); + if (null == line) { + break; + } + list.add(line); + } + } + } catch (IOException e) { + return NONE; + } + return (String[]) list.toArray(NONE); + } + + /** Skip to next blank line + * @return the String containing all lines skipped (delimited with RETURN) + */ + public String readToBlankLine() throws IOException { + StringBuffer sb = new StringBuffer(); + String input; + while (null != (input = nextLine(false))) { // get next empty line to restart + sb.append(input); + sb.append(RETURN);// XXX verify/ignore/correct + } + return sb.toString(); + } + + /** + * lastLine is set only by readClippedLine, not readLine. + * @return the last line read, after clipping + */ + public String lastLine() { + return lastLine; + } + + /** + * Get the next line from the input stream, stripping eol and + * leading comments. + * If emptyLinesOk is true, then this reads past lines which are + * empty after omitting comments and trimming until the next non-empty line. + * Otherwise, this returns null on reading an empty line. + * (The input stream is not exhausted until this + * returns null when emptyLines is true.) + * @param skipEmpties if true, run to next non-empty line; if false, return next line + * @return null if no more lines or got an empty line when they are not ok, + * or next non-null, non-empty line in reader, + * ignoring comments + */ + public String nextLine(boolean skipEmpties) throws IOException { + String result; + do { + result = readClippedLine(); + if ((null != result) && skipEmpties && (0 == result.length())) { + continue; + } + return result; + } while (true); + } + + /** @return null if no more lines or a clipped line otherwise */ + protected String readClippedLine() throws IOException { + String result = readLine(); + if (result != null) { + result = result.trim(); + int len = result.length(); + for (int i = 0; ((0 < len) && (i < leadComments.length)); i++) { + if (result.startsWith(leadComments[i])) { + result = ""; + len = 0; + } + } + for (int i = 0; ((0 < len) && (i < eolComments.length)); i++) { + int loc = result.indexOf(eolComments[i]); + if (-1 != loc) { + result = result.substring(0, loc); + len = result.length(); + } + } + } + lastLine = result; + return result; + } + + private String[] normalize(String[] input) { + if ((null == input) || (0 == input.length)) return NONE; + String[] result = new String[input.length]; + System.arraycopy(input, 0, result, 0, result.length); + for (int i = 0; i < result.length; i++) { + if ((null == result[i]) || (0 == result[i].length())) { + throw new IllegalArgumentException("empty input at [" + i + "]"); + } + } + return result; + } +} + diff --git a/util/src/org/aspectj/util/NonLocalExit.java b/util/src/org/aspectj/util/NonLocalExit.java new file mode 100644 index 000000000..1c75d075d --- /dev/null +++ b/util/src/org/aspectj/util/NonLocalExit.java @@ -0,0 +1,39 @@ +/* ******************************************************************* + * 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.util; + +/** + * Throw this when a non-local exit is required (suggested for tests only). + */ +public class NonLocalExit extends RuntimeException { + + public static final int SUCCEESS = 0; + public static final int FAULURE = 1; + + private int exitCode; + + public NonLocalExit(int exitCode) { + this(); + this.exitCode = exitCode; + } + + public NonLocalExit() { + super(); + } + + public int getExitCode() { + return exitCode; + } + +} diff --git a/util/src/org/aspectj/util/PartialOrder.java b/util/src/org/aspectj/util/PartialOrder.java new file mode 100644 index 000000000..6051caffd --- /dev/null +++ b/util/src/org/aspectj/util/PartialOrder.java @@ -0,0 +1,213 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + +import java.util.*; + + +/** This class implements a partial order + * + * It includes routines for doing a topo-sort + */ + +public class PartialOrder { + + /** All classes that want to be part of a partial order must implement + * PartialOrder.PartialComparable. + */ + public static interface PartialComparable { + /** + * @returns <ul> + * <li>+1 if this is greater than other</li> + * <li>-1 if this is less than other</li> + * <li>0 if this is not comparable to other</li> + * </ul> + * + * <b> Note: returning 0 from this method doesn't mean the same thing as returning + * 0 from java.util.Comparable.compareTo()</b> + */ + public int compareTo(Object other); + + /** + * This method can provide a deterministic ordering for elements that + * are strictly not comparable. If you have no need for this, this method + * can just return 0 whenever called. + */ + public int fallbackCompareTo(Object other); + } + + private static class SortObject { + PartialComparable object; + List/*SortObject*/ smallerObjects = new LinkedList(); + List/*SortObject*/ biggerObjects = new LinkedList(); + + public SortObject(PartialComparable o) { + object = o; + } + + boolean hasNoSmallerObjects() { return smallerObjects.size() == 0; } + + boolean removeSmallerObject(SortObject o) { + smallerObjects.remove(o); + return hasNoSmallerObjects(); + } + + void addDirectedLinks(SortObject other) { + int cmp = object.compareTo(other.object); + if (cmp == 0) return; + if (cmp > 0) { + this.smallerObjects.add(other); + other.biggerObjects.add(this); + } else { + this.biggerObjects.add(other); + other.smallerObjects.add(this); + } + } + + public String toString() { + return object.toString(); //+smallerObjects+biggerObjects; + } + } + + private static void addNewPartialComparable(List graph, PartialComparable o) { + SortObject so = new SortObject(o); + for (Iterator i = graph.iterator(); i.hasNext(); ) { + SortObject other = (SortObject)i.next(); + so.addDirectedLinks(other); + } + graph.add(so); + } + + private static void removeFromGraph(List graph, SortObject o) { + for (Iterator i = graph.iterator(); i.hasNext(); ) { + SortObject other = (SortObject)i.next(); + + if (o == other) i.remove(); + //??? could use this to build up a new queue of objects with no + //??? smaller ones + other.removeSmallerObject(o); + } + } + + /** + * @param objects must all implement PartialComparable + * + * @returns the same members as objects, but sorted according to their partial + * order. returns null if the objects are cyclical + * + */ + public static List sort(List objects) { + // lists of size 0 or 1 don't need any sorting + if (objects.size() < 2) return objects; + + //??? we might want to optimize a few other cases of small size + + //??? I don't like creating this data structure, but it does give good + //??? separation of concerns. + List sortList = new LinkedList(); //objects.size()); + for (Iterator i = objects.iterator(); i.hasNext(); ) { + addNewPartialComparable(sortList, (PartialComparable)i.next()); + } + + //System.out.println(sortList); + + // now we have built our directed graph + // use a simple sort algorithm from here + // can increase efficiency later + // List ret = new ArrayList(objects.size()); + final int N = objects.size(); + for (int index = 0; index < N; index++) { + //System.out.println(sortList); + //System.out.println("-->" + ret); + + SortObject leastWithNoSmallers = null; + + for (Iterator i = sortList.iterator(); i.hasNext(); ) { + SortObject so = (SortObject)i.next(); + //System.out.println(so); + if (so.hasNoSmallerObjects()) { + if (leastWithNoSmallers == null || + so.object.fallbackCompareTo(leastWithNoSmallers.object) < 0) + { + leastWithNoSmallers = so; + } + } + } + + if (leastWithNoSmallers == null) return null; + + removeFromGraph(sortList, leastWithNoSmallers); + objects.set(index, leastWithNoSmallers.object); + } + + return objects; + } + + /*********************************************************************************** + /* a minimal testing harness + ***********************************************************************************/ + static class Token implements PartialComparable { + private String s; + + Token(String s) { + this.s = s; + } + + public int compareTo(Object other) { + Token t = (Token)other; + + int cmp = s.charAt(0) - t.s.charAt(0); + if (cmp == 1) return 1; + if (cmp == -1) return -1; + return 0; + } + + public int fallbackCompareTo(Object other) { + return -s.compareTo( ((Token)other).s ); + } + + public String toString() { + return s; + } + } + + public static void main(String[] args) { + List l = new ArrayList(); + l.add(new Token("a1")); + l.add(new Token("c2")); + l.add(new Token("b3")); + l.add(new Token("f4")); + l.add(new Token("e5")); + l.add(new Token("d6")); + l.add(new Token("c7")); + l.add(new Token("b8")); + + l.add(new Token("z")); + l.add(new Token("x")); + + l.add(new Token("f9")); + l.add(new Token("e10")); + l.add(new Token("a11")); + l.add(new Token("d12")); + l.add(new Token("b13")); + l.add(new Token("c14")); + + System.out.println(l); + + sort(l); + + System.out.println(l); + } +} diff --git a/util/src/org/aspectj/util/Reflection.java b/util/src/org/aspectj/util/Reflection.java new file mode 100644 index 000000000..bee7bd70e --- /dev/null +++ b/util/src/org/aspectj/util/Reflection.java @@ -0,0 +1,106 @@ +/* ******************************************************************* + * 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.util; + +import java.lang.reflect.*; +import java.lang.reflect.Method; + +public class Reflection { + + private Reflection() { + } + + public static Object invokestatic(Class class_, String name) { + return invokestaticN(class_, name, new Object[0]); + } + + public static Object invokestatic(Class class_, String name, Object arg1) { + return invokestaticN(class_, name, new Object[] { arg1 }); + } + + public static Object invokestatic(Class class_, String name, Object arg1, Object arg2) { + return invokestaticN(class_, name, new Object[] { arg1, arg2 }); + } + + public static Object invokestatic(Class class_, String name, Object arg1, Object arg2, Object arg3) { + return invokestaticN(class_, name, new Object[] { arg1, arg2, arg3 }); + } + + + public static Object invokestaticN(Class class_, String name, Object[] args) { + return invokeN(class_, name, null, args); + } + + + public static Object invoke(Class class_, Object target, String name, Object arg1) { + return invokeN(class_, name, target, new Object[] { arg1 }); + } + + public static Object invoke(Class class_, Object target, String name, Object arg1, Object arg2) { + return invokeN(class_, name, target, new Object[] { arg1, arg2 }); + } + + public static Object invoke(Class class_, Object target, String name, Object arg1, Object arg2, Object arg3) { + return invokeN(class_, name, target, new Object[] { arg1, arg2, arg3 }); + } + + + + + public static Object invokeN(Class class_, String name, Object target, Object[] args) { + Method meth = getMatchingMethod(class_, name, args); + try { + return meth.invoke(target, args); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.toString()); + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t instanceof Error) throw (Error)t; + if (t instanceof RuntimeException) throw (RuntimeException)t; + t.printStackTrace(); + throw new RuntimeException(t.toString()); + } + } + + + public static Method getMatchingMethod(Class class_, String name, Object[] args) { + Method[] meths = class_.getMethods(); + for (int i=0; i < meths.length; i++) { + Method meth = meths[i]; + if (meth.getName().equals(name) && isCompatible(meth, args)) { + return meth; + } + } + return null; + } + + private static boolean isCompatible(Method meth, Object[] args) { + // ignore methods with overloading other than lengths + return meth.getParameterTypes().length == args.length; + } + + + + + public static Object getStaticField(Class class_, String name) { + try { + return class_.getField(name).get(null); + } catch (IllegalAccessException e) { + throw new RuntimeException("unimplemented"); + } catch (NoSuchFieldException e) { + throw new RuntimeException("unimplemented"); + } + } + +} diff --git a/util/src/org/aspectj/util/StreamPrintWriter.java b/util/src/org/aspectj/util/StreamPrintWriter.java new file mode 100644 index 000000000..6167e6694 --- /dev/null +++ b/util/src/org/aspectj/util/StreamPrintWriter.java @@ -0,0 +1,101 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + +import java.io.*; + +/** + * Used for writing converting text written to an output stream into + * a string. Deprecated - use StringWriter: + * <pre> + * StringWriter sw = new StringWriter(); + * PrintWriter pw = new PrintWriter(sw, true); + * ... write to pw + * String result = sw.getBuffer().toString(); + * </pre> + * @deprecated use StringWriter to construct PrintWriter + * @author Mik Kersten + */ +public class StreamPrintWriter extends PrintWriter { + private String contents = ""; + + public StreamPrintWriter(Writer out) { + super(out); + } + + public String getContents() { + return contents; + } + + public void flushBuffer() { + contents = ""; + super.flush(); + } + + public void print(char x) { + contents += x + "\n"; + } + + public void print(char[] x) { + contents += new String( x ); + } + + public void print(int x) { + contents += x; + } + + public void print(String x) { + contents += x; + } + + public void println(char x) { + contents += x + "\n"; + } + + public void println(char[] x) { + contents += new String( x ) + "\n"; + } + + public void println(int x) { + contents += x + "\n"; + } + + public void println(String x) { + contents += x + "\n"; + } + + public void write( byte[] x ) { + contents += new String( x ); + } + + public void write( byte[] x, int i1, int i2 ) { + StringWriter writer = new StringWriter(); + String s = new String( x ); + writer.write( s.toCharArray(), i1, i2 ); + contents += writer.getBuffer().toString(); + } + + public void write( int c ) { + contents += c; + } + + public void write( String s ) { + contents += s; + } + + public void write( String s, int i1, int i2 ) { + contents += s; + } +} diff --git a/util/src/org/aspectj/util/TypeSafeEnum.java b/util/src/org/aspectj/util/TypeSafeEnum.java new file mode 100644 index 000000000..6980d39c9 --- /dev/null +++ b/util/src/org/aspectj/util/TypeSafeEnum.java @@ -0,0 +1,38 @@ +/* ******************************************************************* + * 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.util; + +import java.io.*; + +public class TypeSafeEnum { + private byte key; + private String name; + + public TypeSafeEnum(String name, int key) { + this.name = name; + if (key > Byte.MAX_VALUE || key < Byte.MIN_VALUE) { + throw new IllegalArgumentException("key doesn't fit into a byte: " + key); + } + this.key = (byte)key; + } + + public String toString() { return name; } + + public String getName() { return name; } + public byte getKey() { return key; } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(key); + } +} diff --git a/util/testsrc/UtilModuleTests.java b/util/testsrc/UtilModuleTests.java new file mode 100644 index 000000000..ddb1da5f5 --- /dev/null +++ b/util/testsrc/UtilModuleTests.java @@ -0,0 +1,30 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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 + * ******************************************************************/ + + +// default package + +import junit.framework.*; +import junit.framework.Test; + +public class UtilModuleTests extends TestCase { + + public static Test suite() { + TestSuite suite = new TestSuite(UtilModuleTests.class.getName()); + suite.addTest(org.aspectj.util.UtilTests.suite()); + return suite; + } + + public UtilModuleTests(String name) { super(name); } + +} diff --git a/util/testsrc/org/aspectj/util/FileUtilTest.java b/util/testsrc/org/aspectj/util/FileUtilTest.java new file mode 100644 index 000000000..7cda1692c --- /dev/null +++ b/util/testsrc/org/aspectj/util/FileUtilTest.java @@ -0,0 +1,377 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + +import java.io.EOFException; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import junit.framework.TestCase; +import junit.textui.TestRunner; + +/** + * + */ +public class FileUtilTest extends TestCase { + public static final String[] NONE = new String[0]; + + boolean log = false; + + /** List of File files or directories to delete when exiting */ + final ArrayList tempFiles; + public FileUtilTest(String s) { + super(s); + tempFiles = new ArrayList(); + } + + public static void main(String[] args) { + TestRunner.main(new String[] {"org.aspectj.util.FileUtilUT"}); + } + + public void tearDown() { + for (ListIterator iter = tempFiles.listIterator(); iter.hasNext();) { + File dir = (File) iter.next(); + FileUtil.deleteContents(dir); + dir.delete(); + iter.remove(); + } + } + + public void testDirCopySubdirs() throws IOException { // XXX dir diff + File srcDir = new File("src"); + File destDir = FileUtil.getTempDir("testDirCopySubdirs"); + FileUtil.copyDir(srcDir, destDir); + FileUtil.deleteContents(destDir); + destDir.delete(); + } + + public void testDirCopySubdirsSuffix() throws IOException { // XXX dir diff + File srcDir = new File("src"); + File destDir = FileUtil.getTempDir("testDirCopySubdirsSuffix"); + FileUtil.copyDir(srcDir, destDir, ".java", ".aj"); + + FileUtil.deleteContents(destDir); + destDir.delete(); + } + + public void testGetURL() { + String[] args = new String[] + {".", "../util/testdata", "../lib/test/aspectjrt.jar" }; + for (int i = 0; i < args.length; i++) { + checkGetURL(args[i]); + } + } + + /** + * Method checkGetURL. + * @param string + * @param uRL + */ + private void checkGetURL(String arg) { + assertTrue(null != arg); + File f = new File(arg); + assertTrue(null != f); + URL url = FileUtil.getFileURL(f); + assertTrue(null != url); + log("url " + url); + if (!f.exists()) { + log("not exist " + f); + } else if (f.isDirectory()) { + log("directory " + f); + } else { + log(" file " + f); + InputStream in = null; + try { + in = url.openStream(); + } catch (IOException e) { + assertTrue("IOException: " + e, false); + } finally { + if (null != in) { + try { in.close(); } + catch (IOException e) {} + } + } + } + } + + + public void testGetTempDir() { + boolean pass = true; + boolean delete = true; + checkGetTempDir("parent", null, pass, delete); + checkGetTempDir(null, "child", pass, delete); + tempFiles.add(checkGetTempDir("parent", "child", pass, !delete)); + tempFiles.add(checkGetTempDir("parent", "child", pass, !delete)); + tempFiles.add(checkGetTempDir("parent", "child", pass, !delete)); + } + + File checkGetTempDir(String parent, String child, boolean ok, boolean delete) { + File parentDir = FileUtil.getTempDir(parent); + assertTrue("unable to create " + parent, null != parentDir); + File dir = FileUtil.makeNewChildDir(parentDir, child); + log("parent=" + parent + " child=" + child + " -> " + dir); + assertTrue("dir: " + dir, ok == (dir.canWrite() && dir.isDirectory())); + if (delete) { + dir.delete(); + } + return dir; + } + + public void testRandomFileString() { + ArrayList results = new ArrayList(); + for (int i = 0; i < 1000; i++) { + String s = FileUtil.randomFileString(); + if (results.contains(s)) { + System.err.println("warning: got duplicate at iteration " + i); + } + results.add(s); +// System.err.print(" " + s); +// if (0 == (i % 5)) { +// System.err.println(""); +// } + } + } + + public void testNormalizedPath() { + File tempFile = null; + try { + tempFile = File.createTempFile("FileUtilTest", "tmp"); + } catch (IOException e) { + System.err.println("aborting test - unable to create temp file"); + } + File parentDir = tempFile.getParentFile(); + String tempFilePath = FileUtil.normalizedPath(tempFile, parentDir); + assertEquals(tempFile.getName(), tempFilePath); + } + + public void testFileToClassName() { + + File basedir = new File("/base/dir"); + File classFile = new File(basedir, "foo/Bar.class"); + assertEquals("foo.Bar", FileUtil.fileToClassName(basedir, classFile)); + + classFile = new File(basedir, "foo\\Bar.class"); + assertEquals("foo.Bar", FileUtil.fileToClassName(basedir, classFile)); + + assertEquals("Bar", FileUtil.fileToClassName(null, classFile)); + + classFile = new File("/home/classes/org/aspectj/lang/JoinPoint.class"); + assertEquals("org.aspectj.lang.JoinPoint", FileUtil.fileToClassName(null, classFile)); + + classFile = new File("/home/classes/com/sun/tools/Javac.class"); + assertEquals("com.sun.tools.Javac", FileUtil.fileToClassName(null, classFile)); + } + + public void testDeleteContents() { + File f = new File("testdata/foo"); + f.mkdirs(); + File g = new File(f, "bar"); + g.mkdirs(); + File h = new File(g, "bash"); + h.mkdirs(); + int d = FileUtil.deleteContents(f); + assertTrue(0 == d); + assertTrue(0 == f.list().length); + f.delete(); + assertTrue(!f.exists()); + } + + public void testLineSeek() { + String path = "testdata/testLineSeek"; + File file = new File(path); + path = file.getPath(); + String contents = "0123456789" + LangUtil.EOL; + contents += contents; + FileUtil.writeAsString(file, contents); + tempFiles.add(file); + List sourceList = new ArrayList(); + sourceList.add(file.getPath()); + + final ArrayList errors = new ArrayList(); + final PrintStream errorSink = new PrintStream(System.err, true) { + public void println(String error) { + errors.add(error); + } + }; + for (int i = 0; i < 10; i++) { + List result = FileUtil.lineSeek(""+i, sourceList, true, errorSink); + assertEquals(2, result.size()); + assertEquals(path + ":1:" + i, result.get(0)); + assertEquals(path + ":2:" + i, result.get(1)); + if (!LangUtil.isEmpty(errors)) { // XXX prefer fast-fail? + assertTrue("errors: " + errors, false); + } + } + + } + public void testLineSeekMore() { + final int MAX = 3; // 1..10 + final String prefix = new File("testdata/testLineSeek").getPath(); + // setup files 0..MAX with 2*MAX lines + String[] sources = new String[MAX]; + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < sources.length; i++) { + sources[i] = new File(prefix + i).getPath(); + sb.append("not matched"); + sb.append(LangUtil.EOL); + sb.append("0123456789"); + sb.append(LangUtil.EOL); + } + final String contents = sb.toString(); + for (int i = 0; i < sources.length; i++) { + File file = new File(sources[i]); + FileUtil.writeAsString(file, contents); + tempFiles.add(file); + } + // now test + final ArrayList errors = new ArrayList(); + final PrintStream errorSink = new PrintStream(System.err, true) { + public void println(String error) { + errors.add(error); + } + }; + List sourceList = new ArrayList(); + sourceList.addAll(Arrays.asList(sources)); + sourceList = Collections.unmodifiableList(sourceList); + for (int k = 0; k < sources.length; k++) { + List result = FileUtil.lineSeek(""+k, sourceList, true, errorSink); + // number k found in every other line of every file at index k + Iterator iter = result.iterator(); + for (int i = 0; i < MAX; i++) { // for each file + for (int j = 1; j < (MAX+1); j++) { // for every other line + assertTrue(iter.hasNext()); + assertEquals(prefix + i + ":" + 2*j + ":" + k, iter.next()); + } + } + if (!LangUtil.isEmpty(errors)) { // XXX prefer fast-fail? + assertTrue("errors: " + errors, false); + } + } + } + + public void testDirCopyNoSubdirs() throws IOException { + String[] srcFiles = new String[] { "one.java", "two.java", "three.java"}; + String[] destFiles = new String[] { "three.java", "four.java", "five.java" }; + String[] allFiles = new String[] + { "one.java", "two.java", "three.java", "four.java", "five.java" }; + File srcDir = makeDir("FileUtilUT_srcDir", srcFiles); + File destDir = makeDir("FileUtilUT_destDir", destFiles); + assertTrue(null != srcDir); + assertTrue(null != destDir); + assertTrue(NONE == dirContains(srcDir, srcFiles)); + assertTrue(NONE == dirContains(destDir, destFiles)); + + FileUtil.copyDir(srcDir, destDir); + String[] resultOne = dirContains(destDir, allFiles); + FileUtil.copyDir(srcDir, destDir); + String[] resultTwo = dirContains(destDir, allFiles); + + FileUtil.deleteContents(srcDir); + FileUtil.deleteContents(destDir); + srcDir.delete(); + destDir.delete(); + + assertTrue(NONE == resultOne); + assertTrue(NONE == resultTwo); + } + + public void testDirCopyNoSubdirsWithSuffixes() throws IOException { + String[] srcFiles = new String[] { "one.java", "two.java", "three.java"}; + String[] destFiles = new String[] { "three.java", "four.java", "five.java" }; + String[] allFiles = new String[] + { "one.aj", "two.aj", "three.aj", "three.java", "four.java", "five.java" }; + File srcDir = makeDir("FileUtilUT_srcDir", srcFiles); + File destDir = makeDir("FileUtilUT_destDir", destFiles); + assertTrue(null != srcDir); + assertTrue(null != destDir); + assertTrue(NONE == dirContains(srcDir, srcFiles)); + assertTrue(NONE == dirContains(destDir, destFiles)); + + FileUtil.copyDir(srcDir, destDir, ".java", ".aj"); + String[] resultOne = dirContains(destDir, allFiles); + FileUtil.copyDir(srcDir, destDir, ".java", ".aj"); + String[] resultTwo = dirContains(destDir, allFiles); + + FileUtil.deleteContents(srcDir); + FileUtil.deleteContents(destDir); + srcDir.delete(); + destDir.delete(); + + assertTrue(NONE == resultOne); + assertTrue(NONE == resultTwo); + } + + public void testDirCopySubdirsSuffixRoundTrip() throws IOException { + final File srcDir = new File("src"); + final File one = FileUtil.getTempDir("testDirCopySubdirsSuffixRoundTrip_1"); + final File two = FileUtil.getTempDir("testDirCopySubdirsSuffixRoundTrip_2"); + FileUtil.copyDir(srcDir, one); // no selection + FileUtil.copyDir(two, one, ".java", ".aj"); // only .java files + FileUtil.copyDir(one, two, ".aj", ".java"); + + FileUtil.deleteContents(one); + one.delete(); + FileUtil.deleteContents(two); + two.delete(); + } + + /** + * Verify that dir contains files, + * and return the names of other files in dir. + * @return the contents of dir after excluding files + * or NONE if none + * @throws AssertionFailedError if any files are not in dir + */ + String[] dirContains(File dir, final String[] files) { + final ArrayList toFind = new ArrayList(Arrays.asList(files)); + FilenameFilter filter = new FilenameFilter() { + public boolean accept(File d, String name) { + return !toFind.remove(name); + } + }; + String[] result = dir.list(filter); + if (0 < toFind.size()) { + assertTrue(""+toFind, false); + } + return (result.length == 0 ? NONE : result); + } + + File makeDir(String loc, String[] files) throws IOException { + File d = new File(loc); + d.mkdirs(); + assertTrue(d.exists()); + assertTrue(d.canWrite()); + for (int i = 0; i < files.length; i++) { + File f = new File(d, files[i]); + assertTrue(files[i], f.createNewFile()); + } + return d; + } + + private void log(String s) { + if (log) { + System.err.println(s); + } + } +} diff --git a/util/testsrc/org/aspectj/util/LangUtilTest.java b/util/testsrc/org/aspectj/util/LangUtilTest.java new file mode 100644 index 000000000..98aab88ba --- /dev/null +++ b/util/testsrc/org/aspectj/util/LangUtilTest.java @@ -0,0 +1,266 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import junit.framework.TestCase; + +/** + * + */ +public class LangUtilTest extends TestCase { + + public LangUtilTest(String name) { + super(name); + } + + /** @see LangUtil.extractOptions(String[], String[], int[], List) */ + public void testExtractOptions() { + ArrayList extracted = new ArrayList(); + String[] args = new String[] { "-d", "classes", "-classpath", "foo.jar", "-verbose", "Bar.java" }; + String[] validOptions = new String[] { "-classpath", "-d", "-verbose", "-help" }; + int[] optionArgs = new int[] { 1, 1, 0, 0 }; + String[] result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted); + String resultString = "" + Arrays.asList(result); + String EXP = "[Bar.java]"; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + EXP = "[-d, classes, -classpath, foo.jar, -verbose]"; + resultString = "" + extracted; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + + // no input, no output + extracted.clear(); + args = new String[] {}; + result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted); + resultString = "" + Arrays.asList(result); + EXP = "[]"; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + resultString = "" + extracted; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + + // one input, nothing extracted + extracted.clear(); + args = new String[] {"Bar.java"}; + result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted); + resultString = "" + Arrays.asList(result); + EXP = "[Bar.java]"; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + EXP = "[]"; + resultString = "" + extracted; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + + // one input, extracted + extracted.clear(); + args = new String[] {"-verbose"}; + result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted); + resultString = "" + Arrays.asList(result); + EXP = "[]"; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + EXP = "[-verbose]"; + resultString = "" + extracted; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + + // ------- booleans + validOptions = new String[] { "-help", "-verbose" }; + optionArgs = null; + + // one input, extracted + extracted.clear(); + args = new String[] {"-verbose"}; + result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted); + resultString = "" + Arrays.asList(result); + EXP = "[]"; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + EXP = "[-verbose]"; + resultString = "" + extracted; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + + // one input, not extracted + extracted.clear(); + args = new String[] {"Bar.java"}; + result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted); + resultString = "" + Arrays.asList(result); + EXP = "[Bar.java]"; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + EXP = "[]"; + resultString = "" + extracted; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + } + + /** @see LangUtil.extractOptions(String[], String[][]) */ + public void testExtractOptionsArrayCollector() { + String[] args = new String[] { "-d", "classes", "-classpath", "foo.jar", "-verbose", "Bar.java" }; + String[][] OPTIONS = new String[][] { + new String[] {"-classpath", null }, + new String[] {"-d", null}, + new String[] {"-verbose"}, + new String[] { "-help" }}; + + String[][] options = LangUtil.copyStrings(OPTIONS); + + String[] result = LangUtil.extractOptions(args, options); + String resultString = "" + Arrays.asList(result); + String EXP = "[Bar.java]"; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + assertTrue("-verbose".equals(options[2][0])); + assertTrue("foo.jar".equals(options[0][1])); + assertTrue("classes".equals(options[1][1])); + assertTrue("-classpath".equals(options[0][0])); + assertTrue("-d".equals(options[1][0])); + assertTrue(null == options[3][0]); + + // get args back, no options set + args = new String[] { "Bar.java" }; + options = LangUtil.copyStrings(OPTIONS); + + result = LangUtil.extractOptions(args, options); + resultString = "" + Arrays.asList(result); + EXP = "[Bar.java]"; + assertTrue(resultString + " != " + EXP, resultString.equals(EXP)); + assertTrue(null == options[0][0]); + assertTrue(null == options[1][0]); + assertTrue(null == options[2][0]); + assertTrue(null == options[3][0]); + } + + public void testOptionVariants() { + String[] NONE = new String[0]; + String[] one = new String[] {"-1"}; + String[] two = new String[] {"-2"}; + String[] three= new String[] {"-3"}; + String[] both = new String[] {"-1", "-2" }; + String[] oneB = new String[] {"-1-"}; + String[] bothB = new String[] {"-1-", "-2-" }; + String[] onetwoB = new String[] {"-1", "-2-" }; + String[] oneBtwo = new String[] {"-1-", "-2" }; + String[] threeB = new String[] {"-1-", "-2-", "-3-"}; + String[] athreeB = new String[] {"a", "-1-", "-2-", "-3-"}; + String[] threeaB = new String[] {"-1-", "a", "-2-", "-3-"}; + + checkOptionVariants(NONE, new String[][] { NONE }); + checkOptionVariants(one, new String[][] { one }); + checkOptionVariants(both, new String[][] { both }); + checkOptionVariants(oneB, new String[][] { NONE, one }); + checkOptionVariants(bothB, new String[][] { NONE, one, new String[] {"-2"}, both }); + checkOptionVariants(onetwoB, new String[][] { one, new String[] {"-1", "-2"}}); + checkOptionVariants(oneBtwo, new String[][] { two, new String[] {"-1", "-2"}}); + checkOptionVariants(threeB, new String[][] + { + NONE, + one, + two, + new String[] {"-1", "-2"}, + three, + new String[] {"-1", "-3"}, + new String[] {"-2", "-3"}, + new String[] {"-1", "-2", "-3"} + }); + checkOptionVariants(athreeB, new String[][] + { + new String[] {"a"}, + new String[] {"a", "-1"}, + new String[] {"a", "-2"}, + new String[] {"a", "-1", "-2"}, + new String[] {"a", "-3"}, + new String[] {"a", "-1", "-3"}, + new String[] {"a", "-2", "-3"}, + new String[] {"a", "-1", "-2", "-3"} + }); + checkOptionVariants(threeaB, new String[][] + { + new String[] {"a"}, + new String[] {"-1", "a"}, + new String[] {"a", "-2"}, + new String[] {"-1", "a", "-2"}, + new String[] {"a", "-3"}, + new String[] {"-1", "a", "-3"}, + new String[] {"a", "-2", "-3"}, + new String[] {"-1", "a", "-2", "-3"} + }); + } + + void checkOptionVariants(String[] options, String[][] expected) { + String[][] result = LangUtil.optionVariants(options); + if (expected.length != result.length) { + assertTrue("exp=" + expected.length + " actual=" + result.length, false); + } + for (int i = 0; i < expected.length; i++) { + assertEquals(""+i, + "" + Arrays.asList(expected[i]), + "" + Arrays.asList(result[i])); + } + } + + /** @see XMLWriterTest#testUnflattenList() */ + public void testCommaSplit() { + checkCommaSplit("", new String[] {""}); + checkCommaSplit("1", new String[] {"1"}); + checkCommaSplit(" 1 2 ", new String[] {"1 2"}); + checkCommaSplit(" 1 , 2 ", new String[] {"1", "2"}); + checkCommaSplit("1,2,3,4", new String[] {"1", "2", "3", "4"}); + } + + void checkCommaSplit(String input, String[] expected) { + List actual = LangUtil.commaSplit(input); + String a = "" + actual; + String e = "" + Arrays.asList(expected); + assertTrue(e + "==" + a, e.equals(a)); + } + + public void testElideEndingLines() { + StringBuffer stackBuffer = LangUtil.stackToString(new RuntimeException(""), true); + LangUtil.elideEndingLines(LangUtil.StringChecker.TEST_PACKAGES, stackBuffer, 100); + String result = stackBuffer.toString(); + if (-1 == result.indexOf("(... ")) { + // brittle - will fail under different top-level drivers + String m = "when running under eclipse or Ant, expecting (... in trace: "; + assertTrue( m + result, false); + } + + stackBuffer = new StringBuffer("java.lang.RuntimeException: unimplemented" + + "\n at org.aspectj.ajdt.internal.core.builder.EclipseUnwovenClassFile.writeWovenBytes(EclipseUnwovenClassFile.java:59)" + + "\n at org.aspectj.bcweaver.bcel.BcelWeaver.dump(BcelWeaver.java:271)" + + "\n at org.aspectj.bcweaver.bcel.BcelWeaver.weave(BcelWeaver.java:233)" + + "\n at org.aspectj.bcweaver.bcel.BcelWeaver.weave(BcelWeaver.java:198)" + + "\n at org.aspectj.ajdt.internal.core.builder.AjBuildManager.weaveAndGenerateClassFiles(AjBuildanager.java:230)" + + "\n at org.aspectj.ajdt.internal.core.builder.AjBuildManager.batchBuild(AjBuildManager.java:50)" + + "\n at org.aspectj.ajdt.ajc.AjdtCommand.runCommand(AjdtCommand.java:42)" + + "\n at org.aspectj.testing.harness.bridge.CompilerRun.run(CompilerRun.java:222)" + + "\n at org.aspectj.testing.run.Runner.runPrivate(Runner.java:363)" + + "\n at org.aspectj.testing.run.Runner.runChild(Runner.java:167)" + + "\n at org.aspectj.testing.run.Runner.runChild(Runner.java:126)" + + "\n at org.aspectj.testing.run.Runner$IteratorWrapper.run(Runner.java:441)" + + "\n at org.aspectj.testing.run.Runner.runPrivate(Runner.java:363)" + + "\n at org.aspectj.testing.run.Runner.runChild(Runner.java:167)" + + "\n at org.aspectj.testing.run.Runner.runChild(Runner.java:126)" + + "\n at org.aspectj.testing.run.Runner$IteratorWrapper.run(Runner.java:441)" + + "\n at org.aspectj.testing.run.Runner.runPrivate(Runner.java:363)" + + "\n at org.aspectj.testing.run.Runner.run(Runner.java:114)" + + "\n at org.aspectj.testing.run.Runner.run(Runner.java:105)" + + "\n at org.aspectj.testing.run.Runner.runIterator(Runner.java:228)" + + "\n at org.aspectj.testing.drivers.Harness.run(Harness.java:254)" + + "\n at org.aspectj.testing.drivers.Harness.runMain(Harness.java:217)" + + "\n at org.aspectj.testing.drivers.Harness.main(Harness.java:99)" + + "\n at org.aspectj.testing.Harness.main(Harness.java:37)" + + "\n clip me"); + + LangUtil.elideEndingLines(LangUtil.StringChecker.TEST_PACKAGES, stackBuffer, 25); + result = stackBuffer.toString(); + assertTrue(result, -1 != result.indexOf("(... ")); + assertTrue(result, -1 == result.indexOf("org.aspectj.testing")); + } +} diff --git a/util/testsrc/org/aspectj/util/UtilTests.java b/util/testsrc/org/aspectj/util/UtilTests.java new file mode 100644 index 000000000..7dc577941 --- /dev/null +++ b/util/testsrc/org/aspectj/util/UtilTests.java @@ -0,0 +1,32 @@ +/* ******************************************************************* + * Copyright (c) 1999-2001 Xerox Corporation, + * 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.util; + +import junit.framework.*; + +public class UtilTests extends TestCase { + + public static Test suite() { + TestSuite suite = new TestSuite(UtilTests.class.getName()); + //$JUnit-BEGIN$ + suite.addTestSuite(FileUtilTest.class); + suite.addTestSuite(LangUtilTest.class); + //$JUnit-END$ + return suite; + } + + public UtilTests(String name) { super(name); } + +} |