bug 28945 (202 Branch)
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaRuntime.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaRuntime.java
index d2b4acb..a135c03 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaRuntime.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaRuntime.java
@@ -1,1605 +1,1609 @@
-package org.eclipse.jdt.launching;

-

-/*******************************************************************************

- * Copyright (c) 2001, 2002 International Business Machines Corp. and others.

- * All rights reserved. This program and the accompanying materials 

- * are made available under the terms of the Common Public License v0.5 

- * which accompanies this distribution, and is available at

- * http://www.eclipse.org/legal/cpl-v05.html

- * 

- * Contributors:

- *     IBM Corporation - initial API and implementation

- ******************************************************************************/

-

-import java.io.BufferedInputStream;

-import java.io.File;

-import java.io.FileInputStream;

-import java.io.FileOutputStream;

-import java.io.IOException;

-import java.io.InputStream;

-import java.io.InputStreamReader;

-import java.io.Reader;

-import java.text.MessageFormat;

-import java.util.ArrayList;

-import java.util.Collections;

-import java.util.HashMap;

-import java.util.Iterator;

-import java.util.List;

-import java.util.Map;

-

-import javax.xml.parsers.DocumentBuilder;

-import javax.xml.parsers.DocumentBuilderFactory;

-import javax.xml.parsers.ParserConfigurationException;

-

-import org.apache.xerces.dom.DocumentImpl;

-import org.eclipse.core.resources.IResource;

-import org.eclipse.core.resources.ResourcesPlugin;

-import org.eclipse.core.runtime.CoreException;

-import org.eclipse.core.runtime.IConfigurationElement;

-import org.eclipse.core.runtime.IExtensionPoint;

-import org.eclipse.core.runtime.IPath;

-import org.eclipse.core.runtime.IProgressMonitor;

-import org.eclipse.core.runtime.IStatus;

-import org.eclipse.core.runtime.MultiStatus;

-import org.eclipse.core.runtime.Path;

-import org.eclipse.core.runtime.Platform;

-import org.eclipse.core.runtime.Preferences;

-import org.eclipse.core.runtime.Status;

-import org.eclipse.debug.core.ILaunchConfiguration;

-import org.eclipse.jdt.core.IClasspathContainer;

-import org.eclipse.jdt.core.IClasspathEntry;

-import org.eclipse.jdt.core.IJavaModel;

-import org.eclipse.jdt.core.IJavaProject;

-import org.eclipse.jdt.core.JavaCore;

-import org.eclipse.jdt.internal.launching.CompositeId;

-import org.eclipse.jdt.internal.launching.JREContainerInitializer;

-import org.eclipse.jdt.internal.launching.JavaClasspathVariablesInitializer;

-import org.eclipse.jdt.internal.launching.JavaLaunchConfigurationUtils;

-import org.eclipse.jdt.internal.launching.LaunchingMessages;

-import org.eclipse.jdt.internal.launching.LaunchingPlugin;

-import org.eclipse.jdt.internal.launching.ListenerList;

-import org.eclipse.jdt.internal.launching.RuntimeClasspathEntry;

-import org.eclipse.jdt.internal.launching.RuntimeClasspathEntryResolver;

-import org.eclipse.jdt.internal.launching.RuntimeClasspathProvider;

-import org.eclipse.jdt.internal.launching.SocketAttachConnector;

-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;

-

-/**

- * The central access point for launching support. This class manages

- * the registered VM types contributed through the 

- * <code>"org.eclipse.jdt.launching.vmType"</code> extension point.

- * As well, this class provides VM install change notification,

- * and computes classpaths and source lookup paths for launch

- * configurations.

- * <p>

- * This class provides static methods only; it is not intended to be

- * instantiated or subclassed by clients.

- * </p>

- */

-public final class JavaRuntime {

-	

-	/**

-	 * Classpath variable name used for the default JRE's library.

-	 */

-	public static final String JRELIB_VARIABLE= "JRE_LIB"; //$NON-NLS-1$

-

-	/**

-	 * Classpath variable name used for the default JRE's library source.

-	 */

-	public static final String JRESRC_VARIABLE= "JRE_SRC"; //$NON-NLS-1$

-	

-	/**

-	 * Classpath variable name used for the default JRE's library source root.

-	 */	

-	public static final String JRESRCROOT_VARIABLE= "JRE_SRCROOT"; //$NON-NLS-1$

-	

-	/**

-	 * Simple identifier constant (value <code>"runtimeClasspathEntryResolvers"</code>) for the

-	 * runtime classpath entry resolvers extension point.

-	 * 

-	 * @since 2.0

-	 */

-	public static final String EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRY_RESOLVERS= "runtimeClasspathEntryResolvers";	 //$NON-NLS-1$	

-	

-	/**

-	 * Simple identifier constant (value <code>"classpathProviders"</code>) for the

-	 * runtime classpath providers extension point.

-	 * 

-	 * @since 2.0

-	 */

-	public static final String EXTENSION_POINT_RUNTIME_CLASSPATH_PROVIDERS= "classpathProviders";	 //$NON-NLS-1$		

-		

-	/**

-	 * Classpath container used for a project's JRE. A container

-	 * is resolved in the context of a specific Java project, to

-	 * one or more system libraries contained in a JRE. The container

-	 * can have zero or two path segments following the container name. When

-	 * no segments follow the container name, the workspace default JRE is used

-	 * to build a project. Otherwise the segments identify a specific JRE used

-	 * to build a project:

-	 * <ol>

-	 * <li>VM Install Type Identifier - identifies the type of JRE used to build the

-	 * 	project. For example, the standard VM.</li>

-	 * <li>VM Install Name - a user defined name that identifies that a specific VM

-	 * 	of the above kind. For example, <code>IBM 1.3.1</code>. This information is

-	 *  shared in a projects classpath file, so teams must agree on JRE naming

-	 * 	conventions.</li>

-	 * </ol>

-	 * 

-	 * @since 2.0

-	 */

-	public static final String JRE_CONTAINER = LaunchingPlugin.getUniqueIdentifier() + ".JRE_CONTAINER"; //$NON-NLS-1$

-	

-	/**

-	 * A status code indicating that a JRE could not be resolved for a project.

-	 * When a JRE cannot be resolved for a project by this plug-in's container

-	 * initializer, an exception is thrown with this status code. A status handler

-	 * may be registered for this status code. The <code>source</code> object provided

-	 * to the status handler is the Java project for which the path could not be

-	 * resolved. The status handler must return an <code>IVMInstall</code> or <code>null</code>.

-	 * The container resolver will re-set the project's classpath if required.

-	 * 

-	 * @since 2.0

-	 */

-	public static final int ERR_UNABLE_TO_RESOLVE_JRE = 160;

-	

-	/**

-	 * Preference key for launch/connect timeout. VM Runners should honor this timeout

-	 * value when attempting to launch and connect to a debuggable VM. The value is

-	 * an int, indicating a number of millieseconds.

-	 * 

-	 * @since 2.0

-	 */

-	public static final String PREF_CONNECT_TIMEOUT = LaunchingPlugin.getUniqueIdentifier() + ".PREF_CONNECT_TIMEOUT"; //$NON-NLS-1$

-	

-	/**

-	 * Default launch/connect timeout (ms).

-	 * 

-	 * @since 2.0

-	 */

-	public static final int DEF_CONNECT_TIMEOUT = 20000;

-	

-	/**

-	 * Attribute key for a process property. The class

-	 * <code>org.eclipse.debug.core.model.IProcess</code> allows attaching

-	 * String properties to processes.

-	 * The value of this attribute is the command line a process

-	 * was launched with. Implementers of <code>IVMRunner</code> should use

-	 * this attribute key to attach the command lines to the processes they create.

-	 */

-	public final static String ATTR_CMDLINE= LaunchingPlugin.getUniqueIdentifier() + ".launcher.cmdLine"; //$NON-NLS-1$

-

-	private static IVMInstallType[] fgVMTypes= null;

-	private static String fgDefaultVMId= null;

-	private static String fgDefaultVMConnectorId = null;

-	

-	/**

-	 * Resolvers keyed by variable name and container id.

-	 */

-	private static Map fgVariableResolvers = null;

-	private static Map fgContainerResolvers = null;

-	

-	/**

-	 * Path providers keyed by id

-	 */

-	private static Map fgPathProviders = null;

-	

-	/**

-	 * Default classpath and source path providers.

-	 */

-	private static IRuntimeClasspathProvider fgDefaultClasspathProvider = new StandardClasspathProvider();

-	private static IRuntimeClasspathProvider fgDefaultSourcePathProvider = new StandardSourcePathProvider();

-	

-	/**

-	 * VM change listeners

-	 */

-	private static ListenerList fgVMListeners = new ListenerList(5);

-	

-	/**

-	 * Not intended to be instantiated.

-	 */

-	private JavaRuntime() {

-	}

-

-	/**

-	 * Returns the list of registered VM types. VM types are registered via

-	 * <code>"org.eclipse.jdt.launching.vmTypes"</code> extension point.

-	 * Returns an empty list if there are no registered VM types.

-	 * 

-	 * @return the list of registered VM types

-	 */

-	public static IVMInstallType[] getVMInstallTypes() {

-		if (fgVMTypes == null) {

-			initializeVMTypes();

-		}

-		return fgVMTypes; 

-	}

-	

-	private static synchronized void initializeVMTypes() {

-		IExtensionPoint extensionPoint= Platform.getPluginRegistry().getExtensionPoint(LaunchingPlugin.getUniqueIdentifier() + ".vmInstallTypes"); //$NON-NLS-1$

-		IConfigurationElement[] configs= extensionPoint.getConfigurationElements(); 

-		MultiStatus status= new MultiStatus(LaunchingPlugin.getUniqueIdentifier(), IStatus.OK, LaunchingMessages.getString("JavaRuntime.exceptionOccurred"), null); //$NON-NLS-1$

-		fgVMTypes= new IVMInstallType[configs.length];

-

-		for (int i= 0; i < configs.length; i++) {

-			try {

-				IVMInstallType vmType= (IVMInstallType)configs[i].createExecutableExtension("class"); //$NON-NLS-1$

-				fgVMTypes[i]= vmType;

-			} catch (CoreException e) {

-				status.add(e.getStatus());

-			}

-		}

-		if (!status.isOK()) {

-			//only happens on a CoreException

-			LaunchingPlugin.log(status);

-			//cleanup null entries in fgVMTypes

-			List temp= new ArrayList(fgVMTypes.length);

-			for (int i = 0; i < fgVMTypes.length; i++) {

-				if(fgVMTypes[i] != null) {

-					temp.add(fgVMTypes[i]);

-				}

-				fgVMTypes= new IVMInstallType[temp.size()];

-				fgVMTypes= (IVMInstallType[])temp.toArray(fgVMTypes);

-			}

-		}

-		

-		try {

-			initializeVMConfiguration();

-		} catch (IOException e) {

-			LaunchingPlugin.log(e);

-		}

-	}

-

-	/**

-	 * Returns the VM assigned to build the given Java project.

-	 * The project must exist. The VM assigned to a project is

-	 * determined from its build path.

-	 * 

-	 * @return the VM instance that is assigned to build the given Java project

-	 * 		   Returns <code>null</code> if no VM is referenced on the project's build path.

-	 * @throws CoreException if unable to determine the project's VM install

-	 */

-	public static IVMInstall getVMInstall(IJavaProject project) throws CoreException {

-		// check the classpath

-		IVMInstall vm = null;

-		IClasspathEntry[] classpath = project.getRawClasspath();

-		IRuntimeClasspathEntryResolver resolver = null;

-		for (int i = 0; i < classpath.length; i++) {

-			IClasspathEntry entry = classpath[i];

-			switch (entry.getEntryKind()) {

-				case IClasspathEntry.CPE_VARIABLE:

-					resolver = getVariableResolver(entry.getPath().segment(0));

-					if (resolver != null) {

-						vm = resolver.resolveVMInstall(entry);

-					}

-					break;

-				case IClasspathEntry.CPE_CONTAINER:

-					resolver = getContainerResolver(entry.getPath().segment(0));

-					if (resolver != null) {

-						vm = resolver.resolveVMInstall(entry);

-					}

-					break;

-			}

-			if (vm != null) {

-				return vm;

-			}

-		}

-		return null;

-	}

-	

-	private static IVMInstall getVMFromId(String idString) {

-		if (idString == null || idString.length() == 0) {

-			return null;

-		}

-		CompositeId id= CompositeId.fromString(idString);

-		if (id.getPartCount() == 2) {

-			IVMInstallType vmType= getVMInstallType(id.get(0));

-			if (vmType != null) {

-				return vmType.findVMInstall(id.get(1));

-			}

-		}

-		return null;

-	}

-

-	/**

-	 * Returns the VM install type with the given unique id. 

-	 * @return	The VM install type for the given id, or <code>null</code> if no

-	 * 			VM install type with the given id is registered.

-	 */

-	public static IVMInstallType getVMInstallType(String id) {

-		IVMInstallType[] vmTypes= getVMInstallTypes();

-		for (int i= 0; i < vmTypes.length; i++) {

-			if (vmTypes[i].getId().equals(id)) {

-				return vmTypes[i];

-			}

-		}

-		return null;

-	}

-	

-	/**

-	 * Sets a VM as the system-wide default VM, and notifies registered VM install

-	 * change listeners of the change.

-	 * 

-	 * @param vm	The vm to make the default. May be <code>null</code> to clear 

-	 * 				the default.

-	 * @param monitor progress monitor or <code>null</code>

-	 */

-	public static void setDefaultVMInstall(IVMInstall vm, IProgressMonitor monitor) throws CoreException {

-		IVMInstall previous = null;

-		if (fgDefaultVMId != null) {

-			previous = getVMFromId(fgDefaultVMId);

-		}

-		fgDefaultVMId= getIdFromVM(vm);

-		updateJREVariables(monitor);

-		saveVMConfiguration();

-		IVMInstall current = null;

-		if (fgDefaultVMId != null) {

-			current = getVMFromId(fgDefaultVMId);

-		}

-		if (previous != current) {

-			notifyDefaultVMChanged(previous, current);

-		}

-	}	

-	

-	/**

-	 * Sets a VM connector as the system-wide default VM. This setting is persisted when

-	 * saveVMConfiguration is called. 

-	 * @param	connector The connector to make the default. May be null to clear 

-	 * 				the default.

-	 * @since 2.0

-	 */

-	public static void setDefaultVMConnector(IVMConnector connector, IProgressMonitor monitor) throws CoreException {

-		fgDefaultVMConnectorId= connector.getIdentifier();

-		saveVMConfiguration();

-	}		

-	

-	private static void updateJREVariables(IProgressMonitor monitor) throws CoreException {

-		JavaClasspathVariablesInitializer updater= new JavaClasspathVariablesInitializer();

-		updater.updateJREVariables(monitor);

-		JREContainerInitializer conatinerUpdater = new JREContainerInitializer();

-		conatinerUpdater.updateDefaultJREContainers(monitor);

-	}

-	/**

-	 * Return the default VM set with <code>setDefaultVM()</code>.

-	 * @return	Returns the default VM. May return <code>null</code> when no default

-	 * 			VM was set or when the default VM has been disposed.

-	 */

-	public static IVMInstall getDefaultVMInstall() {

-		IVMInstall install= getVMFromId(getDefaultVMId());

-		if (install != null && install.getInstallLocation().exists()) {

-			return install;

-		} else {

-			// if the default JRE goes missing, re-detect

-			if (install != null) {

-				install.getVMInstallType().disposeVMInstall(install.getId());

-			}

-			fgDefaultVMId = null;

-			try {

-				//get rid of bad values on disk

-				saveVMConfiguration();

-			} catch(CoreException e) {

-				LaunchingPlugin.log(e);

-			}

-			detectVMConfiguration();

-			return getVMFromId(getDefaultVMId());

-		}

-	}

-	

-	/**

-	 * Return the default VM connector.

-	 * @return	Returns the default VM connector.

-	 * @since 2.0

-	 */

-	public static IVMConnector getDefaultVMConnector() {

-		String id = getDefaultVMConnectorId();

-		IVMConnector connector = null;

-		if (id != null) {

-			connector = getVMConnector(id);

-		}

-		if (connector == null) {

-			connector = new SocketAttachConnector();

-		}

-		return connector;

-	}	

-	

-	private static String getDefaultVMId() {

-		if (fgVMTypes == null) {

-			initializeVMTypes();

-		}

-		return fgDefaultVMId;

-	}

-	

-	private static String getDefaultVMConnectorId() {

-		if (fgVMTypes == null) {

-			initializeVMTypes();

-		}

-		return fgDefaultVMConnectorId;

-	}	

-	

-	private static String getIdFromVM(IVMInstall vm) {

-		if (vm == null) {

-			return null;

-		}

-		IVMInstallType vmType= vm.getVMInstallType();

-		String typeID= vmType.getId();

-		CompositeId id= new CompositeId(new String[] { typeID, vm.getId() });

-		return id.toString();

-	}

-	

-	/**

-	 * Returns a new runtime classpath entry for the given project.

-	 * 

-	 * @param project Java project

-	 * @return runtime classpath entry

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry newProjectRuntimeClasspathEntry(IJavaProject project) {

-		IClasspathEntry cpe = JavaCore.newProjectEntry(project.getProject().getFullPath());

-		return newRuntimeClasspathEntry(cpe);

-	}

-	

-	

-	/**

-	 * Returns a new runtime classpath entry for the given archive.

-	 * 

-	 * @param resource archive resource

-	 * @return runtime classpath entry

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry newArchiveRuntimeClasspathEntry(IResource resource) {

-		IClasspathEntry cpe = JavaCore.newLibraryEntry(resource.getFullPath(), null, null);

-		return newRuntimeClasspathEntry(cpe);

-	}

-	

-	/**

-	 * Returns a new runtime classpath entry for the given archive (possibly

-	 * external).

-	 * 

-	 * @param path absolute path to an archive

-	 * @return runtime classpath entry

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry newArchiveRuntimeClasspathEntry(IPath path) {

-		IClasspathEntry cpe = JavaCore.newLibraryEntry(path, null, null);

-		return newRuntimeClasspathEntry(cpe);

-	}

-

-	/**

-	 * Returns a new runtime classpath entry for the classpath

-	 * variable with the given path.

-	 * 

-	 * @param path variable path; first segment is the name of the variable; 

-	 * 	trailing segments are appended to the resolved variable value

-	 * @return runtime classpath entry

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry newVariableRuntimeClasspathEntry(IPath path) {

-		IClasspathEntry cpe = JavaCore.newVariableEntry(path, null, null);

-		return newRuntimeClasspathEntry(cpe);

-	}

-

-	/**

-	 * Returns a runtime classpath entry for the given container path with the given

-	 * classpath property.

-	 * 

-	 * @param path container path

-	 * @param classpathProperty the type of entry - one of <code>USER_CLASSES</code>,

-	 * 	<code>BOOTSTRAP_CLASSES</code>, or <code>STANDARD_CLASSES</code>

-	 * @return runtime classpath entry

-	 * @exception CoreException if unable to construct a runtime classpath entry

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry newRuntimeContainerClasspathEntry(IPath path, int classpathProperty) throws CoreException {

-		IClasspathEntry cpe = JavaCore.newContainerEntry(path);

-		return new RuntimeClasspathEntry(cpe, classpathProperty);

-	}

-		

-	/**

-	 * Returns a runtime classpath entry constructed from the given memento.

-	 * 

-	 * @param memento a menento for a runtime classpath entry

-	 * @return runtime classpath entry

-	 * @exception CoreException if unable to construct a runtime classpath entry

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry newRuntimeClasspathEntry(String memento) throws CoreException {

-		return new RuntimeClasspathEntry(memento);

-	}

-	

-	/**

-	 * Returns a runtime classpath entry that corresponds to the given

-	 * classpath entry. The classpath entry may not be of type <code>CPE_SOURCE</code>

-	 * or <code>CPE_CONTAINER</code>.

-	 * 

-	 * @param entry a classpath entry

-	 * @return runtime classpath entry

-	 * @since 2.0

-	 */

-	private static IRuntimeClasspathEntry newRuntimeClasspathEntry(IClasspathEntry entry) {

-		return new RuntimeClasspathEntry(entry);

-	}	

-			

-	/**

-	 * Computes and returns the default unresolved runtime claspath for the

-	 * given project.

-	 * 

-	 * @return runtime classpath entries

-	 * @exception CoreException if unable to compute the runtime classpath

-	 * @see IRuntimeClasspathEntry

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry[] computeUnresolvedRuntimeClasspath(IJavaProject project) throws CoreException {

-		IClasspathEntry entry = JavaCore.newProjectEntry(project.getProject().getFullPath());

-		List classpathEntries = new ArrayList(5);

-		expandProject(entry, classpathEntries);

-		IRuntimeClasspathEntry[] runtimeEntries = new IRuntimeClasspathEntry[classpathEntries == null ? 0 : classpathEntries.size()];

-		for (int i = 0; i < runtimeEntries.length; i++) {

-			Object e = classpathEntries.get(i);

-			if (e instanceof IClasspathEntry) {

-				IClasspathEntry cpe = (IClasspathEntry)e;

-				runtimeEntries[i] = newRuntimeClasspathEntry(cpe);

-			} else {

-				runtimeEntries[i] = (IRuntimeClasspathEntry)e;				

-			}

-		}

-		// sort bootpath and standard entries first

-		IRuntimeClasspathEntry[] ordered = new IRuntimeClasspathEntry[runtimeEntries.length];

-		int index = 0;

-		for (int i = 0; i < runtimeEntries.length; i++) {

-			if (runtimeEntries[i].getClasspathProperty() != IRuntimeClasspathEntry.USER_CLASSES) {

-				ordered[index] = runtimeEntries[i];

-				index++;

-				runtimeEntries[i] = null;

-			} 

-		}

-		for (int i = 0; i < runtimeEntries.length; i++) {

-			if (runtimeEntries[i] != null) {

-				ordered[index] = runtimeEntries[i];

-				index++;

-			}

-		}

-		return ordered;

-	}

-	

-	/**

-	 * Computes and returns the unresolved source lookup path for the given launch

-	 * configuration.

-	 * 

-	 * @param configuration launch configuration

-	 * @return runtime classpath entries

-	 * @exception CoreException if unable to compute the source lookup path

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry[] computeUnresolvedSourceLookupPath(ILaunchConfiguration configuration) throws CoreException {

-		return getSourceLookupPathProvider(configuration).computeUnresolvedClasspath(configuration);

-	}

-	

-	/**

-	 * Resolves the given source lookup path, returning the resolved source lookup path

-	 * in the context of the given launch configuration.

-	 * 

-	 * @param entries unresolved entries

-	 * @param configuration launch configuration

-	 * @return resolved entries

-	 * @exception CoreException if unable to resolve the source lookup path

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry[] resolveSourceLookupPath(IRuntimeClasspathEntry[] entries, ILaunchConfiguration configuration) throws CoreException {

-		return getSourceLookupPathProvider(configuration).resolveClasspath(entries, configuration);

-	}	

-	

-	/**

-	 * Returns the classpath provider for the given launch configuration.

-	 * 

-	 * @param configuration launch configuration

-	 * @return classpath provider

-	 * @exception CoreException if unable to resolve the path provider

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathProvider getClasspathProvider(ILaunchConfiguration configuration) throws CoreException {

-		String providerId = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH_PROVIDER, (String)null);

-		IRuntimeClasspathProvider provider = null;

-		if (providerId == null) {

-			provider = fgDefaultClasspathProvider;

-		} else {

-			provider = (IRuntimeClasspathProvider)getClasspathProviders().get(providerId);	

-		}

-		return provider;

-	}	

-		

-	/**

-	 * Returns the source lookup path provider for the given launch configuration.

-	 * 

-	 * @param configuration launch configuration

-	 * @return source lookup path provider

-	 * @exception CoreException if unable to resolve the path provider

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathProvider getSourceLookupPathProvider(ILaunchConfiguration configuration) throws CoreException {

-		String providerId = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER, (String)null);

-		IRuntimeClasspathProvider provider = null;

-		if (providerId == null) {

-			provider = fgDefaultSourcePathProvider;

-		} else {

-			provider = (IRuntimeClasspathProvider)getClasspathProviders().get(providerId);

-		}

-		return provider;

-	}	

-		

-	/**

-	 * Returns resolved entries for the given entry in the context of the given

-	 * launch configuration. If the entry is of kind

-	 * <code>VARIABLE</code> or <code>CONTAINTER</code>, variable and contanier

-	 * resolvers are consulted, otherwise, the returned entry is the same as the 

-	 * given entry.

-	 * <p>

-	 * If the given entry is a variable entry, and a resolver is not registered,

-	 * the entry itself is returned. If the given entry is a container, and a

-	 * resolver is not registered, resolved runtime classpath entries are calculated

-	 * from the associated container classpath entries, in the context of the project

-	 * associated with the given launch configuration.

-	 * </p>

-	 * @param entry runtime classpath entry

-	 * @param configuration launch configuration

-	 * @return resolved runtime classpath entry

-	 * @exception CoreException if unable to resolve

-	 * @see IRuntimeClasspathEntryResolver

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(IRuntimeClasspathEntry entry, ILaunchConfiguration configuration) throws CoreException {

-		switch (entry.getType()) {

-			case IRuntimeClasspathEntry.VARIABLE:

-				IRuntimeClasspathEntryResolver resolver = getVariableResolver(entry.getVariableName());

-				if (resolver == null) {

-					// no resolution by default

-					break;

-				} else {

-					return resolver.resolveRuntimeClasspathEntry(entry, configuration);

-				}				

-			case IRuntimeClasspathEntry.CONTAINER:

-				resolver = getContainerResolver(entry.getVariableName());

-				if (resolver == null) {

-					return computeDefaultContainerEntries(entry, configuration);

-				} else {

-					return resolver.resolveRuntimeClasspathEntry(entry, configuration);

-				}

-			default:

-				break;

-		}

-		return new IRuntimeClasspathEntry[] {entry};

-	}

-	

-	/**

-	 * Returns resolved entries for the given entry in the context of the given

-	 * Java project. If the entry is of kind

-	 * <code>VARIABLE</code> or <code>CONTAINTER</code>, variable and contanier

-	 * resolvers are consulted, otherwise, the returned entry is the same as the given

-	 * entry.

-	 * <p>

-	 * If the given entry is a variable entry, and a resolver is not registered,

-	 * the entry itself is returned. If the given entry is a container, and a

-	 * resolver is not registered, resolved runtime classpath entries are calculated

-	 * from the associated container classpath entries, in the context of the 

-	 * given project.

-	 * </p>

-	 * @param entry runtime classpath entry

-	 * @param project Java project context

-	 * @return resolved runtime classpath entry

-	 * @exception CoreException if unable to resolve

-	 * @see IRuntimeClasspathEntryResolver

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(IRuntimeClasspathEntry entry, IJavaProject project) throws CoreException {

-		switch (entry.getType()) {

-			case IRuntimeClasspathEntry.VARIABLE:

-				IRuntimeClasspathEntryResolver resolver = getVariableResolver(entry.getVariableName());

-				if (resolver == null) {

-					// no resolution by default

-					break;

-				} else {

-					return resolver.resolveRuntimeClasspathEntry(entry, project);

-				}				

-			case IRuntimeClasspathEntry.CONTAINER:

-				resolver = getContainerResolver(entry.getVariableName());

-				if (resolver == null) {

-					return computeDefaultContainerEntries(entry, project);

-				} else {

-					return resolver.resolveRuntimeClasspathEntry(entry, project);

-				}

-			default:

-				break;

-		}

-		return new IRuntimeClasspathEntry[] {entry};

-	}	

-		

-	/**

-	 * Performs default resolution for a container entry.

-	 * Delegates to the Java model.

-	 */

-	private static IRuntimeClasspathEntry[] computeDefaultContainerEntries(IRuntimeClasspathEntry entry, ILaunchConfiguration config) throws CoreException {

-		return computeDefaultContainerEntries(entry, getJavaProject(config));

-	}

-	

-	/**

-	 * Performs default resolution for a container entry.

-	 * Delegates to the Java model.

-	 */

-	private static IRuntimeClasspathEntry[] computeDefaultContainerEntries(IRuntimeClasspathEntry entry, IJavaProject project) throws CoreException {

-		if (project == null) {

-			// cannot resolve without project context

-			return new IRuntimeClasspathEntry[0];

-		} else {							

-			IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);

-			IClasspathEntry[] cpes = container.getClasspathEntries();

-			int property = -1;

-			switch (container.getKind()) {

-				case IClasspathContainer.K_APPLICATION:

-					property = IRuntimeClasspathEntry.USER_CLASSES;

-					break;

-				case IClasspathContainer.K_DEFAULT_SYSTEM:

-					property = IRuntimeClasspathEntry.STANDARD_CLASSES;

-					break;	

-				case IClasspathContainer.K_SYSTEM:

-					property = IRuntimeClasspathEntry.BOOTSTRAP_CLASSES;

-					break;

-			}			

-			IRuntimeClasspathEntry[] resolved = new IRuntimeClasspathEntry[cpes.length];

-			for (int i = 0; i < resolved.length; i++) {

-				resolved[i] = newRuntimeClasspathEntry(cpes[i]);

-				resolved[i].setClasspathProperty(property);

-			}

-			return resolved;

-		}

-	}

-			

-	/**

-	 * Computes and returns the unresolved class path for the given launch configuration.

-	 * Variable and container entries are unresolved.

-	 * 

-	 * @param configuration launch configuration

-	 * @return unresolved runtime classpath entries

-	 * @exception CoreException if unable to compute the classpath

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry[] computeUnresolvedRuntimeClasspath(ILaunchConfiguration configuration) throws CoreException {

-		return getClasspathProvider(configuration).computeUnresolvedClasspath(configuration);

-	}

-	

-	/**

-	 * Resolves the given classpath, returning the resolved classpath

-	 * in the context of the given launch configuration.

-	 *

-	 * @param entries unresolved classpath

-	 * @param configuration launch configuration

-	 * @return resolved runtime classpath entries

-	 * @exception CoreException if unable to compute the classpath

-	 * @since 2.0

-	 */

-	public static IRuntimeClasspathEntry[] resolveRuntimeClasspath(IRuntimeClasspathEntry[] entries, ILaunchConfiguration configuration) throws CoreException {

-		return getClasspathProvider(configuration).resolveClasspath(entries, configuration);

-	}	

-	

-	/**

-	 * Return the <code>IJavaProject</code> referenced in the specified configuration or

-	 * <code>null</code> if none.

-	 *

-	 * @exception CoreException if the referenced Java project does not exist

-	 * @since 2.0

-	 */

-	public static IJavaProject getJavaProject(ILaunchConfiguration configuration) throws CoreException {

-		String projectName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null);

-		if ((projectName == null) || (projectName.trim().length() < 1)) {

-			return null;

-		}			

-		IJavaProject javaProject = getJavaModel().getJavaProject(projectName);		

-		if ((javaProject == null) || !javaProject.exists()) {

-			abort(MessageFormat.format(LaunchingMessages.getString("JavaRuntime.Launch_configuration_{0}_references_non-existing_project_{1}._1"), new String[] {configuration.getName(), projectName}), IJavaLaunchConfigurationConstants.ERR_NOT_A_JAVA_PROJECT, null); //$NON-NLS-1$

-		}

-		return javaProject;

-	}

-				

-	/**

-	 * Convenience method to get the java model.

-	 */

-	private static IJavaModel getJavaModel() {

-		return JavaCore.create(ResourcesPlugin.getWorkspace().getRoot());

-	}

-	

-	

-	/**

-	 * Returns a collection of runtime classpath entries that are defined in the

-	 * specified attribute of the given launch configuration.

-	 * 

-	 * @param configuration launch configuration

-	 * @param attribute attribute name containing the list of entries

-	 * @return collection of runtime classpath entries that are defined in the

-	 *  specified attribute of the given launch configuration

-	 * @exception CoreException if unable to retrieve the list

-	 */

-	private static IRuntimeClasspathEntry[] recoverRuntimePath(ILaunchConfiguration configuration, String attribute) throws CoreException {

-		List entries = (List)configuration.getAttribute(attribute, Collections.EMPTY_LIST);

-		IRuntimeClasspathEntry[] rtes = new IRuntimeClasspathEntry[entries.size()];

-		Iterator iter = entries.iterator();

-		int i = 0;

-		while (iter.hasNext()) {

-			rtes[i] = newRuntimeClasspathEntry((String)iter.next());

-			i++;

-		}

-		return rtes;		

-	}

-	

-	/**

-	 * Returns the VM install for the given launch configuration.

-	 * The VM install is determined in the following prioritized way:

-	 * <ol>

-	 * <li>The VM install is explicitly specified on the launch configuration

-	 * 	via the <code>ATTR_VM_INSTALL_TYPE</code> and <code>ATTR_VM_INSTALL_ID</code>

-	 *  attributes.</li>

-	 * <li>If no explicit VM install is specified, the VM install associated with

-	 * 	the launch confiugration's project is returned.</li>

-	 * <li>If no project is specified, or the project does not specify a custom

-	 * 	VM install, the workspace default VM install is returned.</li>

-	 * </ol>

-	 * 

-	 * @param configuration launch configuration

-	 * @return vm install

-	 * @exception CoreException if unable to compute a vm install

-	 * @since 2.0

-	 */

-	public static IVMInstall computeVMInstall(ILaunchConfiguration configuration) throws CoreException {

-		String type = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE, (String)null);

-		if (type == null) {

-			IJavaProject proj = getJavaProject(configuration);

-			if (proj != null) {

-				IVMInstall vm = getVMInstall(proj);

-				if (vm != null) {

-					return vm;

-				}

-			}

-		} else {

-			IVMInstallType vt = getVMInstallType(type);

-			if (vt == null) {

-				// error type does not exist

-				abort(MessageFormat.format(LaunchingMessages.getString("JavaRuntime.Specified_VM_install_type_does_not_exist__{0}_2"), new String[] {type}), null); //$NON-NLS-1$

-			}

-			IVMInstall vm = null;

-			// look for a name

-			String name = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME, (String)null);

-			if (name == null) {

-				// error - type specified without a specific install (could be an old config that specified a VM ID)

-				// log the error, but choose the default VM.

-				IStatus status = new Status(IStatus.WARNING, LaunchingPlugin.getUniqueIdentifier(), IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_VM_INSTALL, MessageFormat.format(LaunchingMessages.getString("JavaRuntime.VM_not_fully_specified_in_launch_configuration_{0}_-_missing_VM_name._Reverting_to_default_VM._1"), new String[] {configuration.getName()}), null); //$NON-NLS-1$

-				LaunchingPlugin.log(status);

-				return getDefaultVMInstall();

-			} else {

-				vm = vt.findVMInstallByName(name);

-				if (vm == null) {

-					// error - install not found

-					abort(MessageFormat.format(LaunchingMessages.getString("JavaRuntime.Specified_VM_install_not_found__type_{0},_name_{1}_2"), new String[] {type, name}), null);					 //$NON-NLS-1$

-				} else {

-					return vm;

-				}

-			}

-		}

-		

-		return getDefaultVMInstall();

-	}

-	

-	/**

-	 * Throws a core exception with an internal error status.

-	 * 

-	 * @param message the status message

-	 * @param exception lower level exception associated with the

-	 *  error, or <code>null</code> if none

-	 */

-	private static void abort(String message, Throwable exception) throws CoreException {

-		abort(message, IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR, exception);

-	}	

-		

-		

-	/**

-	 * Throws a core exception with an internal error status.

-	 * 

-	 * @param message the status message

-	 * @param code status code

-	 * @param exception lower level exception associated with the

-	 * 

-	 *  error, or <code>null</code> if none

-	 */

-	private static void abort(String message, int code, Throwable exception) throws CoreException {

-		throw new CoreException(new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), code, message, exception));

-	}	

-					

-	/**

-	 * Returns the transitive closure of classpath entries for the

-	 * given project entry.

-	 * 

-	 * @param projectEntry project classpath entry

-	 * @param a list of entries already expanded, should be empty to begin,

-	 *  and contains the result

-	 * @exception CoreException if unable to expand the classpath

-	 */

-	private static void expandProject(IClasspathEntry projectEntry, List expandedPath) throws CoreException {

-		// 1. Get the raw classpath

-		// 2. Replace source folder entries with a project entry

-		IPath projectPath = projectEntry.getPath();

-		IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(projectPath.lastSegment());

-		if (res == null) {

-			return;

-		}

-		IJavaProject project = (IJavaProject)JavaCore.create(res);

-		if (project == null) {

-			return;

-		}

-		IClasspathEntry[] buildPath = project.getRawClasspath();

-		List unexpandedPath = new ArrayList(buildPath.length);

-		boolean projectAdded = false;

-		for (int i = 0; i < buildPath.length; i++) {

-			if (buildPath[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {

-				if (!projectAdded) {

-					projectAdded = true;

-					unexpandedPath.add(projectEntry);

-				}

-			} else {

-				unexpandedPath.add(buildPath[i]);

-			}

-		}

-		// 3. expand each project entry (except for the root project)

-		// 4. replace each container entry with a runtime entry associated with the project

-		Iterator iter = unexpandedPath.iterator();

-		while (iter.hasNext()) {

-			IClasspathEntry entry = (IClasspathEntry)iter.next();

-			if (entry == projectEntry) {

-				expandedPath.add(entry);

-			} else {

-				switch (entry.getEntryKind()) {

-					case IClasspathEntry.CPE_PROJECT:

-						if (!expandedPath.contains(entry)) {

-							expandProject(entry, expandedPath);

-						}

-						break;

-					case IClasspathEntry.CPE_CONTAINER:

-						IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);

-						int property = -1;

-						switch (container.getKind()) {

-							case IClasspathContainer.K_APPLICATION:

-								property = IRuntimeClasspathEntry.USER_CLASSES;

-								break;

-							case IClasspathContainer.K_DEFAULT_SYSTEM:

-								property = IRuntimeClasspathEntry.STANDARD_CLASSES;

-								break;	

-							case IClasspathContainer.K_SYSTEM:

-								property = IRuntimeClasspathEntry.BOOTSTRAP_CLASSES;

-								break;

-						}

-						IRuntimeClasspathEntry r = newRuntimeContainerClasspathEntry(entry.getPath(), property);

-						// check for duplicate/redundant entries 

-						boolean duplicate = false;

-						for (int i = 0; i < expandedPath.size(); i++) {

-							Object o = expandedPath.get(i);

-							if (o instanceof IRuntimeClasspathEntry) {

-								IRuntimeClasspathEntry re = (IRuntimeClasspathEntry)o;

-								if (re.getType() == IRuntimeClasspathEntry.CONTAINER) {

-									if (container instanceof IRuntimeContainerComparator) {

-										duplicate = ((IRuntimeContainerComparator)container).isDuplicate(re.getPath());

-										if (duplicate) {

-											break;

-										}

-									} else if (re.getVariableName().equals(r.getVariableName())) {

-										duplicate = true;

-										break;

-									}

-								}

-							}

-						}

-						if (!duplicate) {

-							expandedPath.add(r);

-						}	

-						break;

-					case IClasspathEntry.CPE_VARIABLE:

-						if (entry.getPath().segment(0).equals(JRELIB_VARIABLE)) {

-							r = newVariableRuntimeClasspathEntry(entry.getPath());

-							r.setSourceAttachmentPath(entry.getSourceAttachmentPath());

-							r.setSourceAttachmentRootPath(entry.getSourceAttachmentRootPath());

-							r.setClasspathProperty(IRuntimeClasspathEntry.STANDARD_CLASSES);

-							if (!expandedPath.contains(r)) {

-								expandedPath.add(r);

-							}

-							break;

-						}

-						// fall through if not the special JRELIB variable

-					default:

-						if (!expandedPath.contains(entry)) {

-							expandedPath.add(entry);

-						}

-						break;

-				}

-			}

-		}

-		return;

-	}

-		

-	/**

-	 * Computes the default application classpath entries for the given 

-	 * project.

-	 * 

-	 * @param	jproject The project to compute the classpath for

-	 * @return	The computed classpath. May be empty, but not null.

-	 * @throws	CoreException if unable to compute the default classpath

-	 */

-	public static String[] computeDefaultRuntimeClassPath(IJavaProject jproject) throws CoreException {

-		IRuntimeClasspathEntry[] unresolved = computeUnresolvedRuntimeClasspath(jproject);

-		// 1. remove bootpath entries

-		// 2. resolve & translate to local file system paths

-		List resolved = new ArrayList(unresolved.length);

-		for (int i = 0; i < unresolved.length; i++) {

-			IRuntimeClasspathEntry entry = unresolved[i];

-			if (unresolved[i].getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) {

-				switch (entry.getType()) {

-					case IRuntimeClasspathEntry.CONTAINER:

-						IRuntimeClasspathEntry[] contained = computeDefaultContainerEntries(entry, jproject);

-						for (int j = 0; j < contained.length; j++) {

-							resolved.add(contained[j].getLocation());

-						}

-						break;

-					default:

-						resolved.add(entry.getLocation());

-						break;

-				}

-			}

-		}

-		return (String[])resolved.toArray(new String[resolved.size()]);

-	}	

-		

-	/**

-	 * Saves the VM configuration information to disk. This includes

-	 * the following information:

-	 * <ul>

-	 * <li>The list of all defined IVMInstall instances.</li>

-	 * <li>The default VM</li>

-	 * <ul>

-	 * This state will be read again upon first access to VM

-	 * configuration information.

-	 */

-	public static void saveVMConfiguration() throws CoreException {

-		IPath stateLocation= LaunchingPlugin.getDefault().getStateLocation();

-		IPath stateFile= stateLocation.append("vmConfiguration.xml"); //$NON-NLS-1$

-		File f= new File(stateFile.toOSString());

-		try {

-			String xml = getVMsAsXML();

-			FileOutputStream stream = new FileOutputStream(f);

-			stream.write(xml.getBytes("UTF8")); //$NON-NLS-1$

-			stream.close();			

-		} catch (IOException e) {

-			throw new CoreException(new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), IStatus.ERROR, LaunchingMessages.getString("JavaRuntime.ioExceptionOccurred"), e)); //$NON-NLS-1$

-		}

-		

-	}

-	

-	private static String getVMsAsXML() throws IOException {

-		Document doc = new DocumentImpl();

-		Element config = doc.createElement("vmSettings"); //$NON-NLS-1$

-		if (fgDefaultVMId != null) {

-			config.setAttribute("defaultVM", fgDefaultVMId); //$NON-NLS-1$

-		}

-		if (fgDefaultVMConnectorId != null) {

-			config.setAttribute("defaultVMConnector", fgDefaultVMConnectorId); //$NON-NLS-1$

-		}

-		doc.appendChild(config);

-		

-		IVMInstallType[] vmTypes= getVMInstallTypes();

-

-		for (int i = 0; i < vmTypes.length; ++i) {

-			Element vmTypeElement = vmTypeAsElement(doc, vmTypes[i]);

-			config.appendChild(vmTypeElement);

-		}

-

-		return JavaLaunchConfigurationUtils.serializeDocument(doc);

-	}

-	

-	private static Element vmTypeAsElement(Document doc, IVMInstallType vmType) {

-		Element element= doc.createElement("vmType"); //$NON-NLS-1$

-		element.setAttribute("id", vmType.getId()); //$NON-NLS-1$

-		IVMInstall[] vms= vmType.getVMInstalls();

-		for (int i= 0; i < vms.length; i++) {

-			Element vmElement= vmAsElement(doc, vms[i]);

-			element.appendChild(vmElement);

-		}

-		return element;

-	}

-	

-	private static Element vmAsElement(Document doc, IVMInstall vm) {

-		Element element= doc.createElement("vm"); //$NON-NLS-1$

-		element.setAttribute("id", vm.getId());	 //$NON-NLS-1$

-		element.setAttribute("name", vm.getName()); //$NON-NLS-1$

-		String installPath= ""; //$NON-NLS-1$

-		File installLocation= vm.getInstallLocation();

-		if (installLocation != null) {

-			installPath= installLocation.getAbsolutePath();

-		}

-		element.setAttribute("path", installPath); //$NON-NLS-1$

-		LibraryLocation[] libraryLocations= vm.getLibraryLocations();

-		if (libraryLocations != null) {

-			Element libLocationElement=  libraryLocationsAsElement(doc, libraryLocations);

-			element.appendChild(libLocationElement);

-		}

-		return element;

-	}

-	

-	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$

-			element.setAttribute("pkgRoot", locations[i].getPackageRootPath().toString()); //$NON-NLS-1$

-			root.appendChild(element);

-		}

-		return root;

-	}

-	

-	private static void initializeVMConfiguration() throws IOException {

-		IPath stateLocation= LaunchingPlugin.getDefault().getStateLocation();

-		IPath stateFile= stateLocation.append("vmConfiguration.xml"); //$NON-NLS-1$

-		File f= new File(stateFile.toOSString());

-		if (f.isFile()) {

-			loadVMConfiguration(f);

-		} else {

-			detectVMConfiguration();

-		}

-	}

-	

-	private static void loadVMConfiguration(File f) throws IOException {

-		InputStream stream= new BufferedInputStream(new FileInputStream(f));

-		Reader reader= new InputStreamReader(stream, "UTF-8"); //$NON-NLS-1$

-		Element config= null;

-		try {

-			DocumentBuilder parser= DocumentBuilderFactory.newInstance().newDocumentBuilder();

-			config = parser.parse(new InputSource(reader)).getDocumentElement();

-		} catch (SAXException e) {

-			throw new IOException(LaunchingMessages.getString("JavaRuntime.badFormat")); //$NON-NLS-1$

-		} catch (ParserConfigurationException e) {

-			reader.close();

-			throw new IOException(LaunchingMessages.getString("JavaRuntime.badFormat")); //$NON-NLS-1$

-		} finally {

-			reader.close();

-		}

-		if (!config.getNodeName().equalsIgnoreCase("vmSettings")) { //$NON-NLS-1$

-			throw new IOException(LaunchingMessages.getString("JavaRuntime.badFormat")); //$NON-NLS-1$

-		}

-		fgDefaultVMId= config.getAttribute("defaultVM"); //$NON-NLS-1$

-		fgDefaultVMConnectorId = config.getAttribute("defaultVMConnector"); //$NON-NLS-1$

-		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$

-					createFromVMType(vmTypeElement);

-				}

-			}

-		}

-	}

-	

-	private static void detectVMConfiguration() {

-		IVMInstallType[] vmTypes= getVMInstallTypes();

-		boolean defaultSet= false;

-		for (int i= 0; i < vmTypes.length; i++) {

-			File detectedLocation= vmTypes[i].detectInstallLocation();

-			if (detectedLocation != null) {

-				int unique = i;

-				IVMInstallType vmType = vmTypes[i];

-				while (vmType.findVMInstall(String.valueOf(unique)) != null) {

-					unique++;

-				}

-				IVMInstall detected= vmTypes[i].createVMInstall(String.valueOf(unique));

-				detected.setName(LaunchingMessages.getString("JavaRuntime.detectedSuffix")); //$NON-NLS-1$

-				detected.setInstallLocation(detectedLocation);

-				if (detected != null && !defaultSet) {

-					try {

-						setDefaultVMInstall(detected, null);

-						defaultSet= true;

-					} catch (CoreException e) {

-						LaunchingPlugin.log(e);

-					}

-				}

-			}

-		}

-	}

-	

-	private static void createFromVMType(Element vmTypeElement) {

-		String id = vmTypeElement.getAttribute("id"); //$NON-NLS-1$

-		IVMInstallType vmType= getVMInstallType(id);

-		if (vmType != null) {

-			NodeList list = vmTypeElement.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 vmElement = (Element) node;

-					if (vmElement.getNodeName().equalsIgnoreCase("vm")) { //$NON-NLS-1$

-						createVM(vmType, vmElement);

-					}

-				}

-			}

-		} else {

-			LaunchingPlugin.log(LaunchingMessages.getString("JavaRuntime.VM_type_element_with_unknown_id_1")); //$NON-NLS-1$

-		}

-	}

-

-	private static void createVM(IVMInstallType vmType, Element vmElement) {

-		String id= vmElement.getAttribute("id"); //$NON-NLS-1$

-		if (id != null) {

-			String installPath= vmElement.getAttribute("path"); //$NON-NLS-1$

-			if (installPath == null) {

-				return;

-			}

-			File installLocation= new File(installPath);

-			if (!installLocation.exists()) {

-				return;

-			}

-			IVMInstall vm= vmType.createVMInstall(id);

-			vm.setName(vmElement.getAttribute("name")); //$NON-NLS-1$

-			vm.setInstallLocation(installLocation);

-			

-			NodeList list = vmElement.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 libraryLocationElement= (Element)node;

-					if (libraryLocationElement.getNodeName().equals("libraryLocation")) { //$NON-NLS-1$

-						LibraryLocation loc = getLibraryLocation(vm, libraryLocationElement);

-						vm.setLibraryLocations(new LibraryLocation[]{loc});

-						break;

-					} else if (libraryLocationElement.getNodeName().equals("libraryLocations")) { //$NON-NLS-1$

-						setLibraryLocations(vm, libraryLocationElement);

-						break;

-					}

-				}

-			}

-

-		} else {

-			LaunchingPlugin.log(LaunchingMessages.getString("JavaRuntime.VM_element_specified_with_no_id_attribute_2")); //$NON-NLS-1$

-		}

-	}

-	

-	private static LibraryLocation getLibraryLocation(IVMInstall vm, Element libLocationElement) {

-		String jreJar= libLocationElement.getAttribute("jreJar"); //$NON-NLS-1$

-		String jreSrc= libLocationElement.getAttribute("jreSrc"); //$NON-NLS-1$

-		String pkgRoot= libLocationElement.getAttribute("pkgRoot"); //$NON-NLS-1$

-		if (jreJar != null && jreSrc != null && pkgRoot != null) {

-			return new LibraryLocation(new Path(jreJar), new Path(jreSrc), new Path(pkgRoot));

-		} else {

-			LaunchingPlugin.log(LaunchingMessages.getString("JavaRuntime.Library_location_element_incorrectly_specified_3")); //$NON-NLS-1$

-		}

-		return null;

-	}

-	

-	private static void setLibraryLocations(IVMInstall vm, Element libLocationsElement) {

-		NodeList list = libLocationsElement.getChildNodes();

-		int length = list.getLength();

-		List locations = new ArrayList(length);

-		for (int i = 0; i < length; ++i) {

-			Node node = list.item(i);

-			short type = node.getNodeType();

-			if (type == Node.ELEMENT_NODE) {

-				Element libraryLocationElement= (Element)node;

-				if (libraryLocationElement.getNodeName().equals("libraryLocation")) { //$NON-NLS-1$

-					locations.add(getLibraryLocation(vm, libraryLocationElement));

-				}

-			}

-		}	

-		vm.setLibraryLocations((LibraryLocation[])locations.toArray(new LibraryLocation[locations.size()]));

-	}

-		

-	/**

-	 * Evaluates library locations for a IVMInstall. If no library locations are set on the install, a default

-	 * location is evaluated and checked if it exists.

-	 * @return library locations with paths that exist or are empty

-	 * @since 2.0

-	 */

-	public static LibraryLocation[] getLibraryLocations(IVMInstall vm)  {

-		IPath[] libraryPaths;

-		IPath[] sourcePaths;

-		IPath[] sourceRootPaths;

-		LibraryLocation[] locations= vm.getLibraryLocations();

-		if (locations == null) {

-			LibraryLocation[] dflts= vm.getVMInstallType().getDefaultLibraryLocations(vm.getInstallLocation());

-			libraryPaths = new IPath[dflts.length];

-			sourcePaths = new IPath[dflts.length];

-			sourceRootPaths = new IPath[dflts.length];

-			for (int i = 0; i < dflts.length; i++) {

-				libraryPaths[i]= dflts[i].getSystemLibraryPath();

-				if (!libraryPaths[i].toFile().isFile()) {

-					libraryPaths[i]= Path.EMPTY;

-				}

-				

-				sourcePaths[i]= dflts[i].getSystemLibrarySourcePath();

-				if (sourcePaths[i].toFile().isFile()) {

-					sourceRootPaths[i]= dflts[i].getPackageRootPath();

-				} else {

-					sourcePaths[i]= Path.EMPTY;

-					sourceRootPaths[i]= Path.EMPTY;

-				}

-			}

-		} else {

-			libraryPaths = new IPath[locations.length];

-			sourcePaths = new IPath[locations.length];

-			sourceRootPaths = new IPath[locations.length];

-			for (int i = 0; i < locations.length; i++) {			

-				libraryPaths[i]= locations[i].getSystemLibraryPath();

-				sourcePaths[i]= locations[i].getSystemLibrarySourcePath();

-				sourceRootPaths[i]= locations[i].getPackageRootPath();

-			}

-		}

-		locations = new LibraryLocation[sourcePaths.length];

-		for (int i = 0; i < sourcePaths.length; i++) {

-			locations[i] = new LibraryLocation(libraryPaths[i], sourcePaths[i], sourceRootPaths[i]);

-		}

-		return locations;

-	}

-	

-	/**

-	 * Creates and returns a classpath entry describing

-	 * the JRE_LIB classpath variable.

-	 * 

-	 * @return a new IClasspathEntry that describes the JRE_LIB classpath variable

-	 */

-	public static IClasspathEntry getJREVariableEntry() {

-		return JavaCore.newVariableEntry(

-			new Path(JRELIB_VARIABLE),

-			new Path(JRESRC_VARIABLE),

-			new Path(JRESRCROOT_VARIABLE)

-		);

-	}

-	

-	/**

-	 * Creates and returns a classpath entry describing

-	 * the default JRE container entry.

-	 * 

-	 * @return a new IClasspathEntry that describes the default JRE container entry

-	 * @since 2.0

-	 */

-	public static IClasspathEntry getDefaultJREContainerEntry() {

-		return JavaCore.newContainerEntry(new Path(JRE_CONTAINER));

-	}	

-	

-	/**

-	 * Returns the VM connetor defined with the specified identifier,

-	 * or <code>null</code> if none.

-	 * 

-	 * @param id VM connector identifier

-	 * @return VM connector or <code>null</code> if none

-	 * @since 2.0

-	 */

-	public static IVMConnector getVMConnector(String id) {

-		return LaunchingPlugin.getDefault().getVMConnector(id);

-	}

-	

-	/**

-	 * Returns all VM connector extensions.

-	 *

-	 * @return VM connectors

-	 * @since 2.0

-	 */

-	public static IVMConnector[] getVMConnectors() {

-		return LaunchingPlugin.getDefault().getVMConnectors();

-	}	

-	

-	/**

-	 * Returns the preference store for the launching plug-in.

-	 * 

-	 * @return the preference store for the launching plug-in

-	 * @since 2.0

-	 */

-	public static Preferences getPreferences() {

-		return LaunchingPlugin.getDefault().getPluginPreferences();

-	}

-	

-	/**

-	 * Saves the preferences for the launching plug-in.

-	 * 

-	 * @since 2.0

-	 */

-	public static void savePreferences() {

-		LaunchingPlugin.getDefault().savePluginPreferences();

-	}

-	

-	/**

-	 * Registers the given resolver for the specified variable.

-	 * 

-	 * @param resolver runtime classpathe entry resolver

-	 * @param variableName variable name to register for

-	 * @since 2.0

-	 */

-	public static void addVariableResolver(IRuntimeClasspathEntryResolver resolver, String variableName) {

-		Map map = getVariableResolvers();

-		map.put(variableName, resolver);

-	}

-	

-	/**

-	 * Registers the given resolver for the specified container.

-	 * 

-	 * @param resolver runtime classpathe entry resolver

-	 * @param containerIdentifier identifier of the classpath container to register for

-	 * @since 2.0

-	 */

-	public static void addContainerResolver(IRuntimeClasspathEntryResolver resolver, String containerIdentifier) {

-		Map map = getContainerResolvers();

-		map.put(containerIdentifier, resolver);

-	}	

-	

-	/**

-	 * Returns all registered variable resolvers.

-	 */

-	private static Map getVariableResolvers() {

-		if (fgVariableResolvers == null) {

-			initializeResolvers();

-		}

-		return fgVariableResolvers;

-	}

-	

-	/**

-	 * Returns all registered container resolvers.

-	 */

-	private static Map getContainerResolvers() {

-		if (fgContainerResolvers == null) {

-			initializeResolvers();

-		}

-		return fgContainerResolvers;

-	}

-	

-	private static void initializeResolvers() {

-		IExtensionPoint point = LaunchingPlugin.getDefault().getDescriptor().getExtensionPoint(EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRY_RESOLVERS);

-		IConfigurationElement[] extensions = point.getConfigurationElements();

-		fgVariableResolvers = new HashMap(extensions.length);

-		fgContainerResolvers = new HashMap(extensions.length);

-		for (int i = 0; i < extensions.length; i++) {

-			RuntimeClasspathEntryResolver res = new RuntimeClasspathEntryResolver(extensions[i]);

-			String variable = res.getVariableName();

-			String container = res.getContainerId();

-			if (variable != null) {

-				fgVariableResolvers.put(variable, res);

-			}

-			if (container != null) {

-				fgContainerResolvers.put(container, res);

-			}

-		}		

-	}

-

-	/**

-	 * Returns all registered classpath providers.

-	 */

-	private static Map getClasspathProviders() {

-		if (fgPathProviders == null) {

-			initializeProviders();

-		}

-		return fgPathProviders;

-	}

-		

-	private static void initializeProviders() {

-		IExtensionPoint point = LaunchingPlugin.getDefault().getDescriptor().getExtensionPoint(EXTENSION_POINT_RUNTIME_CLASSPATH_PROVIDERS);

-		IConfigurationElement[] extensions = point.getConfigurationElements();

-		fgPathProviders = new HashMap(extensions.length);

-		for (int i = 0; i < extensions.length; i++) {

-			RuntimeClasspathProvider res = new RuntimeClasspathProvider(extensions[i]);

-			fgPathProviders.put(res.getIdentifier(), res);

-		}		

-	}

-		

-	/**

-	 * Returns the resovler registered for the give variable, or

-	 * <code>null</code> if none.

-	 * 

-	 * @return the resovler registered for the give variable, or

-	 * <code>null</code> if none

-	 */

-	private static IRuntimeClasspathEntryResolver getVariableResolver(String variableName) {

-		return (IRuntimeClasspathEntryResolver)getVariableResolvers().get(variableName);

-	}

-	

-	/**

-	 * Returns the resovler registered for the give container id, or

-	 * <code>null</code> if none.

-	 * 

-	 * @return the resovler registered for the give container id, or

-	 * <code>null</code> if none

-	 */	

-	private static IRuntimeClasspathEntryResolver getContainerResolver(String containerId) {

-		return (IRuntimeClasspathEntryResolver)getContainerResolvers().get(containerId);

-	}	

-	

-	/**

-	 * Returns the provider registered for the given identifier, or

-	 * <code>null</code> if none.

-	 * 

-	 * @return the provider registered for the given identifier, or

-	 * <code>null</code> if none

-	 */

-	private static IRuntimeClasspathProvider getClasspathProvider(String identifier) {

-		return (IRuntimeClasspathProvider)getClasspathProviders().get(identifier);

-	}

-	

-	/**

-	 * Adds the given listener to the list of registered VM install changed

-	 * listeners. Has no effect if an identical listener is already registered.

-	 * 

-	 * @param listener the listener to add

-	 * @since 2.0

-	 */

-	public static void addVMInstallChangedListener(IVMInstallChangedListener listener) {

-		fgVMListeners.add(listener);

-	}

-	

-	/**

-	 * Removes the given listener from the list of registered VM install changed

-	 * listeners. Has no effect if an identical listener is not already registered.

-	 * 

-	 * @param listener the listener to remove

-	 * @since 2.0

-	 */

-	public static void removeVMInstallChangedListener(IVMInstallChangedListener listener) {

-		fgVMListeners.remove(listener);

-	}	

-	

-	private static void notifyDefaultVMChanged(IVMInstall previous, IVMInstall current) {

-		Object[] listeners = fgVMListeners.getListeners();

-		for (int i = 0; i < listeners.length; i++) {

-			IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];

-			listener.defaultVMInstallChanged(previous, current);

-		}

-	}

-	

-	/**

-	 * Notifies all VM install changed listeners of the given property change.

-	 * 

-	 * @param vm the VM that has changed

-	 * @param event event desribing the change.

-	 * @since 2.0

-	 */

-	public static void fireVMChanged(PropertyChangeEvent event) {

-		Object[] listeners = fgVMListeners.getListeners();

-		for (int i = 0; i < listeners.length; i++) {

-			IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];

-			listener.vmChanged(event);

-		}		

-	}

-	

-	/**

-	 * Notifies all VM install changed listeners of the VM addition

-	 * 

-	 * @param vm the VM that has been added

-	 * @since 2.0

-	 */

-	public static void fireVMAdded(IVMInstall vm) {

-		Object[] listeners = fgVMListeners.getListeners();

-		for (int i = 0; i < listeners.length; i++) {

-			IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];

-			listener.vmAdded(vm);

-		}		

-	}	

-	

-	/**

-	 * Notifies all VM install changed listeners of the VM removal

-	 * 

-	 * @param vm the VM that has been removed

-	 * @since 2.0

-	 */

-	public static void fireVMRemoved(IVMInstall vm) {

-		Object[] listeners = fgVMListeners.getListeners();

-		for (int i = 0; i < listeners.length; i++) {

-			IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];

-			listener.vmRemoved(vm);

-		}		

-	}		

+package org.eclipse.jdt.launching;
+
+/*******************************************************************************
+ * Copyright (c) 2001, 2002 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v0.5 
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ ******************************************************************************/
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.xerces.dom.DocumentImpl;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.jdt.core.IClasspathContainer;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaModel;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.launching.CompositeId;
+import org.eclipse.jdt.internal.launching.JREContainerInitializer;
+import org.eclipse.jdt.internal.launching.JavaClasspathVariablesInitializer;
+import org.eclipse.jdt.internal.launching.JavaLaunchConfigurationUtils;
+import org.eclipse.jdt.internal.launching.LaunchingMessages;
+import org.eclipse.jdt.internal.launching.LaunchingPlugin;
+import org.eclipse.jdt.internal.launching.ListenerList;
+import org.eclipse.jdt.internal.launching.RuntimeClasspathEntry;
+import org.eclipse.jdt.internal.launching.RuntimeClasspathEntryResolver;
+import org.eclipse.jdt.internal.launching.RuntimeClasspathProvider;
+import org.eclipse.jdt.internal.launching.SocketAttachConnector;
+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;
+
+/**
+ * The central access point for launching support. This class manages
+ * the registered VM types contributed through the 
+ * <code>"org.eclipse.jdt.launching.vmType"</code> extension point.
+ * As well, this class provides VM install change notification,
+ * and computes classpaths and source lookup paths for launch
+ * configurations.
+ * <p>
+ * This class provides static methods only; it is not intended to be
+ * instantiated or subclassed by clients.
+ * </p>
+ */
+public final class JavaRuntime {
+	
+	/**
+	 * Classpath variable name used for the default JRE's library.
+	 */
+	public static final String JRELIB_VARIABLE= "JRE_LIB"; //$NON-NLS-1$
+
+	/**
+	 * Classpath variable name used for the default JRE's library source.
+	 */
+	public static final String JRESRC_VARIABLE= "JRE_SRC"; //$NON-NLS-1$
+	
+	/**
+	 * Classpath variable name used for the default JRE's library source root.
+	 */	
+	public static final String JRESRCROOT_VARIABLE= "JRE_SRCROOT"; //$NON-NLS-1$
+	
+	/**
+	 * Simple identifier constant (value <code>"runtimeClasspathEntryResolvers"</code>) for the
+	 * runtime classpath entry resolvers extension point.
+	 * 
+	 * @since 2.0
+	 */
+	public static final String EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRY_RESOLVERS= "runtimeClasspathEntryResolvers";	 //$NON-NLS-1$	
+	
+	/**
+	 * Simple identifier constant (value <code>"classpathProviders"</code>) for the
+	 * runtime classpath providers extension point.
+	 * 
+	 * @since 2.0
+	 */
+	public static final String EXTENSION_POINT_RUNTIME_CLASSPATH_PROVIDERS= "classpathProviders";	 //$NON-NLS-1$		
+		
+	/**
+	 * Classpath container used for a project's JRE. A container
+	 * is resolved in the context of a specific Java project, to
+	 * one or more system libraries contained in a JRE. The container
+	 * can have zero or two path segments following the container name. When
+	 * no segments follow the container name, the workspace default JRE is used
+	 * to build a project. Otherwise the segments identify a specific JRE used
+	 * to build a project:
+	 * <ol>
+	 * <li>VM Install Type Identifier - identifies the type of JRE used to build the
+	 * 	project. For example, the standard VM.</li>
+	 * <li>VM Install Name - a user defined name that identifies that a specific VM
+	 * 	of the above kind. For example, <code>IBM 1.3.1</code>. This information is
+	 *  shared in a projects classpath file, so teams must agree on JRE naming
+	 * 	conventions.</li>
+	 * </ol>
+	 * 
+	 * @since 2.0
+	 */
+	public static final String JRE_CONTAINER = LaunchingPlugin.getUniqueIdentifier() + ".JRE_CONTAINER"; //$NON-NLS-1$
+	
+	/**
+	 * A status code indicating that a JRE could not be resolved for a project.
+	 * When a JRE cannot be resolved for a project by this plug-in's container
+	 * initializer, an exception is thrown with this status code. A status handler
+	 * may be registered for this status code. The <code>source</code> object provided
+	 * to the status handler is the Java project for which the path could not be
+	 * resolved. The status handler must return an <code>IVMInstall</code> or <code>null</code>.
+	 * The container resolver will re-set the project's classpath if required.
+	 * 
+	 * @since 2.0
+	 */
+	public static final int ERR_UNABLE_TO_RESOLVE_JRE = 160;
+	
+	/**
+	 * Preference key for launch/connect timeout. VM Runners should honor this timeout
+	 * value when attempting to launch and connect to a debuggable VM. The value is
+	 * an int, indicating a number of millieseconds.
+	 * 
+	 * @since 2.0
+	 */
+	public static final String PREF_CONNECT_TIMEOUT = LaunchingPlugin.getUniqueIdentifier() + ".PREF_CONNECT_TIMEOUT"; //$NON-NLS-1$
+	
+	/**
+	 * Default launch/connect timeout (ms).
+	 * 
+	 * @since 2.0
+	 */
+	public static final int DEF_CONNECT_TIMEOUT = 20000;
+	
+	/**
+	 * Attribute key for a process property. The class
+	 * <code>org.eclipse.debug.core.model.IProcess</code> allows attaching
+	 * String properties to processes.
+	 * The value of this attribute is the command line a process
+	 * was launched with. Implementers of <code>IVMRunner</code> should use
+	 * this attribute key to attach the command lines to the processes they create.
+	 */
+	public final static String ATTR_CMDLINE= LaunchingPlugin.getUniqueIdentifier() + ".launcher.cmdLine"; //$NON-NLS-1$
+
+	private static IVMInstallType[] fgVMTypes= null;
+	private static String fgDefaultVMId= null;
+	private static String fgDefaultVMConnectorId = null;
+	
+	/**
+	 * Resolvers keyed by variable name and container id.
+	 */
+	private static Map fgVariableResolvers = null;
+	private static Map fgContainerResolvers = null;
+	
+	/**
+	 * Path providers keyed by id
+	 */
+	private static Map fgPathProviders = null;
+	
+	/**
+	 * Default classpath and source path providers.
+	 */
+	private static IRuntimeClasspathProvider fgDefaultClasspathProvider = new StandardClasspathProvider();
+	private static IRuntimeClasspathProvider fgDefaultSourcePathProvider = new StandardSourcePathProvider();
+	
+	/**
+	 * VM change listeners
+	 */
+	private static ListenerList fgVMListeners = new ListenerList(5);
+	
+	/**
+	 * Not intended to be instantiated.
+	 */
+	private JavaRuntime() {
+	}
+
+	/**
+	 * Returns the list of registered VM types. VM types are registered via
+	 * <code>"org.eclipse.jdt.launching.vmTypes"</code> extension point.
+	 * Returns an empty list if there are no registered VM types.
+	 * 
+	 * @return the list of registered VM types
+	 */
+	public static IVMInstallType[] getVMInstallTypes() {
+		if (fgVMTypes == null) {
+			initializeVMTypes();
+		}
+		return fgVMTypes; 
+	}
+	
+	private static synchronized void initializeVMTypes() {
+		IExtensionPoint extensionPoint= Platform.getPluginRegistry().getExtensionPoint(LaunchingPlugin.getUniqueIdentifier() + ".vmInstallTypes"); //$NON-NLS-1$
+		IConfigurationElement[] configs= extensionPoint.getConfigurationElements(); 
+		MultiStatus status= new MultiStatus(LaunchingPlugin.getUniqueIdentifier(), IStatus.OK, LaunchingMessages.getString("JavaRuntime.exceptionOccurred"), null); //$NON-NLS-1$
+		fgVMTypes= new IVMInstallType[configs.length];
+
+		for (int i= 0; i < configs.length; i++) {
+			try {
+				IVMInstallType vmType= (IVMInstallType)configs[i].createExecutableExtension("class"); //$NON-NLS-1$
+				fgVMTypes[i]= vmType;
+			} catch (CoreException e) {
+				status.add(e.getStatus());
+			}
+		}
+		if (!status.isOK()) {
+			//only happens on a CoreException
+			LaunchingPlugin.log(status);
+			//cleanup null entries in fgVMTypes
+			List temp= new ArrayList(fgVMTypes.length);
+			for (int i = 0; i < fgVMTypes.length; i++) {
+				if(fgVMTypes[i] != null) {
+					temp.add(fgVMTypes[i]);
+				}
+				fgVMTypes= new IVMInstallType[temp.size()];
+				fgVMTypes= (IVMInstallType[])temp.toArray(fgVMTypes);
+			}
+		}
+		
+		try {
+			initializeVMConfiguration();
+		} catch (IOException e) {
+			LaunchingPlugin.log(e);
+		}
+	}
+
+	/**
+	 * Returns the VM assigned to build the given Java project.
+	 * The project must exist. The VM assigned to a project is
+	 * determined from its build path.
+	 * 
+	 * @return the VM instance that is assigned to build the given Java project
+	 * 		   Returns <code>null</code> if no VM is referenced on the project's build path.
+	 * @throws CoreException if unable to determine the project's VM install
+	 */
+	public static IVMInstall getVMInstall(IJavaProject project) throws CoreException {
+		// check the classpath
+		IVMInstall vm = null;
+		IClasspathEntry[] classpath = project.getRawClasspath();
+		IRuntimeClasspathEntryResolver resolver = null;
+		for (int i = 0; i < classpath.length; i++) {
+			IClasspathEntry entry = classpath[i];
+			switch (entry.getEntryKind()) {
+				case IClasspathEntry.CPE_VARIABLE:
+					resolver = getVariableResolver(entry.getPath().segment(0));
+					if (resolver != null) {
+						vm = resolver.resolveVMInstall(entry);
+					}
+					break;
+				case IClasspathEntry.CPE_CONTAINER:
+					resolver = getContainerResolver(entry.getPath().segment(0));
+					if (resolver != null) {
+						vm = resolver.resolveVMInstall(entry);
+					}
+					break;
+			}
+			if (vm != null) {
+				return vm;
+			}
+		}
+		return null;
+	}
+	
+	private static IVMInstall getVMFromId(String idString) {
+		if (idString == null || idString.length() == 0) {
+			return null;
+		}
+		CompositeId id= CompositeId.fromString(idString);
+		if (id.getPartCount() == 2) {
+			IVMInstallType vmType= getVMInstallType(id.get(0));
+			if (vmType != null) {
+				return vmType.findVMInstall(id.get(1));
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Returns the VM install type with the given unique id. 
+	 * @return	The VM install type for the given id, or <code>null</code> if no
+	 * 			VM install type with the given id is registered.
+	 */
+	public static IVMInstallType getVMInstallType(String id) {
+		IVMInstallType[] vmTypes= getVMInstallTypes();
+		for (int i= 0; i < vmTypes.length; i++) {
+			if (vmTypes[i].getId().equals(id)) {
+				return vmTypes[i];
+			}
+		}
+		return null;
+	}
+	
+	/**
+	 * Sets a VM as the system-wide default VM, and notifies registered VM install
+	 * change listeners of the change.
+	 * 
+	 * @param vm	The vm to make the default. May be <code>null</code> to clear 
+	 * 				the default.
+	 * @param monitor progress monitor or <code>null</code>
+	 */
+	public static void setDefaultVMInstall(IVMInstall vm, IProgressMonitor monitor) throws CoreException {
+		IVMInstall previous = null;
+		if (fgDefaultVMId != null) {
+			previous = getVMFromId(fgDefaultVMId);
+		}
+		fgDefaultVMId= getIdFromVM(vm);
+		updateJREVariables(monitor);
+		saveVMConfiguration();
+		IVMInstall current = null;
+		if (fgDefaultVMId != null) {
+			current = getVMFromId(fgDefaultVMId);
+		}
+		if (previous != current) {
+			notifyDefaultVMChanged(previous, current);
+		}
+	}	
+	
+	/**
+	 * Sets a VM connector as the system-wide default VM. This setting is persisted when
+	 * saveVMConfiguration is called. 
+	 * @param	connector The connector to make the default. May be null to clear 
+	 * 				the default.
+	 * @since 2.0
+	 */
+	public static void setDefaultVMConnector(IVMConnector connector, IProgressMonitor monitor) throws CoreException {
+		fgDefaultVMConnectorId= connector.getIdentifier();
+		saveVMConfiguration();
+	}		
+	
+	private static void updateJREVariables(IProgressMonitor monitor) throws CoreException {
+		JavaClasspathVariablesInitializer updater= new JavaClasspathVariablesInitializer();
+		updater.updateJREVariables(monitor);
+		JREContainerInitializer conatinerUpdater = new JREContainerInitializer();
+		conatinerUpdater.updateDefaultJREContainers(monitor);
+	}
+	/**
+	 * Return the default VM set with <code>setDefaultVM()</code>.
+	 * @return	Returns the default VM. May return <code>null</code> when no default
+	 * 			VM was set or when the default VM has been disposed.
+	 */
+	public static IVMInstall getDefaultVMInstall() {
+		IVMInstall install= getVMFromId(getDefaultVMId());
+		if (install != null && install.getInstallLocation().exists()) {
+			return install;
+		} else {
+			// if the default JRE goes missing, re-detect
+			if (install != null) {
+				install.getVMInstallType().disposeVMInstall(install.getId());
+			}
+			fgDefaultVMId = null;
+			try {
+				//get rid of bad values on disk
+				saveVMConfiguration();
+			} catch(CoreException e) {
+				LaunchingPlugin.log(e);
+			}
+			detectVMConfiguration();
+			return getVMFromId(getDefaultVMId());
+		}
+	}
+	
+	/**
+	 * Return the default VM connector.
+	 * @return	Returns the default VM connector.
+	 * @since 2.0
+	 */
+	public static IVMConnector getDefaultVMConnector() {
+		String id = getDefaultVMConnectorId();
+		IVMConnector connector = null;
+		if (id != null) {
+			connector = getVMConnector(id);
+		}
+		if (connector == null) {
+			connector = new SocketAttachConnector();
+		}
+		return connector;
+	}	
+	
+	private static String getDefaultVMId() {
+		if (fgVMTypes == null) {
+			initializeVMTypes();
+		}
+		return fgDefaultVMId;
+	}
+	
+	private static String getDefaultVMConnectorId() {
+		if (fgVMTypes == null) {
+			initializeVMTypes();
+		}
+		return fgDefaultVMConnectorId;
+	}	
+	
+	private static String getIdFromVM(IVMInstall vm) {
+		if (vm == null) {
+			return null;
+		}
+		IVMInstallType vmType= vm.getVMInstallType();
+		String typeID= vmType.getId();
+		CompositeId id= new CompositeId(new String[] { typeID, vm.getId() });
+		return id.toString();
+	}
+	
+	/**
+	 * Returns a new runtime classpath entry for the given project.
+	 * 
+	 * @param project Java project
+	 * @return runtime classpath entry
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry newProjectRuntimeClasspathEntry(IJavaProject project) {
+		IClasspathEntry cpe = JavaCore.newProjectEntry(project.getProject().getFullPath());
+		return newRuntimeClasspathEntry(cpe);
+	}
+	
+	
+	/**
+	 * Returns a new runtime classpath entry for the given archive.
+	 * 
+	 * @param resource archive resource
+	 * @return runtime classpath entry
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry newArchiveRuntimeClasspathEntry(IResource resource) {
+		IClasspathEntry cpe = JavaCore.newLibraryEntry(resource.getFullPath(), null, null);
+		return newRuntimeClasspathEntry(cpe);
+	}
+	
+	/**
+	 * Returns a new runtime classpath entry for the given archive (possibly
+	 * external).
+	 * 
+	 * @param path absolute path to an archive
+	 * @return runtime classpath entry
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry newArchiveRuntimeClasspathEntry(IPath path) {
+		IClasspathEntry cpe = JavaCore.newLibraryEntry(path, null, null);
+		return newRuntimeClasspathEntry(cpe);
+	}
+
+	/**
+	 * Returns a new runtime classpath entry for the classpath
+	 * variable with the given path.
+	 * 
+	 * @param path variable path; first segment is the name of the variable; 
+	 * 	trailing segments are appended to the resolved variable value
+	 * @return runtime classpath entry
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry newVariableRuntimeClasspathEntry(IPath path) {
+		IClasspathEntry cpe = JavaCore.newVariableEntry(path, null, null);
+		return newRuntimeClasspathEntry(cpe);
+	}
+
+	/**
+	 * Returns a runtime classpath entry for the given container path with the given
+	 * classpath property.
+	 * 
+	 * @param path container path
+	 * @param classpathProperty the type of entry - one of <code>USER_CLASSES</code>,
+	 * 	<code>BOOTSTRAP_CLASSES</code>, or <code>STANDARD_CLASSES</code>
+	 * @return runtime classpath entry
+	 * @exception CoreException if unable to construct a runtime classpath entry
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry newRuntimeContainerClasspathEntry(IPath path, int classpathProperty) throws CoreException {
+		IClasspathEntry cpe = JavaCore.newContainerEntry(path);
+		return new RuntimeClasspathEntry(cpe, classpathProperty);
+	}
+		
+	/**
+	 * Returns a runtime classpath entry constructed from the given memento.
+	 * 
+	 * @param memento a menento for a runtime classpath entry
+	 * @return runtime classpath entry
+	 * @exception CoreException if unable to construct a runtime classpath entry
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry newRuntimeClasspathEntry(String memento) throws CoreException {
+		return new RuntimeClasspathEntry(memento);
+	}
+	
+	/**
+	 * Returns a runtime classpath entry that corresponds to the given
+	 * classpath entry. The classpath entry may not be of type <code>CPE_SOURCE</code>
+	 * or <code>CPE_CONTAINER</code>.
+	 * 
+	 * @param entry a classpath entry
+	 * @return runtime classpath entry
+	 * @since 2.0
+	 */
+	private static IRuntimeClasspathEntry newRuntimeClasspathEntry(IClasspathEntry entry) {
+		return new RuntimeClasspathEntry(entry);
+	}	
+			
+	/**
+	 * Computes and returns the default unresolved runtime claspath for the
+	 * given project.
+	 * 
+	 * @return runtime classpath entries
+	 * @exception CoreException if unable to compute the runtime classpath
+	 * @see IRuntimeClasspathEntry
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry[] computeUnresolvedRuntimeClasspath(IJavaProject project) throws CoreException {
+		IClasspathEntry entry = JavaCore.newProjectEntry(project.getProject().getFullPath());
+		List classpathEntries = new ArrayList(5);
+		List expanding = new ArrayList(5);
+		expandProject(entry, classpathEntries, expanding);
+		IRuntimeClasspathEntry[] runtimeEntries = new IRuntimeClasspathEntry[classpathEntries == null ? 0 : classpathEntries.size()];
+		for (int i = 0; i < runtimeEntries.length; i++) {
+			Object e = classpathEntries.get(i);
+			if (e instanceof IClasspathEntry) {
+				IClasspathEntry cpe = (IClasspathEntry)e;
+				runtimeEntries[i] = newRuntimeClasspathEntry(cpe);
+			} else {
+				runtimeEntries[i] = (IRuntimeClasspathEntry)e;				
+			}
+		}
+		// sort bootpath and standard entries first
+		IRuntimeClasspathEntry[] ordered = new IRuntimeClasspathEntry[runtimeEntries.length];
+		int index = 0;
+		for (int i = 0; i < runtimeEntries.length; i++) {
+			if (runtimeEntries[i].getClasspathProperty() != IRuntimeClasspathEntry.USER_CLASSES) {
+				ordered[index] = runtimeEntries[i];
+				index++;
+				runtimeEntries[i] = null;
+			} 
+		}
+		for (int i = 0; i < runtimeEntries.length; i++) {
+			if (runtimeEntries[i] != null) {
+				ordered[index] = runtimeEntries[i];
+				index++;
+			}
+		}
+		return ordered;
+	}
+	
+	/**
+	 * Computes and returns the unresolved source lookup path for the given launch
+	 * configuration.
+	 * 
+	 * @param configuration launch configuration
+	 * @return runtime classpath entries
+	 * @exception CoreException if unable to compute the source lookup path
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry[] computeUnresolvedSourceLookupPath(ILaunchConfiguration configuration) throws CoreException {
+		return getSourceLookupPathProvider(configuration).computeUnresolvedClasspath(configuration);
+	}
+	
+	/**
+	 * Resolves the given source lookup path, returning the resolved source lookup path
+	 * in the context of the given launch configuration.
+	 * 
+	 * @param entries unresolved entries
+	 * @param configuration launch configuration
+	 * @return resolved entries
+	 * @exception CoreException if unable to resolve the source lookup path
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry[] resolveSourceLookupPath(IRuntimeClasspathEntry[] entries, ILaunchConfiguration configuration) throws CoreException {
+		return getSourceLookupPathProvider(configuration).resolveClasspath(entries, configuration);
+	}	
+	
+	/**
+	 * Returns the classpath provider for the given launch configuration.
+	 * 
+	 * @param configuration launch configuration
+	 * @return classpath provider
+	 * @exception CoreException if unable to resolve the path provider
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathProvider getClasspathProvider(ILaunchConfiguration configuration) throws CoreException {
+		String providerId = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH_PROVIDER, (String)null);
+		IRuntimeClasspathProvider provider = null;
+		if (providerId == null) {
+			provider = fgDefaultClasspathProvider;
+		} else {
+			provider = (IRuntimeClasspathProvider)getClasspathProviders().get(providerId);	
+		}
+		return provider;
+	}	
+		
+	/**
+	 * Returns the source lookup path provider for the given launch configuration.
+	 * 
+	 * @param configuration launch configuration
+	 * @return source lookup path provider
+	 * @exception CoreException if unable to resolve the path provider
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathProvider getSourceLookupPathProvider(ILaunchConfiguration configuration) throws CoreException {
+		String providerId = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER, (String)null);
+		IRuntimeClasspathProvider provider = null;
+		if (providerId == null) {
+			provider = fgDefaultSourcePathProvider;
+		} else {
+			provider = (IRuntimeClasspathProvider)getClasspathProviders().get(providerId);
+		}
+		return provider;
+	}	
+		
+	/**
+	 * Returns resolved entries for the given entry in the context of the given
+	 * launch configuration. If the entry is of kind
+	 * <code>VARIABLE</code> or <code>CONTAINTER</code>, variable and contanier
+	 * resolvers are consulted, otherwise, the returned entry is the same as the 
+	 * given entry.
+	 * <p>
+	 * If the given entry is a variable entry, and a resolver is not registered,
+	 * the entry itself is returned. If the given entry is a container, and a
+	 * resolver is not registered, resolved runtime classpath entries are calculated
+	 * from the associated container classpath entries, in the context of the project
+	 * associated with the given launch configuration.
+	 * </p>
+	 * @param entry runtime classpath entry
+	 * @param configuration launch configuration
+	 * @return resolved runtime classpath entry
+	 * @exception CoreException if unable to resolve
+	 * @see IRuntimeClasspathEntryResolver
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(IRuntimeClasspathEntry entry, ILaunchConfiguration configuration) throws CoreException {
+		switch (entry.getType()) {
+			case IRuntimeClasspathEntry.VARIABLE:
+				IRuntimeClasspathEntryResolver resolver = getVariableResolver(entry.getVariableName());
+				if (resolver == null) {
+					// no resolution by default
+					break;
+				} else {
+					return resolver.resolveRuntimeClasspathEntry(entry, configuration);
+				}				
+			case IRuntimeClasspathEntry.CONTAINER:
+				resolver = getContainerResolver(entry.getVariableName());
+				if (resolver == null) {
+					return computeDefaultContainerEntries(entry, configuration);
+				} else {
+					return resolver.resolveRuntimeClasspathEntry(entry, configuration);
+				}
+			default:
+				break;
+		}
+		return new IRuntimeClasspathEntry[] {entry};
+	}
+	
+	/**
+	 * Returns resolved entries for the given entry in the context of the given
+	 * Java project. If the entry is of kind
+	 * <code>VARIABLE</code> or <code>CONTAINTER</code>, variable and contanier
+	 * resolvers are consulted, otherwise, the returned entry is the same as the given
+	 * entry.
+	 * <p>
+	 * If the given entry is a variable entry, and a resolver is not registered,
+	 * the entry itself is returned. If the given entry is a container, and a
+	 * resolver is not registered, resolved runtime classpath entries are calculated
+	 * from the associated container classpath entries, in the context of the 
+	 * given project.
+	 * </p>
+	 * @param entry runtime classpath entry
+	 * @param project Java project context
+	 * @return resolved runtime classpath entry
+	 * @exception CoreException if unable to resolve
+	 * @see IRuntimeClasspathEntryResolver
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(IRuntimeClasspathEntry entry, IJavaProject project) throws CoreException {
+		switch (entry.getType()) {
+			case IRuntimeClasspathEntry.VARIABLE:
+				IRuntimeClasspathEntryResolver resolver = getVariableResolver(entry.getVariableName());
+				if (resolver == null) {
+					// no resolution by default
+					break;
+				} else {
+					return resolver.resolveRuntimeClasspathEntry(entry, project);
+				}				
+			case IRuntimeClasspathEntry.CONTAINER:
+				resolver = getContainerResolver(entry.getVariableName());
+				if (resolver == null) {
+					return computeDefaultContainerEntries(entry, project);
+				} else {
+					return resolver.resolveRuntimeClasspathEntry(entry, project);
+				}
+			default:
+				break;
+		}
+		return new IRuntimeClasspathEntry[] {entry};
+	}	
+		
+	/**
+	 * Performs default resolution for a container entry.
+	 * Delegates to the Java model.
+	 */
+	private static IRuntimeClasspathEntry[] computeDefaultContainerEntries(IRuntimeClasspathEntry entry, ILaunchConfiguration config) throws CoreException {
+		return computeDefaultContainerEntries(entry, getJavaProject(config));
+	}
+	
+	/**
+	 * Performs default resolution for a container entry.
+	 * Delegates to the Java model.
+	 */
+	private static IRuntimeClasspathEntry[] computeDefaultContainerEntries(IRuntimeClasspathEntry entry, IJavaProject project) throws CoreException {
+		if (project == null) {
+			// cannot resolve without project context
+			return new IRuntimeClasspathEntry[0];
+		} else {							
+			IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);
+			IClasspathEntry[] cpes = container.getClasspathEntries();
+			int property = -1;
+			switch (container.getKind()) {
+				case IClasspathContainer.K_APPLICATION:
+					property = IRuntimeClasspathEntry.USER_CLASSES;
+					break;
+				case IClasspathContainer.K_DEFAULT_SYSTEM:
+					property = IRuntimeClasspathEntry.STANDARD_CLASSES;
+					break;	
+				case IClasspathContainer.K_SYSTEM:
+					property = IRuntimeClasspathEntry.BOOTSTRAP_CLASSES;
+					break;
+			}			
+			IRuntimeClasspathEntry[] resolved = new IRuntimeClasspathEntry[cpes.length];
+			for (int i = 0; i < resolved.length; i++) {
+				resolved[i] = newRuntimeClasspathEntry(cpes[i]);
+				resolved[i].setClasspathProperty(property);
+			}
+			return resolved;
+		}
+	}
+			
+	/**
+	 * Computes and returns the unresolved class path for the given launch configuration.
+	 * Variable and container entries are unresolved.
+	 * 
+	 * @param configuration launch configuration
+	 * @return unresolved runtime classpath entries
+	 * @exception CoreException if unable to compute the classpath
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry[] computeUnresolvedRuntimeClasspath(ILaunchConfiguration configuration) throws CoreException {
+		return getClasspathProvider(configuration).computeUnresolvedClasspath(configuration);
+	}
+	
+	/**
+	 * Resolves the given classpath, returning the resolved classpath
+	 * in the context of the given launch configuration.
+	 *
+	 * @param entries unresolved classpath
+	 * @param configuration launch configuration
+	 * @return resolved runtime classpath entries
+	 * @exception CoreException if unable to compute the classpath
+	 * @since 2.0
+	 */
+	public static IRuntimeClasspathEntry[] resolveRuntimeClasspath(IRuntimeClasspathEntry[] entries, ILaunchConfiguration configuration) throws CoreException {
+		return getClasspathProvider(configuration).resolveClasspath(entries, configuration);
+	}	
+	
+	/**
+	 * Return the <code>IJavaProject</code> referenced in the specified configuration or
+	 * <code>null</code> if none.
+	 *
+	 * @exception CoreException if the referenced Java project does not exist
+	 * @since 2.0
+	 */
+	public static IJavaProject getJavaProject(ILaunchConfiguration configuration) throws CoreException {
+		String projectName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null);
+		if ((projectName == null) || (projectName.trim().length() < 1)) {
+			return null;
+		}			
+		IJavaProject javaProject = getJavaModel().getJavaProject(projectName);		
+		if ((javaProject == null) || !javaProject.exists()) {
+			abort(MessageFormat.format(LaunchingMessages.getString("JavaRuntime.Launch_configuration_{0}_references_non-existing_project_{1}._1"), new String[] {configuration.getName(), projectName}), IJavaLaunchConfigurationConstants.ERR_NOT_A_JAVA_PROJECT, null); //$NON-NLS-1$
+		}
+		return javaProject;
+	}
+				
+	/**
+	 * Convenience method to get the java model.
+	 */
+	private static IJavaModel getJavaModel() {
+		return JavaCore.create(ResourcesPlugin.getWorkspace().getRoot());
+	}
+	
+	
+	/**
+	 * Returns a collection of runtime classpath entries that are defined in the
+	 * specified attribute of the given launch configuration.
+	 * 
+	 * @param configuration launch configuration
+	 * @param attribute attribute name containing the list of entries
+	 * @return collection of runtime classpath entries that are defined in the
+	 *  specified attribute of the given launch configuration
+	 * @exception CoreException if unable to retrieve the list
+	 */
+	private static IRuntimeClasspathEntry[] recoverRuntimePath(ILaunchConfiguration configuration, String attribute) throws CoreException {
+		List entries = (List)configuration.getAttribute(attribute, Collections.EMPTY_LIST);
+		IRuntimeClasspathEntry[] rtes = new IRuntimeClasspathEntry[entries.size()];
+		Iterator iter = entries.iterator();
+		int i = 0;
+		while (iter.hasNext()) {
+			rtes[i] = newRuntimeClasspathEntry((String)iter.next());
+			i++;
+		}
+		return rtes;		
+	}
+	
+	/**
+	 * Returns the VM install for the given launch configuration.
+	 * The VM install is determined in the following prioritized way:
+	 * <ol>
+	 * <li>The VM install is explicitly specified on the launch configuration
+	 * 	via the <code>ATTR_VM_INSTALL_TYPE</code> and <code>ATTR_VM_INSTALL_ID</code>
+	 *  attributes.</li>
+	 * <li>If no explicit VM install is specified, the VM install associated with
+	 * 	the launch confiugration's project is returned.</li>
+	 * <li>If no project is specified, or the project does not specify a custom
+	 * 	VM install, the workspace default VM install is returned.</li>
+	 * </ol>
+	 * 
+	 * @param configuration launch configuration
+	 * @return vm install
+	 * @exception CoreException if unable to compute a vm install
+	 * @since 2.0
+	 */
+	public static IVMInstall computeVMInstall(ILaunchConfiguration configuration) throws CoreException {
+		String type = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE, (String)null);
+		if (type == null) {
+			IJavaProject proj = getJavaProject(configuration);
+			if (proj != null) {
+				IVMInstall vm = getVMInstall(proj);
+				if (vm != null) {
+					return vm;
+				}
+			}
+		} else {
+			IVMInstallType vt = getVMInstallType(type);
+			if (vt == null) {
+				// error type does not exist
+				abort(MessageFormat.format(LaunchingMessages.getString("JavaRuntime.Specified_VM_install_type_does_not_exist__{0}_2"), new String[] {type}), null); //$NON-NLS-1$
+			}
+			IVMInstall vm = null;
+			// look for a name
+			String name = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME, (String)null);
+			if (name == null) {
+				// error - type specified without a specific install (could be an old config that specified a VM ID)
+				// log the error, but choose the default VM.
+				IStatus status = new Status(IStatus.WARNING, LaunchingPlugin.getUniqueIdentifier(), IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_VM_INSTALL, MessageFormat.format(LaunchingMessages.getString("JavaRuntime.VM_not_fully_specified_in_launch_configuration_{0}_-_missing_VM_name._Reverting_to_default_VM._1"), new String[] {configuration.getName()}), null); //$NON-NLS-1$
+				LaunchingPlugin.log(status);
+				return getDefaultVMInstall();
+			} else {
+				vm = vt.findVMInstallByName(name);
+				if (vm == null) {
+					// error - install not found
+					abort(MessageFormat.format(LaunchingMessages.getString("JavaRuntime.Specified_VM_install_not_found__type_{0},_name_{1}_2"), new String[] {type, name}), null);					 //$NON-NLS-1$
+				} else {
+					return vm;
+				}
+			}
+		}
+		
+		return getDefaultVMInstall();
+	}
+	
+	/**
+	 * Throws a core exception with an internal error status.
+	 * 
+	 * @param message the status message
+	 * @param exception lower level exception associated with the
+	 *  error, or <code>null</code> if none
+	 */
+	private static void abort(String message, Throwable exception) throws CoreException {
+		abort(message, IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR, exception);
+	}	
+		
+		
+	/**
+	 * Throws a core exception with an internal error status.
+	 * 
+	 * @param message the status message
+	 * @param code status code
+	 * @param exception lower level exception associated with the
+	 * 
+	 *  error, or <code>null</code> if none
+	 */
+	private static void abort(String message, int code, Throwable exception) throws CoreException {
+		throw new CoreException(new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), code, message, exception));
+	}	
+					
+	/**
+	 * Returns the transitive closure of classpath entries for the
+	 * given project entry.
+	 * 
+	 * @param projectEntry project classpath entry
+	 * @param a list of entries already expanded, should be empty to begin,
+	 *  and contains the result
+	 * @param expanding a list of project that have been or currently are being
+	 *  expanded (to detect cycles in the classpath)
+	 * @exception CoreException if unable to expand the classpath
+	 */
+	private static void expandProject(IClasspathEntry projectEntry, List expandedPath, List expanding) throws CoreException {
+		expanding.add(projectEntry);
+		// 1. Get the raw classpath
+		// 2. Replace source folder entries with a project entry
+		IPath projectPath = projectEntry.getPath();
+		IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(projectPath.lastSegment());
+		if (res == null) {
+			return;
+		}
+		IJavaProject project = (IJavaProject)JavaCore.create(res);
+		if (project == null) {
+			return;
+		}
+		IClasspathEntry[] buildPath = project.getRawClasspath();
+		List unexpandedPath = new ArrayList(buildPath.length);
+		boolean projectAdded = false;
+		for (int i = 0; i < buildPath.length; i++) {
+			if (buildPath[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
+				if (!projectAdded) {
+					projectAdded = true;
+					unexpandedPath.add(projectEntry);
+				}
+			} else {
+				unexpandedPath.add(buildPath[i]);
+			}
+		}
+		// 3. expand each project entry (except for the root project)
+		// 4. replace each container entry with a runtime entry associated with the project
+		Iterator iter = unexpandedPath.iterator();
+		while (iter.hasNext()) {
+			IClasspathEntry entry = (IClasspathEntry)iter.next();
+			if (entry == projectEntry) {
+				expandedPath.add(entry);
+			} else {
+				switch (entry.getEntryKind()) {
+					case IClasspathEntry.CPE_PROJECT:
+						if (!expanding.contains(entry)) {
+							expandProject(entry, expandedPath, expanding);
+						}
+						break;
+					case IClasspathEntry.CPE_CONTAINER:
+						IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);
+						int property = -1;
+						switch (container.getKind()) {
+							case IClasspathContainer.K_APPLICATION:
+								property = IRuntimeClasspathEntry.USER_CLASSES;
+								break;
+							case IClasspathContainer.K_DEFAULT_SYSTEM:
+								property = IRuntimeClasspathEntry.STANDARD_CLASSES;
+								break;	
+							case IClasspathContainer.K_SYSTEM:
+								property = IRuntimeClasspathEntry.BOOTSTRAP_CLASSES;
+								break;
+						}
+						IRuntimeClasspathEntry r = newRuntimeContainerClasspathEntry(entry.getPath(), property);
+						// check for duplicate/redundant entries 
+						boolean duplicate = false;
+						for (int i = 0; i < expandedPath.size(); i++) {
+							Object o = expandedPath.get(i);
+							if (o instanceof IRuntimeClasspathEntry) {
+								IRuntimeClasspathEntry re = (IRuntimeClasspathEntry)o;
+								if (re.getType() == IRuntimeClasspathEntry.CONTAINER) {
+									if (container instanceof IRuntimeContainerComparator) {
+										duplicate = ((IRuntimeContainerComparator)container).isDuplicate(re.getPath());
+										if (duplicate) {
+											break;
+										}
+									} else if (re.getVariableName().equals(r.getVariableName())) {
+										duplicate = true;
+										break;
+									}
+								}
+							}
+						}
+						if (!duplicate) {
+							expandedPath.add(r);
+						}	
+						break;
+					case IClasspathEntry.CPE_VARIABLE:
+						if (entry.getPath().segment(0).equals(JRELIB_VARIABLE)) {
+							r = newVariableRuntimeClasspathEntry(entry.getPath());
+							r.setSourceAttachmentPath(entry.getSourceAttachmentPath());
+							r.setSourceAttachmentRootPath(entry.getSourceAttachmentRootPath());
+							r.setClasspathProperty(IRuntimeClasspathEntry.STANDARD_CLASSES);
+							if (!expandedPath.contains(r)) {
+								expandedPath.add(r);
+							}
+							break;
+						}
+						// fall through if not the special JRELIB variable
+					default:
+						if (!expandedPath.contains(entry)) {
+							expandedPath.add(entry);
+						}
+						break;
+				}
+			}
+		}
+		return;
+	}
+		
+	/**
+	 * Computes the default application classpath entries for the given 
+	 * project.
+	 * 
+	 * @param	jproject The project to compute the classpath for
+	 * @return	The computed classpath. May be empty, but not null.
+	 * @throws	CoreException if unable to compute the default classpath
+	 */
+	public static String[] computeDefaultRuntimeClassPath(IJavaProject jproject) throws CoreException {
+		IRuntimeClasspathEntry[] unresolved = computeUnresolvedRuntimeClasspath(jproject);
+		// 1. remove bootpath entries
+		// 2. resolve & translate to local file system paths
+		List resolved = new ArrayList(unresolved.length);
+		for (int i = 0; i < unresolved.length; i++) {
+			IRuntimeClasspathEntry entry = unresolved[i];
+			if (unresolved[i].getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) {
+				switch (entry.getType()) {
+					case IRuntimeClasspathEntry.CONTAINER:
+						IRuntimeClasspathEntry[] contained = computeDefaultContainerEntries(entry, jproject);
+						for (int j = 0; j < contained.length; j++) {
+							resolved.add(contained[j].getLocation());
+						}
+						break;
+					default:
+						resolved.add(entry.getLocation());
+						break;
+				}
+			}
+		}
+		return (String[])resolved.toArray(new String[resolved.size()]);
+	}	
+		
+	/**
+	 * Saves the VM configuration information to disk. This includes
+	 * the following information:
+	 * <ul>
+	 * <li>The list of all defined IVMInstall instances.</li>
+	 * <li>The default VM</li>
+	 * <ul>
+	 * This state will be read again upon first access to VM
+	 * configuration information.
+	 */
+	public static void saveVMConfiguration() throws CoreException {
+		IPath stateLocation= LaunchingPlugin.getDefault().getStateLocation();
+		IPath stateFile= stateLocation.append("vmConfiguration.xml"); //$NON-NLS-1$
+		File f= new File(stateFile.toOSString());
+		try {
+			String xml = getVMsAsXML();
+			FileOutputStream stream = new FileOutputStream(f);
+			stream.write(xml.getBytes("UTF8")); //$NON-NLS-1$
+			stream.close();			
+		} catch (IOException e) {
+			throw new CoreException(new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), IStatus.ERROR, LaunchingMessages.getString("JavaRuntime.ioExceptionOccurred"), e)); //$NON-NLS-1$
+		}
+		
+	}
+	
+	private static String getVMsAsXML() throws IOException {
+		Document doc = new DocumentImpl();
+		Element config = doc.createElement("vmSettings"); //$NON-NLS-1$
+		if (fgDefaultVMId != null) {
+			config.setAttribute("defaultVM", fgDefaultVMId); //$NON-NLS-1$
+		}
+		if (fgDefaultVMConnectorId != null) {
+			config.setAttribute("defaultVMConnector", fgDefaultVMConnectorId); //$NON-NLS-1$
+		}
+		doc.appendChild(config);
+		
+		IVMInstallType[] vmTypes= getVMInstallTypes();
+
+		for (int i = 0; i < vmTypes.length; ++i) {
+			Element vmTypeElement = vmTypeAsElement(doc, vmTypes[i]);
+			config.appendChild(vmTypeElement);
+		}
+
+		return JavaLaunchConfigurationUtils.serializeDocument(doc);
+	}
+	
+	private static Element vmTypeAsElement(Document doc, IVMInstallType vmType) {
+		Element element= doc.createElement("vmType"); //$NON-NLS-1$
+		element.setAttribute("id", vmType.getId()); //$NON-NLS-1$
+		IVMInstall[] vms= vmType.getVMInstalls();
+		for (int i= 0; i < vms.length; i++) {
+			Element vmElement= vmAsElement(doc, vms[i]);
+			element.appendChild(vmElement);
+		}
+		return element;
+	}
+	
+	private static Element vmAsElement(Document doc, IVMInstall vm) {
+		Element element= doc.createElement("vm"); //$NON-NLS-1$
+		element.setAttribute("id", vm.getId());	 //$NON-NLS-1$
+		element.setAttribute("name", vm.getName()); //$NON-NLS-1$
+		String installPath= ""; //$NON-NLS-1$
+		File installLocation= vm.getInstallLocation();
+		if (installLocation != null) {
+			installPath= installLocation.getAbsolutePath();
+		}
+		element.setAttribute("path", installPath); //$NON-NLS-1$
+		LibraryLocation[] libraryLocations= vm.getLibraryLocations();
+		if (libraryLocations != null) {
+			Element libLocationElement=  libraryLocationsAsElement(doc, libraryLocations);
+			element.appendChild(libLocationElement);
+		}
+		return element;
+	}
+	
+	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$
+			element.setAttribute("pkgRoot", locations[i].getPackageRootPath().toString()); //$NON-NLS-1$
+			root.appendChild(element);
+		}
+		return root;
+	}
+	
+	private static void initializeVMConfiguration() throws IOException {
+		IPath stateLocation= LaunchingPlugin.getDefault().getStateLocation();
+		IPath stateFile= stateLocation.append("vmConfiguration.xml"); //$NON-NLS-1$
+		File f= new File(stateFile.toOSString());
+		if (f.isFile()) {
+			loadVMConfiguration(f);
+		} else {
+			detectVMConfiguration();
+		}
+	}
+	
+	private static void loadVMConfiguration(File f) throws IOException {
+		InputStream stream= new BufferedInputStream(new FileInputStream(f));
+		Reader reader= new InputStreamReader(stream, "UTF-8"); //$NON-NLS-1$
+		Element config= null;
+		try {
+			DocumentBuilder parser= DocumentBuilderFactory.newInstance().newDocumentBuilder();
+			config = parser.parse(new InputSource(reader)).getDocumentElement();
+		} catch (SAXException e) {
+			throw new IOException(LaunchingMessages.getString("JavaRuntime.badFormat")); //$NON-NLS-1$
+		} catch (ParserConfigurationException e) {
+			reader.close();
+			throw new IOException(LaunchingMessages.getString("JavaRuntime.badFormat")); //$NON-NLS-1$
+		} finally {
+			reader.close();
+		}
+		if (!config.getNodeName().equalsIgnoreCase("vmSettings")) { //$NON-NLS-1$
+			throw new IOException(LaunchingMessages.getString("JavaRuntime.badFormat")); //$NON-NLS-1$
+		}
+		fgDefaultVMId= config.getAttribute("defaultVM"); //$NON-NLS-1$
+		fgDefaultVMConnectorId = config.getAttribute("defaultVMConnector"); //$NON-NLS-1$
+		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$
+					createFromVMType(vmTypeElement);
+				}
+			}
+		}
+	}
+	
+	private static void detectVMConfiguration() {
+		IVMInstallType[] vmTypes= getVMInstallTypes();
+		boolean defaultSet= false;
+		for (int i= 0; i < vmTypes.length; i++) {
+			File detectedLocation= vmTypes[i].detectInstallLocation();
+			if (detectedLocation != null) {
+				int unique = i;
+				IVMInstallType vmType = vmTypes[i];
+				while (vmType.findVMInstall(String.valueOf(unique)) != null) {
+					unique++;
+				}
+				IVMInstall detected= vmTypes[i].createVMInstall(String.valueOf(unique));
+				detected.setName(LaunchingMessages.getString("JavaRuntime.detectedSuffix")); //$NON-NLS-1$
+				detected.setInstallLocation(detectedLocation);
+				if (detected != null && !defaultSet) {
+					try {
+						setDefaultVMInstall(detected, null);
+						defaultSet= true;
+					} catch (CoreException e) {
+						LaunchingPlugin.log(e);
+					}
+				}
+			}
+		}
+	}
+	
+	private static void createFromVMType(Element vmTypeElement) {
+		String id = vmTypeElement.getAttribute("id"); //$NON-NLS-1$
+		IVMInstallType vmType= getVMInstallType(id);
+		if (vmType != null) {
+			NodeList list = vmTypeElement.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 vmElement = (Element) node;
+					if (vmElement.getNodeName().equalsIgnoreCase("vm")) { //$NON-NLS-1$
+						createVM(vmType, vmElement);
+					}
+				}
+			}
+		} else {
+			LaunchingPlugin.log(LaunchingMessages.getString("JavaRuntime.VM_type_element_with_unknown_id_1")); //$NON-NLS-1$
+		}
+	}
+
+	private static void createVM(IVMInstallType vmType, Element vmElement) {
+		String id= vmElement.getAttribute("id"); //$NON-NLS-1$
+		if (id != null) {
+			String installPath= vmElement.getAttribute("path"); //$NON-NLS-1$
+			if (installPath == null) {
+				return;
+			}
+			File installLocation= new File(installPath);
+			if (!installLocation.exists()) {
+				return;
+			}
+			IVMInstall vm= vmType.createVMInstall(id);
+			vm.setName(vmElement.getAttribute("name")); //$NON-NLS-1$
+			vm.setInstallLocation(installLocation);
+			
+			NodeList list = vmElement.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 libraryLocationElement= (Element)node;
+					if (libraryLocationElement.getNodeName().equals("libraryLocation")) { //$NON-NLS-1$
+						LibraryLocation loc = getLibraryLocation(vm, libraryLocationElement);
+						vm.setLibraryLocations(new LibraryLocation[]{loc});
+						break;
+					} else if (libraryLocationElement.getNodeName().equals("libraryLocations")) { //$NON-NLS-1$
+						setLibraryLocations(vm, libraryLocationElement);
+						break;
+					}
+				}
+			}
+
+		} else {
+			LaunchingPlugin.log(LaunchingMessages.getString("JavaRuntime.VM_element_specified_with_no_id_attribute_2")); //$NON-NLS-1$
+		}
+	}
+	
+	private static LibraryLocation getLibraryLocation(IVMInstall vm, Element libLocationElement) {
+		String jreJar= libLocationElement.getAttribute("jreJar"); //$NON-NLS-1$
+		String jreSrc= libLocationElement.getAttribute("jreSrc"); //$NON-NLS-1$
+		String pkgRoot= libLocationElement.getAttribute("pkgRoot"); //$NON-NLS-1$
+		if (jreJar != null && jreSrc != null && pkgRoot != null) {
+			return new LibraryLocation(new Path(jreJar), new Path(jreSrc), new Path(pkgRoot));
+		} else {
+			LaunchingPlugin.log(LaunchingMessages.getString("JavaRuntime.Library_location_element_incorrectly_specified_3")); //$NON-NLS-1$
+		}
+		return null;
+	}
+	
+	private static void setLibraryLocations(IVMInstall vm, Element libLocationsElement) {
+		NodeList list = libLocationsElement.getChildNodes();
+		int length = list.getLength();
+		List locations = new ArrayList(length);
+		for (int i = 0; i < length; ++i) {
+			Node node = list.item(i);
+			short type = node.getNodeType();
+			if (type == Node.ELEMENT_NODE) {
+				Element libraryLocationElement= (Element)node;
+				if (libraryLocationElement.getNodeName().equals("libraryLocation")) { //$NON-NLS-1$
+					locations.add(getLibraryLocation(vm, libraryLocationElement));
+				}
+			}
+		}	
+		vm.setLibraryLocations((LibraryLocation[])locations.toArray(new LibraryLocation[locations.size()]));
+	}
+		
+	/**
+	 * Evaluates library locations for a IVMInstall. If no library locations are set on the install, a default
+	 * location is evaluated and checked if it exists.
+	 * @return library locations with paths that exist or are empty
+	 * @since 2.0
+	 */
+	public static LibraryLocation[] getLibraryLocations(IVMInstall vm)  {
+		IPath[] libraryPaths;
+		IPath[] sourcePaths;
+		IPath[] sourceRootPaths;
+		LibraryLocation[] locations= vm.getLibraryLocations();
+		if (locations == null) {
+			LibraryLocation[] dflts= vm.getVMInstallType().getDefaultLibraryLocations(vm.getInstallLocation());
+			libraryPaths = new IPath[dflts.length];
+			sourcePaths = new IPath[dflts.length];
+			sourceRootPaths = new IPath[dflts.length];
+			for (int i = 0; i < dflts.length; i++) {
+				libraryPaths[i]= dflts[i].getSystemLibraryPath();
+				if (!libraryPaths[i].toFile().isFile()) {
+					libraryPaths[i]= Path.EMPTY;
+				}
+				
+				sourcePaths[i]= dflts[i].getSystemLibrarySourcePath();
+				if (sourcePaths[i].toFile().isFile()) {
+					sourceRootPaths[i]= dflts[i].getPackageRootPath();
+				} else {
+					sourcePaths[i]= Path.EMPTY;
+					sourceRootPaths[i]= Path.EMPTY;
+				}
+			}
+		} else {
+			libraryPaths = new IPath[locations.length];
+			sourcePaths = new IPath[locations.length];
+			sourceRootPaths = new IPath[locations.length];
+			for (int i = 0; i < locations.length; i++) {			
+				libraryPaths[i]= locations[i].getSystemLibraryPath();
+				sourcePaths[i]= locations[i].getSystemLibrarySourcePath();
+				sourceRootPaths[i]= locations[i].getPackageRootPath();
+			}
+		}
+		locations = new LibraryLocation[sourcePaths.length];
+		for (int i = 0; i < sourcePaths.length; i++) {
+			locations[i] = new LibraryLocation(libraryPaths[i], sourcePaths[i], sourceRootPaths[i]);
+		}
+		return locations;
+	}
+	
+	/**
+	 * Creates and returns a classpath entry describing
+	 * the JRE_LIB classpath variable.
+	 * 
+	 * @return a new IClasspathEntry that describes the JRE_LIB classpath variable
+	 */
+	public static IClasspathEntry getJREVariableEntry() {
+		return JavaCore.newVariableEntry(
+			new Path(JRELIB_VARIABLE),
+			new Path(JRESRC_VARIABLE),
+			new Path(JRESRCROOT_VARIABLE)
+		);
+	}
+	
+	/**
+	 * Creates and returns a classpath entry describing
+	 * the default JRE container entry.
+	 * 
+	 * @return a new IClasspathEntry that describes the default JRE container entry
+	 * @since 2.0
+	 */
+	public static IClasspathEntry getDefaultJREContainerEntry() {
+		return JavaCore.newContainerEntry(new Path(JRE_CONTAINER));
+	}	
+	
+	/**
+	 * Returns the VM connetor defined with the specified identifier,
+	 * or <code>null</code> if none.
+	 * 
+	 * @param id VM connector identifier
+	 * @return VM connector or <code>null</code> if none
+	 * @since 2.0
+	 */
+	public static IVMConnector getVMConnector(String id) {
+		return LaunchingPlugin.getDefault().getVMConnector(id);
+	}
+	
+	/**
+	 * Returns all VM connector extensions.
+	 *
+	 * @return VM connectors
+	 * @since 2.0
+	 */
+	public static IVMConnector[] getVMConnectors() {
+		return LaunchingPlugin.getDefault().getVMConnectors();
+	}	
+	
+	/**
+	 * Returns the preference store for the launching plug-in.
+	 * 
+	 * @return the preference store for the launching plug-in
+	 * @since 2.0
+	 */
+	public static Preferences getPreferences() {
+		return LaunchingPlugin.getDefault().getPluginPreferences();
+	}
+	
+	/**
+	 * Saves the preferences for the launching plug-in.
+	 * 
+	 * @since 2.0
+	 */
+	public static void savePreferences() {
+		LaunchingPlugin.getDefault().savePluginPreferences();
+	}
+	
+	/**
+	 * Registers the given resolver for the specified variable.
+	 * 
+	 * @param resolver runtime classpathe entry resolver
+	 * @param variableName variable name to register for
+	 * @since 2.0
+	 */
+	public static void addVariableResolver(IRuntimeClasspathEntryResolver resolver, String variableName) {
+		Map map = getVariableResolvers();
+		map.put(variableName, resolver);
+	}
+	
+	/**
+	 * Registers the given resolver for the specified container.
+	 * 
+	 * @param resolver runtime classpathe entry resolver
+	 * @param containerIdentifier identifier of the classpath container to register for
+	 * @since 2.0
+	 */
+	public static void addContainerResolver(IRuntimeClasspathEntryResolver resolver, String containerIdentifier) {
+		Map map = getContainerResolvers();
+		map.put(containerIdentifier, resolver);
+	}	
+	
+	/**
+	 * Returns all registered variable resolvers.
+	 */
+	private static Map getVariableResolvers() {
+		if (fgVariableResolvers == null) {
+			initializeResolvers();
+		}
+		return fgVariableResolvers;
+	}
+	
+	/**
+	 * Returns all registered container resolvers.
+	 */
+	private static Map getContainerResolvers() {
+		if (fgContainerResolvers == null) {
+			initializeResolvers();
+		}
+		return fgContainerResolvers;
+	}
+	
+	private static void initializeResolvers() {
+		IExtensionPoint point = LaunchingPlugin.getDefault().getDescriptor().getExtensionPoint(EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRY_RESOLVERS);
+		IConfigurationElement[] extensions = point.getConfigurationElements();
+		fgVariableResolvers = new HashMap(extensions.length);
+		fgContainerResolvers = new HashMap(extensions.length);
+		for (int i = 0; i < extensions.length; i++) {
+			RuntimeClasspathEntryResolver res = new RuntimeClasspathEntryResolver(extensions[i]);
+			String variable = res.getVariableName();
+			String container = res.getContainerId();
+			if (variable != null) {
+				fgVariableResolvers.put(variable, res);
+			}
+			if (container != null) {
+				fgContainerResolvers.put(container, res);
+			}
+		}		
+	}
+
+	/**
+	 * Returns all registered classpath providers.
+	 */
+	private static Map getClasspathProviders() {
+		if (fgPathProviders == null) {
+			initializeProviders();
+		}
+		return fgPathProviders;
+	}
+		
+	private static void initializeProviders() {
+		IExtensionPoint point = LaunchingPlugin.getDefault().getDescriptor().getExtensionPoint(EXTENSION_POINT_RUNTIME_CLASSPATH_PROVIDERS);
+		IConfigurationElement[] extensions = point.getConfigurationElements();
+		fgPathProviders = new HashMap(extensions.length);
+		for (int i = 0; i < extensions.length; i++) {
+			RuntimeClasspathProvider res = new RuntimeClasspathProvider(extensions[i]);
+			fgPathProviders.put(res.getIdentifier(), res);
+		}		
+	}
+		
+	/**
+	 * Returns the resovler registered for the give variable, or
+	 * <code>null</code> if none.
+	 * 
+	 * @return the resovler registered for the give variable, or
+	 * <code>null</code> if none
+	 */
+	private static IRuntimeClasspathEntryResolver getVariableResolver(String variableName) {
+		return (IRuntimeClasspathEntryResolver)getVariableResolvers().get(variableName);
+	}
+	
+	/**
+	 * Returns the resovler registered for the give container id, or
+	 * <code>null</code> if none.
+	 * 
+	 * @return the resovler registered for the give container id, or
+	 * <code>null</code> if none
+	 */	
+	private static IRuntimeClasspathEntryResolver getContainerResolver(String containerId) {
+		return (IRuntimeClasspathEntryResolver)getContainerResolvers().get(containerId);
+	}	
+	
+	/**
+	 * Returns the provider registered for the given identifier, or
+	 * <code>null</code> if none.
+	 * 
+	 * @return the provider registered for the given identifier, or
+	 * <code>null</code> if none
+	 */
+	private static IRuntimeClasspathProvider getClasspathProvider(String identifier) {
+		return (IRuntimeClasspathProvider)getClasspathProviders().get(identifier);
+	}
+	
+	/**
+	 * Adds the given listener to the list of registered VM install changed
+	 * listeners. Has no effect if an identical listener is already registered.
+	 * 
+	 * @param listener the listener to add
+	 * @since 2.0
+	 */
+	public static void addVMInstallChangedListener(IVMInstallChangedListener listener) {
+		fgVMListeners.add(listener);
+	}
+	
+	/**
+	 * Removes the given listener from the list of registered VM install changed
+	 * listeners. Has no effect if an identical listener is not already registered.
+	 * 
+	 * @param listener the listener to remove
+	 * @since 2.0
+	 */
+	public static void removeVMInstallChangedListener(IVMInstallChangedListener listener) {
+		fgVMListeners.remove(listener);
+	}	
+	
+	private static void notifyDefaultVMChanged(IVMInstall previous, IVMInstall current) {
+		Object[] listeners = fgVMListeners.getListeners();
+		for (int i = 0; i < listeners.length; i++) {
+			IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];
+			listener.defaultVMInstallChanged(previous, current);
+		}
+	}
+	
+	/**
+	 * Notifies all VM install changed listeners of the given property change.
+	 * 
+	 * @param vm the VM that has changed
+	 * @param event event desribing the change.
+	 * @since 2.0
+	 */
+	public static void fireVMChanged(PropertyChangeEvent event) {
+		Object[] listeners = fgVMListeners.getListeners();
+		for (int i = 0; i < listeners.length; i++) {
+			IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];
+			listener.vmChanged(event);
+		}		
+	}
+	
+	/**
+	 * Notifies all VM install changed listeners of the VM addition
+	 * 
+	 * @param vm the VM that has been added
+	 * @since 2.0
+	 */
+	public static void fireVMAdded(IVMInstall vm) {
+		Object[] listeners = fgVMListeners.getListeners();
+		for (int i = 0; i < listeners.length; i++) {
+			IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];
+			listener.vmAdded(vm);
+		}		
+	}	
+	
+	/**
+	 * Notifies all VM install changed listeners of the VM removal
+	 * 
+	 * @param vm the VM that has been removed
+	 * @since 2.0
+	 */
+	public static void fireVMRemoved(IVMInstall vm) {
+		Object[] listeners = fgVMListeners.getListeners();
+		for (int i = 0; i < listeners.length; i++) {
+			IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];
+			listener.vmRemoved(vm);
+		}		
+	}		
 }
\ No newline at end of file