Index: axis/ParseTopdl.java
===================================================================
--- axis/ParseTopdl.java	(revision c6f04f77459ce101cb19be5ac382b00faafcab75)
+++ axis/ParseTopdl.java	(revision 72176de2db057de38ee457bb835cd5bcb8b2e073)
@@ -12,82 +12,167 @@
 import org.xml.sax.helpers.*;
 
-class ParseTopdl {
+public class ParseTopdl {
     /** Parser instance */
     protected XMLReader xr;
-
+    /** Handler that parses topdl file */
+    protected TopdlHandler h;
+
+    /**
+     * This class encapsulates the state of an XML parse of a topdl file.  It
+     * contains abunch of parsing state and is called from the standard SAX
+     * parser at 3 places: when an XML element starts (&lt;element&gt;) when
+     * one ends (&lt;element/&gt;) and whenever characters inside an element
+     * are encountered.  It mostly initializes fileds as elements are exited,
+     * collecting other parsed fields into objects that are finally attached to
+     * the topology itself.
+     */
     protected class TopdlHandler extends DefaultHandler {
+	/** The name of the outermost element, "experiment" by default */
 	protected String topName;
 
 	// Topology parameters
+	/** The current topology being built */
 	protected TopologyType topo;
+	/** The current element being built */
 	protected ElementType element;
+	/** The current computer being built */
 	protected ComputerType comp;
+	/** The current testbed being built */
 	protected TestbedType tb;
+	/** The current segment being built */
 	protected SegmentType seg;
+	/** The current other element being built */
 	protected OtherType other;
 
 	// Many elements have a name
+	/** the most recent name element parsed */
 	protected String name;
 
 	// CPU parameters
+	/** current cpu type */
 	protected String type;
+	/** current number of cpus */
 	protected int ncpus;
 
 	// Operatingsystem parameters
+	/** Current OS version */
 	protected String version;
+	/** Current OS distro */
 	protected String distribution;
+	/** Current OS distro version */
 	protected String distributionversion;
 
 	// Software parameters
+	/** Current software installation point */
 	protected String install;
+	/** Current software location */
 	protected String location;
 
 	// Storage parameters
+	/** Current storage amount */
 	protected double amount;
+	/** Current storage persistence */
 	protected PersistenceType persistence;
 
 	// Interface Parameters
+	/** Vector of substrate names the current interface is attached to */
 	protected Vector<String> ifsubs;
+	/** Current interface capacity */
 	protected edu.isi.www.topdl.CapacityType cap;
+	/** Current interface latency */
 	protected LatencyType lat;
 
 	// Capacity parameters
+	/** Current capacity rate (bandwidth) */
 	protected double rate;
+	/** Current capacity kind (max, peak)*/
 	protected edu.isi.www.topdl.KindType kind;
 
 	// Latency parameters (shares kind)
+	/** Current latency time */
 	protected double time;
 
 	// Testbed parameters (shares interfaces, type)
+	/** Current URI */
 	protected String uri;
 
 	// Segment parameters (shares interfaces, type, uri)
+	/** Current segment ID */
 	protected IDType id;
 	// IDType parameters
+	/** Current ID uuid (if any) */
 	protected byte[] uuid;
+	/** Current ID fedid (if any) */
 	protected byte[] fedid;
+	/** Current ID uri (if any) */
 	protected String id_uri;
+	/** Current ID localname (if any) */
 	protected String localname;
+	/** Current ID kerberosUsername (if any) */
 	protected String kerberosUsername;
+	/** True when we are parsing an ID (so URIs are stored in id_uri) */
 	protected boolean inID;
 
 	// Attribute parameters
+	/** Current attribute name */
 	protected String aname;
+	/** Current attribute value */
 	protected String aval;
 
+	/** Elements seen so far */
 	protected Vector<ElementType> elements;
+	/** Substrates seen so far */
 	protected Vector<SubstrateType> subs;
+	/** Attributes seen so far */
 	protected Vector<AttributeType> attrs;
+	/** CPUs seen so far */
 	protected Vector<CpuType> cpus;
+	/** Operating Systems seen so far */
 	protected Vector<OperatingsystemType> oses;
+	/** Software seen so far */
 	protected Vector<SoftwareType> software;
+	/** Storage seen so far */
 	protected Vector<StorageType> storage;
+	/** Interfaces seen so far */
 	protected Vector<InterfaceType> interfaces;
 
+	/**
+	 * Attributes appear in many elements, some of which can appear inside
+	 * the definition of others.  We keep a stack of live attributes so
+	 * that a sub-element does not overwrite a super-element's attributes.
+	 * attrElements is a set of element names that should start a new set
+	 * of recorded attributes, and attrStack keeps the contexts stacked. 
+	 */
 	protected Set<String> attrElements;
+	/**
+	 * The stack of attribute contexts.
+	 */
 	protected Stack<Vector<AttributeType>> attrStack;
+	/**
+	 * Analogous to attrElements for names.
+	 */
+	protected Set<String> nameElements;
+	/**
+	 * Analogous to attrStack for names.
+	 */
+	protected Stack<String> nameStack;
+	/**
+	 * The current buffer of characters collected.
+	 */
 	protected char[] c;
 
-	TopdlHandler(String top) {
+	/**
+	 * Print parsing info if true
+	 */
+	protected boolean debug;
+
+	/**
+	 * Initialize the internal data structures.  Top is the outer element
+	 * name.  If d is true, debugging info is printed.
+	 * @param top a String containing the outer element name
+	 * @param d a boolean, if true pring debugging info
+	 */
+	TopdlHandler(String top, boolean d) {
+	    debug = d;
 	    topName = top;
 	    topo = null;
@@ -129,10 +214,11 @@
 
 	    elements = new Vector<ElementType>();
+	    cpus = new Vector<CpuType>();
 	    subs = new Vector<SubstrateType>();
-	    attrs = new Vector<AttributeType>();
 	    oses = new Vector<OperatingsystemType>();
 	    software = new Vector<SoftwareType>();
 	    storage = new Vector<StorageType>();
 	    interfaces = new Vector<InterfaceType>();
+	    attrs = new Vector<AttributeType>();
 
 	    attrElements = new TreeSet<String>();
@@ -143,14 +229,40 @@
 
 	    attrStack = new Stack<Vector<AttributeType>>();
+
+	    nameElements = new TreeSet<String>();
+	    for (String e : new String[] {
+		"computer", "os", "interface", "substrates" 
+	    }) nameElements.add(e);
+	    nameStack = new Stack<String>();
 	    c = new char[0];
 	}
 
+	/**
+	 * Called when an element begins.  qn is the element and a has
+	 * attributes assigned in the element.  This starts new name or
+	 * attribute contexts, if necessary as well as noting the start of an
+	 * id (which is a lightweight uri context).  The parameter definitions
+	 * below are from org.xml.sax.helpers.DefaultHandler
+	 * @param u - The Namespace URI, or the empty string if the element has
+	 * no Namespace URI or if Namespace processing is not being performed.
+	 * @param l - The local name (without prefix), or the empty string if
+	 * Namespace processing is not being performed.
+	 * @param qn - The qualified name (with prefix), or the empty string if
+	 * qualified names are not available.
+	 * @param a - The attributes attached to the element. If there are no
+	 * attributes, it shall be an empty Attributes object. 
+	 */
 	public void startElement(String u, String l, String qn, Attributes a) 
 		throws SAXException {
 
+	    if (debug) System.err.println("<" + qn + ">");
 	    c = new char[0];
 	    if ( attrElements.contains(qn) ) {
 		attrStack.push(attrs);
 		attrs = new Vector<AttributeType>();
+	    }
+	    if ( nameElements.contains(qn) ) {
+		nameStack.push(name);
+		name = null;
 	    }
 	    if (qn.equals("id")) inID = true;
@@ -162,7 +274,27 @@
 	}
 
+	/**
+	 * Collect the data from each element and stash it where any containing
+	 * elent can find it when it is time to construct that thing.  Clear
+	 * any fields used.  This is long but straightforward parsing.
+	 * @param u - The Namespace URI, or the empty string if the element has
+	 * no Namespace URI or if Namespace processing is not being performed.
+	 * @param l - The local name (without prefix), or the empty string if
+	 * Namespace processing is not being performed.
+	 * @param qn - The qualified name (with prefix), or the empty string if
+	 * qualified names are not available.
+	 */
 	public void endElement(String u, String l, String qn) 
 		throws SAXException {
 
+	    if (debug) System.err.println("<" + qn + "/>");
+
+	    // Each branch parses the data from the given element, e.g,
+	    // "computer" parses the fields collected for </computer>.  In that
+	    // case the data stashed by trips through here for
+	    // <operatingsystem>, <name>, etc.
+	    //
+	    // The vector.toArray(new Type[vector.size()], idiom just returns
+	    // the contents of the vector as a java array of the vector's type.
 	    if (qn.equals(topName)) {
 		topo = new TopologyType("1.0",
@@ -174,5 +306,5 @@
 		attrs = attrStack.pop();
 	    }
-	    else if (qn.equals("element")) {
+	    else if (qn.equals("elements")) {
 		elements.add(new ElementType(comp, tb, seg, other));
 		comp = null;
@@ -190,5 +322,5 @@
 			    new InterfaceType[interfaces.size()]),
 			attrs.toArray(new AttributeType[attrs.size()]));
-		name = null;
+		name = nameStack.pop();
 		cpus = new Vector<CpuType>();
 		oses = new Vector<OperatingsystemType>();
@@ -210,5 +342,6 @@
 			distribution, distributionversion, 
 			attrs.toArray(new AttributeType[attrs.size()])));
-		name = version = distribution = distributionversion = null;
+		name = nameStack.pop();
+		version = distribution = distributionversion = null;
 		attrs = attrStack.pop();
 	    }
@@ -250,4 +383,5 @@
 			    attrs.toArray(new AttributeType[attrs.size()])));
 		ifsubs = new Vector<String>();
+		name = nameStack.pop();
 		cap = null;
 		lat = null;
@@ -332,5 +466,5 @@
 		subs.add(new SubstrateType(name, cap, lat, 
 			attrs.toArray(new AttributeType[attrs.size()])));
-		name = null;
+		name = nameStack.pop();
 		cap = null;
 		lat = null;
@@ -347,4 +481,5 @@
 	    else if ( qn.equals("name")) { name = new String(c).trim(); }
 
+	    // Always clear any accumulated characters
 	    c = new char[0];
 	}
@@ -359,13 +494,69 @@
 	    c = nc;
 	}
+	/**
+	 * Return the parsed topology
+	 * @return the parsed topology
+	 */
+	public TopologyType getTopology() { return topo; }
     }
 
-    public ParseTopdl(InputStream s) 
+    /**
+     * Main constructor.  Parse the given stream assuming that the outermost
+     * element is in topName (defaults to "experiment" if topName is null).  If
+     * debug is true, print extra debugging information to the standard error
+     * stream.
+     * @param s the InputStream to parse
+     * @param topName a String with the outer element name
+     * @param debug a boolean, true for extra debugging output
+     * @throws IOException if the stream cannot be read
+     * @throws SAXException if the parsing fails
+     * @throws ParserConfigurationException if the parser creation fails
+     */
+    public ParseTopdl(InputStream s, String topName, boolean debug) 
 	throws IOException, SAXException, ParserConfigurationException {
+	h = new TopdlHandler(topName != null ? topName: "experiment", debug);
+
 	xr = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
-
+	xr.setContentHandler(h);
 	xr.parse(new InputSource(s));
     }
 
-
+    /**
+     * Equivalent to ParseTopdl(s, topName, false)
+     * @param s the InputStream to parse
+     * @param topName a String with the outer element name
+     * @throws IOException if the stream cannot be read
+     * @throws SAXException if the parsing fails
+     * @throws ParserConfigurationException if the parser creation fails
+     */
+    public ParseTopdl(InputStream s, String topName)
+	throws IOException, SAXException, ParserConfigurationException {
+	this(s, topName, false);
+    }
+
+    /**
+     * Return the parsed topology
+     * @return the parsed topology
+     */
+    public TopologyType getTopology() { return h.getTopology(); }
+
+    /**
+     * Test code.  Shouldn't really be called.
+     */
+    static public void main(String args[]) {
+	ParseTopdl p = null;
+	try {
+	    p = new ParseTopdl(new FileInputStream(new File(args[0])),
+		    "experiment", true);
+	}
+	catch (ParserConfigurationException e) {
+	    System.err.println(e);
+	}
+	catch (SAXException e) {
+	    System.err.println(e);
+	}
+	catch (IOException e) {
+	    System.err.println(e);
+	}
+    }
 }
