0.103c
diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/boot/BootLoader.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/boot/BootLoader.java
index 6174308..700962c 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/boot/BootLoader.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/boot/BootLoader.java
@@ -26,6 +26,78 @@
  * @see org.eclipse.core.runtime.Platform

  */

 public final class BootLoader {

+

+	/**

+	 * Constant string (value "win32") indicating the platform is running on a

+	 * Window 32-bit operating system (e.g., Windows 98, NT, 2000).

+	 */

+	public static final String OS_WIN32 = "win32";

+

+	/**

+	 * Constant string (value "linux") indicating the platform is running on a

+	 * Linux-based operating system.

+	 */

+	public static final String OS_LINUX = "linux";

+

+	/**

+	 * Constant string (value "aix") indicating the platform is running on an

+	 * AIX-based machine.

+	 */

+	public static final String OS_AIX = "aix";

+

+	/**

+	 * Constant string (value "solaris") indicating the platform is running on a

+	 * Solaris-based machine.

+	 */

+	public static final String OS_SOLARIS = "solaris";

+

+	/**

+	 * Constant string (value "hpux") indicating the platform is running on an

+	 * HP/UX-based machine.

+	 */

+	public static final String OS_HPUX = "hpux";

+

+	/**

+	 * Constant string (value "neutrino") indicating the platform is running on a

+	 * Neutrino-based machine.

+	 */

+	public static final String OS_NEUTRINO = "neutrino";

+

+	/**

+	 * Constant string (value "unknown") indicating the platform is running on a

+	 * machine running an unknown operating system.

+	 */

+	public static final String OS_UNKNOWN = "unknown";

+

+	/**

+	 * Constant string (value "win32") indicating the platform is running on a

+	 * machine using the Windows windowing system.

+	 */

+	public static final String WS_WIN32 = "win32";

+

+	/**

+	 * Constant string (value "motif") indicating the platform is running on a

+	 * machine using the Motif windowing system.

+	 */

+	public static final String WS_MOTIF = "motif";

+

+	/**

+	 * Constant string (value "gtk") indicating the platform is running on a

+	 * machine using the GTK windowing system.

+	 */

+	public static final String WS_GTK = "gtk";

+

+	/**

+	 * Constant string (value "photon") indicating the platform is running on a

+	 * machine using the Photon windowing system.

+	 */

+	public static final String WS_PHOTON = "photon";

+

+	/**

+	 * Constant string (value "unknown") indicating the platform is running on a

+	 * machine running an unknown windowing system.

+	 */

+	public static final String WS_UNKNOWN = "unknown";

 /**

  * Private constructor to block instance creation.

  */

@@ -73,6 +145,30 @@
 	return InternalBootLoader.getInstallURL();

 }

 /**

+ * Returns the string name of the current locale for use in finding files

+ * whose path starts with <code>$nl$</code>.  <code>null</code> is returned

+ * if the locale cannot be determined.

+ *

+ * @return the string name of the current locale or <code>null</code>

+ */

+public static String getNL() {

+	return InternalBootLoader.getNL();

+}

+/**

+ * Returns the string name of the current operating system for use in finding files

+ * whose path starts with <code>$os$</code>.  <code>OS_UNKNOWN</code> is returned

+ * if the operating system cannot be determined.  The value may indicate one of the following

+ * operating systems known to the platform (<code>OS_WIN32</code>, <code>OS_LINUX</code>,

+ * <code>OS_AIX</code>, <code>OS_SOLARIS</code>, <code>OS_HPUX</code> or

+ * a user-defined string if the operating system name is specified on the command line.

+ *

+ * @return the string name of the current operating system

+ * 

+ */

+public static String getOS() {

+	return InternalBootLoader.getOS();

+}

+/**

  * Returns the complete plugin path defined by the file at the given location.

  * If the given location is <code>null</code> or does not indicate a valid 

  * plug-in path definition file, <code>null</code> is returned.

@@ -114,6 +210,16 @@
 	return InternalBootLoader.getRunnable(pluginId, className, args);

 }

 /**

+ * Returns the string name of the current window system for use in finding files

+ * whose path starts with <code>$ws$</code>.  <code>null</code> is returned

+ * if the window system cannot be determined.

+ *

+ * @return the string name of the current window system or <code>null</code>

+ */

+public static String getWS() {

+	return InternalBootLoader.getWS();

+}

+/**

  * Returns <code>true</code> if the platform is currently running in 

  * debug mode.  The platform is run

  * in debug mode using the "-debug" command line argument.

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/DelegatingURLClassLoader.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/DelegatingURLClassLoader.java
index 706524b..fe60697 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/DelegatingURLClassLoader.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/DelegatingURLClassLoader.java
@@ -10,9 +10,8 @@
 import java.io.*;

 import java.security.CodeSource;

 import java.security.ProtectionDomain;

+import org.eclipse.core.boot.BootLoader;

 

-/**

- */

 public abstract class DelegatingURLClassLoader extends URLClassLoader {

 

 	// loader base

@@ -21,14 +20,17 @@
 	// delegation chain

 	protected DelegateLoader[] imports = null;

 

+	// extra resource class loader

+	protected URLClassLoader resourceLoader = null;

+

 	// filter table

-	private Hashtable libTable = new Hashtable();

+	private Hashtable filterTable = new Hashtable();

 

 	// development mode class path additions

 	public static String devClassPath = null;

 	// native library loading

-	private String prefix;

-	private String suffix;

+	private static String libPrefix;

+	private static String libSuffix;

 	private static final String WIN_LIBRARY_PREFIX = "";

 	private static final String WIN_LIBRARY_SUFFIX = ".dll";

 	private static final String UNIX_LIBRARY_PREFIX = "lib";

@@ -102,19 +104,26 @@
 		}

 	}

 

-/**

- * DelegatingURLClassLoader constructor comment.

- * @param urls java.net.URL[] search path

- * @param URLContentFilter[] content filters

- * @param parent java.lang.ClassLoader parent loader

- */

-public DelegatingURLClassLoader(URL[] urls, URLContentFilter[] filters, ClassLoader parent) {

-	super(urls, parent);

+public DelegatingURLClassLoader(URL[] codePath, URLContentFilter[] codeFilters, URL[] resourcePath, URLContentFilter[] resourceFilters, ClassLoader parent) {

+	super(codePath, parent);

+	initialize();

+	if (resourcePath != null)

+		resourceLoader = new ResourceLoader(resourcePath);

 

-	if (urls!=null) {

-		if (filters==null || filters.length!=urls.length) throw new DelegatingLoaderException();

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

-			if (filters[i]!=null) libTable.put(urls[i],filters[i]);

+	if (codePath != null) {

+		if (codeFilters == null || codeFilters.length != codePath.length)

+			throw new DelegatingLoaderException();

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

+			if (codeFilters[i] != null)

+				filterTable.put(codePath[i], codeFilters[i]);

+		}

+	}

+	if (resourcePath != null) {

+		if (resourceFilters == null || resourceFilters.length != resourcePath.length)

+			throw new DelegatingLoaderException();

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

+			if (resourceFilters[i] != null)

+				filterTable.put(resourcePath[i], resourceFilters[i]);

 		}

 	}

 }

@@ -123,7 +132,7 @@
  * given requestor.  The <code>inCache</code> flag controls how this action is

  * reported if in debug mode.

  */

-protected Class checkVisibility(Class result, DelegatingURLClassLoader requestor, boolean inCache) {

+protected Class checkClassVisibility(Class result, DelegatingURLClassLoader requestor, boolean inCache) {

 	if (result == null)

 		return null;

 	if (isClassVisible(result, requestor)) {

@@ -136,6 +145,23 @@
 	}

 	return result;

 }

+/**

+ * Returns the given resource URL or <code>null</code> if the resource is not visible to the

+ * given requestor.  

+ */

+protected URL checkResourceVisibility(String name, URL result, DelegatingURLClassLoader requestor) {

+	if (result == null)

+		return null;

+	if (isResourceVisible(name, result, requestor)) {

+		if (DEBUG && DEBUG_SHOW_SUCCESS && debugResource(name))

+			debug("found " + result);

+	} else {

+		if (DEBUG && DEBUG_SHOW_ACTIONS && debugResource(name))

+			debug("skip " + result);

+		result = null;

+	}

+	return result;

+}

 protected void debug(String s) {

 

 	System.out.println(toString()+"^"+Integer.toHexString(Thread.currentThread().hashCode())+" "+s);

@@ -148,18 +174,19 @@
 	return false;

 }

 protected void debugConstruction() {

-	

-	if(DEBUG && DEBUG_SHOW_CREATE && debugLoader()) {

+	if (DEBUG && DEBUG_SHOW_CREATE && debugLoader()) {

 		URL[] urls = getURLs();

 		debug("Class Loader Created");

-		debug("> baseURL="+base);

-		if (urls==null || urls.length==0) debug("> empty search path");

+		debug("> baseURL=" + base);

+		if (urls == null || urls.length == 0)

+			debug("> empty search path");

 		else {

 			URLContentFilter filter;

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

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

 				debug("> searchURL=" + urls[i].toString());

-				filter = (URLContentFilter)libTable.get(urls[i]);

-				if (filter!=null) debug(">    export=" + filter.toString());

+				filter = (URLContentFilter) filterTable.get(urls[i]);

+				if (filter != null)

+					debug(">    export=" + filter.toString());

 			}

 		}

 	}

@@ -269,6 +296,18 @@
 	return null;

 }

 /**

+ * Finds the resource with the specified name on the URL search path.

+ * This method is used specifically to find the file containing a class to verify

+ * that the class exists without having to load it.

+ * Returns a URL for the resource.  Searches only this loader's classpath.

+ * <code>null</code> is returned if the resource cannot be found.

+ *

+ * @param name the name of the resource

+ */

+protected URL findClassResource(String name) {

+	return super.findResource(name);

+}

+/**

  * Returns the absolute path name of a native library. The VM

  * invokes this method to locate the native libraries that belong

  * to classes loaded with this class loader. If this method returns

@@ -279,36 +318,33 @@
  * @return     the absolute path of the native library

  */

 protected String findLibrary(String libname) {

-	

-	if(DEBUG && DEBUG_SHOW_ACTIONS && debugNative(libname)) 

-		debug("findLibrary("+libname+")");

+	if (DEBUG && DEBUG_SHOW_ACTIONS && debugNative(libname))

+		debug("findLibrary(" + libname + ")");

 

-	if (base==null) return null;

-

+	if (base == null)

+		return null;

 	File libFile = null;

-	String osLibFileName = getLibraryName(libname);

-	

-	if (base.getProtocol().equals(EclipseURLHandler.FILE) || base.getProtocol().equals(EclipseURLHandler.VA)) {

+	String osLibFileName = libPrefix + libname + libSuffix;

+	if (base.getProtocol().equals(PlatformURLHandler.FILE) || base.getProtocol().equals(PlatformURLHandler.VA)) {

 		// directly access library	

-		String libFileName = (base.getFile()+osLibFileName).replace('/',File.separatorChar);

+		String libFileName = (base.getFile() + osLibFileName).replace('/', File.separatorChar);

 		libFile = new File(libFileName);

-	}

-	else if (base.getProtocol().equals(EclipseURLHandler.ECLIPSE)) {

-		// access library through eclipse URL

-		libFile = getNativeLibraryAsLocal(osLibFileName);	

-	}

+	} else

+		if (base.getProtocol().equals(PlatformURLHandler.PROTOCOL))

+			// access library through eclipse URL

+			libFile = getNativeLibraryAsLocal(osLibFileName);

 

-	if (libFile==null) return null;

-	

+	if (libFile == null)

+		return null;

 	if (!libFile.exists()) {

-		if(DEBUG && DEBUG_SHOW_FAILURE && debugNative(libname)) 

-			debug("not found "+libname);

+		if (DEBUG && DEBUG_SHOW_FAILURE && debugNative(libname))

+			debug("not found " + libname);

 		return null; // can't find the file

 	}

 

-	if(DEBUG && DEBUG_SHOW_SUCCESS && debugNative(libname)) 

-		debug("found "+libname+" as "+libFile.getAbsolutePath());

-		

+	if (DEBUG && DEBUG_SHOW_SUCCESS && debugNative(libname))

+		debug("found " + libname + " as " + libFile.getAbsolutePath());

+

 	return libFile.getAbsolutePath();

 }

 /**

@@ -320,60 +356,43 @@
  * @param name the name of the resource

  */

 public URL findResource(String name) {

-

 	return findResource(name, this, null);

 }

 /**

  * Delegated resource access call. 

  * Does not check prerequisite loader parent chain.

  */

-private URL findResource(String name, DelegatingURLClassLoader requestor, Vector seen) {

-				

+protected URL findResource(String name, DelegatingURLClassLoader requestor, Vector seen) {

 	// guard against delegation loops

-	if (seen!=null && seen.contains(this)) return null;

+	if (seen != null && seen.contains(this))

+		return null;

 

-	if(DEBUG && DEBUG_SHOW_ACTIONS && debugResource(name)) 

-		debug("findResource("+name+")");

-			

-	// check own URL search path

-	URL url = super.findResource(name);

+	if (DEBUG && DEBUG_SHOW_ACTIONS && debugResource(name))

+		debug("findResource(" + name + ")");

 

-	if (url!=null) {

-		if (isResourceVisible(name,url,requestor)) {		

-			if(DEBUG && DEBUG_SHOW_SUCCESS && debugResource(name)) {

-				debug("found "+url);

-			}

-		}

-		else {	

-			if(DEBUG && DEBUG_SHOW_ACTIONS && debugResource(name)) 

-				debug("skip "+url);

-			url = null;

-		}

+	// check the normal class path for self

+	URL result = super.findResource(name);

+	result = checkResourceVisibility(name, result, requestor);

+	if (result != null)

+		return result;

+

+	// check our extra resource path if any

+	if (resourceLoader != null) {

+		result = resourceLoader.findResource(name);

+		result = checkResourceVisibility(name, result, requestor);

+		if (result != null)

+			return result;

 	}

 

-	// delegate down the prerequisite chain

-	if (url==null) {

-		if (imports != null) {

-			if (seen==null) seen = new Vector(); // guard against delegation loops

-			seen.addElement(this);

-			

-			for (int i=0; i<imports.length && url==null; i++) {

-				url = imports[i].findResource(name, this, requestor, seen);

-			}

-		}

+	// delegate down the prerequisite chain if we haven't found anything yet.

+	if (imports != null) {

+		if (seen == null)

+			seen = new Vector(); // guard against delegation loops

+		seen.addElement(this);

+		for (int i = 0; i < imports.length && result == null; i++)

+			result = imports[i].findResource(name, this, requestor, seen);

 	}

-	

-	return url;

-}

-/**

- * Finds the resource with the specified name on the URL search path.

- * Returns a URL for the resource.  Searches only this loader's classpath.

- * <code>null</code> is returned if the resource cannot be found.

- *

- * @param name the name of the resource

- */

-protected URL findResourceLocal(String name) {

-	return super.findResource(name);

+	return result;

 }

 /**

  * Returns an Enumeration of URLs representing all of the resources

@@ -382,7 +401,6 @@
  * @param name the resource name

  */

 public Enumeration findResources(String name) throws IOException {

-

 	return findResources(name, this, null);

 }

 /**

@@ -390,75 +408,53 @@
  * Does not check prerequisite loader parent chain.

  */

 private Enumeration findResources(String name, DelegatingURLClassLoader requestor, Vector seen) {

-				

 	// guard against delegation loops

-	if (seen!=null && seen.contains(this)) return null;

+	if (seen != null && seen.contains(this))

+		return null;

 

-	if(DEBUG && DEBUG_SHOW_ACTIONS && debugResource(name)) 

-		debug("findResources("+name+")");

-			

+	if (DEBUG && DEBUG_SHOW_ACTIONS && debugResource(name))

+		debug("findResources(" + name + ")");

+

 	// check own URL search path

 	Enumeration e = null;

-	try { e = super.findResources(name); }

-	catch(IOException ioe) {}

-	ResourceEnumeration re = new ResourceEnumeration(name, e, this, requestor);

+	try {

+		e = super.findResources(name);

+	} catch (IOException ioe) {

+	}

+	ResourceEnumeration result = new ResourceEnumeration(name, e, this, requestor);

 

 	// delegate down the prerequisite chain

 	if (imports != null) {

-		if (seen==null) seen = new Vector(); // guard against delegation loops

+		if (seen == null)

+			seen = new Vector(); // guard against delegation loops

 		seen.addElement(this);

+		for (int i = 0; i < imports.length; i++)

+			result.add(imports[i].findResources(name, this, requestor, seen));

+	}

 

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

-			re.add(imports[i].findResources(name, this, requestor, seen));

-		}

-	}

-	

-	return re;

-}

-private String getLibraryName(String name) {

-	

-	if (prefix == null || suffix == null) {		

-		if (System.getProperty("os.name").indexOf("Windows")!=-1) {

-			prefix = WIN_LIBRARY_PREFIX;

-			suffix = WIN_LIBRARY_SUFFIX;

-		}

-		else {

-			prefix = UNIX_LIBRARY_PREFIX;

-			suffix = UNIX_LIBRARY_SUFFIX;

-		}

-	}

-	

-	return prefix + name + suffix;

+	return result;

 }

 private File getNativeLibraryAsLocal(String osname) {

-

-	File lib = null;

-	

+	File result = null;

 	try {

 		URL liburl = new URL(base, osname);

-		EclipseURLConnection c = (EclipseURLConnection) liburl.openConnection();

+		PlatformURLConnection c = (PlatformURLConnection) liburl.openConnection();

 		URL localName = c.getURLAsLocal();

-		lib = new File(localName.getFile());

+		result = new File(localName.getFile());

+	} catch (IOException e) {

 	}

-	catch(IOException e) {}

-

-	return lib;

+	return result;

 }

-/**

- */

 public URL getResource(String name) {

-	

-	if(DEBUG && DEBUG_SHOW_ACTIONS && debugResource(name)) 

-		debug("getResource("+name+")");

-	

-	URL r = super.getResource(name);

-	

-	if (r==null) {	

-		if(DEBUG && DEBUG_SHOW_FAILURE && debugResource(name)) 

-			debug("not found "+name);

-		}

-	

-	return r;

+	if (DEBUG && DEBUG_SHOW_ACTIONS && debugResource(name))

+		debug("getResource(" + name + ")");

+

+	URL result = super.getResource(name);

+	if (result == null) {

+		if (DEBUG && DEBUG_SHOW_FAILURE && debugResource(name))

+			debug("not found " + name);

+	}

+	return result;

 }

 private URL getURLforClass(Class clazz) {

 	ProtectionDomain pd = clazz.getProtectionDomain();

@@ -471,6 +467,15 @@
 		debug("*** " + clazz.getName());

 	return null;

 }

+private void initialize() {

+	if (BootLoader.getOS().equals(BootLoader.OS_WIN32)) {

+		libPrefix = WIN_LIBRARY_PREFIX;

+		libSuffix = WIN_LIBRARY_SUFFIX;

+	} else {

+		libPrefix = UNIX_LIBRARY_PREFIX;

+		libSuffix = UNIX_LIBRARY_SUFFIX;

+	}

+}

 public void initializeImportedLoaders() {

 }

 /**

@@ -481,7 +486,7 @@
 	if (lib == null)

 		return true; // have a system class (see comment below)

 

-	URLContentFilter filter = (URLContentFilter) libTable.get(lib);

+	URLContentFilter filter = (URLContentFilter) filterTable.get(lib);

 	if (filter == null) {

 		// This code path is being executed because some VMs (eg. Sun JVM)

 		// return from the class cache classes that were not loaded

@@ -501,23 +506,24 @@
 /**

  * check to see if resource is visible (exported)

  */

-boolean isResourceVisible(String name, URL r, DelegatingURLClassLoader requestor) {

+boolean isResourceVisible(String name, URL resource, DelegatingURLClassLoader requestor) {

 	URL lib = null;

-	String file = r.getFile();

+	String file = resource.getFile();

 	try {

-		lib = new URL(r.getProtocol(),r.getHost(),file.substring(0,file.length()-name.length()));

-	}

-	catch(MalformedURLException e) {

-		if (DEBUG) debug("Unable to determine resource lib for "+name+" from "+r);

+		lib = new URL(resource.getProtocol(), resource.getHost(), file.substring(0, file.length() - name.length()));

+	} catch (MalformedURLException e) {

+		if (DEBUG)

+			debug("Unable to determine resource lib for " + name + " from " + resource);

 		return false;

 	}

-	

-	URLContentFilter filter = (URLContentFilter)this.libTable.get(lib);

-	if (filter==null) {

-		if (DEBUG) debug("Unable to find library filter for "+name+" from "+lib);

+

+	URLContentFilter filter = (URLContentFilter) filterTable.get(lib);

+	if (filter == null) {

+		if (DEBUG)

+			debug("Unable to find library filter for " + name + " from " + lib);

 		return false;

-	}

-	else return filter.isResourceVisible(name, this, requestor);

+	} else

+		return filter.isResourceVisible(name, this, requestor);

 }

 /**

  * Non-delegated load call.  This method is not synchronized.  Implementations of

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLHandlerFactoryProxy.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLHandlerFactoryProxy.java
deleted file mode 100644
index 8032e7b..0000000
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLHandlerFactoryProxy.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.eclipse.core.internal.boot;

-

-/*

- * Licensed Materials - Property of IBM,

- * WebSphere Studio Workbench

- * (c) Copyright IBM Corp 2000

- */

-

-import java.net.*;

- 

-public class EclipseURLHandlerFactoryProxy implements URLStreamHandlerFactory {

-

-	private static EclipseURLHandlerFactoryProxy p = null;	// singleton - set into URL as factory

-	private EclipseURLHandlerFactory f = null; // current actual factory

-EclipseURLHandlerFactoryProxy() {

-	super();

-	if (p==null) p = this;

-}

-public URLStreamHandler createURLStreamHandler(String protocol) {

-

-	if (f==null) return null;

-	else return f.createURLStreamHandler(protocol);

-}

-EclipseURLHandlerFactory getFactory() {

-	return f;

-}

-static EclipseURLHandlerFactoryProxy getFactoryProxy() {

-	return p;

-}

-void setFactory(EclipseURLHandlerFactory factory) {

-	f = factory;

-}

-}

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/InternalBootLoader.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/InternalBootLoader.java
index 8d94c8b..d40ea1c 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/InternalBootLoader.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/InternalBootLoader.java
@@ -46,6 +46,12 @@
 	private static Properties options = null;

 	private static boolean inDevelopmentMode = false;

 

+	// state for tracking the Platform context (e.g., the OS, Window system, locale, ...)

+	private static String NL = null;

+	private static String WS = null;

+	private static String OS = null;

+	private static final String[] OS_LIST = { BootLoader.OS_WIN32, BootLoader.OS_LINUX, BootLoader.OS_AIX, BootLoader.OS_SOLARIS, BootLoader.OS_HPUX };

+	

 	private static final String PLATFORM_ENTRYPOINT = "org.eclipse.core.internal.runtime.InternalPlatform";

 	private static final String BOOTNAME = "org.eclipse.core.boot";

 	private static final String RUNTIMENAME = "org.eclipse.core.runtime";

@@ -79,10 +85,10 @@
 	private static final String OPTION_LOADER_FILTER_LOADER = PI_RUNTIME + "/loader/debug/filter/loader";

 	private static final String OPTION_LOADER_FILTER_RESOURCE = PI_RUNTIME + "/loader/debug/filter/resource";

 	private static final String OPTION_LOADER_FILTER_NATIVE = PI_RUNTIME + "/loader/debug/filter/native";

-	private static final String OPTION_ECLIPSEURL_DEBUG = PI_RUNTIME+ "/eclipseurl/debug";

-	private static final String OPTION_ECLIPSEURL_DEBUG_CONNECT = PI_RUNTIME+ "/eclipseurl/debug/connect";

-	private static final String OPTION_ECLIPSEURL_DEBUG_CACHE_LOOKUP = PI_RUNTIME+ "/eclipseurl/debug/cachelookup";

-	private static final String OPTION_ECLIPSEURL_DEBUG_CACHE_COPY = PI_RUNTIME+ "/eclipseurl/debug/cachecopy";

+	private static final String OPTION_URL_DEBUG = PI_RUNTIME+ "/url/debug";

+	private static final String OPTION_URL_DEBUG_CONNECT = PI_RUNTIME+ "/url/debug/connect";

+	private static final String OPTION_URL_DEBUG_CACHE_LOOKUP = PI_RUNTIME+ "/url/debug/cachelookup";

+	private static final String OPTION_URL_DEBUG_CACHE_COPY = PI_RUNTIME+ "/url/debug/cachecopy";

 	private static final String OPTION_UPDATE_DEBUG = PI_RUNTIME+ "/update/debug";

 

 	// command line arguments

@@ -161,7 +167,7 @@
 	Object[] loadPath = getPlatformClassLoaderPath(config);

 	URL base = null;

 	try {

-		base = new URL(EclipseURLPlatformConnection.PLATFORM_URL_STRING+RUNTIMEDIR);

+		base = new URL(PlatformURLBaseConnection.PLATFORM_URL_STRING+RUNTIMEDIR);

 	} catch (MalformedURLException e) {

 	}

 	return new PlatformClassLoader((URL[]) loadPath[0], (URLContentFilter[]) loadPath[1], InternalBootLoader.class.getClassLoader(), base);

@@ -252,6 +258,18 @@
 		result.add(tokenizer.nextToken());

 	return (String[]) result.toArray(new String[result.size()]);

 }

+/**

+ * @see BootLoader

+ */

+public static String getNL() {

+	return NL;

+}

+/**

+ * @see BootLoader

+ */

+public static String getOS() {

+	return OS;

+}

 private static Object[] getPlatformClassLoaderPath(Properties config) {

 	// If running in va, check for va properties file. 

 	// The property file has entries corresponding to <library>

@@ -348,10 +366,10 @@
 		if (!(InternalBootLoader.inVAJ || InternalBootLoader.inVAME)) {

 			String libSpec = execBase + library.replace(File.separatorChar, '/');

 			if (!libSpec.endsWith("/")) {

-				if (libSpec.startsWith(EclipseURLHandler.ECLIPSE + EclipseURLHandler.PROTOCOL_SEPARATOR))

-					libSpec += EclipseURLHandler.JAR_SEPARATOR;

+				if (libSpec.startsWith(PlatformURLHandler.PROTOCOL + PlatformURLHandler.PROTOCOL_SEPARATOR))

+					libSpec += PlatformURLHandler.JAR_SEPARATOR;

 				else

-					libSpec = EclipseURLHandler.JAR + EclipseURLHandler.PROTOCOL_SEPARATOR + libSpec + EclipseURLHandler.JAR_SEPARATOR;

+					libSpec = PlatformURLHandler.JAR + PlatformURLHandler.PROTOCOL_SEPARATOR + libSpec + PlatformURLHandler.JAR_SEPARATOR;

 			}

 			libSpecs.add(libSpec);

 			libSpecs.add(filters);

@@ -390,7 +408,7 @@
 	// definition in the install location.

 	if (input == null)

 		try {

-			URL url = new URL(EclipseURLPlatformConnection.PLATFORM_URL_STRING + PLUGIN_PATH);

+			URL url = new URL(PlatformURLBaseConnection.PLATFORM_URL_STRING + PLUGIN_PATH);

 			input = url.openStream();

 		} catch (MalformedURLException e) {

 		} catch (IOException e) {

@@ -489,6 +507,12 @@
 /**

  * @see BootLoader

  */

+public static String getWS() {

+	return WS;

+}

+/**

+ * @see BootLoader

+ */

 public static boolean inDebugMode() {

 	return debugRequested;

 }

@@ -507,7 +531,8 @@
 	String[] appArgs = processCommandLine(args);

 	// setup the devClassPath if any

 	DelegatingURLClassLoader.devClassPath = devClassPath;

-	

+	setupSystemContext();

+

 	// if a platform location was not found in the arguments, set it to user.dir.		

 	// In VAJ, set user.dir to be <code>eclipse</code> in the parent of the install 

 	// directory.  This typically makes the platform working directory:

@@ -525,12 +550,12 @@
 

 	// load update profile

 	LaunchInfo.startup(getInstallURL());

-	

+

 	// initialize eclipse URL handling

-	EclipseURLHandlerFactory.startup(baseLocation+File.separator+META_AREA);

-	EclipseURLPlatformConnection.startup(getInstallURL()); // past this point we can use eclipse:/platform/ URLs

-	EclipseURLConfigurationConnection.startup(getInstallURL()); // past this point we can use eclipse:/configuration/ URLs

-	EclipseURLComponentConnection.startup(getInstallURL()); // past this point we can use eclipse:/component/ URLs

+	PlatformURLHandlerFactory.startup(baseLocation + File.separator + META_AREA);

+	PlatformURLBaseConnection.startup(getInstallURL()); // past this point we can use eclipse:/platform/ URLs

+	PlatformURLConfigurationConnection.startup(getInstallURL()); // past this point we can use eclipse:/configuration/ URLs

+	PlatformURLComponentConnection.startup(getInstallURL()); // past this point we can use eclipse:/component/ URLs

 

 	// create and configure platform class loader

 	Properties config = loadConfiguration();

@@ -829,13 +854,31 @@
 	DelegatingURLClassLoader.DEBUG_FILTER_LOADER = getListOption(OPTION_LOADER_FILTER_LOADER);

 	DelegatingURLClassLoader.DEBUG_FILTER_RESOURCE = getListOption(OPTION_LOADER_FILTER_RESOURCE);

 	DelegatingURLClassLoader.DEBUG_FILTER_NATIVE = getListOption(OPTION_LOADER_FILTER_NATIVE);

-	EclipseURLConnection.DEBUG = getBooleanOption(OPTION_ECLIPSEURL_DEBUG, false);

-	EclipseURLConnection.DEBUG_CONNECT = getBooleanOption(OPTION_ECLIPSEURL_DEBUG_CONNECT, true);

-	EclipseURLConnection.DEBUG_CACHE_LOOKUP = getBooleanOption(OPTION_ECLIPSEURL_DEBUG_CACHE_LOOKUP, true);

-	EclipseURLConnection.DEBUG_CACHE_COPY = getBooleanOption(OPTION_ECLIPSEURL_DEBUG_CACHE_COPY, true);

+	PlatformURLConnection.DEBUG = getBooleanOption(OPTION_URL_DEBUG, false);

+	PlatformURLConnection.DEBUG_CONNECT = getBooleanOption(OPTION_URL_DEBUG_CONNECT, true);

+	PlatformURLConnection.DEBUG_CACHE_LOOKUP = getBooleanOption(OPTION_URL_DEBUG_CACHE_LOOKUP, true);

+	PlatformURLConnection.DEBUG_CACHE_COPY = getBooleanOption(OPTION_URL_DEBUG_CACHE_COPY, true);

 	LaunchInfo.DEBUG = getBooleanOption(OPTION_UPDATE_DEBUG, false);

 }

 /**

+ * Initializes the execution context for this run of the platform.  The context

+ * includes information about the locale, operating system and window system.

+ */

+private static void setupSystemContext() {

+	if (NL == null)

+		NL = Locale.getDefault().toString();

+	if (OS == null) {

+		String name = System.getProperty("os.name");

+		for (int i = 0; i < OS_LIST.length; i++)

+			if (name.regionMatches(true, 0, OS_LIST[i], 0, 3))

+				OS = OS_LIST[i];

+		if (OS == null)

+			OS = BootLoader.OS_UNKNOWN;

+	}

+	if (WS == null)

+		WS = BootLoader.WS_UNKNOWN;

+}

+/**

  * @see BootLoader

  */

 public static void shutdown() throws Exception {

@@ -852,7 +895,7 @@
 		else

 			throw e;

 	} finally {

-		EclipseURLHandlerFactory.shutdown();

+		PlatformURLHandlerFactory.shutdown();

 		LaunchInfo.shutdown();

 		loader = null;

 	}

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/LaunchInfo.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/LaunchInfo.java
index 79e4d99..276a9ec 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/LaunchInfo.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/LaunchInfo.java
@@ -78,15 +78,19 @@
 	private static final String DEFAULT_PLATFORM = "";

 	private static final String DEFAULT_APP = "org.eclipse.ui.workbench";

 	private static final String DEFAULT_APP_CONFIG = "";

-	private static final int DEFAULT_HISTORY_COUNT = 3;

+	private static final int DEFAULT_HISTORY_COUNT = 5;

 

 	private static final String URL_FILE = "file";

 	private static final String URL_VA = "valoader";

 

-	private static final String ECLIPSE_CONFIG_URL = EclipseURLConfigurationConnection.CONFIG_URL_STRING;

-	private static final String ECLIPSE_COMP_URL = EclipseURLComponentConnection.COMP_URL_STRING;

+	private static final String CONFIG_URL = PlatformURLConfigurationConnection.CONFIG_URL_STRING;

+	private static final String COMP_URL = PlatformURLComponentConnection.COMP_URL_STRING;

+

+	// uninstall

+	private static final String UNINSTALLFLAG = "-uninstall";

 	

 	// debug tracing

+	private static final String DEBUGFLAG = "-debug";

 	public static boolean DEBUG = false;

 

 	public static class History {

@@ -206,8 +210,10 @@
 	installurl = install;

 	

 	props = new Properties();

+	InputStream is = null;

 	try {

-		props.load(baseurl.openStream());

+		is = baseurl.openStream();

+		props.load(is);

 		id = props.getProperty(ID,"");

 		if (id.trim().equals(""))

 			id = Long.toString((new java.util.Date()).getTime(),Character.MAX_RADIX);

@@ -242,6 +248,9 @@
 	catch(IOException e) {

 		setDefaults();

 	}

+	finally {

+		if (is!=null) try {is.close();} catch(IOException e) {}

+	}

 }

 

 public LaunchInfo(History history) {

@@ -285,6 +294,8 @@
 

 	VersionedIdentifier[] result = new VersionedIdentifier[delta.size()];

 	delta.toArray(result);

+	if (DEBUG) for (int i=0; i<result.length; i++)

+		debug("   new "+result[i].toString());

 	return result;

 }

 

@@ -301,6 +312,9 @@
 	// flush the current state to disk. Only has effect if the state has changed.

 	// This method should be called by the UM ui each time the preference page

 	// is closed

+

+	// perform cleanup sweep

+//	uninstall();

 }

 

 synchronized private VersionedIdentifier[] get(List list) {

@@ -345,7 +359,7 @@
 	if (componentId==null || componentId.trim().equals(""))

 		throw new IllegalArgumentException();

 	try {

-		return new URL(ECLIPSE_COMP_URL + componentId.trim() + "/");

+		return new URL(COMP_URL + componentId.trim() + "/");

 	} catch (MalformedURLException e) {

 		throw new IllegalStateException();

 	}

@@ -361,7 +375,7 @@
 	if (configurationId==null || configurationId.trim().equals(""))

 		throw new IllegalArgumentException();

 	try {

-		return new URL(ECLIPSE_CONFIG_URL + configurationId.trim() + "/");

+		return new URL(CONFIG_URL + configurationId.trim() + "/");

 	} catch (MalformedURLException e) {

 		throw new IllegalStateException();

 	}

@@ -589,6 +603,15 @@
 	}

 	return;

 }

+private static String[] processCommandLine(String[] args) throws Exception {

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

+		if (args[i].equalsIgnoreCase(DEBUGFLAG)) {

+			DEBUG = true;

+			break;

+		}

+	}

+	return args;

+}

 

 synchronized private void remove(VersionedIdentifier id, List active, List inactive) {

 	if (active.contains(id)) {

@@ -672,6 +695,26 @@
 	

 	return inactive;

 }

+public static Object run(String flag, String value, String location, String[] args) throws Exception {

+	processCommandLine(args);

+	if (DEBUG) {

+		debug(flag+" "+value);

+	}

+

+	if (flag.equalsIgnoreCase(UNINSTALLFLAG)) {

+		URL cookie = null;	

+		URL base = InternalBootLoader.getInstallURL();	

+		try {

+			cookie = new URL("file",null,0,value);

+		}

+		catch(MalformedURLException e) {

+			return null;

+		}

+		startup(base);

+		BootUpdateManager.uninstall(cookie);

+	}

+	return null;

+}

 synchronized private void set(VersionedIdentifier id, List active, List inactive) {

 	if (id == null)

 		return;

@@ -783,11 +826,20 @@
 public void setHistoryCount(int count) {

 

 	changed = true;

-	if (count<0)

+	if (count<=0)

 		historyCount = DEFAULT_HISTORY_COUNT;

 	else

 		historyCount = count;

 }

+/**

+ * This method is called by the BootUpdateManager with a list of

+ * configurations, components, plugins and fragments that could not

+ * be installer (after they were discovered). If these items

+ * do not exist on an active or inactive list already, they are added

+ * to the corresponding inactive list.

+ */

+synchronized public void setInactive(VersionedIdentifier[] configId, VersionedIdentifier[] compId, VersionedIdentifier[] pluginId, VersionedIdentifier[] fragId) {

+}

 

 public void setPlugin(VersionedIdentifier plugin) {

 	set(plugin, plugins, pluginsInact);

@@ -847,22 +899,28 @@
 					File.separatorChar);

 			dir = new File(path);

 			list = dir.list(filter);

+			if (DEBUG) debug("Detecting configuration changes");

 			VersionedIdentifier[] configDelta;

 			if (list == null)

 				configDelta = new VersionedIdentifier[0];

-			else

+			else {

+				profile.synchConfigurations(list);

 				configDelta = profile.computeDelta(list, profile.configs, profile.configsInact);

+			}

 

 			// look for components	

 			path =

 				(base.getFile() + INSTALL_INFO_DIR + COMPSDIR).replace('/', File.separatorChar);

 			dir = new File(path);

 			list = dir.list(filter);

+			if (DEBUG) debug("Detecting component changes");

 			VersionedIdentifier[] compDelta;

 			if (list == null)

 				compDelta = new VersionedIdentifier[0];

-			else

+			else {

+				profile.synchComponents(list);

 				compDelta = profile.computeDelta(list, profile.comps, profile.compsInact);

+			}

 

 			// complete "installation" of new configurations and components	

 			if (configDelta.length > 0 || compDelta.length > 0) 

@@ -873,11 +931,14 @@
 				(base.getFile() + PLUGINSDIR).replace('/', File.separatorChar);

 			dir = new File(path);

 			list = dir.list(filter);

+			if (DEBUG) debug("Detecting plugin changes");

 			VersionedIdentifier[] pluginDelta;

 			if (list == null)

 				pluginDelta = new VersionedIdentifier[0];

-			else

+			else {

+				profile.synchPlugins(list);

 				pluginDelta = profile.computeDelta(list, profile.plugins, profile.pluginsInact);

+			}

 			for (int i=0; i<pluginDelta.length; i++)

 				profile.pluginsUnmgd.add(pluginDelta[i]);

 				

@@ -886,11 +947,14 @@
 				(base.getFile() + FRAGMENTSDIR).replace('/', File.separatorChar);

 			dir = new File(path);

 			list = dir.list(filter);

+			if (DEBUG) debug("Detecting fragment changes");

 			VersionedIdentifier[] fragmentDelta;

 			if (list == null)

 				fragmentDelta = new VersionedIdentifier[0];

-			else

+			else {

+				profile.synchFragments(list);

 				fragmentDelta = profile.computeDelta(list, profile.fragments, profile.fragmentsInact);

+			}

 			for (int i=0; i<fragmentDelta.length; i++)

 				profile.fragmentsUnmgd.add(fragmentDelta[i]);

 

@@ -953,22 +1017,71 @@
 		props.put(name+"."+i, prop);

 	}

 }

+private synchronized void synch(List dirlist, List infoList) {

+	// remove state entries that do not exist in file system

+	List list = new ArrayList(infoList); // clone list

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

+		VersionedIdentifier vid = (VersionedIdentifier) list.get(i);

+		if (!dirlist.contains(vid)) {

+			infoList.remove(vid);

+			if (DEBUG)

+				debug("   missing "+vid.toString());

+		}

+	}

+}

+

+private void synchComponents(String[] dirlist) {

+	List list = Arrays.asList(dirlist);

+	synch(list, configs);

+	synch(list, configsInact);

+}

+

+private void synchConfigurations(String[] dirlist) {	

+	List list = Arrays.asList(dirlist);

+	synch(list, comps);

+	synch(list, compsInact);

+	synch(list, compsDang);

+}

+

+private void synchFragments(String[] dirlist) {

+	List list = Arrays.asList(dirlist);

+	synch(list, plugins);

+	synch(list, pluginsInact);

+	synch(list, pluginsUnmgd);

+}

+

+private void synchPlugins(String[] dirlist) {

+	List list = Arrays.asList(dirlist);

+	synch(list, fragments);

+	synch(list, fragmentsInact);

+	synch(list, fragmentsUnmgd);

+}

 

 public static void todo() {

 /*

-	* platform:/base/ /plugin/ /componennt/ /configuration/ /resource/

-	* computeAdditions, computeDeletions instead of computeDelta, cleanup lists wrt file state

-	* cleanup dangling list on startup as well (see item 2), on uninstall

-	* use ArrayList instead of Vector

-	* deletion/ uninstall processing .... what should be the UI/ trigger?

+	* uninstallMarkForDeletion is getting dups, flush() not activated

+	*

+	* computeAdditions, computeDeletions instead of computeDelta, cleanup all lists wrt file state

+	*    (active, inactive, unmanaged, dangling, pendingdelete, ...)

+	*

+	* setInactive implementation (failed install after discovery)

+	*

+	* flush() ... trigger cleanup sweep (old histories, unused directories). Called after any change in UI

+	*

 	* detecting bad failure and recovering from it

+	*

 	* need to hook in error recovery that recomputes all from scratch (when I can't trust state)

 	* ... but how do we know which plugins comps should be inactive vs. be reinstalled?

-	* do own writing with EOF marker to detect bad state files

-	* install.properties ... write .bak, delete old, rename .bak, write state

+	*

 	* batch uninstall

-

-	* UI: to call flush() after every batch of updates (eg. on exit from preference page)

+	*

+	* "reliability" sweep ... handling hard errors at critical points in processing

+	*    - harden state on flush (but only create new history on shutdown)

+	*    - write pending deletes before deleting

+	*    - startup - cleanup lists wrt. file state (computeAdd/ computeMissing)

+	*    - startup - bad config.properties

+	*    - backup for install.properties (needs to be manually renamed)

+	*    - startup - no state (recompute from scratch)

 */

 }

 

@@ -980,101 +1093,43 @@
 	History [] history = getLaunchInfoHistory();

 	if (history.length <= historyCount) return;

 

-	LaunchInfo historyInfo;

+	// poof up launch info objects

+	LaunchInfo[] historyInfo = new LaunchInfo[history.length];

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

+		if (history[i].isCurrent())

+			historyInfo[i] = LaunchInfo.getCurrent();

+		else 

+			historyInfo[i] = new LaunchInfo(history[i]);

+	}

+

+	// determine list of deletion candidates

 	Set candidateConfigs = new HashSet();

 	Set candidateComps = new HashSet();

 	Set candidatePlugins = new HashSet();

 	Set candidateFragments = new HashSet();

-	

+

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

-		historyInfo = new LaunchInfo(history[i]);

-		uninstallGetCandidates(candidateConfigs, historyInfo.configs, historyInfo.configsInact);

-		uninstallGetCandidates(candidateComps, historyInfo.comps, historyInfo.compsInact);

-		uninstallGetCandidates(candidatePlugins, historyInfo.plugins, historyInfo.pluginsInact);

-		uninstallGetCandidates(candidateFragments, historyInfo.fragments, historyInfo.fragmentsInact);

+		uninstallGetCandidates(candidateConfigs, historyInfo[i].configs, historyInfo[i].configsInact);

+		uninstallGetCandidates(candidateComps, historyInfo[i].comps, historyInfo[i].compsInact);

+		uninstallGetCandidates(candidatePlugins, historyInfo[i].plugins, historyInfo[i].pluginsInact);

+		uninstallGetCandidates(candidateFragments, historyInfo[i].fragments, historyInfo[i].fragmentsInact);

 	}

 

-	Set deleteConfigs = new HashSet();

-	Set deleteComps = new HashSet();

-	Set deletePlugins = new HashSet();

-	Set deleteFragments = new HashSet();

-	

-	for (int i=historyCount; i<history.length; i++) {

-		historyInfo = new LaunchInfo(history[i]);

-		uninstallMarkForDeletion(deleteConfigs, candidateConfigs, historyInfo.configs, historyInfo.configsInact);

-		uninstallMarkForDeletion(deleteComps, candidateComps, historyInfo.comps, historyInfo.compsInact);

-		uninstallMarkForDeletion(deletePlugins, candidatePlugins, historyInfo.plugins, historyInfo.pluginsInact);

-		uninstallMarkForDeletion(deleteFragments, candidateFragments, historyInfo.fragments, historyInfo.fragmentsInact);

-	}

+	// determine which candidates are not active in recent histories

+	List deleteConfigs = uninstallMarkForDeletion(candidateConfigs, historyInfo);

+	List deleteComps = uninstallMarkForDeletion(candidateComps, historyInfo);

+	List deletePlugins = uninstallMarkForDeletion(candidatePlugins, historyInfo);

+	List deleteFragments = uninstallMarkForDeletion(candidateFragments, historyInfo);

 

-	VersionedIdentifier[] vidConfigs = (VersionedIdentifier[])deleteConfigs.toArray();

-	VersionedIdentifier[] vidComps = (VersionedIdentifier[]) deleteComps.toArray();

-	VersionedIdentifier[] vidPlugins = (VersionedIdentifier[]) deletePlugins.toArray();

-	VersionedIdentifier[] vidFragments = (VersionedIdentifier[]) deleteFragments.toArray();

-

-	uninstall(vidConfigs, vidComps, vidPlugins, vidFragments);

-}

-/**

- * deprecated

- */

-synchronized public void uninstall(String[] configId, String[] compId, String[] pluginId, String[] fragId) {

-

-	if (baseurl==null || !isFileProtocol(baseurl)) return;

-	if (this!=LaunchInfo.getCurrent()) return;

-	

-	if (DEBUG) {

-		debug("Deleting configurations");

-		for (int i=0; i<configId.length; i++) debug("   "+configId[i]);

-		debug("Deleting components");

-		for (int i=0; i<compId.length; i++) debug("   "+compId[i]);

-		debug("Deleting plugins");

-		for (int i=0; i<pluginId.length; i++) debug("   "+pluginId[i]);

-		debug("Deleting fragments");

-		for (int i=0; i<fragId.length; i++) debug("   "+fragId[i]);

-	}

-}

-

-synchronized public void uninstall(VersionedIdentifier[] configId, VersionedIdentifier[] compId, VersionedIdentifier[] pluginId, VersionedIdentifier[] fragId) {

-

-	if (installurl==null || !isFileProtocol(installurl)) return;

-	if (this!=LaunchInfo.getCurrent()) return;

-	

-	if (DEBUG) {

-		debug("Deleting configurations");

-		for (int i=0; i<configId.length; i++) debug("   "+configId[i].toString());

-		debug("Deleting components");

-		for (int i=0; i<compId.length; i++) debug("   "+compId[i].toString());

-		debug("Deleting plugins");

-		for (int i=0; i<pluginId.length; i++) debug("   "+pluginId[i].toString());

-		debug("Deleting fragments");

-		for (int i=0; i<fragId.length; i++) debug("   "+fragId[i].toString());

-	}

-	

-	String root = installurl.getFile().replace('/',File.separatorChar);

-	File dir;

-	

-	// uninstall configurations

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

-		dir = new File(root+INSTALL_INFO_DIR+CONFIGSDIR+configId[i].toString()+File.separator);

-		uninstall(dir);

-	}

-

-	// unistall components

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

-		dir = new File(root+INSTALL_INFO_DIR+COMPSDIR+compId[i].toString()+File.separator);

-		uninstall(dir);

-	}

-

-	// uninstall plugins

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

-		dir = new File(root+PLUGINSDIR+pluginId[i].toString()+File.separator);

-		uninstall(dir);

-	}

-

-	// uninstall fragments

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

-		dir = new File(root+FRAGMENTSDIR+fragId[i].toString()+File.separator);

-		uninstall(dir);

+	// uninstall files

+	uninstall(deleteConfigs, deleteComps, deletePlugins, deleteFragments);

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

+		if (history[i].isCurrent()) continue; // just in case

+		if (DEBUG) debug("Removing state "+history[i].getLaunchInfoDate().toString());

+		File info = new File(history[i].getLaunchInfoURL().getFile().replace('/',File.separatorChar));

+		boolean ok = info.delete();

+		if (DEBUG)

+			debug((ok?"Unistalled ":"Unable to uninstall ")+info.toString());

 	}

 }

 

@@ -1093,20 +1148,63 @@
 		debug((ok?"Unistalled ":"Unable to uninstall ")+f.toString());

 }

 

+synchronized private void uninstall(List configId, List compId, List pluginId, List fragId) {

+

+	if (installurl==null || !isFileProtocol(installurl)) return;

+	if (this!=LaunchInfo.getCurrent()) return;

+	

+	String root = installurl.getFile().replace('/',File.separatorChar);

+	File dir;

+	

+	// uninstall configurations

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

+		if (DEBUG) debug("Removing configuration "+configId.get(i).toString());

+		dir = new File(root+INSTALL_INFO_DIR+CONFIGSDIR+configId.get(i).toString()+File.separator);

+		uninstall(dir);

+	}

+

+	// unistall components

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

+		if (DEBUG) debug("Removing component "+compId.get(i).toString());

+		dir = new File(root+INSTALL_INFO_DIR+COMPSDIR+compId.get(i).toString()+File.separator);

+		uninstall(dir);

+	}

+

+	// uninstall plugins

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

+		if (DEBUG) debug("Removing plugin "+pluginId.get(i).toString());

+		dir = new File(root+PLUGINSDIR+pluginId.get(i).toString()+File.separator);

+		uninstall(dir);

+	}

+

+	// uninstall fragments

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

+		if (DEBUG) debug("Removing fragment "+fragId.get(i).toString());

+		dir = new File(root+FRAGMENTSDIR+fragId.get(i).toString()+File.separator);

+		uninstall(dir);

+	}

+}

+

 private void uninstallGetCandidates(Set candidates, List active, List inactive) {

 	candidates.addAll(active);

 	candidates.addAll(inactive);

 }

 

-private void uninstallMarkForDeletion(Set delete, Set candidates, List active, List inactive) {

-	VersionedIdentifier vid;

-	Iterator all = candidates.iterator();

-	while(all.hasNext()) {

-		vid = (VersionedIdentifier) all.next();

-		if (!active.contains(vid) && !inactive.contains(vid)) {

-			delete.add(vid);

+private List uninstallMarkForDeletion(Set candidates, LaunchInfo[] history) {

+	List delete = new ArrayList();

+	Iterator list = candidates.iterator();

+	while(list.hasNext()) {

+		boolean found = false;

+		VersionedIdentifier vid = (VersionedIdentifier) list.next();

+		for (int i=historyCount; i<history.length; i++) {

+			if (history[i].configs.contains(vid)) {

+				found = true;

+				break;

+			}

 		}

+		if (!found) delete.add(vid); // needs to be a set

 	}

+	return delete;

 }

 

 synchronized private void write(String id, PrintWriter w) throws IOException {

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformClassLoader.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformClassLoader.java
index 949b13a..b6c85a1 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformClassLoader.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformClassLoader.java
@@ -18,7 +18,7 @@
  * given classpath, filters and parent.

  */

 public PlatformClassLoader(URL[] searchPath, URLContentFilter[] filters, ClassLoader parent, URL base) {

-	super(searchPath, filters, parent);

+	super(searchPath, filters, null, null, parent);

 	this.base = base;

 	if (singleton == null)

 		singleton = this;

@@ -30,10 +30,15 @@
 /**

  * Finds and loads the class with the specified name from the URL search

  * path. Any URLs referring to JAR files are loaded and opened as needed

- * until the class is found. Only our own URL search path is used.

- *

+ * until the class is found. Only our own URL search path and that of our parent

+ * is used.  This method consults this loader's parent first but only if <code>checkParents</code>

+ * is <code>true</code>.  Following that, this loader's own search path is checked. 

+ * <code>null</code> is returned if the class cannot be found.

+ 

  * @param name the name of the class

+ * @param resolve whether to resolve any loaded class

  * @param requestor class loader originating the request

+ * @param checkParents whether to check the parent loader

  * @return the resulting class

  */

 protected Class findClassParentsSelf(final String name, boolean resolve, DelegatingURLClassLoader requestor, boolean checkParents) {

@@ -44,7 +49,7 @@
 		// no point in looking in self as the class was already in the cache.

 		result = findLoadedClass(name);

 		if (result != null) {

-			result = checkVisibility(result, requestor, true);

+			result = checkClassVisibility(result, requestor, true);

 			if (result != null || !checkParents)

 				return result;

 		}

@@ -57,7 +62,7 @@
 		}

 		try {

 			result = super.findClass(name);

-			return checkVisibility(result, requestor, false);

+			return checkClassVisibility(result, requestor, false);

 		} catch (ClassNotFoundException e) {

 			return null;

 		}

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLPlatformConnection.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLBaseConnection.java
similarity index 60%
rename from bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLPlatformConnection.java
rename to bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLBaseConnection.java
index 9c1ee6b..bf08b1e 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLPlatformConnection.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLBaseConnection.java
@@ -7,22 +7,22 @@
  */

 

 /**

- * Eclipse URL support

- * eclipse:/platform/	maps to platform installation location

+ * Platform URL support

+ * platform:/base/	maps to platform installation location

  */

 

 import java.net.*;

 import java.io.*;

 import java.util.*;

  

-public class EclipseURLPlatformConnection extends EclipseURLConnection {

+public class PlatformURLBaseConnection extends PlatformURLConnection {

 

 	// platform/ protocol

-	public static final String PLATFORM = "platform";

-	public static final String PLATFORM_URL_STRING = EclipseURLHandler.ECLIPSE+EclipseURLHandler.PROTOCOL_SEPARATOR+"/"+PLATFORM+"/";

+	public static final String PLATFORM = "base";

+	public static final String PLATFORM_URL_STRING = PlatformURLHandler.PROTOCOL+PlatformURLHandler.PROTOCOL_SEPARATOR+"/"+PLATFORM+"/";

 	

 	private static URL installURL;

-public EclipseURLPlatformConnection(URL url) {

+public PlatformURLBaseConnection(URL url) {

 	super(url);

 }

 protected boolean allowCaching() {

@@ -39,9 +39,9 @@
 }

 public static void startup(URL url) {

 	

-	// register connection type for eclipse:/platform/ handling

+	// register connection type for platform:/base/ handling

 	if (installURL!=null) return;

 	installURL = url;

-	EclipseURLHandler.register(PLATFORM, EclipseURLPlatformConnection.class);

+	PlatformURLHandler.register(PLATFORM, PlatformURLBaseConnection.class);

 }

 }

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLComponentConnection.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLComponentConnection.java
similarity index 69%
rename from bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLComponentConnection.java
rename to bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLComponentConnection.java
index cf0411d..1df5ea1 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLComponentConnection.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLComponentConnection.java
@@ -7,23 +7,23 @@
  */

 

 /**

- * Eclipse URL support

- * eclipse:/component/<identifeir>/	maps to component installation location

+ * Platform URL support

+ * platform:/component/<identifeir>/	maps to component installation location

  */

 

 import java.net.*;

 import java.io.*;

 import java.util.*;

  

-public class EclipseURLComponentConnection extends EclipseURLConnection {

+public class PlatformURLComponentConnection extends PlatformURLConnection {

 

 	// component/ protocol

 	public static final String COMP = "component";

-	public static final String COMP_URL_STRING = EclipseURLHandler.ECLIPSE+EclipseURLHandler.PROTOCOL_SEPARATOR+"/"+COMP+"/";

+	public static final String COMP_URL_STRING = PlatformURLHandler.PROTOCOL+PlatformURLHandler.PROTOCOL_SEPARATOR+"/"+COMP+"/";

 	

 	private static final String COMP_INSTALL = "install/components/";

 	private static URL installURL;

-public EclipseURLComponentConnection(URL url) {

+public PlatformURLComponentConnection(URL url) {

 	super(url);

 }

 protected boolean allowCaching() {

@@ -43,9 +43,9 @@
 }

 public static void startup(URL url) {

 	

-	// register connection type for eclipse:/configuration/ handling

+	// register connection type for platform:/configuration/ handling

 	if (installURL!=null) return;

 	installURL = url;

-	EclipseURLHandler.register(COMP, EclipseURLComponentConnection.class);

+	PlatformURLHandler.register(COMP, PlatformURLComponentConnection.class);

 }

 }

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLConfigurationConnection.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLConfigurationConnection.java
similarity index 68%
rename from bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLConfigurationConnection.java
rename to bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLConfigurationConnection.java
index de060ff..4b0f6e5 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLConfigurationConnection.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLConfigurationConnection.java
@@ -7,24 +7,24 @@
  */

 

 /**

- * Eclipse URL support

- * eclipse:/configuration/<identifeir>/	maps to configuration installation location

+ * Platform URL support

+ * platform:/configuration/<identifeir>/	maps to configuration installation location

  */

 

 import java.net.*;

 import java.io.*;

 import java.util.*;

  

-public class EclipseURLConfigurationConnection extends EclipseURLConnection {

+public class PlatformURLConfigurationConnection extends PlatformURLConnection {

 

 	// configuration/ protocol

 	public static final String CONFIG = "configuration";

-	public static final String CONFIG_URL_STRING = EclipseURLHandler.ECLIPSE+EclipseURLHandler.PROTOCOL_SEPARATOR+"/"+CONFIG+"/";

+	public static final String CONFIG_URL_STRING = PlatformURLHandler.PROTOCOL+PlatformURLHandler.PROTOCOL_SEPARATOR+"/"+CONFIG+"/";

 

 		

 	private static final String CONFIG_INSTALL = "install/configurations/";

 	private static URL installURL;

-public EclipseURLConfigurationConnection(URL url) {

+public PlatformURLConfigurationConnection(URL url) {

 	super(url);

 }

 protected boolean allowCaching() {

@@ -44,9 +44,9 @@
 }

 public static void startup(URL url) {

 	

-	// register connection type for eclipse:/configuration/ handling

+	// register connection type for platform:/configuration/ handling

 	if (installURL!=null) return;

 	installURL = url;

-	EclipseURLHandler.register(CONFIG, EclipseURLConfigurationConnection.class);

+	PlatformURLHandler.register(CONFIG, PlatformURLConfigurationConnection.class);

 }

 }

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLConnection.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLConnection.java
similarity index 84%
rename from bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLConnection.java
rename to bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLConnection.java
index ab73910..e553e23 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLConnection.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLConnection.java
@@ -7,20 +7,20 @@
  */

 

 /**

- * Eclipse URL support

+ * Platform URL support

  */

 

 import java.net.*;

 import java.io.*;

 import java.util.*;

  

-public abstract class EclipseURLConnection extends URLConnection {

+public abstract class PlatformURLConnection extends URLConnection {

 

 	// URL access

 	private boolean isInCache = false;

 	private boolean isJar = false;

 	

-//	protected URL url;				// declared in super (eclipse: URL)

+//	protected URL url;				// declared in super (platform: URL)

 	private URL resolvedURL = null;	// resolved file URL (eg. http: URL)

 	private URL cachedURL = null;	// file URL in cache (file: URL)

 

@@ -40,14 +40,14 @@
 	private static final String CACHE_INDEX_PROP = "index";

 	private static final String CACHE_PREFIX_PROP = "prefix";

 	private static final String CACHE_INDEX = ".index.properties";

-	private static final String CACHE_DIR = EclipseURLHandler.ECLIPSE + File.separator;

+	private static final String CACHE_DIR = PlatformURLHandler.PROTOCOL + File.separator;

 

 	// debug tracing

 	public static boolean DEBUG = false;

 	public static boolean DEBUG_CONNECT = true;

 	public static boolean DEBUG_CACHE_LOOKUP = true;

 	public static boolean DEBUG_CACHE_COPY = true;

-protected EclipseURLConnection(URL url) {

+protected PlatformURLConnection(URL url) {

 	super(url);

 }

 protected boolean allowCaching() {

@@ -84,7 +84,7 @@
 	String key;

 	if (isJar) {

 		tmp = url.getFile();

-		ix = tmp.lastIndexOf(EclipseURLHandler.JAR_SEPARATOR);

+		ix = tmp.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);

 		if (ix!=-1) tmp = tmp.substring(0,ix);

 		key = tmp;

 	}

@@ -94,7 +94,7 @@
 	URL src;

 	if (isJar) {

 		tmp = resolvedURL.getFile();

-		ix = tmp.lastIndexOf(EclipseURLHandler.JAR_SEPARATOR);

+		ix = tmp.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);

 		if (ix!=-1) tmp = tmp.substring(0,ix);

 		src = new URL(tmp);

 	}

@@ -105,9 +105,9 @@
 	String tgt;

 	if (isJar) {

 		tmp = cachedURL.getFile();

-		ix = tmp.indexOf(EclipseURLHandler.PROTOCOL_SEPARATOR);

+		ix = tmp.indexOf(PlatformURLHandler.PROTOCOL_SEPARATOR);

 		if (ix!=-1) tmp = tmp.substring(ix+1);

-		ix = tmp.lastIndexOf(EclipseURLHandler.JAR_SEPARATOR);

+		ix = tmp.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);

 		if (ix!=-1) tmp = tmp.substring(0,ix);

 		tgt = tmp;

 	}

@@ -179,7 +179,7 @@
 	connect(true);	// connect and force caching if necessary

 	URL u = connection.getURL();

 	String up = u.getProtocol();

-	if (!up.equals(EclipseURLHandler.FILE) && !up.equals(EclipseURLHandler.JAR) && !up.equals(EclipseURLHandler.VA)) throw new IOException("Unable to access URL as local "+url.toString());

+	if (!up.equals(PlatformURLHandler.FILE) && !up.equals(PlatformURLHandler.JAR) && !up.equals(PlatformURLHandler.VA)) throw new IOException("Unable to access URL as local "+url.toString());

 	return u;

 }

 private URL getURLInCache() throws IOException {

@@ -195,9 +195,9 @@
 	String jarEntry = null;

 	if (isJar) {

 		file = url.getFile();

-		int ix = file.lastIndexOf(EclipseURLHandler.JAR_SEPARATOR);

+		int ix = file.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);

 		if (ix!=-1) {

-			jarEntry = file.substring(ix+EclipseURLHandler.JAR_SEPARATOR.length());

+			jarEntry = file.substring(ix+PlatformURLHandler.JAR_SEPARATOR.length());

 			file = file.substring(0,ix);

 		}

 	}

@@ -223,13 +223,13 @@
 		if (isJar) {

 			if (DEBUG && DEBUG_CACHE_LOOKUP)

 				debug("Jar located in cache as "+tmp);

-			tmp = EclipseURLHandler.FILE + EclipseURLHandler.PROTOCOL_SEPARATOR + tmp + EclipseURLHandler.JAR_SEPARATOR + jarEntry;

-			cachedURL = new URL(EclipseURLHandler.JAR,null,-1,tmp);

+			tmp = PlatformURLHandler.FILE + PlatformURLHandler.PROTOCOL_SEPARATOR + tmp + PlatformURLHandler.JAR_SEPARATOR + jarEntry;

+			cachedURL = new URL(PlatformURLHandler.JAR,null,-1,tmp);

 		}

 		else {

 			if (DEBUG && DEBUG_CACHE_LOOKUP)

 				debug("Located in cache as "+tmp);

-			cachedURL = new URL(EclipseURLHandler.FILE,null,-1,tmp);

+			cachedURL = new URL(PlatformURLHandler.FILE,null,-1,tmp);

 		}

 		isInCache = true;

 	}

@@ -240,10 +240,10 @@
 		tmp = cacheLocation + filePrefix + Long.toString((new java.util.Date()).getTime(),36) + "_" + tmp;

 		tmp = tmp.replace(File.separatorChar,'/');

 		if (isJar) {

-			tmp = EclipseURLHandler.FILE + EclipseURLHandler.PROTOCOL_SEPARATOR + tmp + EclipseURLHandler.JAR_SEPARATOR + jarEntry;

-			cachedURL = new URL(EclipseURLHandler.JAR,null,-1,tmp);

+			tmp = PlatformURLHandler.FILE + PlatformURLHandler.PROTOCOL_SEPARATOR + tmp + PlatformURLHandler.JAR_SEPARATOR + jarEntry;

+			cachedURL = new URL(PlatformURLHandler.JAR,null,-1,tmp);

 		}

-		else cachedURL = new URL(EclipseURLHandler.FILE,null,-1,tmp);

+		else cachedURL = new URL(PlatformURLHandler.FILE,null,-1,tmp);

 		copyToCache();

 	}

 	

@@ -259,11 +259,11 @@
 }

 void setResolvedURL(URL url) throws IOException {

 	if (resolvedURL==null) {

-		int ix = url.getFile().lastIndexOf(EclipseURLHandler.JAR_SEPARATOR);

+		int ix = url.getFile().lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);

 		isJar = -1 != ix;

 		// Resolved URLs containing !/ separator are assumed to be jar URLs.

 		// If the resolved protocol is not jar, new jar URL is created.

-		if (isJar && !url.getProtocol().equals(EclipseURLHandler.JAR)) url = new URL(EclipseURLHandler.JAR,null,-1,url.toExternalForm());

+		if (isJar && !url.getProtocol().equals(PlatformURLHandler.JAR)) url = new URL(PlatformURLHandler.JAR,null,-1,url.toExternalForm());

 		resolvedURL=url;

 	}

 }

@@ -272,8 +272,8 @@
 	// don't cache files that are known to be local

 	String rp = resolvedURL.getProtocol();

 	String rf = resolvedURL.getFile();

-	if (rp.equals(EclipseURLHandler.FILE) || rp.equals(EclipseURLHandler.VA)) return false;

-	if (rp.equals(EclipseURLHandler.JAR) && (rf.startsWith(EclipseURLHandler.FILE) || rf.startsWith(EclipseURLHandler.VA) )) return false;

+	if (rp.equals(PlatformURLHandler.FILE) || rp.equals(PlatformURLHandler.VA)) return false;

+	if (rp.equals(PlatformURLHandler.JAR) && (rf.startsWith(PlatformURLHandler.FILE) || rf.startsWith(PlatformURLHandler.VA) )) return false;

 

 	// for other files force caching if local connection was requested

 	if (asLocal) return true;

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLHandler.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLHandler.java
similarity index 75%
rename from bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLHandler.java
rename to bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLHandler.java
index b5e6139..d436f08 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLHandler.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLHandler.java
@@ -12,20 +12,20 @@
 import java.lang.reflect.Constructor;

 

  /**

- * URL handler for the "eclipse:" protocol

+ * URL handler for the "platform" protocol

  */

-public class EclipseURLHandler extends URLStreamHandler {

+public class PlatformURLHandler extends URLStreamHandler {

 

 	private static Hashtable connectionType = new Hashtable();

 

 	// URL protocol designations

-	public static final String ECLIPSE = "eclipse";

+	public static final String PROTOCOL = "platform";

 	public static final String FILE = "file";

 	public static final String JAR = "jar";

 	public static final String VA = "valoader";

 	public static final String JAR_SEPARATOR = "!/";

 	public static final String PROTOCOL_SEPARATOR = ":";

-protected EclipseURLHandler() {

+protected PlatformURLHandler() {

 	super();

 }

 protected URLConnection openConnection(URL url) throws IOException {

@@ -33,15 +33,15 @@
 	String spec = url.getFile().trim();

 	if (spec.startsWith("/")) spec = spec.substring(1);

 	int ix = spec.indexOf("/");

-	if (ix==-1) throw new MalformedURLException("Invalid \""+ECLIPSE+":\" URL "+url.toString());

+	if (ix==-1) throw new MalformedURLException("Invalid \""+PROTOCOL+":\" URL "+url.toString());

 

 	String type = spec.substring(0,ix);

 	Constructor construct = (Constructor) connectionType.get(type);

-	if (construct==null) throw new MalformedURLException("Unsupported \""+ECLIPSE+":\" protocol variation "+url.toString());

+	if (construct==null) throw new MalformedURLException("Unsupported \""+PROTOCOL+":\" protocol variation "+url.toString());

 

-	EclipseURLConnection c = null;

+	PlatformURLConnection c = null;

 	try {

-		c = (EclipseURLConnection) construct.newInstance(new Object[] { url });

+		c = (PlatformURLConnection) construct.newInstance(new Object[] { url });

 	}

 	catch(Exception e) { throw new IOException("Unable to create connection "+url.toString()+"\n"+e); }

 	

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLHandlerFactory.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLHandlerFactory.java
similarity index 65%
rename from bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLHandlerFactory.java
rename to bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLHandlerFactory.java
index d6b3b95..07f128b 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/EclipseURLHandlerFactory.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLHandlerFactory.java
@@ -9,14 +9,14 @@
 import java.net.*;

 import java.util.*;

  

-public class EclipseURLHandlerFactory implements URLStreamHandlerFactory {

+public class PlatformURLHandlerFactory implements URLStreamHandlerFactory {

 

 	private static Hashtable handlers = new Hashtable();

-public EclipseURLHandlerFactory() {

+public PlatformURLHandlerFactory() {

 	super();

 

 	// register eclipse handler

-	handlers.put(EclipseURLHandler.ECLIPSE, new EclipseURLHandler());

+	handlers.put(PlatformURLHandler.PROTOCOL, new PlatformURLHandler());

 }

 public URLStreamHandler createURLStreamHandler(String protocol) {

 

@@ -36,23 +36,23 @@
 	return handler;

 }

 public static void register(String protocol, URLStreamHandlerFactory factory) {

-	if (protocol.equals(EclipseURLHandler.ECLIPSE)) return;	// just in case ...

+	if (protocol.equals(PlatformURLHandler.PROTOCOL)) return;	// just in case ...

 	handlers.put(protocol,factory);

 }

 public static void shutdown() {	

 	

-	EclipseURLHandlerFactoryProxy p = EclipseURLHandlerFactoryProxy.getFactoryProxy();

+	PlatformURLHandlerFactoryProxy p = PlatformURLHandlerFactoryProxy.getFactoryProxy();

 	if (p!=null) p.setFactory(null);

-	EclipseURLConnection.shutdown();

+	PlatformURLConnection.shutdown();

 }

 public static void startup(String location) {

 

-	EclipseURLHandlerFactoryProxy p = EclipseURLHandlerFactoryProxy.getFactoryProxy();

+	PlatformURLHandlerFactoryProxy p = PlatformURLHandlerFactoryProxy.getFactoryProxy();

 	if (p==null) {

-		p = new EclipseURLHandlerFactoryProxy();	

+		p = new PlatformURLHandlerFactoryProxy();	

 		URL.setURLStreamHandlerFactory(p);

 	}

-	p.setFactory(new EclipseURLHandlerFactory());

-	EclipseURLConnection.startup(location);

+	p.setFactory(new PlatformURLHandlerFactory());

+	PlatformURLConnection.startup(location);

 }

 }

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLHandlerFactoryProxy.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLHandlerFactoryProxy.java
new file mode 100644
index 0000000..8b3e429
--- /dev/null
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/PlatformURLHandlerFactoryProxy.java
@@ -0,0 +1,33 @@
+package org.eclipse.core.internal.boot;

+

+/*

+ * Licensed Materials - Property of IBM,

+ * WebSphere Studio Workbench

+ * (c) Copyright IBM Corp 2000

+ */

+

+import java.net.*;

+ 

+public class PlatformURLHandlerFactoryProxy implements URLStreamHandlerFactory {

+

+	private static PlatformURLHandlerFactoryProxy p = null;	// singleton - set into URL as factory

+	private PlatformURLHandlerFactory f = null; // current actual factory

+PlatformURLHandlerFactoryProxy() {

+	super();

+	if (p==null) p = this;

+}

+public URLStreamHandler createURLStreamHandler(String protocol) {

+

+	if (f==null) return null;

+	else return f.createURLStreamHandler(protocol);

+}

+PlatformURLHandlerFactory getFactory() {

+	return f;

+}

+static PlatformURLHandlerFactoryProxy getFactoryProxy() {

+	return p;

+}

+void setFactory(PlatformURLHandlerFactory factory) {

+	f = factory;

+}

+}

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/ResourceEnumeration.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/ResourceEnumeration.java
index 8c27977..e9fdc35 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/ResourceEnumeration.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/ResourceEnumeration.java
@@ -24,44 +24,50 @@
 	this.name = name;

 	if (e == null)

 		e = new Enumeration() {

-			public boolean hasMoreElements() { return false; }

-			public Object nextElement() { return null; }

-		};

+		public boolean hasMoreElements() {

+			return false;

+		}

+		public Object nextElement() {

+			return null;

+		}

+	};

 	enums.add(e);

 	this.current = current;

 	this.requestor = requestor;

 }

 public void add(Enumeration e) {

-	if (e==null) return;

+	if (e == null)

+		return;

 	enums.add(e);

 }

 public boolean hasMoreElements() {

-	if (nextElement!=null) return true;

-	

+	if (nextElement != null)

+		return true;

 	nextElement = nextVisibleElement();

-	if (nextElement!=null) return true;

-	else return false;

+	return nextElement != null;

 }

 public Object nextElement() {

-	if (nextElement!=null) {

+	if (nextElement != null) {

 		Object result = nextElement;

 		nextElement = null;

 		return result;

-	}

-	else return nextVisibleElement();

+	} else

+		return nextVisibleElement();

 }

 private Object nextVisibleElement() {

 	Enumeration e;

 	Object element = null;

-	while(element==null && ix<enums.size()) {

-		e = (Enumeration)enums.elementAt(ix);

-		while(element==null && e.hasMoreElements()) {

+	while (element == null && ix < enums.size()) {

+		e = (Enumeration) enums.elementAt(ix);

+		while (element == null && e.hasMoreElements()) {

 			element = e.nextElement();

-			if (ix==0) {

-				if (!current.isResourceVisible(name,(URL)element,requestor)) element = null;

-			}	

+			if (ix == 0) {

+				if (!current.isResourceVisible(name, (URL) element, requestor))

+					element = null;

+			}

 		}

-		if (element==null) ix++;

+		if (element == null)

+			ix++;

 	}

 	return element;

 }

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/ResourceLoader.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/ResourceLoader.java
new file mode 100644
index 0000000..d65357d
--- /dev/null
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/ResourceLoader.java
@@ -0,0 +1,28 @@
+package org.eclipse.core.internal.boot;

+

+/*

+ * Licensed Materials - Property of IBM,

+ * WebSphere Studio Workbench

+ * (c) Copyright IBM Corp 2000

+ */

+import java.net.*;

+

+public class ResourceLoader extends URLClassLoader {

+public ResourceLoader(URL[] resourcePath) {

+	super(resourcePath, null);

+}

+/**

+ * Looks for a given class.   Resource loaders can never find classes and

+ * so always throw <code>ClassNotFoundException</code>.

+ */

+protected Class findClass(final String name) throws ClassNotFoundException {

+	throw new ClassNotFoundException(name);

+}

+/**

+ * Looks for a given class.   Resource loaders can never find classes and

+ * so always throw <code>ClassNotFoundException</code>.

+ */

+protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {

+	throw new ClassNotFoundException();

+}

+}

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/BootUpdateManager.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/BootUpdateManager.java
index 8143309..662671e 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/BootUpdateManager.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/BootUpdateManager.java
@@ -90,7 +90,7 @@
 

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

 

-			IComponentDescriptor componentDescriptor = registryInstalled.getComponentDescriptor(vidComponents[i].getIdentifier(), vidConfigurations[i].getVersion());

+			IComponentDescriptor componentDescriptor = registryInstalled.getComponentDescriptor(vidComponents[i].getIdentifier(), vidComponents[i].getVersion());

 

 			// Validate existence

 			//-------------------

@@ -224,9 +224,9 @@
  */

 private static void uninstallComponents(Vector vectorComponents, IUMRegistry registry, LaunchInfo launchInfo) {

 

-	if( vectorComponents == null || vectorComponents.size() == 0 )

+	if (vectorComponents == null || vectorComponents.size() == 0)

 		return;

-		

+

 	Vector vectorComponentsRemoving = new Vector();

 	Vector vectorPluginsRemoving = new Vector();

 	Vector vectorFragmentsRemoving = new Vector();

@@ -269,36 +269,36 @@
 

 		// Create a string array of component identifiers

 		//-----------------------------------------------

-		String[] straComponents = new String[vectorComponentsRemoving.size()];

+		LaunchInfo.VersionedIdentifier[] vidaComponents = new LaunchInfo.VersionedIdentifier[vectorComponentsRemoving.size()];

 

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

 			componentInstalled = (IComponentDescriptor) vectorComponentsRemoving.elementAt(i);

-			straComponents[i] = componentInstalled.getUniqueIdentifier() + "_" + componentInstalled.getVersionStr();

+			vidaComponents[i] = new LaunchInfo.VersionedIdentifier(componentInstalled.getUniqueIdentifier(), componentInstalled.getVersionStr());

 		}

 

 		// Create a string array of plugin identifiers

 		//--------------------------------------------

-		String[] straPlugins = new String[vectorPluginsRemoving.size()];

+		LaunchInfo.VersionedIdentifier[] vidaPlugins = new LaunchInfo.VersionedIdentifier[vectorPluginsRemoving.size()];

 		IPluginEntryDescriptor pluginInstalled = null;

-		

+

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

 			pluginInstalled = (IPluginEntryDescriptor) vectorPluginsRemoving.elementAt(i);

-			straPlugins[i] = pluginInstalled.getUniqueIdentifier() + "_" + pluginInstalled.getVersionStr();

+			vidaPlugins[i] = new LaunchInfo.VersionedIdentifier(pluginInstalled.getUniqueIdentifier(), pluginInstalled.getVersionStr());

 		}

 

 		// Create a string array of fragment identifiers

 		//----------------------------------------------

-		String[] straFragments = new String[vectorFragmentsRemoving.size()];

+		LaunchInfo.VersionedIdentifier[] vidaFragments = new LaunchInfo.VersionedIdentifier[vectorFragmentsRemoving.size()];

 		IFragmentEntryDescriptor fragmentInstalled = null;

-		

+

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

 			fragmentInstalled = (IFragmentEntryDescriptor) vectorFragmentsRemoving.elementAt(i);

-			straFragments[i] = fragmentInstalled.getUniqueIdentifier() + "_" + fragmentInstalled.getVersionStr();

+			vidaFragments[i] = new LaunchInfo.VersionedIdentifier(fragmentInstalled.getUniqueIdentifier(), fragmentInstalled.getVersionStr());

 		}

 

 		// Remove the components, plugins, and fragments

 		//----------------------------------------------

-		launchInfo.uninstall(null, straComponents, straPlugins, straFragments);

+		launchInfo.setInactive(null, vidaComponents, vidaPlugins, vidaFragments);

 	}

 

 	return;

@@ -306,10 +306,10 @@
 /**

  */

 private static void uninstallProducts(Vector vectorProducts, IUMRegistry registry, LaunchInfo launchInfo) {

-	

-	if( vectorProducts == null || vectorProducts.size() == 0 )

+

+	if (vectorProducts == null || vectorProducts.size() == 0)

 		return;

-		

+

 	// Determine which products may be removed

 	//----------------------------------------

 	Vector vectorProductsRemoving = new Vector();

@@ -334,19 +334,19 @@
 	// Remove the products

 	//--------------------

 	if (vectorProductsRemoving.size() > 0) {

-	    

+

 		// Create a string array of product identifiers

 		//---------------------------------------------	    

-		String[] straProducts = new String[vectorProductsRemoving.size()];

-		

+		LaunchInfo.VersionedIdentifier[] vidaProducts = new LaunchInfo.VersionedIdentifier[vectorProductsRemoving.size()];

+

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

 			productInstalled = (IProductDescriptor) vectorProductsRemoving.elementAt(i);

-			straProducts[i] = productInstalled.getUniqueIdentifier() + "_" + productInstalled.getVersionStr();

+			vidaProducts[i] = new LaunchInfo.VersionedIdentifier(productInstalled.getUniqueIdentifier(), productInstalled.getVersionStr());

 		}

 

 		// Remove the products

 		//--------------------

-		launchInfo.uninstall(straProducts, null, null, null);

+		launchInfo.setInactive(vidaProducts, null, null, null);

 	}

 

 	return;

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ComponentDescriptor.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ComponentDescriptor.java
index b44f2e7..cf2401e 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ComponentDescriptor.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ComponentDescriptor.java
@@ -6,7 +6,7 @@
  * (c) Copyright IBM Corp 2001

  *

  */

-

+import org.eclipse.core.internal.boot.LaunchInfo;

 import java.net.*;

 import java.util.*;

 

@@ -310,7 +310,8 @@
  *   <code>false</code> otherwise

  */

 public boolean isDanglingComponent() {	

-	return _isDangling();

+	LaunchInfo.VersionedIdentifier vid = new LaunchInfo.VersionedIdentifier(getUniqueIdentifier(), getVersionStr());

+	return LaunchInfo.getCurrent().isDanglingComponent(vid);

 }

 /**

  * Checks all the upgrade rules to determine if this remote component can be

@@ -357,6 +358,18 @@
 	return UpdateManagerConstants.OK_TO_INSTALL;

 }

 /**

+ * Returns whether the component described by this descriptor

+ * belongs to a product or not.   Used only by remote

+ * registries.

+ *

+ * @return <code>true</code> if this component does not belong to any 

+ * product configuration, and

+ *   <code>false</code> otherwise

+ */

+public boolean isLoose() {

+	return false;

+}

+/**

  * Returns whether the component or configuration described by this descriptor

  * can be removed or not.  The following condition is checked:

  * 

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ComponentDescriptorModel.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ComponentDescriptorModel.java
index 4d5c133..02a0df5 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ComponentDescriptorModel.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ComponentDescriptorModel.java
@@ -26,7 +26,7 @@
 

 	// properties determined at UM run time

 	private String _dirName = null;			// dir name in .install/.components/

-	private boolean _isDangling = false;	// not part of a product when downloaded

+	private boolean _isLoose = true;	

 	private Vector _containingProducts = null;

 	private Vector _pluginEntries = null;

 	private Vector _fragmentEntries = null;

@@ -136,13 +136,19 @@
 	

 	return _version;

 }

-public boolean _isDangling() {

+/*

+ * Loose and Dangling are the same idea - a component that can and has been

+ * decided to, exist on its own.  However, the term loose is used on the

+ * server side (managed by install.index), and dangling is used on the 

+ * local side (managed by LaunchInfo).  The two must not mix, and thus are named differently.

+ */

+public boolean _isLoose() {

 	

-	return _isDangling;

+	return _isLoose;

 }

-public void _isDangling(boolean dangling) {

+public void _isLoose(boolean loose) {

 	

-	_isDangling = dangling;

+	_isLoose = loose;

 }

 public void _loadManifest(URL url, UMRegistryModel parent, IUMFactory factory) {

 

@@ -341,7 +347,7 @@
 	// Register

 	//---------

 	_setUMRegistry(parent);

-	parent._addToComponentsRel(this);

+	parent._addToComponentProxysRel(this);

 

 }

 public ProductDescriptorModel _lookupContainingProducts(String key) {

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/IComponentDescriptor.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/IComponentDescriptor.java
index 05ada6b..479f242 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/IComponentDescriptor.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/IComponentDescriptor.java
@@ -121,7 +121,8 @@
 public IUMRegistry getUMRegistry() ;

 /**

  * Returns whether the component described by this descriptor

- * belongs to a product or not.

+ * belongs to a product or not.   Used only by local or current

+ * registries.

  *

  * @return <code>true</code> if this component does not belong to any 

  * product configuration, and

@@ -142,6 +143,16 @@
  */

 public int isInstallable(IComponentDescriptor comp);

 /**

+ * Returns whether the component described by this descriptor

+ * belongs to a product or not.   Used only by remote

+ * registries.

+ *

+ * @return <code>true</code> if this component does not belong to any 

+ * product configuration, and

+ *   <code>false</code> otherwise

+ */

+public boolean isLoose();

+/**

  * Returns whether the component or configuration described by this descriptor

  * can be removed or not.  The following condition is checked:

  * 

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/IUMRegistry.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/IUMRegistry.java
index c0f0d58..186bea1 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/IUMRegistry.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/IUMRegistry.java
@@ -28,14 +28,6 @@
  */

 public IComponentDescriptor[] getAllComponentDescriptors();

 /**

- * Returns all plugin entry descriptors known to this registry, entries can

- * have duplicate plugin IDs but at different versions.

- * Returns an empty array if there are no installed plugins.

- *

- * @return all plugin descriptors, including all versions, known to this registry

- */

-public IPluginEntryDescriptor[] getAllPluginEntryDescriptors();

-/**

  * Returns all product descriptors known to this registry, entries can

  * have duplicate product IDs but at different versions.

  * Returns an empty array if there are no installed products.

@@ -83,35 +75,6 @@
 

 public IComponentDescriptor[] getDanglingComponents() ;

 /**

- * Returns the plug-in entry descriptor with the given plug-in identifier

- * at the latest version number in this registry, or <code>null</code> if there is no such

- * plug-in.

- *

- * @param pluginId the unique identifier of the plug-in (e.g. <code>"com.example.myplugin"</code>).

- * @return the plug-in entry descriptor, or <code>null</code>

- */

-public IPluginEntryDescriptor getPluginEntryDescriptor(String pluginId);

-/**

- * Returns the plug-in entry descriptor with the given plug-in identifier

- * and version number in this registry, or <code>null</code> if there is no such

- * plug-in.   If a version number is not specified (null), the latest

- * version of such plug-in will be returned

- *

- * @param pluginId the unique identifier of the plug-in (e.g. <code>"com.example.myplugin"</code>).

- * @param version the version number

- * @return the plug-in entry descriptor at the specified version number, or <code>null</code>

- */

-public IPluginEntryDescriptor getPluginEntryDescriptor(String pluginId, String version);

-/**

- * Returns all plug-in entry descriptors known to this registry.

- * Due to duplicate plugin IDs, the latest version of each descriptor

- * is returned.

- * Returns an empty array if there are no installed plug-ins.

- *

- * @return the plug-in entry descriptors at their latest version known to this registry

- */

-public IPluginEntryDescriptor[] getPluginEntryDescriptors();

-/**

  * Returns the Product descriptor with the given Product identifier

  * at the latest version number in this registry, or <code>null</code> if there is no such

  * Product.

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ProductDescriptor.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ProductDescriptor.java
index 216733f..e0205e7 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ProductDescriptor.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ProductDescriptor.java
@@ -68,29 +68,53 @@
 	return s==null ? "" : s;

 }

 /**

- * Returns a list of components shipped in this product.

- * These are the entries specified in the product jar manifest file

+ * Returns a list of component entries shipped in this product.  Entries can

+ * have duplicate component IDs but at different versions.

+ * These are the entries specified in the product install manifest file

+ * Note that this does the same as getAllComponentEntries()

  *

- * @return an array of component shipped in this product

+ * @return an array of all components shipped in this product

+ * 

  */

 public IComponentEntryDescriptor[] getComponentEntries() {

-	int size = _getSizeOfComponentEntriesRel();	

+	Vector compEntry_list = _getAllComponentEntries();

+

+	int size;

+	if (compEntry_list == null) size = 0;

+	else size = compEntry_list.size();

 	if(size == 0) return new IComponentEntryDescriptor[0];

 	

-	IComponentEntryDescriptor[] list = new IComponentEntryDescriptor[size];

-	_copyComponentEntriesRelInto(list);

-	return list;

+	IComponentEntryDescriptor[] array = new IComponentEntryDescriptor[size];

+	Enumeration list = compEntry_list.elements();

+		for(int i=0; list.hasMoreElements(); i++) {

+			array[i] = (IComponentEntryDescriptor) list.nextElement();

+		}

+	

+	return array;

 	

 }

 /**

- * Returns the component entry with the given identifier shipped in

- * this product, or <code>null</code> if there is no component entry.

+ * Returns the component entry with the given identifier at the latest

+ * version number shipped in  * this product, or <code>null</code> if 

+ * there is no such component entry.

  *

- * @param id the identifier of the component (e.g. <code>""</code>).

+ * @param id the identifier of the component entry (e.g. <code>""</code>).

  * @return the component entry, or <code>null</code>

  */

 public IComponentEntryDescriptor getComponentEntry(java.lang.String id) {

-	return (IComponentEntryDescriptor)_lookupComponentEntry(id);

+	return getComponentEntry(id, null);

+}

+/**

+ * Returns the component entry with the given identifier and

+ * version number shipped in this product, or <code>null</code> if 

+ * there is no such component entry.  If a version number is not 

+ * specified (null), the latest version of such component entry will be returned

+ *

+ * @param compId the identifier of the component entry (e.g. <code>""</code>).

+ * @return the component entry at the specified version number, or <code>null</code>

+ */

+public IComponentEntryDescriptor getComponentEntry(java.lang.String compId, String version) {

+	return (IComponentEntryDescriptor)_lookupComponentEntry(compId,version);

 }

 /**

  * Returns a description of this Product

@@ -317,7 +341,7 @@
  * all nested children of this configuration is installed 

  */

 public boolean isAllInstalled() {

-	Enumeration list = _enumerateComponentEntriesRel();

+	Enumeration list = _getAllComponentEntries().elements();

 	while(list.hasMoreElements()) {

 		IComponentEntryDescriptor comp =  (IComponentEntryDescriptor)list.nextElement();

 		if (!comp.isInstalled())

@@ -374,9 +398,7 @@
  *   <code>false</code> otherwise

  */

 public boolean isRemovable() {

-	

-	

-	Enumeration list = _enumerateComponentEntriesRel();

+	Enumeration list = _getAllComponentEntries().elements();

 	IComponentDescriptor comp;

 	while(list.hasMoreElements()) {

 		comp = ((IComponentEntryDescriptor) list.nextElement()).getComponentDescriptor();

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ProductDescriptorModel.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ProductDescriptorModel.java
index 9d41d01..b777f69 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ProductDescriptorModel.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/ProductDescriptorModel.java
@@ -28,7 +28,7 @@
 	private long   _stamp = 0;

 	private String _dirName = null;			// dir name in .install/.products/

 

-	private Vector _componentEntries = null;

+	private Hashtable compEntry_proxys_list = null; // component Entries

 

 /**

  * ComponentDescriptorModel constructor comment.

@@ -36,28 +36,79 @@
 public ProductDescriptorModel() {

 	super();

 }

-public void _addToComponentEntriesRel(Object o) {

-	

-	if (_componentEntries == null) _componentEntries = new Vector();

-	_componentEntries.addElement(o);

-	

-}

-public void _copyComponentEntriesRelInto(Object[] array) {

+// add a new component entry

+public void _addToComponentEntryProxysRel(Object o) {

 

-	if (_componentEntries != null) _componentEntries.copyInto(array);

+	if (compEntry_proxys_list == null) compEntry_proxys_list = new Hashtable();

+	String key = ((ComponentEntryDescriptorModel)o)._getId();

+	String version = ((ComponentEntryDescriptorModel)o)._getVersion();

+	

+	if (compEntry_proxys_list.containsKey(key)) { // a different version?  

+		UMProxy proxy = (UMProxy) compEntry_proxys_list.get(key);

+		Map versions = proxy._getVersionsRel();

+		if (versions.containsKey(version))	

+			; // LINDA - error condition - version collision

+		else {

+			proxy._addToVersionsRel(o, version);

+		}

+	} else {

+		UMProxy proxy = new UMProxy(key);

+		proxy._addToVersionsRel(o, version);

+		compEntry_proxys_list.put(key, proxy);

+	}

 }

-public Enumeration _enumerateComponentEntriesRel() {

+public void _copyComponentEntryProxysRelInto(Object[] array) {

 

-	if (_componentEntries == null) return (new Vector()).elements();

-	return _componentEntries.elements();

+	if (compEntry_proxys_list != null) {

+		Enumeration list = compEntry_proxys_list.elements();

+		for(int i=0; list.hasMoreElements(); i++) {

+			array[i] = list.nextElement();

+		}

+	}

+}

+public Enumeration _enumerateComponentProxysRel() {

+

+	if (compEntry_proxys_list == null) return (new Vector()).elements();

+	else return compEntry_proxys_list.elements();

+}

+public Vector _getAllComponentEntries() {

+

+	Vector all_comp_entries = new Vector();

+	if (compEntry_proxys_list == null) return all_comp_entries;

+	ComponentEntryDescriptorModel ced;

+	Enumeration list = compEntry_proxys_list.elements();

+	

+	while(list.hasMoreElements()) {

+		Map m = ((UMProxy)list.nextElement())._getVersionsRel();

+		for (Iterator i=m.entrySet().iterator(); i.hasNext(); ) {

+			  Map.Entry me = (Map.Entry) i.next();

+			  ced = (ComponentEntryDescriptorModel) me.getValue();

+			  all_comp_entries.addElement(ced);

+			  

+	    }

+	}

+	return all_comp_entries;

 }

 public String _getApplication() {

 	

 	return _application;

 }

-public Vector _getComponentEntriesRel() {

+public Hashtable _getComponentEntriesAtLatestVersion() {

+	

+	Hashtable _compEntry_list = new Hashtable();

+	if (compEntry_proxys_list == null) return _compEntry_list;

 

-	return _componentEntries;

+	ComponentEntryDescriptorModel ced;

+	Enumeration list = compEntry_proxys_list.elements();

+	while(list.hasMoreElements()) {

+		ced = (ComponentEntryDescriptorModel) ((UMProxy)list.nextElement())._getLatestVersion();

+		_compEntry_list.put(ced._getId(), ced);

+	}

+	return _compEntry_list;

+}

+public Hashtable _getComponentEntryProxysRel() {

+	

+	return compEntry_proxys_list;

 }

 public String _getDescription() {

 	

@@ -82,10 +133,10 @@
 	

 	return _vendorName;

 }

-public int _getSizeOfComponentEntriesRel() {

+public int _getSizeOfComponentProxysRel() {

 

-	if (_componentEntries == null) return 0;

-	else return _componentEntries.size();

+	if (compEntry_proxys_list == null) return 0;

+	else return compEntry_proxys_list.size();

 }

 public long _getStamp() {

 	return _stamp;

@@ -233,7 +284,7 @@
 		componentEntryDescriptor._setProdInstallURL(_getInstallURL());

 		componentEntryDescriptor._setContainingProduct(this);

 		componentEntryDescriptor._setUMRegistry(parent);

-		_addToComponentEntriesRel(componentEntryDescriptor);

+		_addToComponentEntryProxysRel(componentEntryDescriptor);

 

 		// see if it is installed physically 

 		try {

@@ -242,13 +293,14 @@
 			path = new URL(path, comp_dir);

 			File check = new File( path.getFile());

 			if (check.exists()) {

-				componentEntryDescriptor._isInstalled(true);

-				componentEntryDescriptor._setCompInstallURL(path.toString());	

-				// find the corresponding component descriptor and add this 

+				// load the corresponding component descriptor and add this 

 				// product to the list of containing products

-				ComponentDescriptorModel comp = parent._lookupComponentDescriptor(componentEntryDescriptor._getId(), componentEntryDescriptor._getVersion());

-				if (comp != null)

+				ComponentDescriptorModel comp = parent._loadComponentManifest(UMEclipseTree.getComponentURL().toString(), comp_dir, factory);

+				if (comp != null) {

 					comp._addToContainingProductsRel(this);

+					componentEntryDescriptor._isInstalled(true);

+					componentEntryDescriptor._setCompInstallURL(path.toString());

+				}

 			}

 			componentEntryDescriptor._setDirName(comp_dir);	

 		} catch (java.net.MalformedURLException ex) {

@@ -260,25 +312,41 @@
 	// Register

 	//---------

 	_setUMRegistry(parent);

-	parent._addToProductsRel(this);

+	parent._addToProductProxysRel(this);

 }

-public ComponentEntryDescriptorModel _lookupComponentEntry(String key) {

+public ComponentEntryDescriptorModel _lookupComponentEntry(String compId, String version) {

+

+

+	if(compId == null) return null;

+	if (compEntry_proxys_list == null) return null;

+	UMProxy proxy = (UMProxy) _lookupComponentEntryProxy(compId);

+	if (proxy == null) return null;

+	if (version == null)

+		return (ComponentEntryDescriptorModel)proxy._getLatestVersion();

+	return (ComponentEntryDescriptorModel)proxy._lookupVersion(version);

+	

+}

+public UMProxy _lookupComponentEntryProxy(String key) {

 

 	if(key == null) return null;

-	

-	Enumeration list = _enumerateComponentEntriesRel();

-	ComponentEntryDescriptorModel comp;

-	while(list.hasMoreElements()) {

-		comp = (ComponentEntryDescriptorModel) list.nextElement();

-		if(key.equals(comp._getId())) return comp;

-	}

-	

-	return null;

+	if (compEntry_proxys_list == null) return null;

+	return (UMProxy) compEntry_proxys_list.get(key);

 }

-public void _removeFromComponentEntriesRel(Object o) {

+public void _removeFromComponentEntryProxysRel(Object o) {

 

-	if (o==null || _componentEntries == null) return;

-	_componentEntries.removeElement(o);		

+	if (o==null || compEntry_proxys_list == null) return;

+	String key = ((ComponentEntryDescriptorModel)o)._getId();

+	String version = ((ComponentEntryDescriptorModel)o)._getVersion();

+	

+	if (compEntry_proxys_list.containsKey(key)) {  

+		UMProxy proxy = (UMProxy) compEntry_proxys_list.get(key);

+		Map versions = proxy._getVersionsRel();

+		versions.remove(version);

+		if (versions.size() ==0)	// no other versions of this id left

+			compEntry_proxys_list.remove(key);

+	} else {

+		// error condition - component id doesn't exist

+	}

 }

 public void _setApplication(String app) {

 	 _application = app;

@@ -307,7 +375,7 @@
  public Object clone() throws CloneNotSupportedException{

 	try {

 		ProductDescriptorModel clone = (ProductDescriptorModel)super.clone();

-		clone._componentEntries = (Vector) _componentEntries.clone();

+		clone.compEntry_proxys_list = (Hashtable) compEntry_proxys_list.clone();

 

 		return clone;

 	} catch (CloneNotSupportedException e) {

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMProxy.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMProxy.java
new file mode 100644
index 0000000..126a0f7
--- /dev/null
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMProxy.java
@@ -0,0 +1,44 @@
+package org.eclipse.core.internal.boot.update;

+

+// holds different versions of an entity (prod, comp or plug-in) that have the same id

+import java.util.*;

+public class UMProxy {

+	private String _id;

+	private Map _versions ;	// sorted versions

+/**

+ * UMProxy constructor comment.

+ */

+public UMProxy(String id)      { 

+	_id = id;

+	_versions = null;

+}

+/**

+ * Insert the method's description here.

+ * Creation date: (5/2/01 1:58:01 PM)

+ * @param o java.lang.Object

+ * @param key java.lang.String

+ */

+public void _addToVersionsRel(Object o, String key) {

+	if (_versions == null)  

+		_versions = Collections.synchronizedMap(new TreeMap(new VersionComparator()));	

+	_versions.put(key,o);

+}

+public Object _getEarliestVersion() {

+	TreeMap tm = new TreeMap(_versions);

+	String key = tm.firstKey().toString();

+	return _versions.get(key);

+}

+public Object _getLatestVersion() {

+	TreeMap tm = new TreeMap(_versions);

+	String key = tm.lastKey().toString();

+	return _versions.get(key);

+}

+public Map _getVersionsRel() {

+	return _versions;

+}

+public Object _lookupVersion(String key) {

+	if(key == null) return null;

+	if (_versions == null) return null;

+	return _versions.get(key);

+}

+}

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistry.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistry.java
index 432423f..e122ae4 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistry.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistry.java
@@ -46,29 +46,6 @@
 	

 }

 /**

- * Returns all plugin entry descriptors known to this registry, entries can

- * have duplicate plugin IDs but at different versions.

- * Returns an empty array if there are no installed plugins.

- *

- * @return all plugin descriptors, including all versions, known to this registry

- */

-public IPluginEntryDescriptor[] getAllPluginEntryDescriptors() {

-	Vector plugins_list = _getAllPluginEntries();

-

-	int size;

-	if (plugins_list == null) size = 0;

-	else size = plugins_list.size();

-	if(size == 0) return new IPluginEntryDescriptor[0];

-	

-	IPluginEntryDescriptor[] array = new IPluginEntryDescriptor[size];

-	Enumeration list = plugins_list.elements();

-		for(int i=0; list.hasMoreElements(); i++) {

-			array[i] = (IPluginEntryDescriptor) list.nextElement();

-		}

-	

-	return array;

-}

-/**

  * Returns all product descriptors known to this registry, entries can

  * have duplicate product IDs but at different versions.

  * Returns an empty array if there are no installed products.

@@ -174,22 +151,33 @@
 

 }

 // return a list of components that don't belong to any products

+// if registry = current or local, return danglingComponents

+// else if registry is remote, return looseComponents

 

 public IComponentDescriptor[] getDanglingComponents() {

 

 	Vector comp_list = new Vector();

 

-	Enumeration list = _getAllComponents().elements();

-	for(int i=0; list.hasMoreElements(); i++) {

-		IComponentDescriptor comp = (IComponentDescriptor) list.nextElement();

-		LaunchInfo.VersionedIdentifier vid = new LaunchInfo.VersionedIdentifier(comp.getUniqueIdentifier(), comp.getVersionStr());

-		if (LaunchInfo.getCurrent().isDanglingComponent(vid)) {

-			comp_list.add(comp);

-		} else {	// sometimes the LaunchInfo list might be out-of-sync

-			IProductDescriptor[] prod = comp.getContainingProducts();

-			if (prod.length == 0) {

+	if (_getType() == UpdateManagerConstants.REMOTE_REGISTRY) {

+		Enumeration list = _getAllComponents().elements();

+		for(int i=0; list.hasMoreElements(); i++) {

+			IComponentDescriptor comp = (IComponentDescriptor) list.nextElement();

+			if (comp.isLoose())

 				comp_list.add(comp);

-				LaunchInfo.getCurrent().isDanglingComponent(vid, true); //add

+		}

+	} else {

+		Enumeration list = _getAllComponents().elements();

+		for(int i=0; list.hasMoreElements(); i++) {

+			IComponentDescriptor comp = (IComponentDescriptor) list.nextElement();

+			LaunchInfo.VersionedIdentifier vid = new LaunchInfo.VersionedIdentifier(comp.getUniqueIdentifier(), comp.getVersionStr());

+			if (LaunchInfo.getCurrent().isDanglingComponent(vid)) {

+				comp_list.add(comp);

+			} else {	// sometimes the LaunchInfo list might be out-of-sync

+				IProductDescriptor[] prod = comp.getContainingProducts();

+				if (prod.length == 0) {

+					comp_list.add(comp);

+					_addToDanglingComponentIVPsRel(vid);

+				}

 			}

 		}

 	}

@@ -202,55 +190,6 @@
 	

 }

 /**

- * Returns the plug-in entry descriptor with the given plug-in identifier

- * at the latest version number in this  registry, or <code>null</code> if there is no such

- * plug-in.

- *

- * @param pluginId the unique identifier of the plug-in (e.g. <code>"com.example.myplugin"</code>).

- * @return the plug-in entry descriptor, or <code>null</code>

- */

-public IPluginEntryDescriptor getPluginEntryDescriptor(String pluginId) {

-	return getPluginEntryDescriptor(pluginId, null);

-}

-/**

- * Returns the plug-in entry descriptor with the given plug-in identifier

- * and version number in this registry, or <code>null</code> if there is no such

- * plug-in.   If a version number is not specified (null), the latest

- * version of such plug-in will be returned

- *

- * @param pluginId the unique identifier of the plug-in (e.g. <code>"com.example.myplugin"</code>).

- * @param version the version number

- * @return the plug-in entry descriptor at the specified version number, or <code>null</code>

- */

-public IPluginEntryDescriptor getPluginEntryDescriptor(java.lang.String pluginId, java.lang.String version) {

-	return (IPluginEntryDescriptor)_lookupPluginEntryDescriptor(pluginId,version);

-}

-/**

- * Returns all plug-in entry descriptors known to this registry.

- * Due to duplicate plugin IDs, the latest version of each descriptor

- * is returned.

- * Returns an empty array if there are no installed plug-ins.

- *

- * @return the plug-in entry descriptors at their latest versions known to this registry

- */

-public IPluginEntryDescriptor[] getPluginEntryDescriptors() {

-	Hashtable plugins_list = _getPluginEntriesAtLatestVersion();

-

-	int size;

-	if (plugins_list == null) size = 0;

-	else size = plugins_list.size();

-	if(size == 0) return new IPluginEntryDescriptor[0];

-	

-	IPluginEntryDescriptor[] array = new IPluginEntryDescriptor[size];

-	Enumeration list = plugins_list.elements();

-		for(int i=0; list.hasMoreElements(); i++) {

-			array[i] = (IPluginEntryDescriptor) list.nextElement();

-		}

-	

-	return array;

-	

-}

-/**

  * Returns the Product descriptor with the given Product identifier

  * at the latest version number in this registry, or <code>null</code> if there is no such

  * Product.

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistryManager.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistryManager.java
index 4397b64..e7e8c86 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistryManager.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistryManager.java
@@ -51,8 +51,8 @@
 	// need to reload the manifest so it'll reflect the state of things as the component

 	// exists relative to the current registry.  Cannot just add the component descriptor

 	// to the current registry

-	fCurrentRegistry._loadComponentManifest(UMEclipseTree.getComponentURL().toString(),comp.getDirName(),fFactory);

-	fLocalRegistry._loadComponentManifest(UMEclipseTree.getComponentURL().toString(),comp.getDirName(),fFactory);

+	ComponentDescriptorModel newComp1 =	fCurrentRegistry._loadComponentManifest(UMEclipseTree.getComponentURL().toString(),comp.getDirName(),fFactory);

+	ComponentDescriptorModel newComp2 = fLocalRegistry._loadComponentManifest(UMEclipseTree.getComponentURL().toString(),comp.getDirName(),fFactory);

 

 	LaunchInfo.VersionedIdentifier vid = new LaunchInfo.VersionedIdentifier(comp.getUniqueIdentifier(), comp.getVersionStr());

 	if (dangling) {

@@ -60,36 +60,34 @@
 		fLocalRegistry._addToDanglingComponentIVPsRel(vid);

 	} 	

 	

-	// look for freshly added comp descriptor and sync up the product

+	// for freshly added comp descriptor, sync up the product

 	// and compEntry sides

 	//---------------------------------------------------------------

 

-	// Current Registry 

-	ComponentDescriptorModel newComp = fCurrentRegistry._lookupComponentDescriptor(vid.getIdentifier(), vid.getVersion());

-	if (newComp != null) {

+	if (newComp1 != null) {

 		Vector prod_list = fCurrentRegistry._getAllProducts();

 		Enumeration list = prod_list.elements();

 		while ( list.hasMoreElements()) {

 			ProductDescriptorModel prod = (ProductDescriptorModel) list.nextElement();

-			ComponentEntryDescriptorModel compEntry = prod._lookupComponentEntry(vid.getIdentifier());

+			ComponentEntryDescriptorModel compEntry = prod._lookupComponentEntry(vid.getIdentifier(), vid.getVersion());

 			if (compEntry != null) {

 				compEntry._isInstalled(true);

-				newComp._addToContainingProductsRel(prod);

+				newComp1._addToContainingProductsRel(prod);

 			}

 		}

 	}

 

 	// Repeat for local registry

-	newComp = fLocalRegistry._lookupComponentDescriptor(vid.getIdentifier(), vid.getVersion());

-	if (newComp != null) {

+

+	if (newComp2 != null) {

 		Vector prod_list = fLocalRegistry._getAllProducts();

 		Enumeration list = prod_list.elements();

 		while ( list.hasMoreElements()) {

 			ProductDescriptorModel prod = (ProductDescriptorModel) list.nextElement();

-			ComponentEntryDescriptorModel compEntry = prod._lookupComponentEntry(vid.getIdentifier());

+			ComponentEntryDescriptorModel compEntry = prod._lookupComponentEntry(vid.getIdentifier(), vid.getVersion());

 			if (compEntry != null) {

 				compEntry._isInstalled(true);

-				newComp._addToContainingProductsRel(prod);

+				newComp2._addToContainingProductsRel(prod);

 			}

 		}

 	}	

@@ -221,6 +219,7 @@
 public IUMRegistry getRegistryAt(URL url) {

 	UMRegistry reg = createNewRegistry();

 	reg._loadManifests(url, fFactory);

+	reg._setType(UpdateManagerConstants.REMOTE_REGISTRY);

 	fDiscoveryRegistry = reg;

 	return (IUMRegistry) fDiscoveryRegistry;

 	

@@ -232,12 +231,74 @@
 	if (fLocalRegistry == null) {

 		fLocalRegistry = createNewRegistry();

 //		fLocalRegistry._loadSettings(fFactory);

-		fLocalRegistry._loadManifests(fEclipseBaseURL, fFactory); 

+		fLocalRegistry._loadManifests(fEclipseBaseURL, fFactory);

+		fLocalRegistry._setType(UpdateManagerConstants.LOCAL_REGISTRY);

 	}

 	if (fCurrentRegistry == null) {

 		fCurrentRegistry = createNewRegistry();

 //		fCurrentRegistry._loadSettings(fFactory);

 		fCurrentRegistry._loadManifests(fEclipseBaseURL, fFactory, true); // filtered for LaunchInfo

+		fCurrentRegistry._setType(UpdateManagerConstants.CURRENT_REGISTRY);

 	}

 }

+/**

+ * Removes the component descriptor with the given identifier

+ * and version number from this registry.  If a version number is not specified (null), the latest

+ * version of such component will be removed.

+ * This will also remove the pluginEntry and FragmentEntry descriptors belonging to

+ * this component.

+ * Important assumption here is that comp.isRemovable() is called before this is called

+ *

+ * @param prodId the unique identifier of the component .

+ * @param version the version number

+ * 

+ */

+public void removeComponentDescriptorFromLocal(IComponentDescriptor comp) {

+	removeComponentDescriptorFromLocal(comp, null);

+}

+/**

+ * Removes the component descriptor with the given identifier

+ * and version number from this registry.  If a version number is not specified (null), the latest

+ * version of such component will be removed.

+ * This will also remove the pluginEntry and FragmentEntry descriptors belonging to

+ * this component.

+ * Important assumption here is that comp.isRemovable() is called before this is called

+ *

+ * @param prodId the unique identifier of the component .

+ * @param version the version number

+ * 

+ */

+public void removeComponentDescriptorFromLocal(IComponentDescriptor comp, IProductDescriptor prod) {

+

+	// Important: comp.isRemovable() == true   called already

+	fCurrentRegistry._removeFromComponentProxysRel(comp);

+	if (comp.isDanglingComponent())

+		fCurrentRegistry._removeFromDanglingComponentIVPsRel(comp);

+

+	// repeat for local registry

+	fLocalRegistry._removeFromComponentProxysRel(comp);

+	if (comp.isDanglingComponent())

+		fLocalRegistry._removeFromDanglingComponentIVPsRel(comp);

+}

+/**

+ * Removes the product descriptor with the given product identifier

+ * and version number from this registry.  If a version number is not specified (null), the latest

+ * version of such product will be removed.

+ * This will also remove the componentEntry descriptors that belong to this

+ * product.

+ * Important assumption here is that prod.isRemovable() is called before this is called

+ *

+ * @param prodId the unique identifier of the product .

+ * @param version the version number

+ * 

+ */

+public void removeProductDescriptorFromLocal(IProductDescriptor prod) {

+

+	// Important: prod.isRemovable() == true   called already

+	//fCurrentRegistry._removeFromProductProxysRel(prod);

+	// for each compEntry, getComponentDescriptor(), remove prod from containing prod

+	// if comp is danglingComp, continue;

+	// else if comp still has containingprod, continue;

+	// else removeComponentDescriptor() from registry

+}

 }

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistryModel.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistryModel.java
index 9d3318c..d1813a5 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistryModel.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UMRegistryModel.java
@@ -15,50 +15,17 @@
 		// persistent properties (marshaled)

 		private Hashtable comp_proxys_list = null; // components

 		private Hashtable product_proxys_list = null;

-		private Hashtable plugin_proxys_list = null;

+//		private Hashtable plugin_proxys_list = null;

 

 //		private Set extra_updateURLs = null;	// specified by users in UI

 //		private Vector _programPaths = null;

+		private int _type;				// current, local, or remote(discovery)

 		private URL _registryBase;		// Base of the Eclipse tree of this registry

 		private boolean _initialStartup = true;

 		private boolean _filtered = false; // whether this registry reflects LaunchInfo

 		

 		private long _lastRefreshed = 0;

 

-		// holds different versions of an entity (prod, comp or plug-in) that have the same id

-		class Proxy {

-			private String _id;

-			private Map _versions ;

-			Proxy(String id)      { 

-				_id = id;

-				_versions = null;

-			}

-			public void _addToVersionsRel(Object o, String key) {

-				if (_versions == null)  _versions = Collections.synchronizedMap(new TreeMap(new VersionComparator()));	

-				_versions.put(key,o);

-			}

-			public Object _lookupVersion(String key) {

-	

-				if(key == null) return null;

-				if (_versions == null) return null;

-				return _versions.get(key);

-			}

-			public Object _getEarliestVersion() {

-				TreeMap tm = new TreeMap(_versions);

-				String key = tm.firstKey().toString();

-				return _versions.get(key);

-			}

-			public Object _getLatestVersion() {

-				TreeMap tm = new TreeMap(_versions);

-				String key = tm.lastKey().toString();

-				return _versions.get(key);

-			}

-			public Map _getVersionsRel() {

-		

-				return _versions;

-	

-			}

-		}

 

 /**

  * UMRegistryModel constructor comment.

@@ -68,14 +35,14 @@
 

 }

 // add a new component

-public void _addToComponentsRel(Object o) {

+public void _addToComponentProxysRel(Object o) {

 

 	if (comp_proxys_list == null) comp_proxys_list = new Hashtable();

 	String key = ((ComponentDescriptorModel)o)._getId();

 	String version = ((ComponentDescriptorModel)o)._getVersion();

 	

 	if (comp_proxys_list.containsKey(key)) { // a different version?  

-		Proxy proxy = (Proxy) comp_proxys_list.get(key);

+		UMProxy proxy = (UMProxy) comp_proxys_list.get(key);

 		Map versions = proxy._getVersionsRel();

 		if (versions.containsKey(version))	

 			; // LINDA - error condition - version collision

@@ -83,7 +50,7 @@
 			proxy._addToVersionsRel(o, version);

 		}

 	} else {

-		Proxy proxy = new Proxy(key);

+		UMProxy proxy = new UMProxy(key);

 		proxy._addToVersionsRel(o, version);

 		comp_proxys_list.put(key, proxy);

 	}

@@ -93,35 +60,14 @@
 	LaunchInfo.VersionedIdentifier vid = (LaunchInfo.VersionedIdentifier) o;

 	LaunchInfo.getCurrent().isDanglingComponent(vid, true); // add

 }

-// add a new component

-public void _addToPluginsRel(Object o) {

-

-	if (plugin_proxys_list == null) plugin_proxys_list = new Hashtable();

-	String key = ((PluginEntryDescriptorModel)o)._getId();

-	String version = ((PluginEntryDescriptorModel)o)._getVersion();

-	

-	if (plugin_proxys_list.containsKey(key)) { // a different version?  

-		Proxy proxy = (Proxy) plugin_proxys_list.get(key);

-		Map versions = proxy._getVersionsRel();

-		if (versions.containsKey(version))	

-			; // LINDA - error condition - version collision

-		else {

-			proxy._addToVersionsRel(o, version);

-		}

-	} else {

-		Proxy proxy = new Proxy(key);

-		proxy._addToVersionsRel(o, version);

-		plugin_proxys_list.put(key, proxy);

-	}

-}

-public void _addToProductsRel(Object o) {

+public void _addToProductProxysRel(Object o) {

 

 	if (product_proxys_list == null) product_proxys_list = new Hashtable();

 	String key = ((ProductDescriptorModel)o)._getId();

 	String version = ((ProductDescriptorModel)o)._getVersion();

 	

 	if (product_proxys_list.containsKey(key)) { // a different version?  

-		Proxy proxy = (Proxy) product_proxys_list.get(key);

+		UMProxy proxy = (UMProxy) product_proxys_list.get(key);

 		Map versions = proxy._getVersionsRel();

 		if (versions.containsKey(version))	

 			; // error condition - version collision

@@ -129,7 +75,7 @@
 			proxy._addToVersionsRel(o, version);

 		}

 	} else {

-		Proxy proxy = new Proxy(key);

+		UMProxy proxy = new UMProxy(key);

 		proxy._addToVersionsRel(o, version);

 		product_proxys_list.put(key, proxy);

 	}

@@ -143,15 +89,6 @@
 		}

 	}

 }

-public void _copyPluginProxysRelInto(Object[] array) {

-

-	if (plugin_proxys_list != null) {

-		Enumeration list = plugin_proxys_list.elements();

-		for(int i=0; list.hasMoreElements(); i++) {

-			array[i] = list.nextElement();

-		}

-	}

-}

 public void _copyProductProxysRelInto(Object[] array) {

 

 	if (product_proxys_list != null) {

@@ -166,11 +103,6 @@
 	if (comp_proxys_list == null) return (new Vector()).elements();

 	else return comp_proxys_list.elements();

 }

-public Enumeration _enumeratePluginProxysRel() {

-

-	if (plugin_proxys_list == null) return (new Vector()).elements();

-	else return plugin_proxys_list.elements();

-}

 public Enumeration _enumerateProductProxysRel() {

 

 	if (product_proxys_list == null) return (new Vector()).elements();

@@ -184,7 +116,7 @@
 	Enumeration list = comp_proxys_list.elements();

 	

 	while(list.hasMoreElements()) {

-		Map m = ((Proxy)list.nextElement())._getVersionsRel();

+		Map m = ((UMProxy)list.nextElement())._getVersionsRel();

 		for (Iterator i=m.entrySet().iterator(); i.hasNext(); ) {

 			  Map.Entry me = (Map.Entry) i.next();

 			  cd = (ComponentDescriptorModel) me.getValue();

@@ -194,24 +126,6 @@
 	}

 	return all_comp;

 }

-public Vector _getAllPluginEntries() {

-

-	Vector all_plugins = new Vector();

-	if (plugin_proxys_list == null) return all_plugins;

-	

-	PluginEntryDescriptorModel ped;

-	Enumeration list = plugin_proxys_list.elements();

-	

-	while(list.hasMoreElements()) {

-		Map m = ((Proxy)list.nextElement())._getVersionsRel();

-		for (Iterator i=m.entrySet().iterator(); i.hasNext(); ) {

-			Map.Entry me = (Map.Entry) i.next();

-			ped = (PluginEntryDescriptorModel) me.getValue();

-			all_plugins.addElement(ped);

-	    }

-	}

-	return all_plugins;

-}

 public Vector _getAllProducts() {

 

 	Vector all_prod = new Vector();

@@ -221,7 +135,7 @@
 	Enumeration list = product_proxys_list.elements();

 	

 	while(list.hasMoreElements()) {

-		Map m = ((Proxy)list.nextElement())._getVersionsRel();

+		Map m = ((UMProxy)list.nextElement())._getVersionsRel();

 		for (Iterator i=m.entrySet().iterator(); i.hasNext(); ) {

 			Map.Entry me = (Map.Entry) i.next();

 			pd = (ProductDescriptorModel) me.getValue();

@@ -242,7 +156,7 @@
 	ComponentDescriptorModel cd;

 	Enumeration list = comp_proxys_list.elements();

 	while(list.hasMoreElements()) {

-		cd = (ComponentDescriptorModel) ((Proxy)list.nextElement())._getLatestVersion();

+		cd = (ComponentDescriptorModel) ((UMProxy)list.nextElement())._getLatestVersion();

 		_comp_list.put(cd._getId(), cd);

 	}

 	return _comp_list;

@@ -250,23 +164,6 @@
 public long _getLastRefreshed() {

 	return _lastRefreshed;

 }

-public Hashtable _getPluginEntriesAtLatestVersion() {

-	

-	Hashtable _plugins_list = new Hashtable();

-	if (plugin_proxys_list == null) return _plugins_list;

-

-	PluginEntryDescriptorModel ped;

-	Enumeration list = plugin_proxys_list.elements();

-	while(list.hasMoreElements()) {

-		ped = (PluginEntryDescriptorModel) ((Proxy)list.nextElement())._getLatestVersion();

-		_plugins_list.put(ped._getId(), ped);

-	}

-	return _plugins_list;

-}

-public Hashtable _getPluginProxysRel() {

-	

-	return plugin_proxys_list;

-}

 public Hashtable _getProductProxysRel() {

 	

 	return product_proxys_list;

@@ -279,7 +176,7 @@
 	ProductDescriptorModel pd;

 	Enumeration list = product_proxys_list.elements();

 	while(list.hasMoreElements()) {

-		pd = (ProductDescriptorModel) ((Proxy)list.nextElement())._getLatestVersion();

+		pd = (ProductDescriptorModel) ((UMProxy)list.nextElement())._getLatestVersion();

 		_prod_list.put(pd._getId(), pd);

 	}

 	return _prod_list;

@@ -292,16 +189,14 @@
 	if (comp_proxys_list == null) return 0;

 	else return comp_proxys_list.size();

 }

-public int _getSizeOfPluginProxysRel() {

-

-	if (plugin_proxys_list == null) return 0;

-	else return plugin_proxys_list.size();

-}

 public int _getSizeOfProductProxysRel() {

 

 	if (product_proxys_list == null) return 0;

 	else return product_proxys_list.size();

 }

+public int _getType() {

+	return _type;

+}

 public boolean _isFiltered() {

 	

 	return _filtered;

@@ -317,22 +212,35 @@
 /* load component manifest in the directory compDir/dirName

  * which is of the form ...../install/components/comp_dirname

  */

-public void _loadComponentManifest(String compDir, String dirName, IUMFactory factory) {

+public ComponentDescriptorModel _loadComponentManifest(String compDir, String dirName, IUMFactory factory) {

 

+	ComponentDescriptorModel cd = null;

 	try {	

-		ComponentDescriptorModel cd = (ComponentDescriptorModel) factory.createComponentDescriptor();

+		cd = (ComponentDescriptorModel) factory.createComponentDescriptor();

 		cd._setDirName(dirName);

 		cd._setInstallURL(compDir + dirName);

 		cd._loadManifest(new URL(cd._getInstallManifestURL()), this, factory);

 	} catch (java.net.MalformedURLException e) {

 	}

-

+	return cd;

 }

 public void _loadManifests(URL url, IUMFactory factory) {

 	

 	_loadManifests(url, factory, false);

 

 }

+/* The whole picture:

+ * Products load first, which in turn load their componentEntries

+ * for each componentEntry, look for actual component -

+ *     if exists on filesys, then compEntries.installed=true, load component

+ *     else compEntries.instaled = false

+ *

+ * Next we go to the components directory

+ * Look for install.index, if it exists on filesys, load all the components listed

+ * if component not already loaded (must be loose), load component 

+ * if this is a remote reg, comp._isLoose(true);

+ * for a local/current reg, see getDanglingComponents() to see how these are found

+ */

 public void _loadManifests(URL url, IUMFactory factory, boolean filtered) {

 

 	_filtered = filtered;

@@ -341,39 +249,54 @@
 		

 	URL installURLs[] = UMEclipseTree.getDirectoriesInChain(url);

 	

-	// Components load first, so the componentEntries in products can be resolved later

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

-		URL componentPath = UMEclipseTree.getComponentURL(installURLs[i]);

-		if (filtered) {

-			LaunchInfo.VersionedIdentifier[] ivps = LaunchInfo.getCurrent().getComponents();

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

-				_loadComponentManifest(componentPath.toString(), ivps[j].toString(), factory);

-			}

-		} else {

-			// get all components

-			String[] members = UMEclipseTree.getPathMembers(componentPath);

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

-				if (members[j].equals(IManifestAttributes.INSTALL_INDEX)) continue;

-				_loadComponentManifest(componentPath.toString(), members[j] , factory);

-			}

-		}

-

 		// Products

 		//---------

 		URL productPath = UMEclipseTree.getProductURL(installURLs[i]);

-		if (filtered) {

+		if (filtered) {		// load specific products according to LaunchInfo

 			LaunchInfo.VersionedIdentifier[] ivps = LaunchInfo.getCurrent().getConfigurations();

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

 				_loadProductManifest(productPath.toString(), ivps[j].toString(), factory);

 			}

-		} else {

-			// get all products

+		} else {			// get all products

 			String[] members = UMEclipseTree.getPathMembers(productPath);

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

 				if (members[j].equals(IManifestAttributes.INSTALL_INDEX)) continue;

 				_loadProductManifest(productPath.toString(), members[j] , factory);		

 			}

 		}

+		

+		// Loose Components  

+		//-----------------

+		URL componentPath = UMEclipseTree.getComponentURL(installURLs[i]);

+		if (filtered) {		// load specific components according to LaunchInfo

+			LaunchInfo.VersionedIdentifier[] ivps = LaunchInfo.getCurrent().getComponents();

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

+				ComponentDescriptorModel cd = _lookupComponentDescriptor(ivps[j].getIdentifier(), ivps[j].getVersion());

+				if (cd == null) { // these are the dangling ones

+					_loadComponentManifest(componentPath.toString(), ivps[j].toString(), factory);

+				}

+			}

+		} else {			// get all components in install.index or dir

+			String[] members = UMEclipseTree.getPathMembers(componentPath);

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

+				if (members[j].equals(IManifestAttributes.INSTALL_INDEX)) continue;

+				LaunchInfo.VersionedIdentifier vid = new LaunchInfo.VersionedIdentifier(members[j]);

+				ComponentDescriptorModel cd = _lookupComponentDescriptor(vid.getIdentifier(), vid.getVersion());

+				if (cd == null) {

+					cd = _loadComponentManifest(componentPath.toString(), members[j] , factory);

+				}

+				if (cd !=null) {

+					if (_getType() == UpdateManagerConstants.REMOTE_REGISTRY)

+						cd._isLoose(true);

+				}

+			}

+		}

+		

+

+

+

+

 	}

 	_lastRefreshed = startTime; 

 

@@ -396,50 +319,74 @@
 

 	if(compId == null) return null;

 	if (comp_proxys_list == null) return null;

-	Proxy proxy = (Proxy) _lookupComponentProxy(compId);

+	UMProxy proxy = (UMProxy) _lookupComponentProxy(compId);

 	if (proxy == null) return null;

 	if (version == null)

 		return (ComponentDescriptorModel)proxy._getLatestVersion();

 	return (ComponentDescriptorModel)proxy._lookupVersion(version);

 	

 }

-public Proxy _lookupComponentProxy(String key) {

+public UMProxy _lookupComponentProxy(String key) {

 

 	if(key == null) return null;

 	if (comp_proxys_list == null) return null;

-	return (Proxy) comp_proxys_list.get(key);

-}

-public PluginEntryDescriptorModel _lookupPluginEntryDescriptor(String plugId, String version) {

-

-	if(plugId == null) return null;

-	if (plugin_proxys_list == null) return null;

-	Proxy proxy = (Proxy) _lookupPluginProxy(plugId);

-	if (proxy == null) return null;

-	if (version == null)

-		return (PluginEntryDescriptorModel)proxy._getLatestVersion();

-	return (PluginEntryDescriptorModel)proxy._lookupVersion(version);

-}

-public Proxy _lookupPluginProxy(String key) {

-

-	if(key == null) return null;

-	if (plugin_proxys_list == null) return null;

-	return (Proxy)plugin_proxys_list.get(key);

+	return (UMProxy) comp_proxys_list.get(key);

 }

 public ProductDescriptorModel _lookupProductDescriptor(String prodId, String version) {

 

 	if(prodId == null) return null;

 	if (product_proxys_list == null) return null;

-	Proxy proxy = (Proxy) _lookupProductProxy(prodId);

+	UMProxy proxy = (UMProxy) _lookupProductProxy(prodId);

 	if (proxy == null) return null;

 	if (version == null)

 		return (ProductDescriptorModel)proxy._getLatestVersion();

 	return (ProductDescriptorModel)proxy._lookupVersion(version);

 	

 }

-public Proxy _lookupProductProxy(String key) {

+public UMProxy _lookupProductProxy(String key) {

 

 	if(key == null) return null;

 	if (product_proxys_list == null) return null;

-	return (Proxy)product_proxys_list.get(key);

+	return (UMProxy)product_proxys_list.get(key);

+}

+public void _removeFromComponentProxysRel(Object o) {

+

+	if (o==null || comp_proxys_list == null) return;

+	String key = ((ComponentDescriptorModel)o)._getId();

+	String version = ((ComponentDescriptorModel)o)._getVersion();

+	

+	if (comp_proxys_list.containsKey(key)) {  

+		UMProxy proxy = (UMProxy) comp_proxys_list.get(key);

+		Map versions = proxy._getVersionsRel();

+		versions.remove(version);

+		if (versions.size() ==0)	// no other versions of this id left

+			comp_proxys_list.remove(key);

+	} else {

+		// error condition - component id doesn't exist

+	}

+}

+public void _removeFromDanglingComponentIVPsRel(Object o) {

+

+	LaunchInfo.VersionedIdentifier vid = (LaunchInfo.VersionedIdentifier) o;

+	LaunchInfo.getCurrent().isDanglingComponent(vid, false); // remove

+}

+public void _removeFromProductProxysRel(Object o) {

+

+	if (o==null || product_proxys_list == null) return;

+	String key = ((ProductDescriptorModel)o)._getId();

+	String version = ((ProductDescriptorModel)o)._getVersion();

+	

+	if (product_proxys_list.containsKey(key)) {  

+		UMProxy proxy = (UMProxy) product_proxys_list.get(key);

+		Map versions = proxy._getVersionsRel();

+		versions.remove(version);

+		if (versions.size() ==0)	// no other versions of this id left

+			product_proxys_list.remove(key);

+	} else {

+		// error condition - product id doesn't exist

+	}

+}

+public void _setType(int type) {

+	_type = type;

 }

 }

diff --git a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UpdateManagerConstants.java b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UpdateManagerConstants.java
index 548b445..29ee54d 100644
--- a/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UpdateManagerConstants.java
+++ b/bundles/org.eclipse.core.boot/src/org/eclipse/core/internal/boot/update/UpdateManagerConstants.java
@@ -69,4 +69,8 @@
 	public static final int URL_INVALID     =  9;

 	public static final int URL_MISSING     = 10;

 	public static final int URL_NOT_FOUND   = 11;

+

+	public static final int CURRENT_REGISTRY = 0;

+	public static final int LOCAL_REGISTRY = 1;

+	public static final int REMOTE_REGISTRY = 2;

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Extension.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Extension.java
index e9f4ca0..cf4c059 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Extension.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Extension.java
@@ -45,6 +45,6 @@
 	return getParentPluginDescriptor().getId() + "." + simple;

 }

 public String toString() {

-	return getDeclaringPluginDescriptor().toString()+"."+getSimpleIdentifier();

+	return getParent().getPluginId() + "." + getSimpleIdentifier();

 }

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ExtensionPoint.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ExtensionPoint.java
index fe78e68..8fea4a0 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ExtensionPoint.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ExtensionPoint.java
@@ -68,6 +68,6 @@
 	return getParentPluginDescriptor().getId() + "." + getSimpleIdentifier();

 }

 public String toString() {

-	return getDeclaringPluginDescriptor().toString()+"."+getSimpleIdentifier();

+	return getParent().getPluginId() + "." + getSimpleIdentifier();

 }

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IModel.java
index d695bb8..fa3e7ae 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IModel.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IModel.java
@@ -16,20 +16,27 @@
 	public static final String REGISTRY = "plugin-registry";

 	public static final String REGISTRY_PATH = "path";

 

+	public static final String FRAGMENT = "fragment";

+	public static final String FRAGMENT_ID = "id";

+	public static final String FRAGMENT_NAME = "name";

+	public static final String FRAGMENT_PROVIDER = "provider-name";

+	public static final String FRAGMENT_VERSION = "version";

+	public static final String FRAGMENT_PLUGIN_ID = "plugin-id";

+	public static final String FRAGMENT_PLUGIN_VERSION = "plugin-version";

+

 	public static final String PLUGIN = "plugin";

 	public static final String PLUGIN_ID = "id";

 	public static final String PLUGIN_NAME = "name";

 	public static final String PLUGIN_VENDOR = "vendor-name";

 	public static final String PLUGIN_PROVIDER = "provider-name";

 	public static final String PLUGIN_VERSION = "version";

-	public static final String PLUGIN_GENERATION = "generation";

-	public static final String PLUGIN_INSTALL_URL = "base";

 	public static final String PLUGIN_CLASS = "class";

 

 	public static final String PLUGIN_REQUIRES = "requires";

 	public static final String PLUGIN_REQUIRES_PLATFORM = "platform-version";

 	public static final String PLUGIN_REQUIRES_PLUGIN = "plugin";

 	public static final String PLUGIN_REQUIRES_PLUGIN_VERSION = "version";

+	public static final String PLUGIN_REQUIRES_OPTIONAL = "optional";

 	public static final String PLUGIN_REQUIRES_IMPORT = "import";

 	public static final String PLUGIN_REQUIRES_EXPORT = "export";

 	public static final String PLUGIN_REQUIRES_MATCH = "match";

@@ -42,11 +49,10 @@
 

 	public static final String LIBRARY = "library";

 	public static final String LIBRARY_NAME = "name";

+	public static final String LIBRARY_SOURCE = "source";

 	public static final String LIBRARY_TYPE = "type";

 	public static final String LIBRARY_EXPORT = "export";

 	public static final String LIBRARY_EXPORT_MASK = "name";

-	public static final String LIBRARY_EXPORT_MASK_PROTECTED = "protected";

-	public static final String LIBRARY_MASK_ALL = "*";

 

 	public static final String EXTENSION_POINT = "extension-point";

 	public static final String EXTENSION_POINT_NAME = "name";

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginClassLoader.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginClassLoader.java
index 22272d9..937e570 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginClassLoader.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginClassLoader.java
@@ -26,11 +26,11 @@
 	private PluginDescriptor descriptor;

 	private boolean pluginActivationInProgress = false;

 	private boolean loadInProgress = false;

-public PluginClassLoader(URL[] searchPath, URLContentFilter[] filters, PlatformClassLoader parent, PluginDescriptor descriptor) {

+public PluginClassLoader(URL[] codePath, URLContentFilter[] codeFilters, URL[] resourcePath, URLContentFilter[] resourceFilters, PlatformClassLoader parent, PluginDescriptor descriptor) {

 	// create a class loader with the given classpath and filters.  Also, set the parent

 	// to be the parent of the platform class loader.  This allows us to decouple standard

 	// parent loading from platform loading.

-	super(searchPath, filters, parent.getParent());

+	super(codePath, codeFilters, resourcePath, resourceFilters, parent.getParent());

 	this.descriptor = descriptor;

 	base = descriptor.getInstallURL();

 	debugConstruction(); // must have initialized loader

@@ -82,7 +82,7 @@
 		// no point in looking in self as the class was already in the cache.

 		result = findLoadedClass(name);

 		if (result != null) {

-			result = checkVisibility(result, requestor, true);

+			result = checkClassVisibility(result, requestor, true);

 			if (result != null || !checkParents)

 				return result;

 		}

@@ -103,7 +103,7 @@
 			} catch (ClassNotFoundException e) {

 				return null;

 			}

-			return checkVisibility(result, requestor, false);

+			return checkClassVisibility(result, requestor, false);

 		}

 		// Check to see if we would find the class if we looked.  If so,

 		// activation is required.  If not, don't bother, just return null

@@ -125,12 +125,12 @@
 	synchronized (this) {

 		result = findLoadedClass(name);

 		if (result != null)

-			return checkVisibility(result, requestor, true);

+			return checkClassVisibility(result, requestor, true);

 

 		// do search/load in this class loader

 		try {

 			result = super.findClass(name);

-			return checkVisibility(result, requestor, false);

+			return checkClassVisibility(result, requestor, false);

 		} catch (ClassNotFoundException e) {

 			return null;

 		}

@@ -149,6 +149,7 @@
 	ArrayList require = new ArrayList();

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

 		desc = (PluginDescriptor) registry.getPluginDescriptor(prereqs[i].getUniqueIdentifier(), prereqs[i].getResolvedVersionIdentifier());

+		// can be null if the prereq was optional and did not exst.

 		if (desc != null)

 			require.add(new DelegateLoader((DelegatingURLClassLoader) desc.getPluginClassLoader(true), prereqs[i].isExported()));

 	}

@@ -170,7 +171,7 @@
 	// (2) the check cannot be added to the "right" spot inside private

 	//     implementation of URLClassLoader

 	String resource = name.replace('.', '/');

-	if (findResourceLocal(resource + ".class") == null)

+	if (findClassResource(resource + ".class") == null)

 		return false;

 

 	// check if plugin is permanently deactivated

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginDescriptor.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginDescriptor.java
index b4596fd..1ce8f6e 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginDescriptor.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginDescriptor.java
@@ -29,7 +29,7 @@
 	private boolean bundleNotFound = false; // marker to prevent unnecessary lookups

 

 	// constants

-	private static final String ECLIPSE_URL = EclipseURLHandler.ECLIPSE + EclipseURLHandler.PROTOCOL_SEPARATOR + "/" + EclipseURLPluginConnection.PLUGIN + "/";

+	private static final String PLUGIN_URL = PlatformURLHandler.PROTOCOL + PlatformURLHandler.PROTOCOL_SEPARATOR + "/" + PlatformURLPluginConnection.PLUGIN + "/";

 

 	private static final String DEFAULT_BUNDLE_NAME = "plugin";

 	private static final String KEY_PREFIX = "%";

@@ -37,8 +37,7 @@
 

 	private static final String URL_PROTOCOL_FILE = "file";

 

-	private static final String VERSION_SEPARATOR_OPEN = "(";

-	private static final String VERSION_SEPARATOR_CLOSE = ")";

+	private static final String VERSION_SEPARATOR = "_";

 

 	// Development mode constants

 	private static final String PLUGIN_JARS = "plugin.jars";

@@ -216,7 +215,7 @@
  */

 public URL getInstallURL() {

 	try {

-		return new URL(ECLIPSE_URL + getUniqueIdentifier() + "/");

+		return new URL(PLUGIN_URL + toString() + "/");

 	} catch (MalformedURLException e) {

 		throw new IllegalStateException(); // unchecked

 	}

@@ -255,7 +254,11 @@
 		return loader;

 

 	Object[] path = getPluginClassLoaderPath(eclipseURLs);

-	loader = new PluginClassLoader((URL[]) path[0], (URLContentFilter[]) path[1], PlatformClassLoader.getDefault(), this);

+	URL[] codePath = (URL[]) path[0];

+	URLContentFilter[] codeFilters = (URLContentFilter[]) path[1];

+	URL[] resourcePath = (URL[]) path[2];

+	URLContentFilter[] resourceFilters = (URLContentFilter[]) path[3];

+	loader = new PluginClassLoader(codePath, codeFilters, resourcePath, resourceFilters, PlatformClassLoader.getDefault(), this);

 	loader.initializeImportedLoaders();

 	// Note: need to be able to give out a loader reference before

 	// its prereqs are initialized. Otherwise loops in prereq

@@ -291,15 +294,17 @@
 	// applied to the corresponding loader search path entries

 

 	Properties jarDefinitions = loadJarDefinitions();

-	ArrayList urls = new ArrayList(5);

-	ArrayList cfs = new ArrayList(5);

+	ArrayList resourcePath = new ArrayList(5);

+	ArrayList resourceFilters = new ArrayList(5);

+	ArrayList codePath = new ArrayList(5);

+	ArrayList codeFilters = new ArrayList(5);

 	// compute the base of the classpath urls.  If <code>eclipseURLs</code> is

 	// true, we should use eclipse: URLs.  Otherwise the native URLs are used.

 	URL install = eclipseURLs ? getInstallURL() : getInstallURLInternal();

 	String execBase = install.toExternalForm();

 	String devBase = null;

 	if (InternalPlatform.inVAJ() || InternalPlatform.inVAME())

-		devBase = EclipseURLPlatformConnection.PLATFORM_URL_STRING;

+		devBase = PlatformURLBaseConnection.PLATFORM_URL_STRING;

 	else

 		devBase = execBase;

 

@@ -323,19 +328,21 @@
 	}

 

 	// add in the class path entries spec'd in the plugin.xml.  If in development mode, 

-	// add the entries from the plugin.jars first.

+	// add the entries from the plugin.jars first.  

 	ILibrary[] list = getRuntimeLibraries();

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

 		ILibrary library = list[i];

-		if (library.getPath().isEmpty())

+		// if the library path is empty or the library is source lib, skip it.

+		if (library.getPath().isEmpty() || library.getType().equals(ILibrary.SOURCE))

 			continue;

 		String[] filters = library.isFullyExported() ? exportAll : library.getContentFilters();

 		// add in the plugin.jars entries

 		String libSpec = library.getPath().toString();

+		libSpec = resolveLibraryPath(libSpec);

 		String jarDefinition = null;

 		if (jarDefinitions != null && libSpec != null) {

 			jarDefinition = jarDefinitions.getProperty(libSpec);

-			String[] specs = getArrayFromList(jarDefinition );

+			String[] specs = getArrayFromList(jarDefinition);

 			// convert jar spec into url strings

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

 				libSpecs.add(devBase + specs[j] + "/");

@@ -353,16 +360,22 @@
 				if ((InternalPlatform.inVAJ() || InternalPlatform.inVAME()) && jarDefinition != null) {

 					libSpec = null;

 				} else {

-					if (libSpec.startsWith(EclipseURLHandler.ECLIPSE + EclipseURLHandler.PROTOCOL_SEPARATOR))

-						libSpec += EclipseURLHandler.JAR_SEPARATOR;

+					if (libSpec.startsWith(PlatformURLHandler.PROTOCOL + PlatformURLHandler.PROTOCOL_SEPARATOR))

+						libSpec += PlatformURLHandler.JAR_SEPARATOR;

 					else

-						libSpec = EclipseURLHandler.JAR + EclipseURLHandler.PROTOCOL_SEPARATOR + libSpec + EclipseURLHandler.JAR_SEPARATOR;

+						libSpec = PlatformURLHandler.JAR + PlatformURLHandler.PROTOCOL_SEPARATOR + libSpec + PlatformURLHandler.JAR_SEPARATOR;

 				}

 			}

 			// if we still have a libspec, add it to the list of classpath entries

 			if (libSpec != null) {

-				libSpecs.add(libSpec);

-				libSpecs.add(filters);

+				if (library.getType().equals(ILibrary.CODE)) {

+					libSpecs.add(libSpec);

+					libSpecs.add(filters);

+				} else

+					if (library.getType().equals(ILibrary.RESOURCE)) {

+						resourcePath.add(libSpec);

+						resourceFilters.add(filters);

+					}

 			}

 		}

 	}

@@ -376,20 +389,22 @@
 			URL entry = new URL(spec);

 			URL resolved = Platform.resolve(entry);

 			boolean add = true;

-			if (resolved.getProtocol().equals(EclipseURLHandler.FILE))

+			if (resolved.getProtocol().equals(PlatformURLHandler.FILE))

 				add = new File(resolved.getFile()).exists();

 			if (add) {

-				urls.add(entry);

-				cfs.add(new URLContentFilter(filter));

+				codePath.add(resolved);

+				codeFilters.add(new URLContentFilter(filter));

 			}

 		} catch (IOException e) {

 			// skip bad URLs

 		}

 	}

 

-	Object[] result = new Object[2];

-	result[0] = urls.toArray(new URL[urls.size()]);

-	result[1] = cfs.toArray(new URLContentFilter[cfs.size()]);

+	Object[] result = new Object[4];

+	result[0] = codePath.toArray(new URL[codePath.size()]);

+	result[1] = codeFilters.toArray(new URLContentFilter[codeFilters.size()]);

+	result[2] = resourcePath.toArray(new URL[resourcePath.size()]);

+	result[3] = resourceFilters.toArray(new URLContentFilter[resourceFilters.size()]);

 	return result;

 }

 /**

@@ -489,6 +504,13 @@
 	return getId();

 }

 /**

+ * @see #toString

+ */

+public static String getUniqueIdentifierFromString(String pluginString) {	

+	int ix = pluginString.indexOf(VERSION_SEPARATOR);

+	return ix==-1 ? pluginString : pluginString.substring(0,ix);

+}

+/**

  * @see IPluginDescriptor

  */

 public PluginVersionIdentifier getVersionIdentifier() {

@@ -497,10 +519,23 @@
 		return new PluginVersionIdentifier("1.0.0");

 	try {

 		return new PluginVersionIdentifier(version);

-	} catch (Throwable e) {

+	} catch (Exception e) {

 		return new PluginVersionIdentifier("1.0.0");

 	}

 }

+/**

+ * @see #toString

+ */

+public static PluginVersionIdentifier getVersionIdentifierFromString(String pluginString) {

+	int ix = pluginString.indexOf("_");

+	if (ix==-1) return null;

+	String vid = pluginString.substring(ix+1);	

+	try {

+		return new PluginVersionIdentifier(vid);

+	} catch (Exception e) {

+		return null;

+	}

+}

 private void internalDoPluginActivation() throws CoreException {

 	String errorMsg;

 	// load the runtime class 

@@ -580,6 +615,9 @@
 	return deactivated;

 }

 private Properties loadJarDefinitions() {

+	// XXX this should be changed to just be !(inVAJ || inVAME).  Eclipse

+	// can now copy the resources etc into the right spot so we don't have to

+	// add the source folders any more.

 	if (!InternalPlatform.inDevelopmentMode())

 		return null;

 	Properties result = null;

@@ -630,6 +668,19 @@
 	} else

 		active = true;

 }

+private String resolveLibraryPath(String spec) {

+	if (spec.charAt(0) != '$')

+		return spec;

+	IPath path = new Path(spec);

+	String first = path.segment(0);

+	if (first.equalsIgnoreCase("$ws$"))

+		return new Path("ws/" + BootLoader.getWS()).append(path.removeFirstSegments(1)).toString();

+	if (first.equalsIgnoreCase("$os$"))

+		return new Path("os/" + BootLoader.getOS()).append(path.removeFirstSegments(1)).toString();

+	if (first.equalsIgnoreCase("$nl$"))

+		return new Path("nl/" + BootLoader.getNL()).append(path.removeFirstSegments(1)).toString();

+	return spec;

+}

 public void setPluginClassLoader(DelegatingURLClassLoader value) {

 	loader = value;

 }

@@ -641,7 +692,11 @@
 	logError(status);

 	throw new CoreException(status);

 }

+/**

+ * @see #getUniqueIdentifierFromString

+ * @see #getVersionIdentifierFromString

+ */

 public String toString() {

-	return getUniqueIdentifier()+VERSION_SEPARATOR_OPEN+getVersionIdentifier().toString()+VERSION_SEPARATOR_CLOSE;

+	return getUniqueIdentifier()+VERSION_SEPARATOR+getVersionIdentifier().toString();

 }

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginParser.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginParser.java
index c4add25..c1b762e 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginParser.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginParser.java
@@ -5,7 +5,7 @@
  * WebSphere Studio Workbench

  * (c) Copyright IBM Corp 2000

  */

-import org.eclipse.core.internal.plugins.IModel;

+

 import org.eclipse.core.runtime.model.*;

 import org.eclipse.core.runtime.*;

 import org.eclipse.core.internal.runtime.Policy;

@@ -32,6 +32,7 @@
 	private final int LIBRARY_EXPORT_STATE = 8;

 	private final int PLUGIN_REQUIRES_IMPORT_STATE = 9;

 	private final int CONFIGURATION_ELEMENT_STATE = 10;

+	private final int FRAGMENT_STATE = 11;

 

 	// Current State Information

 	Stack stateStack = new Stack();

@@ -52,8 +53,6 @@
 	private final int LAST_INDEX = 5;

 	Vector scratchVectors[] = new Vector[LAST_INDEX + 1];

 

-	PluginDescriptorModel pluginDescriptorTreeRoot;

-

 	// model parser

 	private SAXParser parser;

 

@@ -90,21 +89,22 @@
 			// shouldn't get here - do some error handling

 			break;

 		case PLUGIN_STATE :

-			if (elementName.equals(PLUGIN)) {

+		case FRAGMENT_STATE :

+			if (elementName.equals(PLUGIN) || elementName.equals(FRAGMENT)) {

 				stateStack.pop();

-				pluginDescriptorTreeRoot = (PluginDescriptorModel) objectStack.pop();

+				PluginModel root = (PluginModel) objectStack.peek();

 

 				// Put the extension points into this plugin

 				Vector extPointVector = scratchVectors[EXTENSION_POINT_INDEX];

 				if (extPointVector.size() > 0) {

-					pluginDescriptorTreeRoot.setDeclaredExtensionPoints((ExtensionPointModel[]) extPointVector.toArray(new ExtensionPointModel[extPointVector.size()]));

+					root.setDeclaredExtensionPoints((ExtensionPointModel[]) extPointVector.toArray(new ExtensionPointModel[extPointVector.size()]));

 					scratchVectors[EXTENSION_POINT_INDEX].removeAllElements();

 				}

 

 				// Put the extensions into this plugin too

 				Vector extVector = scratchVectors[EXTENSION_INDEX];

 				if (extVector.size() > 0) {

-					pluginDescriptorTreeRoot.setDeclaredExtensions((ExtensionModel[]) extVector.toArray(new ExtensionModel[extVector.size()]));

+					root.setDeclaredExtensions((ExtensionModel[]) extVector.toArray(new ExtensionModel[extVector.size()]));

 					scratchVectors[EXTENSION_INDEX].removeAllElements();

 				}

 			}

@@ -116,8 +116,8 @@
 				// descriptor

 				Vector libVector = scratchVectors[RUNTIME_INDEX];

 				if (libVector.size() > 0) {

-					PluginDescriptorModel pluginDescriptor = (PluginDescriptorModel) objectStack.peek();

-					pluginDescriptor.setRuntime((LibraryModel[]) libVector.toArray(new LibraryModel[libVector.size()]));

+					PluginModel model = (PluginModel) objectStack.peek();

+					model.setRuntime((LibraryModel[]) libVector.toArray(new LibraryModel[libVector.size()]));

 					scratchVectors[RUNTIME_INDEX].removeAllElements();

 				}

 			}

@@ -145,8 +145,8 @@
 				stateStack.pop();

 				// Finish up extension object

 				ExtensionModel currentExtension = (ExtensionModel) objectStack.pop();

-				PluginDescriptorModel parent = (PluginDescriptorModel) objectStack.peek();

-				currentExtension.setParentPluginDescriptor(parent);

+				PluginModel parent = (PluginModel) objectStack.peek();

+				currentExtension.setParent(parent);

 				scratchVectors[EXTENSION_INDEX].addElement(currentExtension);

 			}

 			break;

@@ -241,40 +241,41 @@
 	// configuration property for each attribute

 	parseConfigurationElementAttributes(attributes);

 }

-public void handleInitialState(String elementName, Attributes attributes) {

-	// The only valid element is a plugin

-	if (!elementName.equals(PLUGIN)) {

-		// We don't have a plugin, so ignore it.

-		stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+public void handleFragmentState(String elementName, Attributes attributes) {

+

+	if (elementName.equals(RUNTIME)) {

+		// Change State

+		stateStack.push(new Integer(PLUGIN_RUNTIME_STATE));

+		// All runtime attributes are ignored so no further parsing required.

+		return;

+	}

+	if (elementName.equals(EXTENSION_POINT)) {

+		// Change State

+		stateStack.push(new Integer(PLUGIN_EXTENSION_POINT_STATE));

+		// Pick up Extension Point Attributes

+		parseExtensionPointAttributes(attributes);

+		return;

+	}

+	if (elementName.equals(EXTENSION)) {

+		// Change State

+		stateStack.push(new Integer(PLUGIN_EXTENSION_STATE));

+		// Pick up Extension Attributes

+		parseExtensionAttributes(attributes);

 		return;

 	}

 

-	// Change State

-	stateStack.push(new Integer(PLUGIN_STATE));

-

-	// process attributes

-	int len = attributes.getLength();

-	PluginDescriptorModel currentPluginDescriptor = (PluginDescriptorModel) objectStack.peek();

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

-		String attrName = attributes.getLocalName(i);

-		String attrValue = attributes.getValue(i).trim();

-

-		// common (manifest and cached registry)

-		if (attrName.equals(PLUGIN_ID))

-			currentPluginDescriptor.setId(attrValue);

+	// If we get to this point, the element name is one we don't currently accept.

+	// Set the state to indicate that this element will be ignored

+	stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+}

+public void handleInitialState(String elementName, Attributes attributes) {

+	if (elementName.equals(PLUGIN))

+		processPlugin(elementName, attributes);

+	else

+		if (elementName.equals(FRAGMENT))

+			processFragment(elementName, attributes);

 		else

-			if (attrName.equals(PLUGIN_NAME))

-				currentPluginDescriptor.setName(attrValue);

-			else

-				if (attrName.equals(PLUGIN_VERSION))

-					currentPluginDescriptor.setVersion(attrValue);

-				else

-					if (attrName.equals(PLUGIN_VENDOR) || (attrName.equals(PLUGIN_PROVIDER)))

-						currentPluginDescriptor.setProviderName(attrValue);

-					else

-						if (attrName.equals(PLUGIN_CLASS))

-							currentPluginDescriptor.setPluginClass(attrValue);

-	}

+			stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

 }

 public void handleLibraryExportState(String elementName, Attributes attributes) {

 

@@ -391,11 +392,9 @@
 		msg = Policy.bind("parseErrorNameLineColumn", new String[] { name, Integer.toString(ex.getLineNumber()), Integer.toString(ex.getColumnNumber()), ex.getMessage()});

 	factory.error(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, msg, ex));

 }

-public PluginDescriptorModel parse(InputSource in) throws Exception {

-

+public PluginModel parse(InputSource in) throws Exception {

 	parser.parse(in);

-	return pluginDescriptorTreeRoot;

-

+	return (PluginModel) objectStack.pop();

 }

 public void parseConfigurationElementAttributes(Attributes attributes) {

 

@@ -422,7 +421,7 @@
 }

 public void parseExtensionAttributes(Attributes attributes) {

 

-	PluginDescriptorModel parentPluginDescriptor = (PluginDescriptorModel) objectStack.peek();

+	PluginModel parent = (PluginModel) objectStack.peek();

 

 	ExtensionModel currentExtension = factory.createExtension();

 	objectStack.push(currentExtension);

@@ -443,9 +442,10 @@
 				if (attrName.equals(EXTENSION_TARGET)) {

 					// check if point is specified as a simple or qualified name

 					String targetName;

-					if (attrValue.lastIndexOf('.') == -1)

-						targetName = parentPluginDescriptor.getId() + "." + attrValue;

-					else

+					if (attrValue.lastIndexOf('.') == -1) {

+						String baseId = parent instanceof PluginDescriptorModel ? parent.getId() : ((PluginFragmentModel) parent).getPlugin();

+						targetName = baseId + "." + attrValue;

+					} else

 						targetName = attrValue;

 					currentExtension.setExtensionPoint(targetName);

 				}

@@ -472,16 +472,15 @@
 					currentExtPoint.setSchema(attrValue);

 	}

 	// currentExtPoint contains a pointer to the parent plugin descriptor.

-	PluginDescriptorModel currentPluginDescriptor = (PluginDescriptorModel) objectStack.peek();

-	currentExtPoint.setParentPluginDescriptor(currentPluginDescriptor);

+	PluginModel root = (PluginModel) objectStack.peek();

+	currentExtPoint.setParent(root);

 

 	// Now populate the the vector just below us on the objectStack with this extension point

 	scratchVectors[EXTENSION_POINT_INDEX].addElement(currentExtPoint);

 }

 public void parseLibraryAttributes(Attributes attributes) {

-

-	LibraryModel currentLib = factory.createLibrary();

-	objectStack.push(currentLib);

+	LibraryModel current = factory.createLibrary();

+	objectStack.push(current);

 

 	// process attributes

 	int len = (attributes != null) ? attributes.getLength() : 0;

@@ -491,16 +490,17 @@
 

 		// common (manifest and cached registry)

 		if (attrName.equals(LIBRARY_NAME))

-			currentLib.setName(attrValue);

-		// library type attribute no longer supported

-		//		else

-		//			if (attrName.equals(LIBRARY_TYPE))

-		//				currentLib._setType(attrValue);

+			current.setName(attrValue);

+		else

+			if (attrName.equals(LIBRARY_TYPE))

+				current.setType(attrValue.toLowerCase());

+			else

+				if (attrName.equals(LIBRARY_SOURCE))

+					current.setSource(attrValue);

 	}

 }

 public void parsePluginRequiresImport(Attributes attributes) {

-

-	PluginPrerequisiteModel currentReq = factory.createPluginPrerequisite();

+	PluginPrerequisiteModel current = factory.createPluginPrerequisite();

 

 	// process attributes

 	int len = (attributes != null) ? attributes.getLength() : 0;

@@ -509,30 +509,33 @@
 		String attrValue = attributes.getValue(i).trim();

 

 		if (attrName.equals(PLUGIN_REQUIRES_PLUGIN))

-			currentReq.setPlugin(attrValue);

+			current.setPlugin(attrValue);

 		else

 			if (attrName.equals(PLUGIN_REQUIRES_PLUGIN_VERSION))

-				currentReq.setVersion(attrValue);

+				current.setVersion(attrValue);

 			else

-				if (attrName.equals(PLUGIN_REQUIRES_MATCH)) {

-					if (PLUGIN_REQUIRES_MATCH_EXACT.equals(attrValue))

-						currentReq.setMatch(true);

-					else

-						if (PLUGIN_REQUIRES_MATCH_COMPATIBLE.equals(attrValue))

-							currentReq.setMatch(false);

-					// XXX: else error handling

-				} else

-					if (attrName.equals(PLUGIN_REQUIRES_EXPORT)) {

-						if (TRUE.equals(attrValue))

-							currentReq.setExport(true);

+				if (attrName.equals(PLUGIN_REQUIRES_OPTIONAL))

+					current.setOptional("true".equalsIgnoreCase(attrValue));

+				else

+					if (attrName.equals(PLUGIN_REQUIRES_MATCH)) {

+						if (PLUGIN_REQUIRES_MATCH_EXACT.equals(attrValue))

+							current.setMatch(true);

 						else

-							if (FALSE.equals(attrValue))

-								currentReq.setExport(false);

+							if (PLUGIN_REQUIRES_MATCH_COMPATIBLE.equals(attrValue))

+								current.setMatch(false);

 						// XXX: else error handling

-					}

+					} else

+						if (attrName.equals(PLUGIN_REQUIRES_EXPORT)) {

+							if (TRUE.equals(attrValue))

+								current.setExport(true);

+							else

+								if (FALSE.equals(attrValue))

+									current.setExport(false);

+							// XXX: else error handling

+						}

 	}

 	// Populate the scratch vector of imports with this new element

-	scratchVectors[REQUIRES_INDEX].addElement(currentReq);

+	scratchVectors[REQUIRES_INDEX].addElement(current);

 }

 public void parseRequiresAttributes(Attributes attributes) {

 	// This attribute no longer supported

@@ -552,6 +555,68 @@
 	}

 	*/

 }

+public void processFragment(String elementName, Attributes attributes) {

+	// Change State

+	stateStack.push(new Integer(FRAGMENT_STATE));

+	PluginFragmentModel current = factory.createPluginFragment();

+	objectStack.push(current);

+

+	// process attributes

+	int len = attributes.getLength();

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		// common (manifest and cached registry)

+		if (attrName.equals(FRAGMENT_ID))

+			current.setId(attrValue);

+		else

+			if (attrName.equals(FRAGMENT_NAME))

+				current.setName(attrValue);

+			else

+				if (attrName.equals(FRAGMENT_VERSION))

+					current.setVersion(attrValue);

+				else

+					if (attrName.equals(FRAGMENT_PROVIDER))

+						current.setProviderName(attrValue);

+					else

+						if (attrName.equals(FRAGMENT_PLUGIN_ID))

+							current.setPlugin(attrValue);

+						else

+							if (attrName.equals(FRAGMENT_PLUGIN_VERSION))

+								current.setPluginVersion(attrValue);

+	}

+}

+public void processPlugin(String elementName, Attributes attributes) {

+

+	// Change State

+	stateStack.push(new Integer(PLUGIN_STATE));

+	PluginDescriptorModel current = factory.createPluginDescriptor();

+	objectStack.push(current);

+

+	// process attributes

+	int len = attributes.getLength();

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		// common (manifest and cached registry)

+		if (attrName.equals(PLUGIN_ID))

+			current.setId(attrValue);

+		else

+			if (attrName.equals(PLUGIN_NAME))

+				current.setName(attrValue);

+			else

+				if (attrName.equals(PLUGIN_VERSION))

+					current.setVersion(attrValue);

+				else

+					if (attrName.equals(PLUGIN_VENDOR) || (attrName.equals(PLUGIN_PROVIDER)))

+						current.setProviderName(attrValue);

+					else

+						if (attrName.equals(PLUGIN_CLASS))

+							current.setPluginClass(attrValue);

+	}

+}

 static String replace(String s, String from, String to) {

 	String str = s;

 	int fromLen = from.length();

@@ -565,7 +630,6 @@
 }

 public void startDocument() {

 	stateStack.push(new Integer(INITIAL_STATE));

-	objectStack.push(factory.createPluginDescriptor());

 	for (int i = 0; i <= LAST_INDEX; i++) {

 		scratchVectors[i] = new Vector();

 	}

@@ -575,6 +639,9 @@
 		case INITIAL_STATE :

 			handleInitialState(elementName, attributes);

 			break;

+		case FRAGMENT_STATE :

+			handlePluginState(elementName, attributes);

+			break;

 		case PLUGIN_STATE :

 			handlePluginState(elementName, attributes);

 			break;

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginPrerequisite.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginPrerequisite.java
index 88c2e9c..e4728bb 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginPrerequisite.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginPrerequisite.java
@@ -11,24 +11,48 @@
 import java.io.PrintWriter;

 

 public class PluginPrerequisite extends PluginPrerequisiteModel implements IPluginPrerequisite {

+/**

+ * @see IPluginPrerequisite

+ */

 public PluginVersionIdentifier getResolvedVersionIdentifier() {

 	String version = getResolvedVersion();

 	return version == null ? null : new PluginVersionIdentifier(version);

 }

+/**

+ * @see IPluginPrerequisite

+ */

 public String getUniqueIdentifier() {

 	return getPlugin();

 }

+/**

+ * @see IPluginPrerequisite

+ */

 public PluginVersionIdentifier getVersionIdentifier() {

 	String version = getVersion();

 	return version == null ? null : new PluginVersionIdentifier(version);

 }

+/**

+ * @see IPluginPrerequisite

+ */

 public boolean isExported() {

 	return getExport();

 }

+/**

+ * @see IPluginPrerequisite

+ */

 public boolean isMatchedAsCompatible() {

 	return !isMatchedAsExact();

 }

+/**

+ * @see IPluginPrerequisite

+ */

 public boolean isMatchedAsExact() {

 	return getMatch();

 }

+/**

+ * @see IPluginPrerequisite

+ */

+public boolean isOptional() {

+	return getOptional();

+}

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheReader.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheReader.java
index abb9e97..4a1af9d 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheReader.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheReader.java
@@ -11,59 +11,99 @@
 import java.io.DataInputStream;

 import java.io.IOException;

 import java.io.EOFException;

+import java.util.ArrayList;

 

 public class RegistryCacheReader {

 

 	Factory cacheFactory;

+	// objectTable will be an array list of objects.  The objects will be things 

+	// like a plugin descriptor, extension, extension point, etc.  The integer 

+	// index value will be used in the cache to allow cross-references in the 

+	// cached registry.

+	ArrayList objectTable = null;

 

-	public static final int REGISTRY_CACHE_VERSION = 1;

+	public static final byte REGISTRY_CACHE_VERSION = 1;

 

-	public static final int NONLABEL = 0;

-	public static final int READONLY_LABEL = 1;

-	public static final int NAME_LABEL = 2;

+	public static final byte NONLABEL = 0;

 

-	public static final int ID_LABEL = 10;

-	public static final int PLUGIN_PROVIDER_NAME_LABEL = 11;

-	public static final int VERSION_LABEL = 12;

-	public static final int PLUGIN_CLASS_LABEL = 13;

-	public static final int PLUGIN_LOCATION_LABEL = 14;

-	public static final int PLUGIN_ENABLED_LABEL = 15;

-	public static final int PLUGIN_REQUIRES_LABEL = 20;

-	public static final int PLUGIN_LIBRARY_LABEL = 30;

-	public static final int PLUGIN_EXTENSION_LABEL = 40;

-	public static final int PLUGIN_EXTENSION_POINT_LABEL = 50;

-	public static final int PLUGIN_END_LABEL = 19;

+	public static final byte CONFIGURATION_ELEMENT_END_LABEL = 1;

+	public static final byte CONFIGURATION_ELEMENT_INDEX_LABEL = 45;

+	public static final byte CONFIGURATION_ELEMENT_LABEL = 2;

+	public static final byte CONFIGURATION_ELEMENT_PARENT_LABEL = 3;

+	public static final byte CONFIGURATION_PROPERTY_END_LABEL = 4;

+	public static final byte CONFIGURATION_PROPERTY_LABEL = 5;

 

-	public static final int REQUIRES_MATCH_LABEL = 23;

-	public static final int REQUIRES_EXPORT_LABEL = 24;

-	public static final int REQUIRES_RESOLVED_VERSION_LABEL = 25;

-	public static final int REQUIRES_PLUGIN_NAME_LABEL = 26;

-	public static final int REQUIRES_END_LABEL = 29;

+	public static final byte EXTENSION_END_LABEL = 6;

+	public static final byte EXTENSION_EXT_POINT_NAME_LABEL = 7;

+	public static final byte EXTENSION_INDEX_LABEL = 8;

+	public static final byte EXTENSION_PARENT_LABEL = 9;

 

-	public static final int LIBRARY_EXPORTS_LENGTH_LABEL = 31;

-	public static final int LIBRARY_EXPORTS_LABEL = 32;

-	public static final int LIBRARY_END_LABEL = 39;

+	public static final byte EXTENSION_POINT_END_LABEL = 10;

+	public static final byte EXTENSION_POINT_EXTENSIONS_LENGTH_LABEL = 11;

+	public static final byte EXTENSION_POINT_EXTENSIONS_LABEL = 12;

+	public static final byte EXTENSION_POINT_PARENT_LABEL = 13;

+	public static final byte EXTENSION_POINT_SCHEMA_LABEL = 14;

 

-	public static final int EXTENSION_EXT_POINT_NAME_LABEL = 41;

-	public static final int SUBELEMENTS_LENGTH_LABEL = 42;

-	public static final int EXTENSION_END_LABEL = 49;

+	public static final byte ID_LABEL = 15;

+	public static final byte LIBRARY_END_LABEL = 16;

+	public static final byte LIBRARY_EXPORTS_LABEL = 17;

+	public static final byte LIBRARY_EXPORTS_LENGTH_LABEL = 18;

+	public static final byte NAME_LABEL = 19;

 

-	public static final int EXTENSION_POINT_SCHEMA_LABEL = 51;

-	public static final int EXTENSION_POINT_EXTENSIONS_LABEL = 52;

-	public static final int EXTENSION_POINT_END_LABEL = 59;

+	public static final byte PLUGIN_CLASS_LABEL = 20;

+	public static final byte PLUGIN_ENABLED_LABEL = 21;

+	public static final byte PLUGIN_END_LABEL = 22;

+	public static final byte PLUGIN_EXTENSION_LABEL = 23;

+	public static final byte PLUGIN_EXTENSION_POINT_LABEL = 24;

+	public static final byte PLUGIN_INDEX_LABEL = 25;

+	public static final byte PLUGIN_LABEL = 26;

+	public static final byte PLUGIN_LOCATION_LABEL = 27;

+	public static final byte PLUGIN_LIBRARY_LABEL = 28;

+	public static final byte PLUGIN_PARENT_LABEL = 29;

+	public static final byte PLUGIN_PROVIDER_NAME_LABEL = 30;

+	public static final byte PLUGIN_REQUIRES_LABEL = 31;

 

-	public static final int CONFIGURATION_ELEMENT_LABEL = 60;

-	public static final int VALUE_LABEL = 61;

-	public static final int PROPERTIES_LENGTH_LABEL = 62;

-	public static final int CONFIGURATION_ELEMENT_END_LABEL = 69;

-

-	public static final int CONFIGURATION_PROPERTY_LABEL = 70;

-	public static final int CONFIGURATION_PROPERTY_END_LABEL = 79;

+	public static final byte PROPERTIES_LENGTH_LABEL = 32;

+	public static final byte READONLY_LABEL = 33;

+	public static final byte REGISTRY_END_LABEL = 34;

+	public static final byte REGISTRY_INDEX_LABEL = 46;

+	public static final byte REGISTRY_LABEL = 35;

+	public static final byte REGISTRY_RESOLVED_LABEL = 36;

+	public static final byte REQUIRES_END_LABEL = 37;

+	public static final byte REQUIRES_EXPORT_LABEL = 38;

+	public static final byte REQUIRES_MATCH_LABEL = 39;

+	public static final byte REQUIRES_PLUGIN_NAME_LABEL = 40;

+	public static final byte REQUIRES_RESOLVED_VERSION_LABEL = 41;

+	public static final byte SUBELEMENTS_LENGTH_LABEL = 42;

+	public static final byte VALUE_LABEL = 43;

+	public static final byte VERSION_LABEL = 44;

 public RegistryCacheReader(Factory factory) {

 	super();

 	cacheFactory = factory;

+	objectTable = null;

+}

+public int addToObjectTable(Object object) {

+	if (objectTable == null) {

+		objectTable = new ArrayList();

+	}

+	objectTable.add(object);

+	// return the index of the object just added (i.e. size - 1)

+	return (objectTable.size() - 1);

+

 }

 public int decipherLabel(String labelString) {

+	if (labelString.equals("<registry>")) {

+		return REGISTRY_LABEL;

+	}

+	if (labelString.equals("<resolved>")) {

+		return REGISTRY_RESOLVED_LABEL;

+	}

+	if (labelString.equals("<plugin>")) {

+		return PLUGIN_LABEL;

+	}

+	if (labelString.equals("<endregistry>")) {

+		return REGISTRY_END_LABEL;

+	}

 	if (labelString.equals("<readonly>")) {

 		return READONLY_LABEL;

 	}

@@ -97,7 +137,7 @@
 	if (labelString.equals("<extension>")) {

 		return PLUGIN_EXTENSION_LABEL;

 	}

-	if (labelString.equals("<extension_point>")) {

+	if (labelString.equals("<extensionPoint>")) {

 		return PLUGIN_EXTENSION_POINT_LABEL;

 	}

 	if (labelString.equals("<endplugin>")) {

@@ -133,6 +173,64 @@
 	if (labelString.equals("<endextensionPoint>")) {

 		return EXTENSION_POINT_END_LABEL;

 	}

+	if (labelString.equals("<extension-extPt-name>")) {

+		return EXTENSION_EXT_POINT_NAME_LABEL;

+	}

+	if (labelString.equals("<subElements-length>")) {

+		return SUBELEMENTS_LENGTH_LABEL;

+	}

+	if (labelString.equals("<endextension>")) {

+		return EXTENSION_END_LABEL;

+	}

+	if (labelString.equals("<configuration-element>")) {

+		return CONFIGURATION_ELEMENT_LABEL;

+	}

+	if (labelString.equals("<value>")) {

+		return VALUE_LABEL;

+	}

+	if (labelString.equals("<properties-length>")) {

+		return PROPERTIES_LENGTH_LABEL;

+	}

+	if (labelString.equals("<endconfiguration-element>")) {

+		return CONFIGURATION_ELEMENT_END_LABEL;

+	}

+	if (labelString.equals("<configuration-property>")) {

+		return CONFIGURATION_PROPERTY_LABEL;

+	}

+	if (labelString.equals("<endconfiguration-property>")) {

+		return CONFIGURATION_PROPERTY_END_LABEL;

+	}

+	if (labelString.equals("<parentRegistry>")) {

+		return PLUGIN_PARENT_LABEL;

+	}

+	if (labelString.equals("<ConfigurationElementParent>")) {

+		return CONFIGURATION_ELEMENT_PARENT_LABEL;

+	}

+	if (labelString.equals("<pluginIndex>")) {

+		return PLUGIN_INDEX_LABEL;

+	}

+	if (labelString.equals("<extensionIndex>")) {

+		return EXTENSION_INDEX_LABEL;

+	}

+	if (labelString.equals("<ExtensionPointParent>")) {

+		return EXTENSION_POINT_PARENT_LABEL;

+	}

+	if (labelString.equals("<extensionPointExtensionsLength>")) {

+		return EXTENSION_POINT_EXTENSIONS_LENGTH_LABEL;

+	}

+	if (labelString.equals("<extensionPointExtensions>")) {

+		return EXTENSION_POINT_EXTENSIONS_LABEL;

+	}

+	if (labelString.equals("<extensionParent>")) {

+		return EXTENSION_PARENT_LABEL;

+	}

+	if (labelString.equals("<configElementIndex>")) {

+		return CONFIGURATION_ELEMENT_INDEX_LABEL;

+	}

+	if (labelString.equals("<registryIndex>")) {

+		return REGISTRY_INDEX_LABEL;

+	}

+

 	return NONLABEL;

 }

 public boolean interpretHeaderInformation(DataInputStream in) {

@@ -157,18 +255,19 @@
 	// Use this flag to determine if the read-only flag should be set.  You

 	// can't set it now or you won't be able to add anything more to this

 	// configuration element.

+	addToObjectTable(configurationElement);

 	boolean setReadOnlyFlag = false;

 	try {

-		String inString = null;

+		byte inByte = 0;

 		boolean done = false;

 		while (!done) {

 			try {

-				inString = in.readUTF();

+				inByte = in.readByte();

 			} catch (EOFException eofe) {

 				done = true;

 				break;

 			}

-			switch (decipherLabel(inString)) {

+			switch (inByte) {

 				case READONLY_LABEL :

 					if (in.readBoolean()) {

 						setReadOnlyFlag = true;

@@ -193,11 +292,23 @@
 					int subElementsLength = in.readInt();

 					ConfigurationElementModel[] subElements = new ConfigurationElementModel[subElementsLength];

 					for (int i = 0; i < subElementsLength; i++) {

-						subElements[i] = readConfigurationElement(in);

+						// Do we have an index or a real configuration element?

+						switch (in.readByte()) {

+							case CONFIGURATION_ELEMENT_LABEL :

+								subElements[i] = readConfigurationElement(in);

+								break;

+							case CONFIGURATION_ELEMENT_INDEX_LABEL :

+								subElements[i] = (ConfigurationElementModel) objectTable.get(in.readInt());

+								break;

+						}

 					}

 					configurationElement.setSubElements(subElements);

 					subElements = null;

 					break;

+				case CONFIGURATION_ELEMENT_PARENT_LABEL :

+					// We know the parent already exists, just grab it.

+					configurationElement.setParent(objectTable.get(in.readInt()));

+					break;

 				case CONFIGURATION_ELEMENT_END_LABEL :

 					done = true;

 			}

@@ -205,9 +316,6 @@
 	} catch (IOException ioe) {

 		return null;

 	}

-	if (setReadOnlyFlag) {

-		configurationElement.markReadOnly();

-	}

 	return configurationElement;

 }

 public ConfigurationPropertyModel readConfigurationProperty(DataInputStream in) {

@@ -217,16 +325,16 @@
 	// configuration property.

 	boolean setReadOnlyFlag = false;

 	try {

-		String inString = null;

+		byte inByte = 0;

 		boolean done = false;

 		while (!done) {

 			try {

-				inString = in.readUTF();

+				inByte = in.readByte();

 			} catch (EOFException eofe) {

 				done = true;

 				break;

 			}

-			switch (decipherLabel(inString)) {

+			switch (inByte) {

 				case READONLY_LABEL :

 					if (in.readBoolean()) {

 						setReadOnlyFlag = true;

@@ -245,28 +353,26 @@
 	} catch (IOException ioe) {

 		return null;

 	}

-	if (setReadOnlyFlag) {

-		configurationProperty.markReadOnly();

-	}

 	return configurationProperty;

 }

 public ExtensionModel readExtension(DataInputStream in) {

 	ExtensionModel extension = cacheFactory.createExtension();

+	addToObjectTable(extension);

 	// Use this flag to determine if the read-only flag should be set.  You

 	// can't set it now or you won't be able to add anything more to this

 	// extension.

 	boolean setReadOnlyFlag = false;

 	try {

-		String inString = null;

+		byte inByte = 0;

 		boolean done = false;

 		while (!done) {

 			try {

-				inString = in.readUTF();

+				inByte = in.readByte();

 			} catch (EOFException eofe) {

 				done = true;

 				break;

 			}

-			switch (decipherLabel(inString)) {

+			switch (inByte) {

 				case READONLY_LABEL :

 					if (in.readBoolean()) {

 						setReadOnlyFlag = true;

@@ -285,40 +391,61 @@
 					int subElementsLength = in.readInt();

 					ConfigurationElementModel[] subElements = new ConfigurationElementModel[subElementsLength];

 					for (int i = 0; i < subElementsLength; i++) {

-						subElements[i] = readConfigurationElement(in);

+						// Do we have a configuration element or an index into

+						// objectTable?

+						switch (in.readByte()) {

+							case CONFIGURATION_ELEMENT_LABEL :

+								subElements[i] = readConfigurationElement(in);

+								break;

+							case CONFIGURATION_ELEMENT_INDEX_LABEL :

+								subElements[i] = (ConfigurationElementModel) objectTable.get(in.readInt());

+								break;

+						}

 					}

 					extension.setSubElements(subElements);

 					subElements = null;

 					break;

-				case EXTENSION_POINT_END_LABEL :

+				case EXTENSION_PARENT_LABEL :

+					// Either there is a plugin or there is an index into the

+					// objectTable

+					switch (in.readByte()) {

+						case PLUGIN_LABEL :

+							extension.setParentPluginDescriptor(readPluginDescriptor(in));

+							break;

+						case PLUGIN_INDEX_LABEL :

+							extension.setParentPluginDescriptor((PluginDescriptorModel) objectTable.get(in.readInt()));

+							break;

+					}

+					break;

+				case EXTENSION_END_LABEL :

 					done = true;

 			}

 		}

 	} catch (IOException ioe) {

 		return null;

 	}

-	if (setReadOnlyFlag) {

-		extension.markReadOnly();

-	}

 	return extension;

 }

 public ExtensionPointModel readExtensionPoint(DataInputStream in) {

 	ExtensionPointModel extPoint = cacheFactory.createExtensionPoint();

+	addToObjectTable(extPoint);

+

 	// Use this flag to determine if the read-only flag should be set.  You

 	// can't set it now or you won't be able to add anything more to this

 	// extension point.

 	boolean setReadOnlyFlag = false;

+	int extensionLength = 0;

 	try {

-		String inString = null;

+		byte inByte = 0;

 		boolean done = false;

 		while (!done) {

 			try {

-				inString = in.readUTF();

+				inByte = in.readByte();

 			} catch (EOFException eofe) {

 				done = true;

 				break;

 			}

-			switch (decipherLabel(inString)) {

+			switch (inByte) {

 				case READONLY_LABEL :

 					if (in.readBoolean()) {

 						setReadOnlyFlag = true;

@@ -333,8 +460,28 @@
 				case EXTENSION_POINT_SCHEMA_LABEL :

 					extPoint.setSchema(in.readUTF());

 					break;

+				case EXTENSION_POINT_EXTENSIONS_LENGTH_LABEL :

+					extensionLength = in.readInt();

+					break;

 				case EXTENSION_POINT_EXTENSIONS_LABEL :

-					// Add stuff here

+					ExtensionModel[] extensions = new ExtensionModel[extensionLength];

+					for (int i = 0; i < extensionLength; i++) {

+						switch (in.readByte()) {

+							// Either this is an extension or an index into

+							// the objectTable

+							case PLUGIN_EXTENSION_LABEL :

+								extensions[i] = readExtension(in);

+								break;

+							case EXTENSION_INDEX_LABEL :

+								extensions[i] = (ExtensionModel) objectTable.get(in.readInt());

+								break;

+						}

+					}

+					extPoint.setDeclaredExtensions(extensions);

+					break;

+				case EXTENSION_POINT_PARENT_LABEL :

+					// We know this plugin is already in the objectTable

+					extPoint.setParentPluginDescriptor((PluginDescriptorModel) objectTable.get(in.readInt()));

 					break;

 				case EXTENSION_POINT_END_LABEL :

 					done = true;

@@ -343,9 +490,6 @@
 	} catch (IOException ioe) {

 		return null;

 	}

-	if (setReadOnlyFlag) {

-		extPoint.markReadOnly();

-	}

 	return extPoint;

 }

 public LibraryModel readLibrary(DataInputStream in) {

@@ -356,16 +500,16 @@
 	boolean setReadOnlyFlag = false;

 	int exportsLength = 0;

 	try {

-		String inString = null;

+		byte inByte = 0;

 		boolean done = false;

 		while (!done) {

 			try {

-				inString = in.readUTF();

+				inByte = in.readByte();

 			} catch (EOFException eofe) {

 				done = true;

 				break;

 			}

-			switch (decipherLabel(inString)) {

+			switch (inByte) {

 				case READONLY_LABEL :

 					if (in.readBoolean()) {

 						setReadOnlyFlag = true;

@@ -392,36 +536,26 @@
 	} catch (IOException ioe) {

 		return null;

 	}

-	if (setReadOnlyFlag) {

-		library.markReadOnly();

-	}

 	return library;

 }

 public PluginDescriptorModel readPluginDescriptor(DataInputStream in) {

-	try {

-		String inString = in.readUTF();

-		if (!inString.equals("<plugin>")) {

-			return null;

-		}

-	} catch (IOException ioe) {

-		return null;

-	}

 	PluginDescriptorModel plugin = cacheFactory.createPluginDescriptor();

+	addToObjectTable(plugin);

 	// Use this flag to determine if the read-only flag should be set.  You

 	// can't set it now or you won't be able to add anything more to this

 	// plugin.

 	boolean setReadOnlyFlag = false;

 	try {

-		String inString = null;

+		byte inByte = 0;

 		boolean done = false;

 		while (!done) {

 			try {

-				inString = in.readUTF();

+				inByte = in.readByte();

 			} catch (EOFException eofe) {

 				done = true;

 				break;

 			}

-			switch (decipherLabel(inString)) {

+			switch (inByte) {

 				case READONLY_LABEL :

 					if (in.readBoolean()) {

 						setReadOnlyFlag = true;

@@ -498,6 +632,22 @@
 					extension = null;

 					extList = newExtValues = null;

 					break;

+				case EXTENSION_INDEX_LABEL :

+					extension = (ExtensionModel) objectTable.get(in.readInt());

+					extList = plugin.getDeclaredExtensions();

+					newExtValues = null;

+					if (extList == null) {

+						newExtValues = new ExtensionModel[1];

+						newExtValues[0] = extension;

+					} else {

+						newExtValues = new ExtensionModel[extList.length + 1];

+						System.arraycopy(extList, 0, newExtValues, 0, extList.length);

+						newExtValues[extList.length] = extension;

+					}

+					plugin.setDeclaredExtensions(newExtValues);

+					extension = null;

+					extList = newExtValues = null;

+					break;

 				case PLUGIN_EXTENSION_POINT_LABEL :

 					ExtensionPointModel extensionPoint = readExtensionPoint(in);

 					// Add this extension point to the end of the extension point list

@@ -515,6 +665,9 @@
 					extensionPoint = null;

 					extPointList = newExtPointValues = null;

 					break;

+				case PLUGIN_PARENT_LABEL :

+					plugin.setRegistry((PluginRegistryModel) objectTable.get(in.readInt()));

+					break;

 				case PLUGIN_END_LABEL :

 					done = true;

 			}

@@ -522,9 +675,6 @@
 	} catch (IOException ioe) {

 		return null;

 	}

-	if (setReadOnlyFlag) {

-		plugin.markReadOnly();

-	}

 	return plugin;

 }

 public PluginPrerequisiteModel readPluginPrerequisite(DataInputStream in) {

@@ -534,16 +684,16 @@
 	// prerequisite.

 	boolean setReadOnlyFlag = false;

 	try {

-		String inString = null;

+		byte inByte = 0;

 		boolean done = false;

 		while (!done) {

 			try {

-				inString = in.readUTF();

+				inByte = in.readByte();

 			} catch (EOFException eofe) {

 				done = true;

 				break;

 			}

-			switch (decipherLabel(inString)) {

+			switch (inByte) {

 				case READONLY_LABEL :

 					if (in.readBoolean()) {

 						setReadOnlyFlag = true;

@@ -574,9 +724,6 @@
 	} catch (IOException ioe) {

 		return null;

 	}

-	if (setReadOnlyFlag) {

-		requires.markReadOnly();

-	}

 	return requires;

 }

 public PluginRegistryModel readPluginRegistry(DataInputStream in) {

@@ -584,12 +731,60 @@
 		return null;

 	}

 	PluginRegistryModel cachedRegistry = cacheFactory.createPluginRegistry();

-	PluginDescriptorModel plugin = null;

-	while ((plugin = readPluginDescriptor(in)) != null) {

-		cachedRegistry.addPlugin(plugin);

+	addToObjectTable(cachedRegistry);

+

+	boolean setReadOnlyFlag = false;

+	try {

+		byte inByte = 0;

+		boolean done = false;

+		while (!done) {

+			try {

+				inByte = in.readByte();

+			} catch (EOFException eofe) {

+				done = true;

+				break;

+			}

+			switch (inByte) {

+				case READONLY_LABEL :

+					if (in.readBoolean()) {

+						setReadOnlyFlag = true;

+					}

+					break;

+				case REGISTRY_RESOLVED_LABEL :

+					if (in.readBoolean()) {

+						cachedRegistry.markResolved();

+					}

+					break;

+				case PLUGIN_LABEL :

+					PluginDescriptorModel plugin = null;

+					if ((plugin = readPluginDescriptor(in)) != null) {

+						cachedRegistry.addPlugin(plugin);

+					}

+					break;

+				case PLUGIN_INDEX_LABEL :

+					plugin = (PluginDescriptorModel) objectTable.get(in.readInt());

+					cachedRegistry.addPlugin(plugin);

+					break;

+				case REGISTRY_END_LABEL :

+					done = true;

+			}

+		}

+	} catch (IOException ioe) {

+		return null;

+	}

+	if (setReadOnlyFlag) {

+		// If we are finished reading this registry, we don't need to worry

+		// about setting the read-only flag on other objects we might wish

+		// to write to.  So, just to be safe, mark the whole thing.

+		cachedRegistry.markReadOnly();

 	}

 	// if there are no plugins in the registry, return null instead of

 	// an empty registry?

-	return cachedRegistry;

+	PluginDescriptorModel[] pluginList = cachedRegistry.getPlugins();

+	if ((pluginList == null) || (pluginList.length == 0)) {

+		return null;

+	} else {

+		return cachedRegistry;

+	}

 }

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheWriter.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheWriter.java
index 22133a4..9725da8 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheWriter.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheWriter.java
@@ -9,37 +9,63 @@
 import org.eclipse.core.runtime.model.*;

 import java.io.DataOutputStream;

 import java.io.IOException;

+import java.util.ArrayList;

 

 public class RegistryCacheWriter {

-	// Want this for the writer and the reader.  Where is a good place to

-	// hold this?  On the PluginRegistryModel?  But it isn't the registry

-	// version.

-	public static final int REGISTRY_CACHE_VERSION = 1;

+	// See RegistryCacheReader for constants commonly used here too.

+

+	// objectTable will be an array list of objects.  The objects will be things 

+	// like a plugin descriptor, extension, extension point, etc.  The integer 

+	// index value will be used in the cache to allow cross-references in the 

+	// cached registry.

+	ArrayList objectTable = null;

 public RegistryCacheWriter() {

 	super();

 }

+public int addToObjectTable(Object object) {

+	if (objectTable == null) {

+		objectTable = new ArrayList();

+	}

+	objectTable.add(object);

+	// return the index of the object just added (i.e. size - 1)

+	return (objectTable.size() - 1);

+

+}

 public void writeConfigurationElement(ConfigurationElementModel configElement, DataOutputStream out) {

 	try {

+		// Check to see if this configuration element already exists in the

+		// objectTable.  If it is there, it has already been written to the 

+		// cache so just write out the index.

+		int configElementIndex = objectTable.indexOf(configElement);

+		if (configElementIndex != -1) {

+			// this extension is already there

+			out.writeByte(RegistryCacheReader.CONFIGURATION_ELEMENT_INDEX_LABEL);

+			out.writeInt(configElementIndex);

+			return;

+		}

+

 		String outString;

+		// add this object to the object table first

+		addToObjectTable(configElement);

 

-		out.writeUTF("<configuration-element>");

+		out.writeByte(RegistryCacheReader.CONFIGURATION_ELEMENT_LABEL);

 

-		out.writeUTF("<readonly>");

+		out.writeByte(RegistryCacheReader.READONLY_LABEL);

 		out.writeBoolean(configElement.isReadOnly());

 

 		if ((outString = configElement.getName()) != null) {

-			out.writeUTF("<name>");

+			out.writeByte(RegistryCacheReader.NAME_LABEL);

 			out.writeUTF(outString);

 		}

 

 		if ((outString = configElement.getValue()) != null) {

-			out.writeUTF("<value>");

+			out.writeByte(RegistryCacheReader.VALUE_LABEL);

 			out.writeUTF(outString);

 		}

 

 		ConfigurationPropertyModel[] properties = configElement.getProperties();

 		if (properties != null) {

-			out.writeUTF("<properties-length>");

+			out.writeByte(RegistryCacheReader.PROPERTIES_LENGTH_LABEL);

 			out.writeInt(properties.length);

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

 				writeConfigurationProperty(properties[i], out);

@@ -48,14 +74,21 @@
 

 		ConfigurationElementModel[] subElements = configElement.getSubElements();

 		if (subElements != null) {

-			out.writeUTF("<subElements-length>");

+			out.writeByte(RegistryCacheReader.SUBELEMENTS_LENGTH_LABEL);

 			out.writeInt(subElements.length);

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

 				writeConfigurationElement(subElements[i], out);

 			}

 		}

 

-		out.writeUTF("<endconfiguration-element>");

+		// Write out the parent information.  We can assume that the parent has

+		// already been written out.

+		// Add the index to the registry object for this plugin

+		Object parent = configElement.getParent();

+		out.writeByte(RegistryCacheReader.CONFIGURATION_ELEMENT_PARENT_LABEL);

+		out.writeInt(objectTable.indexOf(parent));

+

+		out.writeByte(RegistryCacheReader.CONFIGURATION_ELEMENT_END_LABEL);

 	} catch (IOException ioe) {

 	}

 }

@@ -63,98 +96,152 @@
 	try {

 		String outString;

 

-		out.writeUTF("<configuration-element>");

+		out.writeByte(RegistryCacheReader.CONFIGURATION_PROPERTY_LABEL);

 

-		out.writeUTF("<readonly>");

+		out.writeByte(RegistryCacheReader.READONLY_LABEL);

 		out.writeBoolean(configProperty.isReadOnly());

 

 		if ((outString = configProperty.getName()) != null) {

-			out.writeUTF("<name>");

+			out.writeByte(RegistryCacheReader.NAME_LABEL);

 			out.writeUTF(outString);

 		}

 

 		if ((outString = configProperty.getValue()) != null) {

-			out.writeUTF("<value>");

+			out.writeByte(RegistryCacheReader.VALUE_LABEL);

 			out.writeUTF(outString);

 		}

 

-		out.writeUTF("<endconfiguration-property>");

+		out.writeByte(RegistryCacheReader.CONFIGURATION_PROPERTY_END_LABEL);

 	} catch (IOException ioe) {

 	}

 }

 public void writeExtension(ExtensionModel extension, DataOutputStream out) {

 	try {

+		// Check to see if this extension already exists in the objectTable.  If it

+		// is there, it has already been written to the cache so just write out

+		// the index.

+		int extensionIndex = objectTable.indexOf(extension);

+		if (extensionIndex != -1) {

+			// this extension is already there

+			out.writeByte(RegistryCacheReader.EXTENSION_INDEX_LABEL);

+			out.writeInt(extensionIndex);

+			return;

+		}

+		// add this object to the object table first

+		addToObjectTable(extension);

+

 		String outString;

 

-		out.writeUTF("<extension>");

+		out.writeByte(RegistryCacheReader.PLUGIN_EXTENSION_LABEL);

 

-		out.writeUTF("<readonly>");

+		out.writeByte(RegistryCacheReader.READONLY_LABEL);

 		out.writeBoolean(extension.isReadOnly());

 

 		if ((outString = extension.getName()) != null) {

-			out.writeUTF("<name>");

+			out.writeByte(RegistryCacheReader.NAME_LABEL);

 			out.writeUTF(outString);

 		}

 

 		if ((outString = extension.getExtensionPoint()) != null) {

-			out.writeUTF("<extension-extPt-name>");

+			out.writeByte(RegistryCacheReader.EXTENSION_EXT_POINT_NAME_LABEL);

 			out.writeUTF(outString);

 		}

 

 		if ((outString = extension.getId()) != null) {

-			out.writeUTF("<id>");

+			out.writeByte(RegistryCacheReader.ID_LABEL);

 			out.writeUTF(outString);

 		}

 

 		ConfigurationElementModel[] subElements = extension.getSubElements();

 		if (subElements != null) {

-			out.writeUTF("<subElements-length>");

+			out.writeByte(RegistryCacheReader.SUBELEMENTS_LENGTH_LABEL);

 			out.writeInt(subElements.length);

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

 				writeConfigurationElement(subElements[i], out);

 			}

 		}

 

-		out.writeUTF("<endextension>");

+		// Now worry about the parent plugin descriptor

+		PluginDescriptorModel parentPlugin = extension.getParentPluginDescriptor();

+		int pluginIndex = objectTable.indexOf(parentPlugin);

+		out.writeByte(RegistryCacheReader.EXTENSION_PARENT_LABEL);

+		if (pluginIndex != -1) {

+			// We have already written this plugin.  Just use the index.

+			out.writeByte(RegistryCacheReader.PLUGIN_INDEX_LABEL);

+			out.writeInt(pluginIndex);

+		} else {

+			// We haven't visited this plugin yet, so write it explicitly

+			writePluginDescriptor(parentPlugin, out);

+		}

+

+		out.writeByte(RegistryCacheReader.EXTENSION_END_LABEL);

 	} catch (IOException ioe) {

 	}

 }

 public void writeExtensionPoint(ExtensionPointModel extPoint, DataOutputStream out) {

+	// add this object to the object table first

+	addToObjectTable(extPoint);

 	try {

 		String outString;

 

-		out.writeUTF("<extensionPoint>");

+		out.writeByte(RegistryCacheReader.PLUGIN_EXTENSION_POINT_LABEL);

 

-		out.writeUTF("<readonly>");

+		out.writeByte(RegistryCacheReader.READONLY_LABEL);

 		out.writeBoolean(extPoint.isReadOnly());

 

 		if ((outString = extPoint.getName()) != null) {

-			out.writeUTF("<name>");

+			out.writeByte(RegistryCacheReader.NAME_LABEL);

 			out.writeUTF(outString);

 		}

 

 		if ((outString = extPoint.getId()) != null) {

-			out.writeUTF("<id>");

+			out.writeByte(RegistryCacheReader.ID_LABEL);

 			out.writeUTF(outString);

 		}

 

 		if ((outString = extPoint.getSchema()) != null) {

-			out.writeUTF("<schema>");

+			out.writeByte(RegistryCacheReader.EXTENSION_POINT_SCHEMA_LABEL);

 			out.writeUTF(outString);

 		}

 

+		// Write out the parent plugin descriptor's index.  We know we have

+		// already written this plugin to the cache

+		PluginDescriptorModel plugin = extPoint.getParentPluginDescriptor();

+		if (plugin != null) {

+			int pluginIndex = objectTable.indexOf(plugin);

+			if (pluginIndex != -1) {

+				out.writeByte(RegistryCacheReader.EXTENSION_POINT_PARENT_LABEL);

+				out.writeInt(pluginIndex);

+			}

+		}

+

 		// Now do the extensions.

 		ExtensionModel[] extensions = extPoint.getDeclaredExtensions();

-		if (extensions != null) {

+		int extLength = extensions == null ? 0 : extensions.length;

+		if (extLength != 0) {

+			out.writeByte(RegistryCacheReader.EXTENSION_POINT_EXTENSIONS_LENGTH_LABEL);

+			out.writeInt(extLength);

+			out.writeByte(RegistryCacheReader.EXTENSION_POINT_EXTENSIONS_LABEL);

+			for (int i = 0; i < extLength; i++) {

+				// Check to see if the extension exists in the objectTable first

+				int extensionIndex = objectTable.indexOf(extensions[i]);

+				if (extensionIndex != -1) {

+					// Already in the objectTable and written to the cache

+					out.writeByte(RegistryCacheReader.EXTENSION_INDEX_LABEL);

+					out.writeInt(extensionIndex);

+				} else {

+					writeExtension(extensions[i], out);

+				}

+			}

 		}

 

-		out.writeUTF("<endextensionPoint>");

+		out.writeByte(RegistryCacheReader.EXTENSION_POINT_END_LABEL);

 	} catch (IOException ioe) {

 	}

 }

 public void writeHeaderInformation(DataOutputStream out) {

 	try {

-		out.writeInt(REGISTRY_CACHE_VERSION);

+		out.writeInt(RegistryCacheReader.REGISTRY_CACHE_VERSION);

 		// output some stamps too

 		// windows system stamp

 		// OS stamp

@@ -167,21 +254,21 @@
 	try {

 		String outString;

 

-		out.writeUTF("<library>");

+		out.writeByte(RegistryCacheReader.PLUGIN_LIBRARY_LABEL);

 

-		out.writeUTF("<readonly>");

+		out.writeByte(RegistryCacheReader.READONLY_LABEL);

 		out.writeBoolean(library.isReadOnly());

 

 		if ((outString = library.getName()) != null) {

-			out.writeUTF("<name>");

+			out.writeByte(RegistryCacheReader.NAME_LABEL);

 			out.writeUTF(outString);

 		}

 

 		String[] exports = null;

 		if ((exports = library.getExports()) != null) {

-			out.writeUTF("<exports-length>");

+			out.writeByte(RegistryCacheReader.LIBRARY_EXPORTS_LENGTH_LABEL);

 			out.writeInt(exports.length);

-			out.writeUTF("<exports>");

+			out.writeByte(RegistryCacheReader.LIBRARY_EXPORTS_LABEL);

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

 				out.writeUTF(exports[i]);

 			}

@@ -190,42 +277,55 @@
 		// Don't bother caching 'isExported' and 'isFullyExported'.  There

 		// is no way of explicitly setting these fields.  They are computed

 		// from the values in the 'exports' list.

-		out.writeUTF("<endlibrary>");

+		out.writeByte(RegistryCacheReader.LIBRARY_END_LABEL);

 	} catch (IOException ioe) {

 	}

 }

 public void writePluginDescriptor(PluginDescriptorModel plugin, DataOutputStream out) {

+

 	try {

+		// Check to see if this plugin already exists in the objectTable.  If it is there,

+		// it has already been written to the cache so just write out the index.

+		int pluginIndex = objectTable.indexOf(plugin);

+		if (pluginIndex != -1) {

+			// this plugin is already there

+			out.writeByte(RegistryCacheReader.PLUGIN_INDEX_LABEL);

+			out.writeInt(pluginIndex);

+			return;

+		}

+

+		// add this object to the object table first

+		addToObjectTable(plugin);

 		String outString;

 

-		out.writeUTF("<plugin>");

-		out.writeUTF("<readonly>");

+		out.writeByte(RegistryCacheReader.PLUGIN_LABEL);

+		out.writeByte(RegistryCacheReader.READONLY_LABEL);

 		out.writeBoolean(plugin.isReadOnly());

 		if ((outString = plugin.getName()) != null) {

-			out.writeUTF("<name>");

+			out.writeByte(RegistryCacheReader.NAME_LABEL);

 			out.writeUTF(outString);

 		}

 		if ((outString = plugin.getId()) != null) {

-			out.writeUTF("<id>");

+			out.writeByte(RegistryCacheReader.ID_LABEL);

 			out.writeUTF(outString);

 		}

 		if ((outString = plugin.getProviderName()) != null) {

-			out.writeUTF("<provider>");

+			out.writeByte(RegistryCacheReader.PLUGIN_PROVIDER_NAME_LABEL);

 			out.writeUTF(outString);

 		}

 		if ((outString = plugin.getVersion()) != null) {

-			out.writeUTF("<version>");

+			out.writeByte(RegistryCacheReader.VERSION_LABEL);

 			out.writeUTF(outString);

 		}

 		if ((outString = plugin.getPluginClass()) != null) {

-			out.writeUTF("<class>");

+			out.writeByte(RegistryCacheReader.PLUGIN_CLASS_LABEL);

 			out.writeUTF(outString);

 		}

 		if ((outString = plugin.getLocation()) != null) {

-			out.writeUTF("<location>");

+			out.writeByte(RegistryCacheReader.PLUGIN_LOCATION_LABEL);

 			out.writeUTF(outString);

 		}

-		out.writeUTF("<enabled>");

+		out.writeByte(RegistryCacheReader.PLUGIN_ENABLED_LABEL);

 		out.writeBoolean(plugin.getEnabled());

 

 		// write out prerequisites

@@ -263,7 +363,13 @@
 			}

 		}

 

-		out.writeUTF("<endplugin>");

+		// Add the index to the registry object for this plugin

+		PluginRegistryModel parentRegistry = plugin.getRegistry();

+		out.writeByte(RegistryCacheReader.PLUGIN_PARENT_LABEL);

+		// We can assume that the parent registry is already written out.

+		out.writeInt(objectTable.indexOf(parentRegistry));

+

+		out.writeByte(RegistryCacheReader.PLUGIN_END_LABEL);

 	} catch (IOException ioe) {

 	}

 }

@@ -271,45 +377,72 @@
 	try {

 		String outString = null;

 

-		out.writeUTF("<requires>");

+		out.writeByte(RegistryCacheReader.PLUGIN_REQUIRES_LABEL);

 

-		out.writeUTF("<readonly>");

+		out.writeByte(RegistryCacheReader.READONLY_LABEL);

 		out.writeBoolean(requires.isReadOnly());

 

 		if ((outString = requires.getName()) != null) {

-			out.writeUTF("<name>");

+			out.writeByte(RegistryCacheReader.NAME_LABEL);

 			out.writeUTF(outString);

 		}

 

 		if ((outString = requires.getVersion()) != null) {

-			out.writeUTF("<version>");

+			out.writeByte(RegistryCacheReader.VERSION_LABEL);

 			out.writeUTF(outString);

 		}

 

-		out.writeUTF("<match>");

+		out.writeByte(RegistryCacheReader.REQUIRES_MATCH_LABEL);

 		out.writeBoolean(requires.getMatch());

 

-		out.writeUTF("<export>");

+		out.writeByte(RegistryCacheReader.REQUIRES_EXPORT_LABEL);

 		out.writeBoolean(requires.getExport());

 

 		if ((outString = requires.getResolvedVersion()) != null) {

-			out.writeUTF("<resolved_version>");

+			out.writeByte(RegistryCacheReader.REQUIRES_RESOLVED_VERSION_LABEL);

 			out.writeUTF(outString);

 		}

 

 		if ((outString = requires.getPlugin()) != null) {

-			out.writeUTF("<requires_plugin_name>");

+			out.writeByte(RegistryCacheReader.REQUIRES_PLUGIN_NAME_LABEL);

 			out.writeUTF(outString);

 		}

 

-		out.writeUTF("<endrequires>");

+		out.writeByte(RegistryCacheReader.REQUIRES_END_LABEL);

 	} catch (IOException ioe) {

 	}

 }

 public void writePluginRegistry(PluginRegistryModel registry, DataOutputStream out) {

-	writeHeaderInformation(out);

-	PluginDescriptorModel[] pluginList = registry.getPlugins();

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

-		writePluginDescriptor(pluginList[i], out);

+	try {

+		// Check to see if this registry already exists in the objectTable.  If it is there,

+		// it has already been written to the cache so just write out the index.

+		if (objectTable != null) {

+			int registryIndex = objectTable.indexOf(registry);

+			if (registryIndex != -1) {

+				// this plugin is already there

+				out.writeByte(RegistryCacheReader.REGISTRY_INDEX_LABEL);

+				out.writeInt(registryIndex);

+				return;

+			}

+		}

+

+		// add this object to the object table first

+		addToObjectTable(registry);

+		writeHeaderInformation(out);

+		String outString = null;

+

+		out.writeByte(RegistryCacheReader.REGISTRY_LABEL);

+

+		out.writeByte(RegistryCacheReader.READONLY_LABEL);

+		out.writeBoolean(registry.isReadOnly());

+

+		out.writeByte(RegistryCacheReader.REGISTRY_RESOLVED_LABEL);

+		out.writeBoolean(registry.isResolved());

+		PluginDescriptorModel[] pluginList = registry.getPlugins();

+		for (int i = 0; i < pluginList.length; i++)

+			writePluginDescriptor(pluginList[i], out);

+		out.writeByte(RegistryCacheReader.REGISTRY_END_LABEL);

+	} catch (IOException ioe) {

+	}

 }

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryLoader.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryLoader.java
index a0ed2a6..eec6c93 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryLoader.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryLoader.java
@@ -58,7 +58,7 @@
 public static PluginRegistryModel parseRegistry(URL[] pluginPath, Factory factory, boolean debug) {

 	return new RegistryLoader(factory, debug).parseRegistry(pluginPath);

 }

-private PluginDescriptorModel processManifestFile(URL manifest) {

+private PluginModel processManifestFile(URL manifest) {

 	InputStream is = null;

 	try {

 		is = manifest.openStream();

@@ -68,12 +68,10 @@
 			debug("No plugin found for: " + manifest);

 		return null;

 	}

-	PluginDescriptorModel result = null;

+	PluginModel result = null;

 	try {

 		try {

 			result = new PluginParser((Factory) factory).parse(new InputSource(is));

-			String url = manifest.toString();

-			result.setLocation(url.substring(0, 1 + url.lastIndexOf('/')));

 		} finally {

 			is.close();

 		}

@@ -87,35 +85,50 @@
 }

 private PluginRegistryModel processManifestFiles(URL[] pluginPath) {

 	PluginRegistryModel result = factory.createPluginRegistry();

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

-		if (debug)

-			debug("Path - " + pluginPath[i]);

-		if (pluginPath[i].getFile().endsWith("/")) {

-			// directory entry - search for plugins

-			String[] members = getPathMembers(pluginPath[i]);

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

-				try {

-					PluginDescriptorModel entry = processManifestFile(new URL(pluginPath[i], members[j] + "/plugin.xml"));

-					if (entry != null) {

-						result.addPlugin(entry);

-						entry.setRegistry(result);

-					}

-				} catch (java.net.MalformedURLException e) {

-				}

-				if (debug)

-					debug("Processed - " + members[j]);

-			}

-		} else {

-			// specific file entry - load the given file

-			PluginDescriptorModel entry = processManifestFile(pluginPath[i]);

-			if (entry != null) {

-				result.addPlugin(entry);

-				entry.setRegistry(result);

+	for (int i = 0; i < pluginPath.length; i++)

+		processPluginPathEntry(result, pluginPath[i]);

+	return result;

+}

+private void processPluginPathEntry(PluginRegistryModel registry, URL location) {

+	if (debug)

+		debug("Path - " + location);

+	if (location.getFile().endsWith("/")) {

+		// directory entry - search for plugins

+		String[] members = getPathMembers(location);

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

+			try {

+				boolean found = processPluginPathFile(registry, new URL(location, members[j] + "/plugin.xml"));

+				if (!found)

+					found = processPluginPathFile(registry, new URL(location, members[j] + "/fragment.xml"));

+			} catch (MalformedURLException e) {

 			}

 			if (debug)

-				debug("Processed - " + pluginPath[i]);

+				debug("Processed - " + members[j]);

 		}

+	} else {

+		// specific file entry - load the given file

+		boolean found = processPluginPathFile(registry, location);

+		if (debug)

+			debug("Processed - " + location);

 	}

-	return result;

+}

+private boolean processPluginPathFile(PluginRegistryModel registry, URL location) {

+	PluginModel entry = processManifestFile(location);

+	if (entry == null)

+		return false;

+

+	String url = location.toString();

+	url = url.substring(0, 1 + url.lastIndexOf('/'));

+	if (entry instanceof PluginDescriptorModel)

+		registry.addPlugin((PluginDescriptorModel) entry);

+	else

+		if (entry instanceof PluginFragmentModel)

+			registry.addFragment((PluginFragmentModel) entry);

+		else

+			// XXX log some kind of error or throw an exception here

+			return false;

+	entry.setRegistry(registry);

+	entry.setLocation(url);

+	return true;

 }

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryResolver.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryResolver.java
index 479f4f1..d8ee706 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryResolver.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryResolver.java
@@ -10,11 +10,10 @@
 public class RegistryResolver {

 

 	private Map idmap;

-	private int size;

 	private PluginRegistryModel reg;

 	private MultiStatus status;

 	private boolean trimPlugins = true;

-	private boolean crossLinking = true;

+	private boolean crossLink = true;

 

 	public static final int MATCH_EXACT = 0;

 	public static final int MATCH_COMPATIBLE = 1;

@@ -413,14 +412,49 @@
 			break;

 	}

 	verList.add(i, pd);

-

-	// keep track of number of entries

-	size++;

 }

 private void addAll(Collection c) {

 	for (Iterator list = c.iterator(); list.hasNext();)

 		add((PluginDescriptorModel) list.next());

 }

+private void addExtension(ExtensionModel extension, PluginDescriptorModel plugin) {

+	ExtensionModel[] list = plugin.getDeclaredExtensions();

+	ExtensionModel[] result = null;

+	if (list == null)

+		result = new ExtensionModel[1];

+	else {

+		result = new ExtensionModel[list.length + 1];

+		System.arraycopy(list, 0, result, 0, list.length);

+	}

+	result[result.length - 1] = extension;

+	plugin.setDeclaredExtensions(result);

+	extension.setParent(plugin);

+}

+private void addExtensionPoint(ExtensionPointModel extensionPoint, PluginDescriptorModel plugin) {

+	ExtensionPointModel[] list = plugin.getDeclaredExtensionPoints();

+	ExtensionPointModel[] result = null;

+	if (list == null)

+		result = new ExtensionPointModel[1];

+	else {

+		result = new ExtensionPointModel[list.length + 1];

+		System.arraycopy(list, 0, result, 0, list.length);

+	}

+	result[result.length - 1] = extensionPoint;

+	plugin.setDeclaredExtensionPoints(result);

+	extensionPoint.setParent(plugin);

+}

+private void addLibrary(LibraryModel library, PluginDescriptorModel plugin) {

+	LibraryModel[] list = plugin.getRuntime();

+	LibraryModel[] result = null;

+	if (list == null)

+		result = new LibraryModel[1];

+	else {

+		result = new LibraryModel[list.length + 1];

+		System.arraycopy(list, 0, result, 0, list.length);

+	}

+	result[result.length - 1] = library;

+	plugin.setRuntime(result);

+}

 private void debug(String s) {

 	System.out.println("Registry Resolve: "+s);

 }

@@ -430,14 +464,6 @@
 	if (InternalPlatform.DEBUG && DEBUG_RESOLVE)

 		System.out.println(error.toString());

 }

-/**

- * Returns a value indicating if extensions are to be linked 

- * with their associated extension point during the resolve process.

- *

- */

-public boolean getCrossLinking() {

-	return crossLinking;

-}

 public IExtensionPoint getExtensionPoint(PluginDescriptorModel plugin, String extensionPointId) {

 	if (extensionPointId == null)

 		return null;

@@ -450,14 +476,6 @@
 	}

 	return null;

 }

-/**

- * Gets the boolean value which determines if disabled plugins

- * will be removed when this resolve is done.

- *

- */

-public boolean getTrimPlugins() {

-	return trimPlugins;

-}

 private PluginVersionIdentifier getVersionIdentifier(PluginDescriptorModel descriptor) {

 	String version = descriptor.getVersion();

 	if (version == null)

@@ -532,7 +550,6 @@
 		return status;

 	reg = registry;

 	idmap = new HashMap();

-	size = 0;

 	addAll(Arrays.asList(reg.getPlugins()));

 	resolve();

 	registry.markResolved();

@@ -576,6 +593,23 @@
 	newValues[newValues.length - 1] = ext;

 	extPt.setDeclaredExtensions(newValues);

 }

+private void resolveFragments() {

+	ArrayList retained = new ArrayList(5);

+	PluginFragmentModel[] fragments = reg.getFragments();

+	HashSet seen = new HashSet(5);

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

+		PluginFragmentModel fragment = fragments[i];

+		if (seen.contains(fragment.getId()))

+			continue;

+		seen.add(fragment.getId());

+		PluginDescriptorModel plugin = reg.getPlugin(fragment.getPluginId(), fragment.getPluginVersion());

+		if (plugin == null)

+			// XXX log something here?

+			continue;

+		PluginFragmentModel[] list = reg.getFragments(fragment.getId());

+		resolvePluginFragments(list, plugin);

+	}

+}

 private Cookie resolveNode(String child, PluginDescriptorModel parent, PluginPrerequisiteModel prq, Cookie cookie, List orphans) {

 	// This method is called recursively to setup dependency constraints.

 	// Top invocation is passed null parent and null prerequisite.

@@ -669,23 +703,61 @@
 	}

 }

 private void resolvePluginDescriptor(PluginDescriptorModel pd) {

-	if (getCrossLinking()) {

-		ExtensionModel[] list = pd.getDeclaredExtensions();

-		if (list == null || list.length == 0)

-			return;

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

-			resolveExtension((ExtensionModel) list[i]);

-		}

+	ExtensionModel[] list = pd.getDeclaredExtensions();

+	if (list == null || list.length == 0)

+		return;

+	for (int i = 0; i < list.length; i++)

+		resolveExtension((ExtensionModel) list[i]);

+}

+private void resolvePluginFragment(PluginFragmentModel fragment, PluginDescriptorModel plugin) {

+	ExtensionModel[] extensions = fragment.getDeclaredExtensions();

+	if (extensions != null)

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

+			addExtension(extensions[i], plugin);

+

+	ExtensionPointModel[] points = fragment.getDeclaredExtensionPoints();

+	if (points != null)

+		for (int i = 0; i < points.length; i++)

+			addExtensionPoint(points[i], plugin);

+

+	LibraryModel[] libraries= fragment.getRuntime();

+	if (libraries!= null)

+		for (int i = 0; i < libraries.length; i++)

+			addLibrary(libraries[i], plugin);

+}

+private void resolvePluginFragments(PluginFragmentModel[] fragments, PluginDescriptorModel plugin) {

+	PluginFragmentModel latestFragment = null;

+	PluginVersionIdentifier latestVersion = null;

+	PluginVersionIdentifier targetVersion = new PluginVersionIdentifier(plugin.getVersion());

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

+		PluginFragmentModel fragment = fragments[i];

+		PluginVersionIdentifier fragmentVersion = new PluginVersionIdentifier(fragment.getVersion());

+		PluginVersionIdentifier pluginVersion = new PluginVersionIdentifier(fragment.getPluginVersion());

+		if (pluginVersion.getMajorComponent() == targetVersion.getMajorComponent() && pluginVersion.getMinorComponent() == targetVersion.getMinorComponent())

+			if (latestFragment == null || fragmentVersion.isGreaterThan(latestVersion)) {

+				latestFragment = fragment;

+				latestVersion = fragmentVersion;

+			}

 	}

+	if (latestFragment != null)

+		resolvePluginFragment(latestFragment, plugin);

 }

 private void resolvePluginRegistry() {

 	// filter out disabled plugins from "live" registry

-	trimRegistry();

+	if (trimPlugins)

+		trimRegistry();

 

 	// resolve relationships

-	PluginDescriptorModel[] list = reg.getPlugins();

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

-		resolvePluginDescriptor((PluginDescriptorModel) list[i]);

+	if (crossLink) {

+		// knit the fragments into the plugins.  This must be done after any trimming

+		// so that fragments for disabled plugins are not added.

+		resolveFragments();

+		

+		// cross link all of the extensions and extension points.

+		PluginDescriptorModel[] plugins = reg.getPlugins();

+		for (int i = 0; i < plugins.length; i++)

+			resolvePluginDescriptor(plugins[i]);

+	}

 }

 private List resolveRootDescriptors() {

 

@@ -742,32 +814,27 @@
 	return ids;

 }

 /**

- * Allows all extensions to be linked with their associated

- * extension point during the resolve process.

- *

+ * Specifies whether extensions and extension points should be cross 

+ * linked during the resolve process.

  */

-public void setCrossLinking(boolean doCrossLinking) {

-	crossLinking = doCrossLinking;

+public void setCrossLink(boolean value) {

+	crossLink = value;

 }

 /**

- * Allows all disabled plugins to be removed when the resolve

+ * Specified whether disabled plugins should to be removed when the resolve

  * is completed.

- *

  */

-public void setTrimPlugins(boolean trimDisabledPlugins) {

-	trimPlugins = trimDisabledPlugins;

+public void setTrimPlugins(boolean value) {

+	trimPlugins = value;

 }

 private void trimRegistry() {

-

-	if (getTrimPlugins()) {

-		PluginDescriptorModel[] list = reg.getPlugins();

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

-			PluginDescriptorModel pd = (PluginDescriptorModel) list[i];

-			if (!pd.getEnabled()) {

-				if (DEBUG_RESOLVE)

-					debug("removing " + pd.toString());

-				reg.removePlugin(pd.getId(), pd.getVersion());

-			}

+	PluginDescriptorModel[] list = reg.getPlugins();

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

+		PluginDescriptorModel pd = (PluginDescriptorModel) list[i];

+		if (!pd.getEnabled()) {

+			if (DEBUG_RESOLVE)

+				debug("removing " + pd.toString());

+			reg.removePlugin(pd.getId(), pd.getVersion());

 		}

 	}

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java
index 9782baf..c567961 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java
@@ -10,7 +10,7 @@
 import org.eclipse.core.boot.IPlatformRunnable;

 import org.eclipse.core.internal.boot.*;

 import org.eclipse.core.runtime.model.*;

-import org.eclipse.core.internal.boot.EclipseURLHandlerFactory;

+import org.eclipse.core.internal.boot.PlatformURLHandlerFactory;

 import org.eclipse.core.internal.boot.InternalBootLoader;

 import org.eclipse.core.runtime.*;

 import org.eclipse.core.internal.runtime.*;

@@ -131,12 +131,12 @@
  */

 public static URL asLocalURL(URL url) throws IOException {

 	URLConnection connection = url.openConnection();

-	if (!(connection instanceof EclipseURLConnection))

+	if (!(connection instanceof PlatformURLConnection))

 		return url;

 	String file = connection.getURL().getFile();

-	if (file.endsWith("/") && !file.endsWith(EclipseURLHandler.JAR_SEPARATOR))

+	if (file.endsWith("/") && !file.endsWith(PlatformURLHandler.JAR_SEPARATOR))

 		throw new IOException();

-	return ((EclipseURLConnection) connection).getURLAsLocal();

+	return ((PlatformURLConnection) connection).getURLAsLocal();

 }

 private static void assertInitialized() {

 	Assert.isTrue(initialized, Policy.bind("appNotInit", new String[] {}));

@@ -406,7 +406,7 @@
 	MultiStatus problems = loadRegistry(pluginPath);

 	initialized = true;

 	// can't register url handlers until after the plugin registry is loaded

-	EclipseURLPluginHandlerFactory.startup();

+	PlatformURLPluginHandlerFactory.startup();

 	activateDefaultPlugins();

 	// can't install the log or log problems until after the platform has been initialized.

 	platformLog = new PlatformLogListener();

@@ -568,8 +568,8 @@
  */

 public static URL resolve(URL url) throws IOException {

 	URLConnection connection = url.openConnection();

-	if (connection instanceof EclipseURLConnection)

-		return ((EclipseURLConnection) connection).getResolvedURL();

+	if (connection instanceof PlatformURLConnection)

+		return ((PlatformURLConnection) connection).getResolvedURL();

 	else

 		return url;

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformLogListener.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformLogListener.java
index 635c242..17c189a 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformLogListener.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformLogListener.java
@@ -8,31 +8,35 @@
 

 import org.eclipse.core.runtime.*;

 import java.io.*;

+import java.util.Date;

 

 class PlatformLogListener implements ILogListener {

-	PrintWriter log = null;

+	private PrintWriter log = null;

+	private boolean usingLogFile = false;

 PlatformLogListener() {

-	try {

-		log = new PrintWriter(new FileOutputStream(InternalPlatform.getMetaArea().getLogLocation().toFile()));

-	} catch (IOException e) {

-		log = null;

-	}

+	usingLogFile = true;

+	// remove old log file

+	InternalPlatform.getMetaArea().getLogLocation().toFile().delete();

 }

+/**

+ * It should only be used to pass System.out .

+ */

 PlatformLogListener(OutputStream out) {

 	log = new PrintWriter(out);

 }

+private void closeLogFile() {

+	try {

+		log.flush();

+		log.close();

+	} finally {

+		log = null;

+	}

+}

 private void indent(int count) {

 	for (int i = 0; i < count; i++)

 		log.print("\t");

 }

-public synchronized void logging(IStatus status) {

-	// thread safety: (Concurrency003)

-	if (log == null)

-		return;

-	log.println("Log: " + new java.util.Date());

-	logging(status, 0);

-}

-protected void logging(IStatus status, int nesting) {

+private void logging(IStatus status, int nesting) {

 	indent(nesting);

 	log.print(status.getSeverity());

 	log.print(" ");

@@ -58,15 +62,29 @@
 }

 public synchronized void logging(IStatus status, String plugin) {

 	// thread safety: (Concurrency003)

+	if (usingLogFile)

+		openLogFile();

 	if (log == null)

 		return;

-	log.println("Log: " + new java.util.Date());

-	logging(status, 0);

+	try {

+		log.println("Log: " + new Date());

+		logging(status, 0);

+	} finally {

+		if (usingLogFile)

+			closeLogFile();

+	}

+}

+private void openLogFile() {

+	try {

+		log = new PrintWriter(new FileOutputStream(InternalPlatform.getMetaArea().getLogLocation().toOSString(), true));

+	} catch (IOException e) {

+		log = null;

+	}

 }

 /**

  * @see ILogListener

  */

-public void shutdown() {

+public synchronized void shutdown() {

 	if (log == null)

 		return;

 	PrintWriter old = log;

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLFragmentConnection.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLFragmentConnection.java
new file mode 100644
index 0000000..62d0cb6
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLFragmentConnection.java
@@ -0,0 +1,63 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * Licensed Materials - Property of IBM,

+ * WebSphere Studio Workbench

+ * (c) Copyright IBM Corp 2000

+ */

+

+/**

+ * Platform URL support

+ * platform:/fragment/<fragmentId>/		maps to fragmentDescriptor.getInstallURLInternal()

+ */

+

+import java.net.*;

+import java.io.*;

+import java.util.*;

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.internal.boot.*;

+import org.eclipse.core.internal.plugins.FragmentDescriptor;

+ 

+public class PlatformURLFragmentConnection extends PlatformURLConnection {

+

+	// fragment/ protocol

+//	private FragmentDescriptor fd = null;

+	private static boolean isRegistered = false;

+	public static final String FRAGMENT = "fragment";

+public PlatformURLFragmentConnection(URL url) {

+	super(url);

+}

+protected boolean allowCaching() {

+	return true;

+}

+protected URL resolve() throws IOException {

+	

+	String spec = url.getFile().trim();

+	if (spec.startsWith("/")) spec = spec.substring(1);

+	int ix;

+	String ref;

+	String id;

+	PluginVersionIdentifier vid;

+	String rest;

+	URL result;

+

+	if (!spec.startsWith(FRAGMENT)) throw new IOException("Unsupported protocol variation "+url.toString());

+

+	ix = spec.indexOf("/",FRAGMENT.length()+1);

+	ref = ix==-1 ? spec.substring(FRAGMENT.length()+1) : spec.substring(FRAGMENT.length()+1,ix);

+	id = FragmentDescriptor.getUniqueIdentifierFromString(ref);

+	vid = FragmentDescriptor.getVersionIdentifierFromString(ref);

+	IPluginRegistry r = Platform.getPluginRegistry();

+	fd = (FragmentDescriptor)(vid==null ? r.getFragmentDescriptor(id) : r.getFragmentDescriptor(id,vid));

+	if (fd == null) throw new IOException("Unable to resolve fragment "+url.toString());

+	result = (ix==-1 || (ix+1)>=spec.length()) ? fd.getInstallURLInternal() : new URL(fd.getInstallURLInternal(),spec.substring(ix+1));

+	return result;

+}

+public static void startup() {

+	

+	// register connection type for platform:/fragment handling

+	if (isRegistered) return;

+	PlatformURLHandler.register(FRAGMENT, PlatformURLFragmentConnection.class);

+	isRegistered = true;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/EclipseURLPluginConnection.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginConnection.java
similarity index 64%
rename from bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/EclipseURLPluginConnection.java
rename to bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginConnection.java
index 6be38ea..9d8515b 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/EclipseURLPluginConnection.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginConnection.java
@@ -7,8 +7,8 @@
  */

 

 /**

- * Eclipse URL support

- * eclipse:plugin/<pluginId>/		maps to pluginDescriptor.getInstallURLInternal()

+ * Platform URL support

+ * platform:/plugin/<pluginId>/		maps to pluginDescriptor.getInstallURLInternal()

  */

 

 import java.net.*;

@@ -18,13 +18,13 @@
 import org.eclipse.core.internal.boot.*;

 import org.eclipse.core.internal.plugins.PluginDescriptor;

  

-public class EclipseURLPluginConnection extends EclipseURLConnection {

+public class PlatformURLPluginConnection extends PlatformURLConnection {

 

 	// plugin/ protocol

 	private PluginDescriptor pd = null;

 	private static boolean isRegistered = false;

 	public static final String PLUGIN = "plugin";

-public EclipseURLPluginConnection(URL url) {

+public PlatformURLPluginConnection(URL url) {

 	super(url);

 }

 protected boolean allowCaching() {

@@ -35,25 +35,29 @@
 	String spec = url.getFile().trim();

 	if (spec.startsWith("/")) spec = spec.substring(1);

 	int ix;

-	String name;

+	String ref;

+	String id;

+	PluginVersionIdentifier vid;

 	String rest;

 	URL result;

 

 	if (!spec.startsWith(PLUGIN)) throw new IOException("Unsupported protocol variation "+url.toString());

 

 	ix = spec.indexOf("/",PLUGIN.length()+1);

-	name = ix==-1 ? spec.substring(PLUGIN.length()+1) : spec.substring(PLUGIN.length()+1,ix);

+	ref = ix==-1 ? spec.substring(PLUGIN.length()+1) : spec.substring(PLUGIN.length()+1,ix);

+	id = PluginDescriptor.getUniqueIdentifierFromString(ref);

+	vid = PluginDescriptor.getVersionIdentifierFromString(ref);

 	IPluginRegistry r = Platform.getPluginRegistry();

-	pd = (PluginDescriptor)r.getPluginDescriptor(name);

+	pd = (PluginDescriptor)(vid==null ? r.getPluginDescriptor(id) : r.getPluginDescriptor(id,vid));

 	if (pd == null) throw new IOException("Unable to resolve plug-in "+url.toString());

 	result = (ix==-1 || (ix+1)>=spec.length()) ? pd.getInstallURLInternal() : new URL(pd.getInstallURLInternal(),spec.substring(ix+1));

 	return result;

 }

 public static void startup() {

 	

-	// register connection type for eclipse:/plugin handling

+	// register connection type for platform:/plugin handling

 	if (isRegistered) return;

-	EclipseURLHandler.register(PLUGIN, EclipseURLPluginConnection.class);

+	PlatformURLHandler.register(PLUGIN, PlatformURLPluginConnection.class);

 	isRegistered = true;

 }

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/EclipseURLPluginHandlerFactory.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginHandlerFactory.java
similarity index 65%
rename from bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/EclipseURLPluginHandlerFactory.java
rename to bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginHandlerFactory.java
index 2c227da..9d08be3 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/EclipseURLPluginHandlerFactory.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginHandlerFactory.java
@@ -9,17 +9,17 @@
 import java.net.*;

 import java.util.*;

 import org.eclipse.core.runtime.*;

-import org.eclipse.core.internal.boot.EclipseURLHandler;

-import org.eclipse.core.internal.boot.EclipseURLHandlerFactory;

+import org.eclipse.core.internal.boot.PlatformURLHandler;

+import org.eclipse.core.internal.boot.PlatformURLHandlerFactory;

  

-public class EclipseURLPluginHandlerFactory implements URLStreamHandlerFactory {

+public class PlatformURLPluginHandlerFactory implements URLStreamHandlerFactory {

 

 	IConfigurationElement ce = null;

 	

 	private static final String URL_HANDLERS_POINT = "org.eclipse.core.runtime.urlHandlers";

 	private static final String PROTOCOL = "protocol";

 	private static final String HANDLER = "class";

-public EclipseURLPluginHandlerFactory(IConfigurationElement ce) {

+public PlatformURLPluginHandlerFactory(IConfigurationElement ce) {

 	super();

 	this.ce = ce;	

 }

@@ -40,10 +40,12 @@
 	for (int i=0; i<ce.length; i++) {

 		// register factory elements (actual handlers lazily created on request)

 		protocol = ce[i].getAttribute(PROTOCOL);

-		if (protocol!=null) EclipseURLHandlerFactory.register(protocol,new EclipseURLPluginHandlerFactory(ce[i]));

+		if (protocol!=null) PlatformURLHandlerFactory.register(protocol,new PlatformURLPluginHandlerFactory(ce[i]));

 	}

 

-	// initialize plugin connection support

-	EclipseURLPluginConnection.startup();

+	// initialize plugin and fragment connection support

+	PlatformURLPluginConnection.startup();

+	// FIXME: uncomment once we get the fragment code merged

+//	PlatformURLFragmentConnection.startup();

 }

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILibrary.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILibrary.java
index ed848b4..998864f 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILibrary.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILibrary.java
@@ -5,8 +5,18 @@
  * WebSphere Studio Workbench

  * (c) Copyright IBM Corp 2000

  */

-/**

- * A runtime library declared in a plug-in.

+

+import org.eclipse.core.runtime.model.LibraryModel;

+

+ /**

+ * A runtime library declared in a plug-in.  Libraries contribute elements to the search path.

+ * These contributions are specified as a path to a directory or Jar file.  This path is always

+ * considered to be relative to the containing plug-in.  

+ * <p>

+ * Libraries are typed.  The type is used to determine to which search path the library's

+ * contribution should be added.  The valid types are: <code>CODE</code>, 

+ * <code>RESOURCE</code> and <code>SOURCE</code>.  

+ * </p>

  * <p>

  * This interface is not intended to be implemented by clients.

  * </p>

@@ -14,6 +24,24 @@
  * @see IPluginDescriptor#getRuntimeLibraries 

  */

 public interface ILibrary {

+	/**

+	 * Constant string (value "code") indicating the code library type.

+	 * @see LibraryModel#CODE

+	 */

+	public static final String CODE = LibraryModel.CODE;

+	

+	/**

+	 * Constant string (value "resource") indicating the resource library type.

+	 * @see LibraryModel#RESOURCE

+	 */

+	public static final String RESOURCE = LibraryModel.RESOURCE;

+	

+	/**

+	 * Constant string (value "source") indicating the source library type.

+	 * @see LibraryModel#SOURCE

+	 */

+	public static final String SOURCE = LibraryModel.SOURCE;

+

 /**

  * Returns the content filters, or <code>null</code>.

  * Each content filter identifies a specific class, or

@@ -35,6 +63,23 @@
  */

 public IPath getPath();

 /**

+ * Returns the path to this library's source or <code>null</code>.  The source

+ * for value is not relevant (is <code>null</code>) for libraries of type <code>RESOURCE</code>.

+ *

+ * @return the path to this library's source.  May be <code>null</code>.

+ */

+public String getSource();

+/**

+ * Returns this library's type.

+ *

+ * @return the type of this library.   The valid types are: <code>CODE</code>, <code>RESOURCE</code>, 

+ * <code>SOURCE</code>.

+ * @see #CODE

+ * @see #RESOURCE

+ * @see #SOURCE

+ */

+public String getType();

+/**

  * Returns whether the library is exported. The contents of an exported

  * library may be visible to other plug-ins that declare a dependency

  * on the plug-in containing this library, subject to content filtering.

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginPrerequisite.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginPrerequisite.java
index b8e6c74..7e8021f 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginPrerequisite.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginPrerequisite.java
@@ -69,4 +69,11 @@
  * plug-in will satisfy this dependency.

  */

 public boolean isMatchedAsExact();

+/**

+ * Indicates whether this plug-in prerequisite is optional.  If a required (i.e., non-optional)

+ * prerequisite is missing, this plugin is disabled.  

+ *

+ * @return <code>true</code> if this prerequisite is optional, <code>false</code> otherwise

+ */

+public boolean isOptional();

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Platform.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Platform.java
index 66bbd52..1cab3f1 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Platform.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Platform.java
@@ -9,8 +9,6 @@
 import org.eclipse.core.boot.*;

 import org.eclipse.core.runtime.model.Factory;

 import org.eclipse.core.runtime.model.PluginRegistryModel;

-import org.eclipse.core.internal.boot.EclipseURLHandler;

-import org.eclipse.core.internal.boot.EclipseURLConnection;

 import org.eclipse.core.internal.plugins.PluginClassLoader;

 import org.eclipse.core.internal.plugins.PluginDescriptor;

 import org.eclipse.core.internal.runtime.*;

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java
index 93d5462..8db11a7 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java
@@ -10,7 +10,7 @@
 import org.eclipse.core.internal.runtime.*;

 import java.util.StringTokenizer;

 import java.util.Vector;

-import java.net.URL;

+import java.net.*;

 import java.io.InputStream;

 import java.io.IOException;

 

@@ -186,6 +186,32 @@
 	this.debug = value == null ? false : value.equalsIgnoreCase("true");

 }

 /**

+ * Returns a URL for the given path.  Returns <code>null</code> if the URL

+ * could not be computed or created.

+ * 

+ * @param file path relative to plug-in installation location 

+ * @return a URL for the given path or <code>null</code>

+ */

+public final URL find(IPath path) {

+	String first = path.segment(0);

+	if (first.charAt(0) != '$') {

+		try {

+			return new URL(getDescriptor().getInstallURL(), path.toString());

+		} catch (MalformedURLException e) {

+			return null;

+		}

+	}

+	if (first.equalsIgnoreCase("$nl$"))

+		return null;

+	if (first.equalsIgnoreCase("$os$"))

+		return null;

+	if (first.equalsIgnoreCase("$ws$"))

+		return null;

+	if (first.equalsIgnoreCase("$files$"))

+		return null;

+	return null;

+}

+/**

  * Returns the plug-in descriptor for this plug-in runtime object.

  *

  * @return the plug-in descriptor for this plug-in runtime object

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionModel.java
index d202a17..cc8d6b5 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionModel.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionModel.java
@@ -21,7 +21,7 @@
 	private ConfigurationElementModel[] elements = null;

 

 	// transient properties (not included in plug-in manifest)

-	private PluginDescriptorModel plugin = null; // declaring plugin

+	private PluginModel plugin = null; // declaring plugin

 /**

  * Creates a new extension model in which all fields

  * are <code>null</code>.

@@ -50,13 +50,22 @@
 	return id;

 }

 /**

+ * Returns the plug-in model (descriptor or fragment) in which this extension is declared.

+ *

+ * @return the plug-in model in which this extension is declared

+ *  or <code>null</code>

+ */

+public PluginModel getParent() {

+	return plugin;

+}

+/**

  * Returns the plug-in descriptor in which this extension is declared.

  *

  * @return the plug-in descriptor in which this extension is declared

  *  or <code>null</code>

  */

 public PluginDescriptorModel getParentPluginDescriptor() {

-	return plugin;

+	return (PluginDescriptorModel) plugin;

 }

 /**

  * Returns the configuration element children of this extension.

@@ -106,10 +115,21 @@
 	id = value;

 }

 /**

+ * Sets the plug-in model in which this extension is declared.

+ * This object must not be read-only.

+ *

+ * @param value the plug-in model in which this extension is declared.  

+ *		May be <code>null</code>.

+ */

+public void setParent(PluginModel value) {

+	assertIsWriteable();

+	plugin = value;

+}

+/**

  * Sets the plug-in descriptor in which this extension is declared.

  * This object must not be read-only.

  *

- * @param descriptor the plug-in descriptor in which this extension is declared.  

+ * @param value the plug-in descriptor in which this extension is declared.  

  *		May be <code>null</code>.

  */

 public void setParentPluginDescriptor(PluginDescriptorModel value) {

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionPointModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionPointModel.java
index d174ee4..7778226 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionPointModel.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionPointModel.java
@@ -20,7 +20,7 @@
 	private String schema = null;

 

 	// transient properties (not included in plug-in manifest)

-	private PluginDescriptorModel plugin = null; // declaring plugin

+	private PluginModel plugin = null; // declaring plugin

 	private ExtensionModel[] extensions = null; // configured extensions

 /**

  * Creates a new extension point model in which all fields

@@ -49,13 +49,22 @@
 	return id;

 }

 /**

+ * Returns the plug-in model (descriptor or fragment) in which this extension is declared.

+ *

+ * @return the plug-in model in which this extension is declared

+ *  or <code>null</code>

+ */

+public PluginModel getParent() {

+	return plugin;

+}

+/**

  * Returns the plug-in descriptor in which this extension point is declared.

  *

  * @return the plug-in descriptor in which this extension point is declared

  *  or <code>null</code>

  */

 public PluginDescriptorModel getParentPluginDescriptor() {

-	return plugin;

+	return (PluginDescriptorModel) plugin;

 }

 /**

  * Returns the schema specification for this extension point.

@@ -92,6 +101,17 @@
 	id = value;

 }

 /**

+ * Sets the plug-in model in which this extension is declared.

+ * This object must not be read-only.

+ *

+ * @param value the plug-in model in which this extension is declared.  

+ *		May be <code>null</code>.

+ */

+public void setParent(PluginModel value) {

+	assertIsWriteable();

+	plugin = value;

+}

+/**

  * Sets the plug-in descriptor in which this extension point is declared.

  * This object must not be read-only.

  *

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/Factory.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/Factory.java
index 68df1fe..1c489c5 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/Factory.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/Factory.java
@@ -80,6 +80,14 @@
 	return new PluginDescriptorModel();

 }

 /**

+ * Returns a new plug-in fragment model which is not initialized.

+ *

+ * @return a new plug-in fragment model

+ */

+public PluginFragmentModel createPluginFragment() {

+	return new PluginFragmentModel();

+}

+/**

  * Returns a new plug-in prerequisite model which is initialized to

  * not export its code and to not require an exact match.

  *

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/LibraryModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/LibraryModel.java
index 3ab4962..8cb3788 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/LibraryModel.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/LibraryModel.java
@@ -7,9 +7,15 @@
  */

 

 /**

- * An object which represents the executable code for plug-in 

- * in a plug-in manifest.

-  * <p>

+ * A runtime library declared in a plug-in.  Libraries contribute elements to the search path.

+ * These contributions are specified as a path to a directory or Jar file.  This path is always

+ * considered to be relative to the containing plug-in.  

+ * <p>

+ * Libraries are typed.  The type is used to determine to which search path the library's

+ * contribution should be added.  The valid types are: <code>CODE</code>, 

+ * <code>RESOURCE</code> and <code>SOURCE</code>.  

+ * </p>

+ * <p>

  * This class may be instantiated, or further subclassed.

  * </p>

  */

@@ -17,10 +23,27 @@
 

 	// DTD properties (included in plug-in manifest)

 	private String[] exports = null;

+	private String type = CODE;

+	private String source = null;

 

 	// transient properties (not included in plug-in manifest)

 	private boolean isExported = false;

 	private boolean isFullyExported = false;

+

+	/**

+	 * Constant string (value "code") indicating the code library type.

+	 */

+	public static final String CODE = "code";

+	

+	/**

+	 * Constant string (value "resource") indicating the resource library type.

+	 */

+	public static final String RESOURCE = "resource";

+	

+	/**

+	 * Constant string (value "source") indicating the source library type.

+	 */

+	public static final String SOURCE = "source";

 /**

  * Creates a new library model in which all fields

  * are <code>null</code>.

@@ -35,6 +58,26 @@
 	return exports;

 }

 /**

+ * Returns the path to this library's source or <code>null</code>.  

+ *

+ * @return the path to this library's source.  May be <code>null</code>.

+ */

+public String getSource() {

+	return source;

+}

+/**

+ * Returns this library's type.  

+ *

+ * @return the type of this library.  The valid types are: <code>CODE</code>, <code>RESOURCE</code>, 

+ * <code>SOURCE</code>.

+ * @see #CODE

+ * @see #RESOURCE

+ * @see #SOURCE

+ */

+public String getType() {

+	return type;

+}

+/**

  * Returns whether or not any of the code in this library is exported.

  *

  * @return whether or not any of the code in this library represents is exported

@@ -57,9 +100,7 @@
  * @param value this library's export mask.  May be <code>null</code>.

  */

 public void setExports(String[] value) {

-

 	assertIsWriteable();

-

 	exports = value;

 	if (value == null) {

 		isExported = false;

@@ -73,4 +114,37 @@
 		}

 	}

 }

+/**

+ * Sets the location of this library's source.  This method has no effect if

+ * this library is of type <code>RESOURCE</code>.

+ * This object must not be read-only.

+ *

+ * @param value the location of this library's source.  May be <code>null</code>.

+ */

+public void setSource(String value) {

+	assertIsWriteable();

+	// cannot set the source for a library of type resource.

+	if (type != null && type.equals(RESOURCE))

+		return;

+	source = value;

+}

+/**

+ * Sets this library's type. The valid types are: <code>CODE</code>, <code>RESOURCE</code>, 

+ * <code>SOURCE</code>.  Setting this library to type <code>RESOURCE</code>

+ * clears the <code>source</code> field of this library.  The given type value is canonicalized

+ * before being set.

+ * This object must not be read-only.

+ *

+ * @param value the type of this library.

+ * @see #CODE

+ * @see #RESOURCE

+ * @see #SOURCE

+ */

+public void setType(String value) {

+	assertIsWriteable();

+	type = value.toLowerCase();

+	// if this is to be a resource library, there should not be a source value.

+	if (type.equals(RESOURCE))

+		source = null;

+}

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginDescriptorModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginDescriptorModel.java
index a8344e8..eece816 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginDescriptorModel.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginDescriptorModel.java
@@ -13,21 +13,13 @@
  * This class may be instantiated, or further subclassed.

  * </p>

  */

-public class PluginDescriptorModel extends PluginModelObject {

+public class PluginDescriptorModel extends PluginModel {

 

 	// DTD properties (included in plug-in manifest)

-	private String id = null;

-	private String providerName = null;

-	private String version = null;

 	private String pluginClass = null;

 	private PluginPrerequisiteModel[] requires = null;

-	private LibraryModel[] runtime = null;

-	private ExtensionPointModel[] extensionPoints = null;

-	private ExtensionModel[] extensions = null;

 

 	// transient properties (not included in plug-in manifest)

-	private PluginRegistryModel registry = null;

-	private String location = null;

 	private boolean enabled = true; // whether or not the plugin definition loaded ok

 /**

  * Creates a new plug-in descriptor model in which all fields

@@ -36,22 +28,6 @@
 public PluginDescriptorModel() {

 	super();

 }

-/**

- * Returns the extension points in this plug-in descriptor.

- *

- * @return the extension points in this plug-in descriptor or <code>null</code>

- */

-public ExtensionPointModel[] getDeclaredExtensionPoints() {

-	return extensionPoints;

-}

-/**

- * Returns the extensions in this plug-in descriptor.

- *

- * @return the extensions in this plug-in descriptor or <code>null</code>

- */

-public ExtensionModel[] getDeclaredExtensions() {

-	return extensions;

-}

 /*

  * Returns true if this plugin has all of it's prerequisites and is,

  * therefore enabled.

@@ -60,28 +36,6 @@
 	return enabled;

 }

 /**

- * Returns the unique identifier of this plug-in descriptor

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

- * This identifier is a non-empty string and is unique 

- * within the plug-in registry.

- *

- * @return the unique identifier of the plug-in 

- *		(e.g. <code>"com.example"</code>) or <code>null</code>. 

- */

-public String getId() {

-	return id;

-}

-/**

- * Returns the location of the plug-in manifest file (e.g., <code>plugin.xml</code>)

- * which corresponds to this plug-in descriptor.  The location is in the

- * form of a URL.

- *

- * @return the location of this plug-in descriptor or <code>null</code>.

- */

-public String getLocation() {

-	return location;

-}

-/**

  * Returns the fully qualified name of the Java class which implements

  * the runtime support for this plug-in.

  *

@@ -91,21 +45,16 @@
 	return pluginClass;

 }

 /**

- * Returns the name of the provider who authored this plug-in.

+ * Returns the unique identifier of the plug-in related to this model

+ * or <code>null</code>.  

+ * This identifier is a non-empty string and is unique 

+ * within the plug-in registry.

  *

- * @return name of the provider who authored this plug-in or <code>null</code>

+ * @return the unique identifier of the plug-in related to this model

+ *		(e.g. <code>"com.example"</code>) or <code>null</code>. 

  */

-public String getProviderName() {

-	return providerName;

-}

-/**

- * Returns the plug-in registry of which this plug-in descriptor is a member.

- *

- * @return the registry in which this descriptor has been installed or 

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

- */

-public PluginRegistryModel getRegistry() {

-	return registry;

+public String getPluginId() {

+	return getId();

 }

 /**

  * Returns the prerequisites of this plug-in.

@@ -116,22 +65,6 @@
 	return requires;

 }

 /**

- * Returns the libraries configured for this plug-in.

- *

- * @return the libraries configured for this plug-in or <code>null</code>

- */

-public LibraryModel[] getRuntime() {

-	return runtime;

-}

-/**

- * Returns the version name of this plug-in.

- *

- * @return the version name of this plug-in or <code>null</code>

- */

-public String getVersion() {

-	return version;

-}

-/**

  * Sets this model object and all of its descendents to be read-only.

  * Subclasses may extend this implementation.

  *

@@ -139,40 +72,9 @@
  */

 public void markReadOnly() {

 	super.markReadOnly();

-	if (runtime != null)

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

-			runtime[i].markReadOnly();

 	if (requires != null)

 		for (int i = 0; i < requires.length; i++)

 			requires[i].markReadOnly();

-	if (extensionPoints != null)

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

-			extensionPoints[i].markReadOnly();

-	if (extensions != null)

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

-			extensions[i].markReadOnly();

-}

-/**

- * Sets the extension points in this plug-in descriptor.

- * This object must not be read-only.

- *

- * @param value the extension points in this plug-in descriptor.

- *		May be <code>null</code>.

- */

-public void setDeclaredExtensionPoints(ExtensionPointModel[] value) {

-	assertIsWriteable();

-	extensionPoints = value;

-}

-/**

- * Sets the extensions in this plug-in descriptor.

- * This object must not be read-only.

- *

- * @param value the extensions in this plug-in descriptor.

- *		May be <code>null</code>.

- */

-public void setDeclaredExtensions(ExtensionModel[] value) {

-	assertIsWriteable();

-	extensions = value;

 }

 /*

  * Sets the value of the field 'enabled' to the parameter 'value'.

@@ -186,31 +88,6 @@
 	enabled = value;

 }

 /**

- * Sets the unique identifier of this plug-in descriptor.

- * The identifier is a non-empty string and is unique 

- * within the plug-in registry.

- * This object must not be read-only.

- *

- * @param value the unique identifier of the plug-in (e.g. <code>"com.example"</code>).

- *		May be <code>null</code>.

- */

-public void setId(String value) {

-	assertIsWriteable();

-	id = value;

-}

-/**

- * Sets the location of the plug-in manifest file (e.g., <code>plugin.xml</code>)

- * which corresponds to this plug-in descriptor.  The location is in the

- * form of a URL.

- * This object must not be read-only.

- *

- * @param value the location of this plug-in descriptor.  May be <code>null</code>.

- */

-public void setLocation(String value) {

-	assertIsWriteable();

-	location = value;

-}

-/**

  * Sets the fully qualified name of the Java class which implements

  * the runtime support for this plug-in.

  * This object must not be read-only.

@@ -223,28 +100,6 @@
 	pluginClass = value;

 }

 /**

- * Sets the name of the provider who authored this plug-in.

- * This object must not be read-only.

- *

- * @param value name of the provider who authored this plug-in.

- *		May be <code>null</code>.

- */

-public void setProviderName(String value) {

-	assertIsWriteable();

-	providerName = value;

-}

-/**

- * Sets the registry with which this plug-in descriptor is associated.

- * This object must not be read-only.

- *

- * @param value the registry with which this plug-in is associated.

- *		May be <code>null</code>.

- */

-public void setRegistry(PluginRegistryModel value) {

-	assertIsWriteable();

-	registry = value;

-}

-/**

  * Sets the prerequisites of this plug-in.

  * This object must not be read-only.

  *

@@ -254,25 +109,4 @@
 	assertIsWriteable();

 	requires = value;

 }

-/**

- * Sets the libraries configured for this plug-in.

- * This object must not be read-only.

- *

- * @param value the libraries configured for this plug-in.  May be <code>null</code>.

- */

-public void setRuntime(LibraryModel[] value) {

-	assertIsWriteable();

-	runtime = value;

-}

-/**

- * Sets the version name of this plug-in.

- * This object must not be read-only.

- *

- * @param value the version name of this plug-in.

- *		May be <code>null</code>.

- */

-public void setVersion(String value) {

-	assertIsWriteable();

-	version = value;

-}

 }

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginFragmentModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginFragmentModel.java
new file mode 100644
index 0000000..ac4711b
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginFragmentModel.java
@@ -0,0 +1,78 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * Licensed Materials - Property of IBM,

+ * WebSphere Studio Workbench

+ * (c) Copyright IBM Corp 2000

+ */

+

+/**

+ * An object which represents the user-defined contents of a plug-in fragment

+ * in a plug-in manifest.

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+public class PluginFragmentModel extends PluginModel {

+

+	// DTD properties (included in plug-in manifest)

+	private String plugin = null;

+	private String pluginVersion = null;

+/**

+ * Creates a new plug-in descriptor model in which all fields

+ * are <code>null</code>.

+ */

+public PluginFragmentModel() {

+	super();

+}

+/**

+ * Returns the fully qualified name of the plug-in for which this is a fragment

+ *

+ * @return the name of this fragment's plug-in or <code>null</code>.

+ */

+public String getPlugin() {

+	return plugin;

+}

+/**

+ * Returns the unique identifier of the plug-in related to this model

+ * or <code>null</code>.  

+ * This identifier is a non-empty string and is unique 

+ * within the plug-in registry.

+ *

+ * @return the unique identifier of the plug-in related to this model

+ *		(e.g. <code>"com.example"</code>) or <code>null</code>. 

+ */

+public String getPluginId() {

+	return getPlugin();

+}

+/**

+ * Returns the version name of the plug-in for which this is a fragment.

+ *

+ * @return the version name of this fragment's plug-in or <code>null</code>

+ */

+public String getPluginVersion() {

+	return pluginVersion;

+}

+/**

+ * Sets the fully qualified name of the plug-in for which this is a fragment

+ * This object must not be read-only.

+ *

+ * @param value the name of this fragment's plug-in.

+ *		May be <code>null</code>.

+ */

+public void setPlugin(String value) {

+	assertIsWriteable();

+	plugin = value;

+}

+/**

+ * Sets the version name of the plug-in for which this is a fragment.

+ * This object must not be read-only.

+ *

+ * @param value the version name of this fragment's plug-in.

+ *		May be <code>null</code>.

+ */

+public void setPluginVersion(String value) {

+	assertIsWriteable();

+	pluginVersion = value;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginModel.java
new file mode 100644
index 0000000..1004621
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginModel.java
@@ -0,0 +1,226 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * Licensed Materials - Property of IBM,

+ * WebSphere Studio Workbench

+ * (c) Copyright IBM Corp 2000

+ */

+

+/**

+ * An object which represents the user-defined contents of a plug-in model

+ * (either a descriptor or a fragment) in a plug-in manifest.

+ * <p>

+ * This class may not be instantiated, but may be further subclassed.

+ * </p>

+ */

+public abstract class PluginModel extends PluginModelObject {

+

+	// DTD properties (included in plug-in manifest)

+	private String id = null;

+	private String providerName = null;

+	private String version = null;

+	private String plugin = null;

+	private LibraryModel[] runtime = null;

+	private ExtensionPointModel[] extensionPoints = null;

+	private ExtensionModel[] extensions = null;

+

+	// transient properties (not included in plug-in manifest)

+	private PluginRegistryModel registry = null;

+	private String location = null;

+/**

+ * Creates a new plug-in descriptor model in which all fields

+ * are <code>null</code>.

+ */

+public PluginModel() {

+	super();

+}

+/**

+ * Returns the extension points in this plug-in descriptor.

+ *

+ * @return the extension points in this plug-in descriptor or <code>null</code>

+ */

+public ExtensionPointModel[] getDeclaredExtensionPoints() {

+	return extensionPoints;

+}

+/**

+ * Returns the extensions in this plug-in descriptor.

+ *

+ * @return the extensions in this plug-in descriptor or <code>null</code>

+ */

+public ExtensionModel[] getDeclaredExtensions() {

+	return extensions;

+}

+/**

+ * Returns the unique identifier of this plug-in model

+ * or <code>null</code>.

+ * This identifier is a non-empty string and is unique 

+ * within the plug-in registry.

+ *

+ * @return the unique identifier of this plugin model

+ *		(e.g. <code>"com.example"</code>) or <code>null</code>. 

+ */

+public String getId() {

+	return id;

+}

+/**

+ * Returns the location of the plug-in manifest file (e.g., <code>plugin.xml</code>)

+ * which corresponds to this plug-in descriptor.  The location is in the

+ * form of a URL.

+ *

+ * @return the location of this plug-in descriptor or <code>null</code>.

+ */

+public String getLocation() {

+	return location;

+}

+/**

+ * Returns the unique identifier of the plug-in related to this model

+ * or <code>null</code>.  

+ * This identifier is a non-empty string and is unique 

+ * within the plug-in registry.

+ *

+ * @return the unique identifier of the plug-in related to this model

+ *		(e.g. <code>"com.example"</code>) or <code>null</code>. 

+ */

+public abstract String getPluginId();

+/**

+ * Returns the name of the provider who authored this plug-in.

+ *

+ * @return name of the provider who authored this plug-in or <code>null</code>

+ */

+public String getProviderName() {

+	return providerName;

+}

+/**

+ * Returns the plug-in registry of which this plug-in descriptor is a member.

+ *

+ * @return the registry in which this descriptor has been installed or 

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

+ */

+public PluginRegistryModel getRegistry() {

+	return registry;

+}

+/**

+ * Returns the libraries configured for this plug-in.

+ *

+ * @return the libraries configured for this plug-in or <code>null</code>

+ */

+public LibraryModel[] getRuntime() {

+	return runtime;

+}

+/**

+ * Returns the version name of this plug-in.

+ *

+ * @return the version name of this plug-in or <code>null</code>

+ */

+public String getVersion() {

+	return version;

+}

+/**

+ * Sets this model object and all of its descendents to be read-only.

+ * Subclasses may extend this implementation.

+ *

+ * @see #isReadOnly

+ */

+public void markReadOnly() {

+	super.markReadOnly();

+	if (runtime != null)

+		for (int i = 0; i < runtime.length; i++)

+			runtime[i].markReadOnly();

+	if (extensionPoints != null)

+		for (int i = 0; i < extensionPoints.length; i++)

+			extensionPoints[i].markReadOnly();

+	if (extensions != null)

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

+			extensions[i].markReadOnly();

+}

+/**

+ * Sets the extension points in this plug-in descriptor.

+ * This object must not be read-only.

+ *

+ * @param value the extension points in this plug-in descriptor.

+ *		May be <code>null</code>.

+ */

+public void setDeclaredExtensionPoints(ExtensionPointModel[] value) {

+	assertIsWriteable();

+	extensionPoints = value;

+}

+/**

+ * Sets the extensions in this plug-in descriptor.

+ * This object must not be read-only.

+ *

+ * @param value the extensions in this plug-in descriptor.

+ *		May be <code>null</code>.

+ */

+public void setDeclaredExtensions(ExtensionModel[] value) {

+	assertIsWriteable();

+	extensions = value;

+}

+/**

+ * Sets the unique identifier of this plug-in model.

+ * The identifier is a non-empty string and is unique 

+ * within the plug-in registry.

+ * This object must not be read-only.

+ *

+ * @param value the unique identifier of the plug-in model (e.g. <code>"com.example"</code>).

+ *		May be <code>null</code>.

+ */

+public void setId(String value) {

+	assertIsWriteable();

+	id = value;

+}

+/**

+ * Sets the location of the plug-in manifest file (e.g., <code>plugin.xml</code>)

+ * which corresponds to this plug-in descriptor.  The location is in the

+ * form of a URL.

+ * This object must not be read-only.

+ *

+ * @param value the location of this plug-in descriptor.  May be <code>null</code>.

+ */

+public void setLocation(String value) {

+	assertIsWriteable();

+	location = value;

+}

+/**

+ * Sets the name of the provider who authored this plug-in.

+ * This object must not be read-only.

+ *

+ * @param value name of the provider who authored this plug-in.

+ *		May be <code>null</code>.

+ */

+public void setProviderName(String value) {

+	assertIsWriteable();

+	providerName = value;

+}

+/**

+ * Sets the registry with which this plug-in descriptor is associated.

+ * This object must not be read-only.

+ *

+ * @param value the registry with which this plug-in is associated.

+ *		May be <code>null</code>.

+ */

+public void setRegistry(PluginRegistryModel value) {

+	assertIsWriteable();

+	registry = value;

+}

+/**

+ * Sets the libraries configured for this plug-in.

+ * This object must not be read-only.

+ *

+ * @param value the libraries configured for this plug-in.  May be <code>null</code>.

+ */

+public void setRuntime(LibraryModel[] value) {

+	assertIsWriteable();

+	runtime = value;

+}

+/**

+ * Sets the version name of this plug-in.

+ * This object must not be read-only.

+ *

+ * @param value the version name of this plug-in.

+ *		May be <code>null</code>.

+ */

+public void setVersion(String value) {

+	assertIsWriteable();

+	version = value;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginPrerequisiteModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginPrerequisiteModel.java
index c253b5d..1383a7d 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginPrerequisiteModel.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginPrerequisiteModel.java
@@ -22,6 +22,7 @@
 	private boolean match = false;

 	private boolean export = false;

 	private String resolvedVersion = null;

+	private boolean optional = false;

 /**

  * Creates a new plug-in prerequisite model in which all fields

  * are <code>null</code>.

@@ -46,6 +47,14 @@
 	return match;

 }

 /**

+ * Returns whether this pre-requisite is optional.

+ *

+ * @return whether this pre-requisite is optional

+ */

+public boolean getOptional() {

+	return optional;

+}

+/**

  * Returns the plug-in identifier of the prerequisite plug-in.

  * 

  * @return the plug-in identifier or <code>null</code>

@@ -92,6 +101,16 @@
 	match = value;

 }

 /**

+ * Sets whether this pre-requisite is optional.

+ * This object must not be read-only.

+ *

+ * @param value whether this pre-requisite is optional

+ */

+public void setOptional(boolean value) {

+	assertIsWriteable();

+	optional = value;

+}

+/**

  * Sets the plug-in identifier of this prerequisite plug-in.

  * This object must not be read-only.

  * 

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginRegistryModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginRegistryModel.java
index 63d28b6..29ef7ae 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginRegistryModel.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginRegistryModel.java
@@ -20,6 +20,7 @@
 

 	// transient properties (not included in plug-in manifest)

 	private Map plugins = new HashMap(30);

+	private Map fragments = new HashMap(30);

 	private boolean readOnly = false;

 	private boolean resolved = false;

 /**

@@ -29,6 +30,28 @@
 	super();

 }

 /**

+ * Adds the specified plug-in fragment to this registry.  An existing fragment

+ * with the same unique id and version is replaced by the new

+ * value.  

+ *

+ * @param fragment the plug-in fragment to add

+ */

+public void addFragment(PluginFragmentModel fragment) {

+	assertIsWriteable();

+	String key = fragment.getId();

+	PluginFragmentModel[] list = getFragments(key);

+	if (list == null) {

+		list = new PluginFragmentModel[1];

+		list[0] = fragment;

+		fragments.put(key, list);

+	} else {

+		PluginFragmentModel[] newList = new PluginFragmentModel[list.length + 1];

+		System.arraycopy(list, 0, newList, 0, list.length);

+		newList[list.length] = fragment;

+		fragments.put(key, newList);

+	}

+}

+/**

  * Adds the specified plug-in to this registry.  An existing plug-in

  * with the same unique id and version is replaced by the new

  * value.  

@@ -58,6 +81,68 @@
 	Assert.isTrue(!isReadOnly(), "Model is read-only");

 }

 /**

+ * Returns the plug-in fragment with the given identifier

+ * in this plug-in registry, or <code>null</code> if there is no such

+ * fragment.  If there are multiple versions of the identified fragment,

+ * one will be non-deterministically choosen and returned.  

+ *

+ * @param id the unique identifier of the plug-in fragment

+ *		(e.g. <code>"com.example.acme"</code>).

+ * @return the plug-in fragment, or <code>null</code>

+ */

+public PluginFragmentModel getFragment(String id) {

+	PluginFragmentModel[] result = (PluginFragmentModel[]) fragments.get(id);

+	return result == null ? null : result[0];

+}

+/**

+ * Returns the identified plug-in fragment or <code>null</code> if

+ * the fragment does not exist.

+ *

+ * @return the matching fragment in this registry

+ */

+public PluginFragmentModel getFragment(String id, String version) {

+	PluginFragmentModel[] list = getFragments(id);

+	if (list == null || list.length == 0)

+		return null;

+	if (version == null)

+		// Just return the first one in the list (random)

+		return list[0];

+

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

+		PluginFragmentModel element = list[i];

+		if (element.getVersion().equals(version))

+			return element;

+	}

+	return null;

+}

+/**

+ * Returns the list of plug-in fragments managed by this registry.

+ *

+ * @return the fragments in this registry

+ */

+public PluginFragmentModel[] getFragments() {

+	List result = new ArrayList(fragments.size());

+	for (Iterator i = fragments.values().iterator(); i.hasNext();) {

+		PluginFragmentModel[] entries = (PluginFragmentModel[]) i.next();

+		for (int j = 0; j < entries.length; j++)

+			result.add(entries[j]);

+	}

+	return (PluginFragmentModel[]) result.toArray(new PluginFragmentModel[result.size()]);

+}

+/**

+ * Returns all versions of the identified plug-in fragment

+ * known to this plug-in registry.

+ * Returns an empty array if there are no fragments

+ * with the specified identifier.

+ *

+ * @param id the unique identifier of the plug-in fragment

+ *		(e.g. <code>"org.eclipse.core.resources"</code>).

+ * @return the fragments known to this plug-in registry with the given id

+ */

+public PluginFragmentModel[] getFragments(String id) {

+	return (PluginFragmentModel[]) fragments.get(id);

+}

+/**

  * Returns the plug-in descriptor with the given plug-in identifier

  * in this plug-in registry, or <code>null</code> if there is no such

  * plug-in.  If there are multiple versions of the identified plug-in,

@@ -78,23 +163,22 @@
  * @return the matching plug-in in this registry

  */

 public PluginDescriptorModel getPlugin(String pluginId, String version) {

-

-	PluginDescriptorModel[] plugins = getPlugins(pluginId);

-	if (plugins == null || plugins.length == 0)

+	PluginDescriptorModel[] list = getPlugins(pluginId);

+	if (list == null || list.length == 0)

 		return null;

 	if (version == null)

 		// Just return the first one in the list (random)

-		return plugins[0];

+		return list[0];

 

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

-		PluginDescriptorModel element = plugins[i];

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

+		PluginDescriptorModel element = list[i];

 		if (element.getVersion().equals(version))

 			return element;

 	}

 	return null;

 }

 /**

- * Returns the of plug-ins managed by this registry.

+ * Returns the list of plug-ins managed by this registry.

  *

  * @return the plug-ins in this registry

  */

@@ -161,6 +245,49 @@
 	resolved = true;

 }

 /**

+ * Removes the fragment with id and version if it exists in this registry.

+ * This method has no effect if a fragment with the given id and version 

+ * cannot be found.

+ *

+ * @param id the unique identifier of the fragment to remove

+ * @param version the version of the fragment to remove

+ */

+public void removeFragment(String id, String version) {

+	assertIsWriteable();

+	PluginFragmentModel[] list = getFragments(id);

+	if (list == null || list.length == 0)

+		return;

+	int removedCount = 0;

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

+		if (version.equals(list[i].getVersion())) {

+			list[i] = null;

+			removedCount++;

+		}

+	}

+	// If all were removed, toss the whole entry.  Otherwise, compact the array

+	if (removedCount == list.length)

+		removeFragments(id);

+	else {

+		PluginFragmentModel[] newList = new PluginFragmentModel[list.length - removedCount];

+		int index = 0;

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

+			if (list[i] != null)

+				newList[index++] = list[i];

+		}

+		fragments.put(id, newList);

+	}

+}

+/**

+ * Removes all versions of the identified plug-in fragment from this registry.

+ * This method has no effect if such a fragment cannot be found.

+ *

+ * @param id the unique identifier of the fragments to remove

+ */

+public void removeFragments(String id) {

+	assertIsWriteable();

+	fragments.remove(id);

+}

+/**

  * Removes the plug-in with id and version if it exists in this registry.

  * This method has no effect if a plug-in with the given id and version 

  * cannot be found.

@@ -226,7 +353,7 @@
 public IStatus resolve(boolean trimDisabledPlugins, boolean doCrossLinking) {

 	RegistryResolver resolver = new RegistryResolver();

 	resolver.setTrimPlugins(trimDisabledPlugins);

-	resolver.setCrossLinking(doCrossLinking);

+	resolver.setCrossLink(doCrossLinking);

 	return resolver.resolve(this);

 }

 }