1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189 |
- /* *******************************************************************
- * 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.testing.harness.bridge;
-
- import java.io.File;
- import java.io.PrintStream;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.BitSet;
- import java.util.Iterator;
- import java.util.List;
- import java.util.ListIterator;
- import java.util.StringTokenizer;
-
- import org.aspectj.bridge.*;
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.IMessageHandler;
- import org.aspectj.bridge.ISourceLocation;
- import org.aspectj.bridge.MessageHandler;
- import org.aspectj.bridge.MessageUtil;
- import org.aspectj.testing.run.IRunIterator;
- //import org.aspectj.testing.util.*;
- import org.aspectj.testing.util.BridgeUtil;
- import org.aspectj.testing.util.options.*;
- import org.aspectj.testing.util.options.Option.InvalidInputException;
- import org.aspectj.testing.xml.IXmlWritable;
- import org.aspectj.testing.xml.SoftMessage;
- import org.aspectj.testing.xml.XMLWriter;
- import org.aspectj.util.LangUtil;
-
- /**
- * Base class for initialization of components expecting messages,
- * options, files/paths, and source locations (resolved files),
- * and potentially containing child Spec.
- * <p>
- * <u>initialization</u>: This defines bean/xml setters for all.
- * This converts String to IMessage using
- * {@link MessageUtil#readMessage(String)}
- * and String to ISourceLocation using
- * {@link BridgeUtil#makeSourceLocation(input)}.
- * See those APIs for input form and limitations.
- * A Spec also accepts (or rejects) runtime configuration from a parent
- * in {@link adoptParentValues(RT, IMessageHandler)}.
- * Since some children Spec may balk but this parent Spec continue,
- * use {@link getChildren()} to get the full list of children Spec,
- * but {@link getWorkingChildren()} to get the list of children that
- * are not being skipped in accordance with runtime configuration.
- * <p>
- * <u>subclassing</u>: subclasses wishing other than
- * the default behavior for reading String input should override the
- * corresponding (bean) setter. They can also override the
- * add{foo} methods to get notice or modify objects constructed
- * from the input.
- * <p>
- * <u>bean properties</u>: because this is designed to work
- * by standard Java bean introspection, take care to follow
- * bean rules when adding methods. In particular, a property
- * is illegal if the setter takes a different type than the
- * getter returns. That means, e.g., that all List and array[] getters
- * should be named "get{property}[List|Array]". Otherwise
- * the XML readers will silently fail to set the property
- * (perhaps with trace information that the property had
- * no write method or was read-only).
- * <p>
- * <u>Coordination with writers</u>: because this reads the contents
- * of values written by IXmlWritable, they should ensure their
- * values are readable. When flattening and unflattening
- * lists, the convention is to use the {un}flattenList(..) methods
- * in XMLWriter.
- * @see XMLWriter@unflattenList(String)
- * @see XMLWriter@flattenList(List)
- */
- abstract public class AbstractRunSpec implements IRunSpec { // XXX use MessageHandler?
-
-
- private static final Fork FORK;
-
- static {
- String value =
- Globals.getSystemProperty(Globals.FORK_NAME, null);
- FORK = (LangUtil.isEmpty(value)
- ? Fork.NOFORK
- : new Fork(value));
- }
- /** true if we expect to use a staging directory */
- boolean isStaging;
-
- /** true if this spec permits bad input (e.g., to test error handling) */
- boolean badInput;
-
- protected String description;
-
- /** optional source location of the specification itself */
- protected ISourceLocation sourceLocation;
-
- private BitSet skipSet;
- private boolean skipAll;
-
- protected String xmlElementName; // nonfinal only for clone()
- protected final ArrayList /*String*/ keywords;
- protected final IMessageHolder /*IMessage*/ messages;
- protected final ArrayList /*String*/ options;
- protected final ArrayList /*String*/ paths;
- protected final ArrayList /*ISourceLocation*/ sourceLocations; // XXX remove?
- protected final ArrayList /*IRunSpec*/ children;
- protected final ArrayList /*DirChanges.Spec*/ dirChanges;
- protected XMLNames xmlNames;
- protected String comment;
-
- /** These options are 1:1 with spec, but set at runtime (not saved) */
- public final RT runtime;
-
- /** if true, then any child skip causes this to skip */
- protected boolean skipIfAnyChildSkipped; // nonfinal only for cloning
-
- public AbstractRunSpec(String xmlElementName) {
- this(xmlElementName, true);
- }
-
- public AbstractRunSpec(String xmlElementName, boolean skipIfAnyChildSkipped) {
- if (null == xmlElementName) {
- xmlElementName = "spec";
- }
- this.xmlElementName = xmlElementName;
- messages = new MessageHandler(true);
- options = new ArrayList();
- paths = new ArrayList();
- sourceLocations = new ArrayList();
- keywords = new ArrayList();
- children = new ArrayList();
- dirChanges = new ArrayList();
- xmlNames = XMLNames.DEFAULT;
- runtime = new RT();
- this.skipIfAnyChildSkipped = skipIfAnyChildSkipped;
- }
-
-
- /** @param comment ignored if null */
- public void setComment(String comment) {
- if (!LangUtil.isEmpty(comment)) {
- this.comment = comment;
- }
- }
-
- public void setStaging(boolean staging) {
- isStaging = staging;
- }
-
- public void setBadInput(boolean badInput) {
- this.badInput = badInput;
- }
-
- boolean isStaging() {
- return isStaging;
- }
-
- // ------- description (title, label...)
- public void setDescription(String description) {
- this.description = description;
- }
-
- public String getDescription() {
- return description;
- }
- // ------- source location of the spec
-
- public void setSourceLocation(ISourceLocation sourceLocation) {
- this.sourceLocation = sourceLocation;
- }
-
- public ISourceLocation getSourceLocation() {
- return sourceLocation;
- }
-
- // ------- keywords
- /** @param keyword added after trimming if not empty */
- public void setKeyword(String keyword) {
- addKeyword(keyword);
- }
-
- /** Add keyword if non-empty and not duplicate */
- public void addKeyword(String keyword) {
- if (!LangUtil.isEmptyTrimmed(keyword)) {
- keyword = keyword.trim();
- if (!keywords.contains(keyword)) {
- keywords.add(keyword);
- }
- }
- }
- public void setKeywords(String items) {
- addKeywords(items);
- }
-
- public void addKeywords(String items) {
- if (null != items) {
- addKeywords(XMLWriter.unflattenList(items));
- }
- }
- public void addKeywords(String[] ra) {
- if (null != ra) {
- for (int i = 0; i < ra.length; i++) {
- addKeyword(ra[i]);
- }
- }
- }
- public ArrayList getKeywordsList() {
- return makeList(keywords);
- }
-
- // ------- options - String args
-
- /** @return ArrayList of String options */
- public ArrayList getOptionsList() {
- return makeList(options);
- }
-
- /** @return String[] of options */
- public String[] getOptionsArray() {
- return (String[]) options.toArray(new String[0]);
- }
-
- public void setOption(String option) {
- addOption(option);
- }
-
- public void addOption(String option) {
- if ((null != option) && (0 < option.length())) {
- options.add(option);
- }
- }
-
- /** add options (from XML/bean) - removes any existing options */
- public void setOptions(String items) {
- this.options.clear();
- addOptions(items);
- }
-
- /**
- * Set options, removing any existing options.
- * @param options String[] options to use - may be null or empty
- */
- public void setOptionsArray(String[] options) {
- this.options.clear();
- if (!LangUtil.isEmpty(options)) {
- this.options.addAll(Arrays.asList(options));
- }
- }
-
- public void addOptions(String items) {
- if (null != items) {
- addOptions(XMLWriter.unflattenList(items));
- }
- }
-
- public void addOptions(String[] ra) {
- if (null != ra) {
- for (int i = 0; i < ra.length; i++) {
- addOption(ra[i]);
- }
- }
- }
-
- // -------------- source locations
- // /** @return ArrayList of ISourceLocation sourceLocs */
- // public ArrayList getSourceLocationsList() {
- // return makeList(sourceLocations);
- // }
- //
- // /** @return ISourceLocation[] sourceLocs */
- // public ISourceLocation[] getSourceLocationsArray() {
- // return (ISourceLocation[]) sourceLocations.toArray(new ISourceLocation[0]);
- // }
- //
- //
- // public void setSourceLocation(String input) {
- // if (null != input) {
- // ISourceLocation sl = BridgeUtil.makeSourceLocation(input);
- // if (null != sl) {
- // addSourceLocation(sl);
- // }
- // // XXX need error-handling for bad input
- // }
- // }
- //
- // public void addSourceLocation(ISourceLocation sourceLoc) {
- // if (null != sourceLoc) {
- // sourceLocations.add(sourceLoc);
- // }
- // }
-
- // --------------- (String) paths
- /** @return ArrayList of String paths */
- public ArrayList getPathsList() {
- return makeList(paths);
- }
-
- /** @return String[] of paths */
- public String[] getPathsArray() {
- return (String[]) paths.toArray(new String[0]);
- }
-
- // /** @return String[] of paths, removing any matching stripPrefix prefix */
- // public String[] getPathsArray(String stripPrefix) {
- // String[] result = getPathsArray();
- // if (!LangUtil.isEmpty(stripPrefix)) {
- // final int LEN = stripPrefix.length();
- // for (int i = 0; i < result.length; i++) {
- // if ((null != result[i]) && result[i].startsWith(stripPrefix)) {
- // result[i] = result[i].substring(LEN);
- // }
- // }
- // }
- // return result;
- // }
- //
- // /** @return ArrayList of File baseDir/{path} */
- // public ArrayList getPathsAsFile(File baseDir) {
- // if (null == baseDir) {
- // baseDir = new File(".");
- // }
- // ArrayList result = makeList(null);
- // for (Iterator iter = paths.iterator(); iter.hasNext();) {
- // String path = (String) iter.next();
- // result.add(new File(baseDir, path));
- // }
- // return result;
- // }
-
- public void setPath(String path) {
- addPath(path);
- }
-
- public void setPaths(String paths) {
- addPaths(paths);
- }
-
- public void addPath(String path) {
- if (null != path) {
- paths.add(path);
- }
- }
-
- public void addPaths(String items) {
- if (null != items) {
- addPaths(XMLWriter.unflattenList(items));
- }
- }
-
- public void addPaths(String[] ra) {
- if (null != ra) {
- for (int i = 0; i < ra.length; i++) {
- addPath(ra[i]);
- }
- }
- }
-
- public void addWrapFile(WrapFile file) {
- if (null != file) {
- paths.add(file.path);
- }
- }
-
- // --------------------- dir changes
- public void addDirChanges(DirChanges.Spec dirChangesSpec) {
- if (null != dirChangesSpec) {
- dirChanges.add(dirChangesSpec);
- }
- }
-
- // --------------------- messages
- public void setMessage(String message) {
- addMessage(message);
- }
-
- public void addMessage(IMessage message) {
- if (null != message) {
- if (!messages.handleMessage(message)) {
- String s = "invalid message: " + message;
- throw new IllegalArgumentException(s);
- }
- }
- }
-
- public void addMessage(String message) {
- if (null != message) {
- addMessage(BridgeUtil.readMessage(message));
- }
- }
-
- /** this can ONLY work if each item has no internal comma
- */
- public void addMessages(String items) {
- if (null != items) {
- String[] ra = XMLWriter.unflattenList(items);
- for (int i = 0; i < ra.length; i++) {
- addMessage(ra[i]);
- }
- }
- }
- public void addMessages(List messages) {
- if (null != messages) {
- for (Iterator iter = messages.iterator(); iter.hasNext();) {
- Object o = iter.next();
- if (o instanceof IMessage) {
- addMessage((IMessage) o);
- } else {
- // XXX warning?
- }
- }
- }
- }
-
- /** @return int number of message of this kind (optionally or greater */
- public int numMessages(IMessage.Kind kind, boolean orGreater) {
- return messages.numMessages(kind, orGreater);
- }
-
- public IMessageHolder getMessages() {
- return messages;
- }
-
-
- public void addChild(IRunSpec child) {
- // fyi, child is added when complete (depth-first), not when initialized,
- // so cannot affect initialization of child here
- if (null != child) {
- children.add(child);
- }
- }
-
- /** @return copy of children list */
- public ArrayList getChildren() {
- return makeList(children);
- }
-
- /** @return copy of children list without children to skip */
- public ArrayList getWorkingChildren() {
- if (skipAll) {
- return new ArrayList();
- }
- if (null == skipSet) {
- return getChildren();
- }
- ArrayList result = new ArrayList();
- int i = 0;
- for (Iterator iter = children.listIterator();
- iter.hasNext(); i++) {
- Object child = iter.next();
- if (!skipSet.get(i)) {
- result.add(child);
- }
- }
- return result;
- }
-
- /**
- * Recursively absorb parent values if different.
- * This implementation calls doAdoptParentValues(..)
- * and then calls this for any children.
- * This is when skipped children are determined.
- * Children may elect to balk at this point, reducing the
- * number of children or causing this spec to skip if
- * skipIfAnyChildrenSkipped. For each test skipped, either
- * this doAdoptParentValues(..) or the child's adoptParentValues(..)
- * should add one info message with the reason this is being skipped.
- * The only reason to override this would be to NOT
- * invoke the same for children, or to do something similar
- * for children which are not AbstractRunSpec.
- * @param parentRuntime the RT values to adopt - ignored if null
- * @param handler the IMessageHandler for info messages when skipping
- * @return false if this wants to be skipped, true otherwise
- */
- public boolean adoptParentValues(RT parentRuntime, IMessageHandler handler) {
- boolean skipped = false;
- skipAll = false;
- skipSet = new BitSet();
- if (null != parentRuntime) {
- skipped = !doAdoptParentValues(parentRuntime, handler);
- if (skipped && skipIfAnyChildSkipped) { // no need to continue checking
- skipAll = true;
- return false;
- }
- int i = 0;
- for (ListIterator iter = children.listIterator(); iter.hasNext(); i++) {
- IRunSpec child = (IRunSpec) iter.next();
- if (child instanceof AbstractRunSpec) { // XXX ugly instanceof
- AbstractRunSpec arsChild = (AbstractRunSpec) child;
- if (!arsChild.adoptParentValues(runtime, handler)) {
- skipSet.set(i);
- //iter.remove();
- if (!skipped) {
- skipped = true;
- if (skipIfAnyChildSkipped) { // no need to continue checking
- // String m = "skipping " + toString() + " because child "
- // + arsChild + " skipped";
- // MessageUtil.info(handler, m);
- skipAll = true;
- //children.clear();
- return false;
- }
- }
- }
- }
- }
- }
- return true;
- }
-
- /**
- * Adopt parent values.
- * This implementation makes a local copy.
- * If we interpret (and absorb) any options, they should be removed
- * from parentRuntime.
- * This sets verbose if different (override)
- * and directly adopts parentOptions if ours is null
- * and otherwise adds any non-null options we don't already have.
- * setting verbose and adding to parent options.
- * Implementors override this to affect how parent values are adopted.
- * Implementors should not recurse into children.
- * This method may be called multiple times, so implementors
- * should not destroy any spec information.
- * Always add an info message when returning false to skip
- * @param parentRuntime the RT values to adopt - never null
- * @return false if this wants to be skipped, true otherwise
- */
- protected boolean doAdoptParentValues(RT parentRuntime, IMessageHandler handler) {
- if (runtime.verbose != parentRuntime.verbose) {
- runtime.verbose = parentRuntime.verbose;
- }
- if (!LangUtil.isEmpty(runtime.parentOptions)) {
- runtime.parentOptions.clear();
- }
- if (!LangUtil.isEmpty(parentRuntime.parentOptions)) {
- runtime.parentOptions.addAll(parentRuntime.parentOptions);
- }
- return true;
- }
-
- /**
- * Implementations call this when signalling skips to ensure consistency
- * in message formatting
- * @param handler the IMessageHandler sink - not null
- * @param reason the String reason to skip - not null
- */
- protected void skipMessage(IMessageHandler handler, String reason) {
- LangUtil.throwIaxIfNull(handler, "handler");
- LangUtil.throwIaxIfNull(handler, "reason");
- // XXX for Runs, label does not identify the test
- String label = toString();
- MessageUtil.info(handler, "skipping \"" + label + "\" because " + reason);
- }
-
- // --------------------------- writing xml - would prefer castor..
-
- /**
- * Control XML output by renaming or suppressing output for
- * attributes and subelements.
- * Subelements are skipped by setting the XMLNames booleans to false.
- * Attributes are skipped by setting their name to null.
- * @param names XMLNames with new names and/or suppress flags.
- */
- protected void setXMLNames(XMLNames names) {
- if (null != names) {
- xmlNames = names;
- }
- }
-
- // /** @return null if value is null or name="{value}" otherwise */
- // private String makeAttr(XMLWriter out, String name, String value) {
- // if (null == value) {
- // return null;
- // }
- // return XMLWriter.makeAttribute(name, value);
- // }
- //
- // /** @return null if list is null or empty or name="{flattenedList}" otherwise */
- // private String makeAttr(XMLWriter out, String name, List list) {
- // if (LangUtil.isEmpty(list)) {
- // return null;
- // }
- // String flat = XMLWriter.flattenList(list);
- // return XMLWriter.makeAttribute(name, flat);
- // }
- //
- /** @return true if writeAttributes(..) will produce any output */
- protected boolean haveAttributes() {
- return ((!LangUtil.isEmpty(xmlNames.descriptionName)
- && !LangUtil.isEmpty(description))
- || (!LangUtil.isEmpty(xmlNames.keywordsName)
- && !LangUtil.isEmpty(keywords))
- || (!LangUtil.isEmpty(xmlNames.optionsName)
- && !LangUtil.isEmpty(options))
- || (!LangUtil.isEmpty(xmlNames.pathsName)
- && !LangUtil.isEmpty(paths)));
- }
-
- /**
- * Write attributes without opening or closing elements/attributes.
- * An attribute is written only if the value is not empty
- * and the name in xmlNames is not empty
- */
- protected void writeAttributes(XMLWriter out) {
- if (!LangUtil.isEmpty(xmlNames.descriptionName)
- && !LangUtil.isEmpty(description)) {
- out.printAttribute(xmlNames.descriptionName, description);
- }
- if (!LangUtil.isEmpty(xmlNames.keywordsName)
- && !LangUtil.isEmpty(keywords)) {
- out.printAttribute(xmlNames.keywordsName,
- XMLWriter.flattenList(keywords));
- }
- if (!LangUtil.isEmpty(xmlNames.optionsName)
- && !LangUtil.isEmpty(options)) {
- out.printAttribute(xmlNames.optionsName, XMLWriter.flattenList(options));
- }
- if (!LangUtil.isEmpty(xmlNames.pathsName)
- && !LangUtil.isEmpty(paths)) {
- out.printAttribute(xmlNames.pathsName, XMLWriter.flattenList(paths));
- }
- if (!LangUtil.isEmpty(xmlNames.commentName)
- && !LangUtil.isEmpty(comment)) {
- out.printAttribute(xmlNames.commentName, comment);
- }
- if (isStaging && !LangUtil.isEmpty(xmlNames.stagingName)) {
- out.printAttribute(xmlNames.stagingName, "true");
- }
- if (badInput && !LangUtil.isEmpty(xmlNames.badInputName)) {
- out.printAttribute(xmlNames.badInputName, "true");
- }
- }
-
- /**
- * The default implementation writes everything as attributes,
- * then subelements for dirChanges, messages, then subelements for children.
- * Subclasses that override may delegate back for any of these.
- * Subclasses may also set XMLNames to name or suppress any attribute
- * or subelement.
- * @see writeMessages(XMLWriter)
- * @see writeChildren(XMLWriter)
- * @see IXmlWritable#writeXml(XMLWriter)
- */
- public void writeXml(XMLWriter out) {
- out.startElement(xmlElementName,false);
- writeAttributes(out);
- out.endAttributes();
- if (!xmlNames.skipMessages) {
- writeMessages(out);
- }
- if (!xmlNames.skipChildren) {
- writeChildren(out);
- }
- out.endElement(xmlElementName);
- }
-
- /**
- * Write messages. Assumes attributes are closed,
- * can write child elements of current element.
- */
- protected void writeMessages(XMLWriter out) {
- if (0 < messages.numMessages(null, true)) {
- SoftMessage.writeXml(out, messages);
- }
-
- }
-
- /**
- * Write children. Assumes attributes are closed,
- * can write child elements of current element.
- */
- protected void writeChildren(XMLWriter out) {
- if (0 < children.size()) {
- for (Iterator iter = children.iterator(); iter.hasNext();) {
- IXmlWritable self = (IXmlWritable) iter.next();
- self.writeXml(out);
- }
- }
- }
-
- // --------------------------- logging
-
- public void printAll(PrintStream out, String prefix) {
- out.println(prefix + toString());
- for (Iterator iter = children.iterator(); iter.hasNext();) {
- AbstractRunSpec child = (AbstractRunSpec) iter.next(); // IRunSpec
- child.printAll(out, prefix + " ");
- }
- }
-
- /**
- * default implementation returns the description if not empty
- * or the unqualified class name otherwise.
- * Subclasses should not call toString from here unless they reimplement it.
- * @return name of this thing or type
- */
- protected String getPrintName() {
- if (!LangUtil.isEmpty(description)) {
- return description;
- } else {
- return LangUtil.unqualifiedClassName(this);
- }
- }
-
- /** @return summary count of spec elements */
- public String toString() {
- return getPrintName() + "(" + containedSummary() + ")";
- }
-
- /** @return String of the form (# [options|paths|locations|messages]).. */
- protected String containedSummary() {
- StringBuffer result = new StringBuffer();
- addListCount("options", options, result);
- addListCount("paths", paths, result);
- addListCount("sourceLocations", sourceLocations, result);
- List messagesList = messages.getUnmodifiableListView();
- addListCount("messages", messagesList, result);
-
- return result.toString().trim();
- }
-
-
- public String toLongString() {
- String mssg = "";
- if (0 < messages.numMessages(null, true)) {
- mssg = " expected messages (" + MessageUtil.renderCounts(messages) + ")";
- }
- return getPrintName() + containedToLongString() + mssg.trim();
- }
-
- /** @return String of the form (# [options|paths|locations|messages]).. */
- protected String containedToLongString() {
- StringBuffer result = new StringBuffer();
- addListEntries("options", options, result);
- addListEntries("paths", paths, result);
- addListEntries("sourceLocations", sourceLocations, result);
- List messagesList = messages.getUnmodifiableListView();
- addListEntries("messages", messagesList, result);
-
- return result.toString();
- }
-
- protected void initClone(AbstractRunSpec spec)
- throws CloneNotSupportedException {
- /*
- * clone associated objects only if not (used as?) read-only.
- */
- spec.badInput = badInput;
- spec.children.clear();
- for (Iterator iter = children.iterator(); iter.hasNext();) {
- // clone these...
- IRunSpec child = (IRunSpec) iter.next();
- // require all child classes to support clone?
- if (child instanceof AbstractRunSpec) {
- spec.addChild((AbstractRunSpec) ((AbstractRunSpec) child).clone());
- } else {
- throw new Error("unable to clone " + child);
- }
- }
- spec.comment = comment;
- spec.description = description;
- spec.dirChanges.clear();
- spec.dirChanges.addAll(dirChanges);
- spec.isStaging = spec.isStaging;
- spec.keywords.clear();
- spec.keywords.addAll(keywords);
- spec.messages.clearMessages();
- MessageUtil.handleAll(spec.messages, messages, false);
- spec.options.clear();
- spec.options.addAll(options);
- spec.paths.clear();
- spec.paths.addAll(paths);
- spec.runtime.copy(runtime);
- spec.skipAll = skipAll;
- spec.skipIfAnyChildSkipped = skipIfAnyChildSkipped;
- if (null != skipSet) {
- spec.skipSet = new BitSet();
- spec.skipSet.or(skipSet);
- }
- spec.sourceLocation = sourceLocation;
- spec.sourceLocations.clear();
- spec.sourceLocations.addAll(sourceLocations);
- spec.xmlElementName = xmlElementName;
- spec.xmlNames = ((AbstractRunSpec.XMLNames) xmlNames.clone());
- }
-
- protected final Fork getFork() {
- // spec ignored now, but perhaps not later...
- return FORK;
- }
-
- private static void addListCount(String name, List list, StringBuffer sink) {
- int size = list.size();
- if ((null != list) && (0 < size)) {
- sink.append(" " + size + " ");
- sink.append(name);
- }
- }
-
- private static void addListEntries(String name, List list, StringBuffer sink) {
- if ((null != list) && (0 < list.size())) {
- sink.append(" " + list.size() + " ");
- sink.append(name);
- sink.append(": ");
- sink.append(list.toString());
- }
- }
- private ArrayList makeList(List list) {
- ArrayList result = new ArrayList();
- if (null != list) {
- result.addAll(list);
- }
- return result;
- }
-
- /**
- * Subclasses use this to rename attributes or omit attributes or subelements.
- * To suppress output of an attribute, * pass "" as the name of the attribute.
- * To use default entries, pass null for that entry.
- */
- public static class XMLNames {
- public static final XMLNames DEFAULT =
- new XMLNames(null, "description", "sourceLocation",
- "keywords", "options", "paths", "comment",
- "staging", "badInput", false, false, false);
- final String descriptionName;
- final String sourceLocationName;
- final String keywordsName;
- final String optionsName;
- final String pathsName;
- final String commentName;
- final String stagingName;
- final String badInputName;
- final boolean skipDirChanges;
- final boolean skipMessages;
- final boolean skipChildren;
- protected Object clone() {
- return new XMLNames(
- null,
- descriptionName,
- sourceLocationName,
- keywordsName,
- optionsName,
- pathsName,
- commentName,
- stagingName,
- badInputName,
- skipDirChanges,
- skipMessages,
- skipChildren);
- }
-
- // not runtime, skipAll, skipIfAnyChildSkipped, skipSet
- // sourceLocations
- /** reset all names/behavior or pass defaultNames
- * as the defaults for any null elements
- */
- XMLNames(XMLNames defaultNames,
- String descriptionName,
- String sourceLocationName,
- String keywordsName,
- String optionsName,
- String pathsName,
- String commentName,
- String stagingName,
- String badInputName,
- boolean skipDirChanges,
- boolean skipMessages,
- boolean skipChildren) {
- this.skipDirChanges = skipDirChanges;
- this.skipMessages = skipMessages;
- this.skipChildren = skipChildren;
- if (null != defaultNames) {
- this.descriptionName = (null != descriptionName? descriptionName : defaultNames.descriptionName);
- this.sourceLocationName = (null != sourceLocationName ? sourceLocationName : defaultNames.sourceLocationName);
- this.keywordsName = (null != keywordsName ? keywordsName : defaultNames.keywordsName);
- this.optionsName = (null != optionsName ? optionsName : defaultNames.optionsName);
- this.pathsName = (null != pathsName ? pathsName : defaultNames.pathsName);
- this.commentName = (null != commentName ? commentName : defaultNames.commentName);
- this.stagingName = (null != stagingName ? stagingName : defaultNames.stagingName);
- this.badInputName = (null != badInputName ? badInputName : defaultNames.badInputName);
- } else {
- this.descriptionName = descriptionName;
- this.sourceLocationName = sourceLocationName;
- this.keywordsName = keywordsName;
- this.optionsName = optionsName;
- this.pathsName = pathsName;
- this.commentName = commentName;
- this.stagingName = stagingName;
- this.badInputName = badInputName;
- }
- }
- }
-
-
- /** subclasses implement this to create and set up a run */
- abstract public IRunIterator makeRunIterator(Sandbox sandbox, Validator validator);
-
- /** This is for separate file (sub-) elements with path attributes */
- public static class WrapFile {
- public String path;
- public void setPath(String path) {
- this.path = path;
- }
- }
-
- /** segregate runtime-only state in spec */
- public static class RT {
- /** true if we should emit verbose messages */
- private boolean verbose;
-
- /** null unless parent set options for children to consider */
- final private ArrayList /*String*/ parentOptions;
-
- public RT() {
- parentOptions = new ArrayList();
- }
-
- public boolean isVerbose() {
- return verbose;
- }
-
- /**
- * Set parent options - old options destroyed.
- * Will result in duplicates if duplicates added.
- * Null or empty entries are ignored
- * @param options ignored if null or empty
- */
- public void setOptions(String[] options) {
- parentOptions.clear();
- if (!LangUtil.isEmpty(options)) {
- for (int i = 0; i < options.length; i++) {
- if (!LangUtil.isEmpty(options[i])) {
- parentOptions.add(options[i]);
- }
- }
- }
- }
-
- /**
- * Copy values from another RT
- * @param toCopy the RT to copy from
- * @throws IllegalArgumentException if toCopy is null
- */
- public void copy(RT toCopy) {
- LangUtil.throwIaxIfNull(toCopy, "parent");
- parentOptions.clear();
- parentOptions.addAll(toCopy.parentOptions);
- verbose = toCopy.verbose;
- }
-
- /**
- * Return any parent option accepted by validOptions,
- * optionally removing the parent option.
- * @param validOptions String[] of options to extract
- * @param remove if true, then remove any parent option matched
- * @return String[] containing any validOptions[i] in parentOptions
- *
- */
- public Values extractOptions(
- Options validOptions,
- boolean remove,
- StringBuffer errors) {
- Values result = Values.EMPTY;
- if (null == errors) {
- errors = new StringBuffer();
- }
- if (null == validOptions) {
- errors.append("null options");
- return result;
- }
- if (LangUtil.isEmpty(parentOptions)) {
- return result;
- }
- // boolean haveOption = false;
- String[] parents = (String[]) parentOptions.toArray(new String[0]);
- try {
- result = validOptions.acceptInput(parents);
- } catch (InvalidInputException e) {
- errors.append(e.getFullMessage());
- return result;
- }
- if (remove) {
- Option.Value[] values = result.asArray();
- for (int i = 0; i < values.length; i++) {
- Option.Value value = values[i];
- if (null == value) {
- continue;
- }
- final int max = i + value.option.numArguments();
- if (max > i) {
- if (max >= parents.length) {
- errors.append("expecting more args for "
- + value.option
- + " at ["
- + i
- + "]: "
- + Arrays.asList(parents));
- return result;
- }
- // XXX verify
- for (int j = i; j < max ; j++) {
- parentOptions.remove(parents[j]);
- }
- i = max-1;
- }
- }
- }
- return result;
- }
-
- /**
- * Return any parent option which has one of validOptions as a prefix,
- * optionally absorbing (removing) the parent option.
- * @param validOptions String[] of options to extract
- * @param absorb if true, then remove any parent option matched
- * @return String[] containing any validOptions[i] in parentOptions
- * (at most once)
- */
- public String[] extractOptions(String[] validOptions, boolean absorb) {
- if (LangUtil.isEmpty(validOptions) || LangUtil.isEmpty(parentOptions)) {
- return new String[0];
- }
- ArrayList result = new ArrayList();
- // boolean haveOption = false;
- for (int i = 0; i < validOptions.length; i++) {
- String option = validOptions[i];
- if (LangUtil.isEmpty(option)) {
- continue;
- }
- for (ListIterator iter = parentOptions.listIterator(); iter.hasNext();) {
- String parentOption = (String) iter.next();
- if (parentOption.startsWith(option)) {
- result.add(parentOption);
- if (absorb) {
- iter.remove();
- }
- }
- }
- }
- return (String[]) result.toArray(new String[0]);
- }
-
- /** Get ListIterator that permits removals */
- ListIterator getListIterator() {
- return parentOptions.listIterator();
- }
-
- /**
- * Enable verbose logging
- * @param verbose if true, do verbose logging
- */
- public void setVerbose(boolean verbose) {
- if (this.verbose != verbose) {
- this.verbose = verbose;
- }
- }
- } // class RT
-
- protected static class Fork {
- public static final Fork NOFORK = new Fork();
- private static final String DELIMITER = ",";
- private final boolean fork;
- private final String version;
- private final String java;
- private final File javaHome;
- private final String bootclasspath;
- private final String errs;
-
- private Fork() {
- this(null);
- }
-
- /**
- * @param spec a String null (no) or of the form
- * <code>1.[12345],{javaHome},{java},{bootclasspath}</code>
- * where {javaHome} is a readable directory and
- * a prefix of {java}.
- */
- private Fork(String spec) {
- if (null == spec) {
- fork = false;
- version = null;
- java = null;
- javaHome = null;
- bootclasspath = null;
- errs = null;
- return;
- }
- String inputVersion = null;
- File inputJavaHome = null;
- String inputJava = null;
- String inputBootclasspath = null;
- //
- // paths should be in system-specific form
- final String EXPECT =
- "{version=1.[12345],{java.home},{java.command},{bootclasspath}";
- final String EXAMPLE =
- "1.1,d:/jdk11,d:/jdk11/bin/java,d:/jdk11/lib/classes.zip";
- if (LangUtil.isEmpty(spec)) {
- spec = "";
- }
- StringBuffer inputErrs = new StringBuffer();
- StringTokenizer st = new StringTokenizer(spec, DELIMITER);
- if (4 != st.countTokens()) {
- inputErrs.append(" expecting 4 tokens.");
- } else {
- inputVersion = st.nextToken().trim();
- String inputJavaHomePath = st.nextToken().trim();
- inputJava = st.nextToken().trim();
- inputBootclasspath = st.nextToken().trim();
- if (!inputVersion.startsWith("1.")
- || (3 != inputVersion.length())
- || ('1' > inputVersion.charAt(2))
- || ('6' < inputVersion.charAt(2)) ) {
- inputErrs.append(" expecting version 1.[12345]");
- }
- inputJavaHome = new File(inputJavaHomePath);
- if (!inputJavaHome.canRead()
- || !inputJavaHome.isDirectory()) {
- inputErrs.append(" expecting java.home dir: "
- + inputJavaHomePath);
- }
- if (!inputJava.startsWith(inputJavaHomePath)) {
- inputErrs.append(" expecting java in java.home.dir: "
- + inputJava);
- }
- if (LangUtil.isEmpty(inputBootclasspath)) {
- inputBootclasspath = null;
- }
- }
- String inputErrString = inputErrs.toString();
- fork = (0 == inputErrString.length());
- if (fork) {
- errs = null;
- } else {
- errs = "bad fork specification. Expecting "
- + EXPECT
- + " - for example, "
- + EXAMPLE
- + ". Problems: "
- + inputErrString;
- }
- version = inputVersion;
- java = inputJava;
- javaHome = inputJavaHome;
- bootclasspath = inputBootclasspath;
- }
- public boolean fork() {
- return fork;
- }
- public String getJavaExecutablePath() {
- return java;
- }
- public File getJavaHome() {
- return javaHome;
- }
- public String getJavaBootclasspath() {
- return bootclasspath;
- }
- public String getErrors() {
- return errs;
- }
- public String toSpecString() {
- if (!fork) {
- return null;
- }
- return version
- + DELIMITER
- + javaHome
- + DELIMITER
- + java
- + DELIMITER
- + bootclasspath;
- }
- public String toString() {
- return (fork ? "Fork [true]" : "Fork [false]"); // XXX upgrade
- }
- } // class Fork
- }
|