123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269 |
- /* *******************************************************************
- * Copyright (c) 1999-2000 Xerox Corporation.
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Xerox/PARC initial implementation
- * ******************************************************************/
-
-
- package org.aspectj.testing.util;
-
- import java.io.File;
- import java.io.FileFilter;
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.io.StringWriter;
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Modifier;
- import java.security.AccessController;
- import java.security.PrivilegedActionException;
- import java.security.PrivilegedExceptionAction;
- import java.util.ArrayList;
- import java.util.BitSet;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Properties;
- import java.util.StringTokenizer;
-
- import org.aspectj.bridge.AbortException;
- import org.aspectj.bridge.IMessage;
-
-
- /**
- * misc lang utilities
- */
- public class LangUtil {
-
- /** Delimiter used by split(String) (and ArrayList.toString()?) */
- public static final String SPLIT_DELIM = ", ";
-
- /** prefix used by split(String) (and ArrayList.toString()?) */
- public static final String SPLIT_START = "[";
-
- /** suffix used by split(String) (and ArrayList.toString()?) */
- public static final String SPLIT_END = "]";
-
- /** system-dependent classpath separator */
- public static final String CLASSPATH_SEP;
-
- private static final String[] NONE = new String[0];
-
- /** bad: hard-wired unix, windows, mac path separators */
- private static final char[] SEPS = new char[] { '/', '\\', ':' };
-
- static {
- // XXX this has to be the wrong way to get system-dependent classpath separator
- String ps = ";";
- try {
- ps = System.getProperty("path.separator");
- if (null == ps) {
- ps = ";";
- String cp = System.getProperty("java.class.path");
- if (null != cp) {
- if (cp.contains(";")) {
- ps = ";";
- } else if (cp.contains(":")) {
- ps = ":";
- }
- // else warn?
- }
- }
- } catch (Throwable t) { // ignore
- } finally {
- CLASSPATH_SEP = ps;
- }
- }
-
- /**
- * @return input if any are empty or no target in input,
- * or input with escape prefixing all original target
- */
- public static String escape(String input, String target, String escape) {
- if (isEmpty(input) || isEmpty(target) || isEmpty(escape)) {
- return input;
- }
- StringBuffer sink = new StringBuffer();
- escape(input, target, escape, sink);
- return sink.toString();
- }
-
-
- /**
- * Append escaped input to sink.
- * Cheap form of arbitrary escaping does not escape the escape String
- * itself, but unflatten treats it as significant only before the target.
- * (so this fails with input that ends with target).
- */
- public static void escape(String input, String target, String escape, StringBuffer sink) {
- if ((null == sink) || isEmpty(input) || isEmpty(target) || isEmpty(escape)) {
- return;
- } else if (!input.contains(target)) { // avoid StringTokenizer construction
- sink.append(input);
- return;
- }
- throw new Error("unimplemented");
- }
-
- /** flatten list per spec to sink */
- public static void flatten(List list, FlattenSpec spec, StringBuffer sink) {
- throwIaxIfNull(spec, "spec");
- final FlattenSpec s = spec;
- flatten(list, s.prefix, s.nullFlattened, s.escape, s.delim, s.suffix, sink);
- }
-
- /**
- * Flatten a List to String by first converting to String[]
- * (using toString() if the elements are not already String)
- * and calling flatten(String[]...).
- */
- public static void flatten(
- List list,
- String prefix,
- String nullFlattened,
- String escape,
- String delim,
- String suffix,
- StringBuffer sink) {
- throwIaxIfNull(list, "list");
- Object[] ra = list.toArray();
- String[] result;
- if (String.class == ra.getClass().getComponentType()) {
- result = (String[]) ra;
- } else {
- result = new String[ra.length];
- for (int i = 0; i < result.length; i++) {
- if (null != ra[i]) {
- result[i] = ra[i].toString();
- }
- }
- }
- flatten(result, prefix, nullFlattened, escape, delim, suffix, sink);
- }
-
-
-
-
- /** flatten String[] per spec to sink */
- public static void flatten(String[] input, FlattenSpec spec, StringBuffer sink) {
- throwIaxIfNull(spec, "spec");
- final FlattenSpec s = spec;
- flatten(input, s.prefix, s.nullFlattened, s.escape, s.delim,s.suffix, sink);
- }
-
-
-
-
- /**
- * Flatten a String[] to String by writing strings to sink,
- * prefixing with leader (if not null),
- * using nullRendering for null entries (skipped if null),
- * escaping any delim in entry by prefixing with escape (if not null),
- * separating entries with delim (if not null),
- * and suffixing with trailer (if not null).
- * Note that nullFlattened is not processed for internal delim,
- * and strings is not copied before processing.
- * @param strings the String[] input - not null
- * @param prefix the output starts with this if not null
- * @param nullFlattened the output of a null entry - entry is skipped (no delim) if null
- * @param escape any delim in an item will be prefixed by escape if not null
- * @param delim two items in the output will be separated by delim if not null
- * @param suffix the output ends with this if not null
- * @param sink the StringBuffer to use for output
- * @return null if sink is not null (results added to sink) or rendering otherwise
- */
- public static void flatten(
- String[] strings,
- String prefix,
- String nullFlattened,
- String escape,
- String delim,
- String suffix,
- StringBuffer sink) {
- throwIaxIfNull(strings, "strings");
- if (null == sink) {
- return;
- }
- final boolean haveDelim = (!isEmpty(delim));
- final boolean haveNullFlattened = (null != nullFlattened);
- final boolean escaping = (haveDelim && (null != escape));
- final int numStrings = (null == strings ? 0 : strings.length);
- if (null != prefix) {
- sink.append(prefix);
- }
- for (int i = 0; i < numStrings; i++) {
- String s = strings[i];
- if (null == s) {
- if (!haveNullFlattened) {
- continue;
- }
- if (haveDelim && (i > 0)) {
- sink.append(delim);
- }
- sink.append(nullFlattened);
- } else {
- if (haveDelim && (i > 0)) {
- sink.append(delim);
- }
-
- if (escaping) {
- escape(s, delim, escape, sink);
- } else {
- sink.append(s);
- }
- }
- }
- if (null != suffix) {
- sink.append(suffix);
- }
- }
-
- /**
- * Get indexes of any invalid entries in array.
- * @param ra the Object[] entries to check
- * (if null, this returns new int[] { -1 })
- * @param superType the Class, if any, to verify that
- * any entries are assignable.
- * @return null if all entries are non-null, assignable to superType
- * or comma-delimited error String, with components
- * <code>"[#] {null || not {superType}"</code>,
- * e.g., "[3] null, [5] not String"
- */
- public static String invalidComponents(Object[] ra, Class superType) {
- if (null == ra) {
- return "null input array";
- } else if (0 == ra.length) {
- return null;
- }
- StringBuffer result = new StringBuffer();
- final String cname = LangUtil.unqualifiedClassName(superType);
- // int index = 0;
- for (int i = 0; i < ra.length; i++) {
- if (null == ra[i]) {
- result.append(", [" + i + "] null");
- } else if ((null != superType)
- && !superType.isAssignableFrom(ra[i].getClass())) {
- result.append(", [" + i + "] not " + cname);
- }
- }
- if (0 == result.length()) {
- return null;
- } else {
- return result.toString().substring(2);
- }
- }
-
- /** @return ((null == ra) || (0 == ra.length)) */
- public static boolean isEmpty(Object[] ra) {
- return ((null == ra) || (0 == ra.length));
- }
-
- /** @return ((null == s) || (0 == s.length())); */
- public static boolean isEmpty(String s) {
- return ((null == s) || (0 == s.length()));
- }
-
-
- /**
- * Throw IllegalArgumentException if any component in input array
- * is null or (if superType is not null) not assignable to superType.
- * The exception message takes the form
- * <code>{name} invalid entries: {invalidEntriesResult}</code>
- * @throws IllegalArgumentException if any components bad
- * @see #invalidComponents(Object[], Class)
- */
- public static final void throwIaxIfComponentsBad(
- final Object[] input,
- final String name,
- final Class superType) {
- String errs = invalidComponents(input, superType);
- if (null != errs) {
- String err = name + " invalid entries: " + errs;
- throw new IllegalArgumentException(err);
- }
- }
- /**
- * 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);
- }
- }
-
- /**
- * 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);
- }
- }
-
- public static ArrayList unflatten(String input, FlattenSpec spec) {
- throwIaxIfNull(spec, "spec");
- final FlattenSpec s = spec;
- return unflatten(input,s.prefix, s.nullFlattened, s.escape, s.delim, s.suffix, s.emptyUnflattened);
- }
-
- /**
- * Unflatten a String to String[] by separating elements at delim,
- * handling prefixes, suffixes, escapes, etc.
- * Any prefix or suffix is stripped from the input
- * (or, if not found, an IllegalArgumentException is thrown).
- * If delim is null or empty or input contains no delim,
- * then return new String[] {stripped input}.
- *
- * XXX fix comments
- * prefixing with leader (if not null),
- * using nullRendering for null entries (skipped if null),
- * escaping any delim in entry by prefixing with escape (if not null),
- * separating entries with delim (if not null),
- * and suffixing with trailer (if not null).
- * Note that nullRendering is not processed for internal delim,
- * and strings is not copied before processing.
- * @param strings the String[] input - not null
- * @param prefix the output starts with this if not null
- * @param nullRendering the output of a null entry - entry is skipped (no delim) if null
- * @param escape any delim in an item will be prefixed by escape if not null
- * @param delim two items in the output will be separated by delim if not null
- * @param suffix the output ends with this if not null
- * @param sink the StringBuffer to use for output
- * @return null if sink is not null (results added to sink) or rendering otherwise
- * @throws IllegalArgumentException if input is null
- * or if any prefix does not start the input
- * or if any suffix does not end the input
- */
- public static ArrayList unflatten(
- String input,
- String prefix,
- String nullFlattened,
- String escape,
- String delim,
- String suffix,
- String emptyUnflattened) {
- throwIaxIfNull(input, "input");
- final boolean haveDelim = (!isEmpty(delim));
- // final boolean haveNullFlattened = (null != nullFlattened);
- // final boolean escaping = (haveDelim && (null != escape));
- if (!isEmpty(prefix)) {
- if (input.startsWith(prefix)) {
- input = input.substring(prefix.length());
- } else {
- String s = "expecting \"" + prefix + "\" at start of " + input + "\"";
- throw new IllegalArgumentException(s);
- }
- }
- if (!isEmpty(suffix)) {
- if (input.endsWith(suffix)) {
- input = input.substring(0, input.length() - suffix.length());
- } else {
- String s = "expecting \"" + suffix + "\" at end of " + input + "\"";
- throw new IllegalArgumentException(s);
- }
- }
-
- final ArrayList result = new ArrayList();
- if (isEmpty(input)) {
- return result;
- }
- if ((!haveDelim) || (!input.contains(delim))) {
- result.add(input);
- return result;
- }
-
- StringTokenizer st = new StringTokenizer(input, delim, true);
- // StringBuffer cur = new StringBuffer();
- // boolean lastEndedWithEscape = false;
- // boolean lastWasDelim = false;
- while (st.hasMoreTokens()) {
- String token = st.nextToken();
- System.out.println("reading " + token);
- if (delim.equals(token)) {
- } else {
- result.add(token);
- }
- }
- return result;
- }
-
- /** combine two string arrays, removing null and duplicates
- * @return concatenation of both arrays, less null in either or dups in two
- * @see Util#combine(Object[], Object[])
- */
- public static String[] combine(String[] one, String[] two) {
- ArrayList twoList = new ArrayList();
- twoList.addAll(org.aspectj.util.LangUtil.arrayAsList(two));
- ArrayList result = new ArrayList();
- if (null != one) {
- for (String s : one) {
- if (null != s) {
- twoList.remove(s);
- result.add(s);
- }
- }
- }
- for (Object o : twoList) {
- String element = (String) o;
- if (null != element) {
- result.add(element);
- }
- }
- return (String[]) result.toArray(NONE);
- }
-
- public static Properties combine(Properties dest, Properties add, boolean respectExisting) { // XXX
- if (null == add) return dest;
- if (null == dest) return add;
- for (Object o : add.keySet()) {
- String key = (String) o;
- if (null == key) {
- continue;
- }
- String value = add.getProperty(key);
- if (null == value) {
- continue;
- }
- if (!respectExisting || (null == dest.getProperty(key))) {
- dest.setProperty(key, value);
- }
- }
- return dest;
- }
-
- public static List arrayAsList(Object[] ra) {
- return org.aspectj.util.LangUtil.arrayAsList(ra);
- }
-
- /**
- * return the fully-qualified class names
- * inferred from the file names in dir
- * assuming dir is the root of the source tree
- * and class files end with ".class".
- * @throws Error if dir is not properly named as prefix
- * of class files found in dir.
- */
- public static String[] classesIn(File dir) {
- boolean alwaysTrue = true;
- FileFilter filter = ValidFileFilter.CLASS_FILE;
- CollectorFileFilter collector = new CollectorFileFilter(filter, alwaysTrue);
- FileUtil.descendFileTree(dir, collector);
- List list = collector.getFiles();
- String[] result = new String[list.size()];
- Iterator it = list.iterator();
- String dirPrefix = dir.getPath();
- for (int i = 0; i < result.length; i++) {
- if (!it.hasNext()) {
- throw new Error("unexpected end of list at " + i);
- }
- result[i] = fileToClassname((File) it.next(), dirPrefix);
- }
- return result;
- }
-
- /**
- * Convert String[] to String by using conventions for
- * split. Will ignore any entries containing SPLIT_DELIM
- * (and write as such to errs if not null).
- * @param input the String[] to convert
- * @param errs the StringBuffer for error messages (if any)
- */
- public static String unsplit(String[] input, StringBuffer errs) {
- StringBuffer sb = new StringBuffer();
- sb.append(SPLIT_START);
- for (int i = 0; i < input.length; i++) {
- if (input[i].contains(SPLIT_DELIM)) {
- if (null != errs) {
- errs.append("\nLangUtil.unsplit(..) - item " + i + ": \"" + input[i]
- + " contains \"" + SPLIT_DELIM + "\"");
- }
- } else {
- sb.append(input[i]);
- if (1+i < input.length) {
- sb.append(SPLIT_DELIM);
- }
- }
- }
- sb.append(SPLIT_END);
- return sb.toString();
-
- }
-
- /**
- * Split input into substrings on the assumption that it is
- * either only one string or it was generated using List.toString(),
- * with tokens
- * <pre>SPLIT_START {string} { SPLIT_DELIM {string}} SPLIT_END<pre>
- * (e.g., <code>"[one, two, three]"</code>).
- */
- public static String[] split(String s) {
- if (null == s) {
- return null;
- }
- if ((!s.startsWith(SPLIT_START)) || (!s.endsWith(SPLIT_END))) {
- return new String[] { s };
- }
- s = s.substring(SPLIT_START.length(),s.length()-SPLIT_END.length());
- final int LEN = s.length();
- int start = 0;
- final ArrayList result = new ArrayList();
- final String DELIM = ", ";
- int loc = s.indexOf(SPLIT_DELIM, start);
- while ((start < LEN) && (-1 != loc)) {
- result.add(s.substring(start, loc));
- start = DELIM.length() + loc;
- loc = s.indexOf(SPLIT_DELIM, start);
- }
- result.add(s.substring(start));
- return (String[]) result.toArray(new String[0]);
- }
-
- public static String[] strip(String[] src, String[] toStrip) {
- if (null == toStrip) {
- return strip(src, NONE);
- } else if (null == src) {
- return strip(NONE, toStrip);
- }
- List slist = org.aspectj.util.LangUtil.arrayAsList(src);
- List tlist = org.aspectj.util.LangUtil.arrayAsList(toStrip);
- slist.removeAll(tlist);
- return (String[]) slist.toArray(NONE);
- }
-
- /**
- * Load all classes specified by args, logging success to out
- * and fail to err.
- */
- public static void loadClasses(String[] args, StringBuffer out,
- StringBuffer err) {
- if (null != args) {
- for (String arg : args) {
- try {
- Class c = Class.forName(arg);
- if (null != out) {
- out.append("\n");
- out.append(arg);
- out.append(": ");
- out.append(c.getName());
- }
- } catch (Throwable t) {
- if (null != err) {
- err.append("\n");
- FileUtil.render(t, err);
- }
- }
- }
-
- }
- }
-
- private static String fileToClassname(File f, String prefix) {
- // this can safely assume file exists, starts at base, ends with .class
- // this WILL FAIL if full path with drive letter on windows
- String path = f.getPath();
- if (!path.startsWith(prefix)) {
- String err = "!\"" + path + "\".startsWith(\"" + prefix + "\")";
- throw new IllegalArgumentException(err);
- }
- int length = path.length() - ".class".length();
- path = path.substring(prefix.length()+1, length);
- for (char sep : SEPS) {
- path = path.replace(sep, '.');
- }
- return path;
- }
-
- public static void main (String[] args) { // todo remove as testing
- StringBuffer err = new StringBuffer();
- StringBuffer out = new StringBuffer();
- for (String arg : args) {
- String[] names = classesIn(new File(arg));
- System.err.println(arg + " -> " + render(names));
- loadClasses(names, out, err);
- }
- if (0 < err.length()) {
- System.err.println(err.toString());
- }
- if (0 < out.length()) {
- System.out.println(out.toString());
- }
- }
-
- public static String render (String[] args) { // todo move as testing
- if ((null == args) || (1 > args.length)) {
- return "[]";
- }
- boolean longFormat = (args.length < 10);
- String sep = (longFormat ? ", " : "\n\t");
- StringBuffer sb = new StringBuffer();
- if (!longFormat) sb.append("[");
- for (int i = 0; i < args.length; i++) {
- if (0 < i) sb.append(sep);
- sb.append(args[i]);
- }
- sb.append(longFormat ? "\n" : "]");
- return sb.toString();
- }
-
-
- /**
- * @param thrown the Throwable to render
- */
- public static String debugStr(Throwable thrown) {
- if (null == thrown) {
- return "((Throwable) null)";
- } else if (thrown instanceof InvocationTargetException) {
- return debugStr(((InvocationTargetException)thrown).getTargetException());
- } else if (thrown instanceof AbortException) {
- IMessage m = ((AbortException) thrown).getIMessage();
- if (null != m) {
- return "" + m;
- }
- }
- StringWriter buf = new StringWriter();
- PrintWriter writer = new PrintWriter(buf);
- writer.println(thrown.getMessage());
- thrown.printStackTrace(writer);
- try { buf.close(); }
- catch (IOException ioe) {}
- return buf.toString();
- }
-
- /**
- * <code>debugStr(o, false);</code>
- * @param source the Object to render
- */
- public static String debugStr(Object o) {
- return debugStr(o, false);
- }
-
- /**
- * Render standard debug string for an object in normal, default form.
- * @param source the Object to render
- * @param recurse if true, then recurse on all non-primitives unless rendered
- */
- public static String debugStr(Object o, boolean recurse) {
- if (null == o) {
- return "null";
- } else if (recurse) {
- ArrayList rendering = new ArrayList();
- rendering.add(o);
- return debugStr(o, rendering);
- } else {
- Class c = o.getClass();
- Field[] fields = c.getDeclaredFields();
- Object[] values = new Object[fields.length];
- String[] names = new String[fields.length];
- for (int i = 0; i < fields.length; i++) {
- Field field = fields[i];
- names[i] = field.getName();
- try {
- values[i] = field.get(o);
- if (field.getType().isArray()) {
- List list = org.aspectj.util.LangUtil.arrayAsList((Object[]) values[i]);
- values[i] = list.toString();
- }
- } catch (IllegalAccessException e) {
- values[i] = "<IllegalAccessException>";
- }
- }
- return debugStr(c, names, values);
- }
- }
-
- /**
- * recursive variant avoids cycles.
- * o added to rendering before call.
- */
- private static String debugStr(Object o, ArrayList rendering) {
- if (null == o) {
- return "null";
- } else if (!rendering.contains(o)) {
- throw new Error("o not in rendering");
- }
- Class c = o.getClass();
- if (c.isArray()) {
- Object[] ra = (Object[]) o;
- StringBuffer sb = new StringBuffer();
- sb.append("[");
- for (int i = 0; i < ra.length; i++) {
- if (i > 0) {
- sb.append(", ");
- }
- rendering.add(ra[i]);
- sb.append(debugStr(ra[i], rendering));
- }
- sb.append("]");
- return sb.toString();
- }
- Field[] fields = nonStaticFields(c.getFields());
- Object[] values = new Object[fields.length];
- String[] names = new String[fields.length];
- for (int i = 0; i < fields.length; i++) {
- Field field = fields[i];
- names[i] = field.getName();
- // collapse to String
- Object value = privilegedGetField(field,o);
- if (null == value) {
- values[i] = "null";
- } else if (rendering.contains(value)) {
- values[i] = "<recursion>";
- } else {
- rendering.add(value);
- values[i] = debugStr(value, rendering);
- }
- }
- return debugStr(c, names, values);
- }
-
- /** incomplete - need protection domain */
- private static Object privilegedGetField(final Field field, final Object o) {
- try {
- return AccessController.doPrivileged(new PrivilegedExceptionAction() {
- public Object run() {
- try {
- return field.get(o);
- } catch(IllegalAccessException e) {
- return "<IllegalAccessException>";
- }
- }
- });
- } catch (PrivilegedActionException e) {
- return "<IllegalAccessException>";
- }
- }
-
- private static Field[] nonStaticFields(Field[] fields) {
- if (null == fields) {
- return new Field[0];
- }
- int to = 0;
- int from = 0;
- while (from < fields.length) {
- if (!Modifier.isStatic(fields[from].getModifiers())) {
- if (to != from) {
- fields[to] = fields[from];
- }
- to++;
- }
- from++;
- }
- if (to < from) {
- Field[] result = new Field[to];
- if (to > 0) {
- System.arraycopy(fields, 0, result, 0, to);
- }
- fields = result;
- }
- return fields;
- }
-
- /** <code> debugStr(source, names, items, null, null, null, null)<code> */
- public static String debugStr(Class source, String[] names, Object[] items) {
- return debugStr(source, null, names, null, items, null, null);
- }
-
- /**
- * Render standard debug string for an object.
- * This is the normal form and an example with the default values:<pre>
- * {className}{prefix}{{name}{infix}{value}{delimiter}}..{suffix}
- * Structure[head=root, tail=leaf]</pre>
- * Passing null for the formatting entries provokes the default values,
- * so to print nothing, you should pass "". Default values:<pre>
- * prefix: "[" SPLIT_START
- * infix: "="
- * delimiter: ", " SPLIT_DELIM
- * suffix: "]" SPLIT_END
- * @param source the Class prefix to render unqualified - omitted if null
- * @param names the String[] (field) names of the items - omitted if null
- * @param items the Object[] (field) values
- * @param prefix the String to separate classname and start of name/values
- * @param delimiter the String to separate name/value instances
- * @param infix the String to separate name and value
- * used only if both name and value exist
- * @param suffix the String to delimit the end of the name/value instances
- * used only if classname exists
- */
- public static String debugStr(Class source, String prefix, String[] names,
- String infix, Object[] items, String delimiter, String suffix) {
-
- if (null == delimiter) {
- delimiter = SPLIT_DELIM;
- }
- if (null == prefix) {
- prefix = SPLIT_START;
- }
- if (null == infix) {
- infix = "=";
- }
- if (null == suffix) {
- suffix = SPLIT_END;
- }
- StringBuffer sb = new StringBuffer();
- if (null != source) {
- sb.append(org.aspectj.util.LangUtil.unqualifiedClassName(source));
- }
- sb.append(prefix);
- if (null == names) {
- names = NONE;
- }
- if (null == items) {
- items = NONE;
- }
- final int MAX
- = (names.length > items.length ? names.length : items.length);
- for (int i = 0; i < MAX; i++) {
- if (i > 0) {
- sb.append(delimiter);
- }
- if (i < names.length) {
- sb.append(names[i]);
- }
- if (i < items.length) {
- if (i < names.length) {
- sb.append(infix);
- }
- sb.append(items[i] + "");
- }
- }
- sb.append(suffix);
- return sb.toString();
- }
-
- /**
- * @return a String with the unqualified class name of the object (or "null")
- */
- public static String unqualifiedClassName(Object o) {
- return unqualifiedClassName(null == o ? null : o.getClass());
- }
-
- /**
- * @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;
- }
-
- /**
- * Calculate exact diffs and report missing and extra items.
- * This assumes the input List are not modified concurrently.
- * @param expectedListIn the List of expected results - treated as empty if null
- * @param actualListIn the List of actual results - treated as empty if null
- * @param extraListOut the List for any actual results not expected - ignored if null
- * @param missingListOut the List for any expected results not found - ignored if null
- * */
- public static void makeDiffs(
- List expectedListIn,
- List actualListIn,
- List missingListOut,
- List extraListOut) {
- if ((null == missingListOut) && (null == extraListOut)) {
- return;
- }
- if (null == expectedListIn) {
- expectedListIn = Collections.EMPTY_LIST;
- }
- if (null == actualListIn) {
- actualListIn = Collections.EMPTY_LIST;
- }
- if ((0 == actualListIn.size()) && (0 == expectedListIn.size()) ) {
- return;
- }
- BitSet actualExpected = new BitSet();
- for (Object expect : expectedListIn) {
- int loc = actualListIn.indexOf(expect);
- if (-1 == loc) {
- if (null != missingListOut) {
- missingListOut.add(expect);
- }
- } else {
- actualExpected.set(loc);
- }
- }
- if (null != extraListOut) {
- for (int i = 0; i < actualListIn.size(); i++) {
- if (!actualExpected.get(i)) {
- extraListOut.add(actualListIn.get(i));
- }
- }
- }
- }
- // XXX unit test for makeSoftDiffs
- /**
- * Calculate potentially "soft" diffs using
- * Comparator.compare(expected, actual).
- * This shallow-copies and sorts the input Lists.
- * @param expectedListIn the List of expected results - treated as empty if null
- * @param actualListIn the List of actual results - treated as empty if null
- * @param extraListOut the List for any actual results not expected - ignored if null
- * @param missingListOut the List for any expected results not found - ignored if null
- * @param comparator the Comparator for comparisons - not null
- * @throws IllegalArgumentException if comp is null
- */
- public static void makeSoftDiffs( // XXX no intersect or union on collections???
- List expectedListIn,
- List actualListIn,
- List missingListOut,
- List extraListOut,
- Comparator comparator) {
- if ((null == missingListOut) && (null == extraListOut)) {
- return;
- }
- if (null == comparator) {
- throw new IllegalArgumentException("null comparator");
- }
- if (null == expectedListIn) {
- expectedListIn = Collections.EMPTY_LIST;
- }
- if (null == actualListIn) {
- actualListIn = Collections.EMPTY_LIST;
- }
- if ((0 == actualListIn.size()) && (0 == expectedListIn.size()) ) {
- return;
- }
-
- ArrayList expected = new ArrayList();
- expected.addAll(expectedListIn);
- Collections.sort(expected, comparator);
-
- ArrayList actual = new ArrayList();
- actual.addAll(actualListIn);
- Collections.sort(actual, comparator);
- Iterator actualIter = actual.iterator();
- Object act = null;
-
- if (missingListOut != null) {
- missingListOut.addAll(expectedListIn);
- }
- if (extraListOut != null) {
- extraListOut.addAll(actualListIn);
- }
-
- // AMC: less efficient, but simplified implementation. Needed since messages can
- // now match on text content too, and the old algorithm did not cope with two expected
- // messages on the same line, but with different text content.
- while (actualIter.hasNext()) {
- act = actualIter.next();
- for (Object exp : expected) {
- // if actual matches expected remove actual from extraListOut, and
- // remove expected from missingListOut
- int diff = comparator.compare(exp, act);
- if (diff == 0) {
- extraListOut.remove(act);
- missingListOut.remove(exp);
- } else if (diff > 0) {
- // since list is sorted, there can be no more matches...
- break;
- }
- }
- }
-
- // while (((null != act) || actualIter.hasNext())
- // && ((null != exp) || expectedIter.hasNext())) {
- // if (null == act) {
- // act = actualIter.next();
- // }
- // if (null == exp) {
- // exp = expectedIter.next();
- // }
- // int diff = comparator.compare(exp, act);
- // if (0 > diff) { // exp < act
- // if (null != missingListOut) {
- // missingListOut.add(exp);
- // exp = null;
- // }
- // } else if (0 < diff) { // exp > act
- // if (null != extraListOut) {
- // extraListOut.add(act);
- // act = null;
- // }
- // } else { // got match of actual to expected
- // // absorb all actual matching expected (duplicates)
- // while ((0 == diff) && actualIter.hasNext()) {
- // act = actualIter.next();
- // diff = comparator.compare(exp, act);
- // }
- // if (0 == diff) {
- // act = null;
- // }
- // exp = null;
- // }
- // }
- // if (null != missingListOut) {
- // if (null != exp) {
- // missingListOut.add(exp);
- // }
- // while (expectedIter.hasNext()) {
- // missingListOut.add(expectedIter.next());
- // }
- // }
- // if (null != extraListOut) {
- // if (null != act) {
- // extraListOut.add(act);
- // }
- // while (actualIter.hasNext()) {
- // extraListOut.add(actualIter.next());
- // }
- // }
- }
- public static class FlattenSpec {
- /**
- * This tells unflatten(..) to throw IllegalArgumentException
- * if it finds two contiguous delimiters.
- */
- public static final String UNFLATTEN_EMPTY_ERROR
- = "empty items not permitted when unflattening";
- /**
- * This tells unflatten(..) to skip empty items when unflattening
- * (since null means "use null")
- */
- public static final String UNFLATTEN_EMPTY_AS_NULL
- = "unflatten empty items as null";
-
- /**
- * This tells unflatten(..) to skip empty items when unflattening
- * (since null means "use null")
- */
- public static final String SKIP_EMPTY_IN_UNFLATTEN
- = "skip empty items when unflattening";
-
- /**
- * For Ant-style attributes: "item,item" (with escaped commas).
- * There is no way when unflattening to distinguish
- * values which were empty from those which were null,
- * so all are unflattened as empty.
- */
- public static final FlattenSpec COMMA
- = new FlattenSpec(null, "", "\\", ",", null, "") {
- public String toString() { return "FlattenSpec.COMMA"; }
- };
-
- /** this attempts to mimic ((List)l).toString() */
- public static final FlattenSpec LIST
- = new FlattenSpec("[", "", null, ", ", "]", UNFLATTEN_EMPTY_ERROR) {
- public String toString() { return "FlattenSpec.LIST"; }
- };
-
- /** how toString renders null values */
- public static final String NULL = "<null>";
- private static String r(String s) {
- return (null == s ? NULL : s);
- }
-
- public final String prefix;
- public final String nullFlattened;
- public final String escape;
- public final String delim;
- public final String suffix;
- public final String emptyUnflattened;
- private transient String toString;
-
- public FlattenSpec(
- String prefix,
- String nullRendering,
- String escape,
- String delim,
- String suffix,
- String emptyUnflattened) {
- this.prefix = prefix;
- this.nullFlattened = nullRendering;
- this.escape = escape;
- this.delim = delim;
- this.suffix = suffix;
- this.emptyUnflattened = emptyUnflattened;
- throwIaxIfNull(emptyUnflattened, "use UNFLATTEN_EMPTY_AS_NULL");
- }
-
- public String toString() {
- if (null == toString) {
- toString = "FlattenSpec("
- + "prefix=" + r(prefix)
- + ", nullRendering=" + r(nullFlattened)
- + ", escape=" + r(escape)
- + ", delim=" + r(delim)
- + ", suffix=" + r(suffix)
- + ", emptyUnflattened=" + r(emptyUnflattened)
- + ")";
- }
- return toString;
- }
- }
- } // class LangUtil
-
- // --------- java runs using Ant
- // /**
- // * Run a Java command separately.
- // * @param className the fully-qualified String name of the class
- // * with the main method to run
- // * @param classpathFiles the File to put on the classpath
- // * @param args to the main method of the class
- // * @param outSink the PrintStream for the output stream - may be null
- // */
- // public static void oldexecuteJava(
- // String className,
- // File[] classpathFiles,
- // String[] args,
- // PrintStream outSink) {
- // Project project = new Project();
- // project.setName("LangUtil.executeJava(" + className + ")");
- // Path classpath = new Path(project, classpathFiles[0].getAbsolutePath());
- // for (int i = 1; i < classpathFiles.length; i++) {
- // classpath.addExisting(new Path(project, classpathFiles[i].getAbsolutePath()));
- // }
- //
- // Commandline cmds = new Commandline();
- // cmds.addArguments(new String[] {className});
- // cmds.addArguments(args);
- //
- // ExecuteJava runner = new ExecuteJava();
- // runner.setClasspath(classpath);
- // runner.setJavaCommand(cmds);
- // if (null != outSink) {
- // runner.setOutput(outSink); // XXX todo
- // }
- // runner.execute(project);
- // }
-
- // public static void executeJava(
- // String className,
- // File dir,
- // File[] classpathFiles,
- // String[] args,
- // PrintStream outSink) {
- // StringBuffer sb = new StringBuffer();
- //
- // sb.append("c:/apps/jdk1.3.1/bin/java.exe -classpath \"");
- // for (int i = 0; i < classpathFiles.length; i++) {
- // if (i < 0) {
- // sb.append(";");
- // }
- // sb.append(classpathFiles[i].getAbsolutePath());
- // }
- // sb.append("\" -verbose " + className);
- // for (int i = 0; i < args.length; i++) {
- // sb.append(" " + args[i]);
- // }
- // Exec exec = new Exec();
- // Project project = new Project();
- // project.setProperty("ant.home", "c:/home/wes/aj/aspectj/modules/lib/ant");
- // System.setProperty("ant.home", "c:/home/wes/aj/aspectj/modules/lib/ant");
- // exec.setProject(new Project());
- // exec.setCommand(sb.toString());
- // exec.setDir(dir.getAbsolutePath());
- // exec.execute();
- // }
- // public static void execJavaProcess(
- // String className,
- // File dir,
- // File[] classpathFiles,
- // String[] args,
- // PrintStream outSink) throws Throwable {
- // StringBuffer sb = new StringBuffer();
- //
- // sb.append("c:\\apps\\jdk1.3.1\\bin\\java.exe -classpath \"");
- // for (int i = 0; i < classpathFiles.length; i++) {
- // if (i > 0) {
- // sb.append(";");
- // }
- // sb.append(classpathFiles[i].getAbsolutePath());
- // }
- // sb.append("\" -verbose " + className);
- // for (int i = 0; i < args.length; i++) {
- // sb.append(" " + args[i]);
- // }
- // String command = sb.toString();
- // System.err.println("launching process: " + command);
- // Process process = Runtime.getRuntime().exec(command);
- // // huh? err/out
- // InputStream errStream = null;
- // InputStream outStream = null;
- // Throwable toThrow = null;
- // int result = -1;
- // try {
- // System.err.println("waiting for process: " + command);
- // errStream = null; // process.getErrorStream();
- // outStream = null; // process.getInputStream(); // misnamed - out
- // result = process.waitFor();
- // System.err.println("Done waiting for process: " + command);
- // process.destroy();
- // } catch (Throwable t) {
- // toThrow = t;
- // } finally {
- // if (null != outStream) {
- // FileUtil.copy(outStream, System.out, false);
- // try { outStream.close(); }
- // catch (IOException e) {}
- // }
- // if (null != errStream) {
- // FileUtil.copy(errStream, System.err, false);
- // try { errStream.close(); }
- // catch (IOException e) {}
- // }
- // }
- // if (null != toThrow) {
- // throw toThrow;
- // }
- // }
- // try {
- // // show the command
- // log(command, Project.MSG_VERBOSE);
- //
- // // exec command on system runtime
- // Process proc = Runtime.getRuntime().exec(command);
- //
- // if (out != null) {
- // fos = new PrintWriter(new FileWriter(out));
- // log("Output redirected to " + out, Project.MSG_VERBOSE);
- // }
- //
- // // copy input and error to the output stream
- // StreamPumper inputPumper =
- // new StreamPumper(proc.getInputStream(), Project.MSG_INFO);
- // StreamPumper errorPumper =
- // new StreamPumper(proc.getErrorStream(), Project.MSG_WARN);
- //
- // // starts pumping away the generated output/error
- // inputPumper.start();
- // errorPumper.start();
- //
- // // Wait for everything to finish
- // proc.waitFor();
- // inputPumper.join();
- // errorPumper.join();
- // proc.destroy();
- //
- // // close the output file if required
- // logFlush();
- //
- // // check its exit value
- // err = proc.exitValue();
- // if (err != 0) {
- // if (failOnError) {
- // throw new BuildException("Exec returned: " + err, getLocation());
- // } else {
- // log("Result: " + err, Project.MSG_ERR);
- // }
- // }
- // } catch (IOException ioe) {
- // throw new BuildException("Error exec: " + command, ioe, getLocation());
- // } catch (InterruptedException ex) {}
- //
-
|