gt: 			for (int i = 0; i < vmNodeList.getLength(); ++i) {
context: package sc.nrel.nwtc.fast.launching;
  
  import java.io.BufferedInputStream;
  import java.io.File;
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.Set;
  
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  import javax.xml.parsers.ParserConfigurationException;
  
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IPath;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.MultiStatus;
  import org.eclipse.core.runtime.Path;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.debug.core.DebugPlugin;
  import org.eclipse.osgi.util.NLS;
  
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  import org.xml.sax.helpers.DefaultHandler;
  
  /**
   * This is a container for VM definitions such as the VM definitions that are
   * stored in the workbench preferences.  
   * <p>
   * An instance of this class may be obtained from an XML document by calling
   * <code>parseXMLIntoContainer</code>.
   * </p>
   * <p>
   * An instance of this class may be translated into an XML document by calling
   * <code>getAsXML</code>.
   * </p>
   * <p>
   * Clients may instantiate this class; it is not intended to be subclassed.
   * </p>
   * 
   * @since 2.1
   */
  public class FASTDefinitionsContainer {
  		
  	/**
  	 * Map of VMInstallTypes to Lists of corresponding VMInstalls.
  	 */
  	private Map<IFASTInstallType, List<IFASTInstall>> fVMTypeToVMMap;
  	
  	/**
  	 * Cached list of VMs in this container
  	 */
  	private List<IFASTInstall> fVMList;
  	
  	/**
  	 * VMs managed by this container whose install locations don't actually exist.
  	 */
  	private List<IFASTInstall> fInvalidVMList;
  			
  	/**
  	 * The composite identifier of the default VM.  This consists of the install type ID
  	 * plus an ID for the VM.
  	 */
  	private String fDefaultVMInstallCompositeID;
  	
  	/**
  	 * The identifier of the connector to use for the default VM.
  	 */
  	private String fDefaultVMInstallConnectorTypeID;
  	
  	/**
  	 * Contains any error/information status of parsing XML
  	 */
  	private MultiStatus fStatus;
  	
  	/**
  	 * Constructs an empty VM container 
  	 */
  	public FASTDefinitionsContainer() {
  		fVMTypeToVMMap = new HashMap<IFASTInstallType, List<IFASTInstall>>(10);
  		fInvalidVMList = new ArrayList<IFASTInstall>(10);	
  		fVMList = new ArrayList<IFASTInstall>(10);		
  	}
  		
  	/**
  	 * Add the specified VM to the VM definitions managed by this container.
  	 * <p>
  	 * If distinguishing valid from invalid VMs is important, the specified VM must
  	 * have already had its install location set.  An invalid VM is one whose install
  	 * location doesn't exist.
  	 * </p>
  	 * 
  	 * @param vm the VM to be added to this container
  	 */
  	public void addVM(IFASTInstall vm) {
  		if (!fVMList.contains(vm)) {	
  			IFASTInstallType vmInstallType = vm.getFASTInstallType();
  			List<IFASTInstall> vmList = fVMTypeToVMMap.get(vmInstallType);
  			if (vmList == null) {
  				vmList = new ArrayList<IFASTInstall>(3);
  				fVMTypeToVMMap.put(vmInstallType, vmList);			
  			}
  			vmList.add(vm);
  			File installLocation = vm.getInstallLocation();
  			if (installLocation == null || vmInstallType.validateInstallLocation(installLocation).getSeverity() == IStatus.ERROR) {
  				fInvalidVMList.add(vm);
  			}
  			fVMList.add(vm);
  		}
  	}
  	
  	/**
  	 * Add all VM's in the specified list to the VM definitions managed by this container.
  	 * <p>
  	 * If distinguishing valid from invalid VMs is important, the specified VMs must
  	 * have already had their install locations set.  An invalid VM is one whose install
  	 * location doesn't exist.
  	 * </p>
  	 * 
  	 * @param vmList a list of VMs to be added to this container
  	 */
  	public void addVMList(List<IFASTInstall> vmList) {
  		Iterator<IFASTInstall> iterator = vmList.iterator();
  		while (iterator.hasNext()) {
  			addVM(iterator.next());
  		}
  	}
  
  	/**
  	 * Return a mapping of VM install types to lists of VMs.  The keys of this map are instances of
  	 * <code>IVMInstallType</code>.  The values are instances of <code>java.util.List</code>
  	 * which contain instances of <code>IVMInstall</code>.  
  	 * 
  	 * @return Map the mapping of VM install types to lists of VMs
  	 */
  	public Map<IFASTInstallType, List<IFASTInstall>> getVMTypeToVMMap() {
  		return fVMTypeToVMMap;
  	}
  	
  	/**
  	 * Return a list of all VMs in this container, including any invalid VMs.  An invalid
  	 * VM is one whose install location does not exist on the file system.
  	 * The order of the list is not specified.
  	 * 
  	 * @return List the data structure containing all VMs managed by this container
  	 */
  	public List<IFASTInstall> getVMList() {
  		return fVMList;
  	}
  	
  	/**
  	 * Return a list of all valid VMs in this container.  A valid VM is one whose install
  	 * location exists on the file system.  The order of the list is not specified.
  	 * 
  	 * @return List 
  	 */
  	public List<IFASTInstall> getValidVMList() {
  		List<IFASTInstall> vms = getVMList();
  		List<IFASTInstall> resultList = new ArrayList<IFASTInstall>(vms.size());
  		resultList.addAll(vms);
  		resultList.removeAll(fInvalidVMList);
  		return resultList;
  	}
  	
  	/**
  	 * Returns the composite ID for the default VM.  The composite ID consists
  	 * of an ID for the VM install type together with an ID for VM.  This is
  	 * necessary because VM ids by themselves are not necessarily unique across
  	 * VM install types.
  	 * 
  	 * @return String returns the composite ID of the current default VM
  	 */
  	public String getDefaultVMInstallCompositeID(){
  		return fDefaultVMInstallCompositeID;
  	}
  	
  	/**
  	 * Sets the composite ID for the default VM.  The composite ID consists
  	 * of an ID for the VM install type together with an ID for VM.  This is
  	 * necessary because VM ids by themselves are not necessarily unique across
  	 * VM install types.
  	 * 
  	 * @param id identifies the new default VM using a composite ID
  	 */
  	public void setDefaultVMInstallCompositeID(String id){
  		fDefaultVMInstallCompositeID = id;
  	}
  	
  	/**
  	 * Return the default VM's connector type ID.
  	 * 
  	 * @return String the current value of the default VM's connector type ID
  	 */
  	public String getDefaultVMInstallConnectorTypeID() {
  		return fDefaultVMInstallConnectorTypeID;
  	}
  	
  	/**
  	 * Set the default VM's connector type ID.
  	 * 
  	 * @param id the new value of the default VM's connector type ID
  	 */
  	public void  setDefaultVMInstallConnectorTypeID(String id){
  		fDefaultVMInstallConnectorTypeID = id;
  	}
  	
  	/**
  	 * Return the VM definitions contained in this object as a String of XML.  The String
  	 * is suitable for storing in the workbench preferences.
  	 * <p>
  	 * The resulting XML is compatible with the static method <code>parseXMLIntoContainer</code>.
  	 * </p>
  	 * @return String the results of flattening this object into XML
  	 * @throws CoreException if serialization of the XML document failed
  	 */
  	public String getAsXML() throws CoreException {
  		
  		// Create the Document and the top-level node
  		Document doc = DebugPlugin.newDocument();
  		Element config = doc.createElement("vmSettings");    //$NON-NLS-1$
  		doc.appendChild(config);
  		
  		// Set the defaultVM attribute on the top-level node
  		if (getDefaultVMInstallCompositeID() != null) {
  			config.setAttribute("defaultVM", getDefaultVMInstallCompositeID()); //$NON-NLS-1$
  		}
  		
  		// Set the defaultVMConnector attribute on the top-level node
  		if (getDefaultVMInstallConnectorTypeID() != null) {
  			config.setAttribute("defaultVMConnector", getDefaultVMInstallConnectorTypeID()); //$NON-NLS-1$
  		}
  				
  		// Create a node for each install type represented in this container
  		Set<IFASTInstallType> vmInstallTypeSet = getVMTypeToVMMap().keySet();
  		Iterator<IFASTInstallType> keyIterator = vmInstallTypeSet.iterator();
  		while (keyIterator.hasNext()) {
  			IFASTInstallType vmInstallType = keyIterator.next();
  			Element vmTypeElement = vmTypeAsElement(doc, vmInstallType);
  			config.appendChild(vmTypeElement);
  		}
  		
  		// Serialize the Document and return the resulting String
  		return DebugPlugin.serializeDocument(doc);
  	}
  	
  	/**
  	 * Create and return a node for the specified VM install type in the specified Document.
  	 * 
  	 * @param doc the backing {@link Document}
  	 * @param vmType the {@link IVMInstallType} to create an {@link Element} for
  	 * @return the new {@link Element}
  	 */
  	private Element vmTypeAsElement(Document doc, IFASTInstallType vmType) {
  		
  		// Create a node for the VM type and set its 'id' attribute
  		Element element= doc.createElement("vmType");   //$NON-NLS-1$
  		element.setAttribute("id", vmType.getId());     //$NON-NLS-1$
  		
  		// For each VM of the specified type, create a subordinate node for it
  		List<IFASTInstall> vmList = getVMTypeToVMMap().get(vmType);
  		Iterator<IFASTInstall> vmIterator = vmList.iterator();
  		while (vmIterator.hasNext()) {
  			IFASTInstall vm = vmIterator.next();
  			Element vmElement = vmAsElement(doc, vm);
  			element.appendChild(vmElement);
  		}
  		
  		return element;
  	}
  	
  	/**
  	 * Create and return a node for the specified VM in the specified Document.
  	 * 
  	 * @param doc the backing {@link Document}
  	 * @param vm the {@link IVMInstall} to create an {@link Element} for
  	 * @return the new {@link Element} representing the given {@link IVMInstall}
  	 */
  	private Element vmAsElement(Document doc, IFASTInstall vm) {
  		
  		// Create the node for the VM and set its 'id' & 'name' attributes
  		Element element= doc.createElement("vm");        //$NON-NLS-1$
  		element.setAttribute("id", vm.getId());	         //$NON-NLS-1$
  		element.setAttribute("name", vm.getName());      //$NON-NLS-1$
  		
  		// Determine and set the 'path' attribute for the VM
  		String installPath= "";                          //$NON-NLS-1$
  		File installLocation= vm.getInstallLocation();
  		if (installLocation != null) {
  			installPath= installLocation.getAbsolutePath();
  		}
  		element.setAttribute("path", installPath);       //$NON-NLS-1$
  		
  		// If the 'libraryLocations' attribute is specified, create a node for it 
  		/* TODO LibraryLocation[] libraryLocations= vm.getLibraryLocations();
  		if (libraryLocations != null) {
  			Element libLocationElement = libraryLocationsAsElement(doc, libraryLocations);
  			element.appendChild(libLocationElement);
  		} */
  		
  		// Java doc location
  		/* TODO URL url = vm.getJavadocLocation();
  		if (url != null) {
  			element.setAttribute("javadocURL", url.toExternalForm()); //$NON-NLS-1$
  		} */
  		
  		/* TODO if (vm instanceof IVMInstall2) {
  			String vmArgs = ((IVMInstall2)vm).getVMArgs();
  			if (vmArgs != null && vmArgs.length() > 0) {
  				element.setAttribute("vmargs", vmArgs); //$NON-NLS-1$
  			}
  		} else {
  			String[] vmArgs = vm.getVMArguments();
  			if (vmArgs != null && vmArgs.length > 0) {
  				StringBuffer buffer = new StringBuffer();
  				for (int i = 0; i < vmArgs.length; i++) {
  					buffer.append(vmArgs[i] + " "); //$NON-NLS-1$
  				}
  				element.setAttribute("vmargs", buffer.toString()); //$NON-NLS-1$
  			}
  		} */
  		
  		// VM attributes
  		if (vm instanceof AbstractFASTInstall) {
  			Map<String, String> attributes = ((AbstractFASTInstall)vm).getAttributes();
  			if (!attributes.isEmpty()) {
  				Element attrElement = doc.createElement("attributeMap"); //$NON-NLS-1$
  				Iterator<Entry<String, String>> iterator = attributes.entrySet().iterator();
  				while (iterator.hasNext()) {
  					Entry<String, String> entry = iterator.next();
  					Element entryElement = doc.createElement("entry"); //$NON-NLS-1$
  					entryElement.setAttribute("key", entry.getKey()); //$NON-NLS-1$
  					entryElement.setAttribute("value", entry.getValue()); //$NON-NLS-1$
  					attrElement.appendChild(entryElement);
  				}
  				element.appendChild(attrElement);
  			}
  		}
  		
  		return element;
  	}
  	
  	/**
  	 * Create and return a 'libraryLocations' node.  This node owns subordinate nodes that
  	 * list individual library locations.
  	 * 
  	 * @param doc the backing {@link Document}
  	 * @param locations the array of {@link LibraryLocation}s to create an {@link Element} for
  	 * @return the new {@link Element} for the given {@link LibraryLocation}s
  	 */
  	/*private static Element libraryLocationsAsElement(Document doc, LibraryLocation[] locations) {
  		Element root = doc.createElement("libraryLocations");       //$NON-NLS-1$
  		for (int i = 0; i < locations.length; i++) {
  			Element element = doc.createElement("libraryLocation");  //$NON-NLS-1$
  			element.setAttribute("jreJar", locations[i].getSystemLibraryPath().toString()); //$NON-NLS-1$
  			element.setAttribute("jreSrc", locations[i].getSystemLibrarySourcePath().toString()); //$NON-NLS-1$
  
  			IPath packageRootPath = locations[i].getPackageRootPath();
              if (packageRootPath != null) {
                  element.setAttribute("pkgRoot", packageRootPath.toString()); //$NON-NLS-1$
              }
              
  			URL url= locations[i].getJavadocLocation();
  			if (url != null) {
  				element.setAttribute("jreJavadoc", url.toExternalForm()); //$NON-NLS-1$
  			}
  			root.appendChild(element);
  		}
  		return root;
  	}*/
  	
  	public static FASTDefinitionsContainer parseXMLIntoContainer(InputStream inputStream) throws IOException {
  		FASTDefinitionsContainer container = new FASTDefinitionsContainer();
  		parseXMLIntoContainer(inputStream, container);
  		return container;
  	}
  			
  	/**
  	 * Parse the VM definitions contained in the specified InputStream into the
  	 * specified container.
  	 * <p>
  	 * The VMs in the returned container are instances of <code>VMStandin</code>.
  	 * </p>
  	 * <p>
  	 * This method has no side-effects.  That is, no notifications are sent for VM adds,
  	 * changes, deletes, and the workbench preferences are not affected.
  	 * </p>
  	 * <p>
  	 * If the <code>getAsXML</code> method is called on the returned container object,
  	 * the resulting XML will be semantically equivalent (though not necessarily syntactically equivalent) as
  	 * the XML contained in <code>inputStream</code>.
  	 * </p>
  	 * @param inputStream the <code>InputStream</code> containing XML that declares a set of VMs and a default VM
  	 * @param container the container to add the VM definitions to
  	 * @throws IOException if this method fails. Reasons include:<ul>
  	 * <li>the XML in <code>inputStream</code> was badly formatted</li>
  	 * <li>the top-level node was not 'vmSettings'</li>
  	 * </ul>
  	 * @since 3.2
  	 */
  	public static void parseXMLIntoContainer(InputStream inputStream, FASTDefinitionsContainer container) throws IOException {
  
  		// Wrapper the stream for efficient parsing
  		InputStream stream= new BufferedInputStream(inputStream);
  
  		// Do the parsing and obtain the top-level node
  		Element config= null;		
  		try {
  			DocumentBuilder parser= DocumentBuilderFactory.newInstance().newDocumentBuilder();
  			parser.setErrorHandler(new DefaultHandler());
  			config = parser.parse(new InputSource(stream)).getDocumentElement();
  		} catch (SAXException e) {
  			throw new IOException(LaunchingMessages.JavaRuntime_badFormat); 
  		} catch (ParserConfigurationException e) {
  			stream.close();
  			throw new IOException(LaunchingMessages.JavaRuntime_badFormat); 
  		} finally {
  			stream.close();
  		}
  		
  		// If the top-level node wasn't what we expected, bail out
  		if (!config.getNodeName().equalsIgnoreCase("vmSettings")) { //$NON-NLS-1$
  			throw new IOException(LaunchingMessages.JavaRuntime_badFormat); 
  		}
  		
  		// Populate the default VM-related fields
  		container.setDefaultVMInstallCompositeID(config.getAttribute("defaultVM")); //$NON-NLS-1$
  		container.setDefaultVMInstallConnectorTypeID(config.getAttribute("defaultVMConnector")); //$NON-NLS-1$
  		
  		// Traverse the parsed structure and populate the VMType to VM Map
  		NodeList list = config.getChildNodes();
  		int length = list.getLength();
  		for (int i = 0; i < length; ++i) {
  			Node node = list.item(i);
  			short type = node.getNodeType();
  			if (type == Node.ELEMENT_NODE) {
  				Element vmTypeElement = (Element) node;
  				if (vmTypeElement.getNodeName().equalsIgnoreCase("vmType")) { //$NON-NLS-1$
  					populateVMTypes(vmTypeElement, container);
  				}
  			}
  		}
  	}
  	
  	/**
  	 * For the specified VM type node, parse all subordinate VM definitions and add them
  	 * to the specified container.
  	 * 
  	 * @param vmTypeElement the {@link Element} to populate the {@link VMDefinitionsContainer} from
  	 * @param container the {@link VMDefinitionsContainer} to populate from the {@link Element}
  	 */
  	private static void populateVMTypes(Element vmTypeElement, FASTDefinitionsContainer container) {
  		// Retrieve the 'id' attribute and the corresponding VM type object
  		String id = vmTypeElement.getAttribute("id");         //$NON-NLS-1$
  		IFASTInstallType vmType= FASTRuntime.getFASTInstallType(id);
  		if (vmType != null) {
  			// For each VM child node, populate the container with a subordinate node
  			NodeList vmNodeList = vmTypeElement.getElementsByTagName("vm"); //$NON-NLS-1$
  