This commit was manufactured by cvs2svn to create branch 'JohnWork'.

Cherrypick from master 2001-08-27 18:19:14 UTC John Arthorne <johna> 'New path implementation using String[] for segments':
    bundles/org.eclipse.core.runtime/.classpath
    bundles/org.eclipse.core.runtime/.cvsignore
    bundles/org.eclipse.core.runtime/.options
    bundles/org.eclipse.core.runtime/.vcm_meta
    bundles/org.eclipse.core.runtime/build.properties
    bundles/org.eclipse.core.runtime/doc/hglegal.htm
    bundles/org.eclipse.core.runtime/doc/ngibmcpy.gif
    bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime.html
    bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime_applications.html
    bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime_urlHandlers.html
    bundles/org.eclipse.core.runtime/plugin.jars
    bundles/org.eclipse.core.runtime/plugin.properties
    bundles/org.eclipse.core.runtime/plugin.xml
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ConfigurationElement.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ConfigurationProperty.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/DefaultPlugin.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Extension.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ExtensionPoint.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/FragmentDescriptor.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IPluginVisitor.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/InternalFactory.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Library.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginClassLoader.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginDescriptor.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginParser.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginPrerequisite.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginRegistry.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheReader.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheWriter.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryLoader.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryResolver.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryWriter.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AdapterManager.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Assert.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AssertionFailedException.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AuthorizationDatabase.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Cipher.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/CipherInputStream.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/CipherOutputStream.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Log.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformLogListener.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformMetaArea.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLFragmentConnection.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginConnection.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginHandlerFactory.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PluginStats.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Policy.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/RuntimeStats.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/SafeFileInputStream.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/SafeFileOutputStream.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/URLTool.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/messages.properties
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/CoreException.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdaptable.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdapterFactory.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdapterManager.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IConfigurationElement.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExecutableExtension.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExtension.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExtensionPoint.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILibrary.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILog.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILogListener.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPath.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginDescriptor.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginPrerequisite.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginRegistry.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IProgressMonitor.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ISafeRunnable.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IStatus.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/MultiStatus.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/NullProgressMonitor.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/OperationCanceledException.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Path.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Platform.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/PlatformObject.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/PluginVersionIdentifier.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ProgressMonitorWrapper.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/QualifiedName.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Status.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/SubProgressMonitor.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ComponentModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationElementModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationPropertyModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionPointModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/Factory.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/InstallModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/LibraryModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginDescriptorModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginFragmentModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginModelObject.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginPrerequisiteModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginRegistryModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/URLModel.java
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/package.html
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/package.html
Cherrypick from master 2001-08-10 18:19:38 UTC dwilson <dwilson> 'Some error reporting + 1GGEPM1: ITPCORE:WIN2000 - More than one runtime element allowed in plugin.xml':
    bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Messages.properties
diff --git a/bundles/org.eclipse.core.runtime/.classpath b/bundles/org.eclipse.core.runtime/.classpath
new file mode 100644
index 0000000..3483c51
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+    <classpathentry kind="var" path="JRE_LIB" rootpath="JRE_SRCROOT" sourcepath="JRE_SRC"/>
+    <classpathentry kind="src" path="/org.eclipse.core.boot"/>
+    <classpathentry kind="src" path="Eclipse Core Runtime"/>
+    <classpathentry kind="var" path="TARGET/org.apache.xerces/xerces.jar"/>
+    <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.core.runtime/.cvsignore b/bundles/org.eclipse.core.runtime/.cvsignore
new file mode 100644
index 0000000..c5e82d7
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/.cvsignore
@@ -0,0 +1 @@
+bin
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.runtime/.options b/bundles/org.eclipse.core.runtime/.options
new file mode 100644
index 0000000..c1fa3e2
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/.options
@@ -0,0 +1,18 @@
+org.eclipse.core.runtime/debug=true

+org.eclipse.core.runtime/registry/debug=false

+org.eclipse.core.runtime/registry/debug/resolve=false

+org.eclipse.core.runtime/loader/debug=false

+org.eclipse.core.runtime/loader/debug/create=false

+org.eclipse.core.runtime/loader/debug/activateplugin=false

+org.eclipse.core.runtime/loader/debug/actions=false

+org.eclipse.core.runtime/loader/debug/success=false

+org.eclipse.core.runtime/loader/debug/failure=false

+org.eclipse.core.runtime/loader/debug/filter/loader=*

+org.eclipse.core.runtime/loader/debug/filter/class=*

+org.eclipse.core.runtime/loader/debug/filter/resource=*

+org.eclipse.core.runtime/loader/debug/filter/native=*

+org.eclipse.core.runtime/url/debug=false

+org.eclipse.core.runtime/url/debug/connect=false

+org.eclipse.core.runtime/url/debug/cachelookup=false

+org.eclipse.core.runtime/url/debug/cachecopy=false

+org.eclipse.core.runtime/update/debug=false
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.runtime/.vcm_meta b/bundles/org.eclipse.core.runtime/.vcm_meta
new file mode 100644
index 0000000..559fef2
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/.vcm_meta
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<project-description>

+	<comment></comment>

+	<nature id="org.eclipse.jdt.core.javanature"/>

+	<reference project-name="org.eclipse.core.boot"/>

+	<builder name="org.eclipse.jdt.core.javabuilder">

+	</builder>

+</project-description>

diff --git a/bundles/org.eclipse.core.runtime/build.properties b/bundles/org.eclipse.core.runtime/build.properties
new file mode 100644
index 0000000..d3c51b3
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/build.properties
@@ -0,0 +1,8 @@
+# VAJ build contribution

+build.includes=doc/,.options,plugin.jars,plugin.xml,build.properties,plugin.properties

+build.vaj.Eclipse\ Core\ Runtime=Eclipse Core Runtime

+

+# Eclipse build contribution

+source.runtime.jar=Eclipse Core Runtime

+bin.includes=.options,plugin.xml,*.jar,plugin.properties

+javadoc.packages=org.eclipse.core.runtime.*

diff --git a/bundles/org.eclipse.core.runtime/doc/hglegal.htm b/bundles/org.eclipse.core.runtime/doc/hglegal.htm
new file mode 100644
index 0000000..b071dbd
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/doc/hglegal.htm
@@ -0,0 +1,14 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">

+<html>

+<head>

+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

+   <meta name="GENERATOR" content="Mozilla/4.73 [en] (Win98; U) [Netscape]">

+   <title>Legal Notices</title>

+</head>

+<body>

+

+<h3>

+<a NAME="Notices"></a>Notices</h3>

+(c) Copyright IBM Corp. 2000, 2001. All Rights Reserved.

+</body>

+</html>

diff --git a/bundles/org.eclipse.core.runtime/doc/ngibmcpy.gif b/bundles/org.eclipse.core.runtime/doc/ngibmcpy.gif
new file mode 100644
index 0000000..360f8e9
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/doc/ngibmcpy.gif
Binary files differ
diff --git a/bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime.html b/bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime.html
new file mode 100644
index 0000000..bc20559
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime.html
@@ -0,0 +1,27 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">

+<html>

+<head>

+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

+   <title>Workbench Extension Points</title>

+</head>

+<body link="#0000FF" vlink="#800080">

+

+<center>

+<h1>Core Runtime Plug-in</h1></center>

+This document lists all of the extension points that the core runtime makes available to tool developers.

+<p>

+<hr WIDTH="100%">

+<h1>

+General Extension Points</h1>

+The following extension points can be used to extend the fundamental capabilities

+of the runtime plug-in:

+<ul>

+<li>

+<a href="org_eclipse_core_runtime_applications.html">org.eclipse.core.runtime.applications</a></li>

+

+<li>

+<a href="org_eclipse_core_runtime_urlHandlers.html">org.eclipse.core.runtime.urlHandlers</a></li>

+</ul>

+<a href="hglegal.htm"><img SRC="ngibmcpy.gif" ALT="Copyright IBM Corp. 2000, 2001.  All Rights Reserved." BORDER=0 height=12 width=195></a>

+</body>

+</html>

diff --git a/bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime_applications.html b/bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime_applications.html
new file mode 100644
index 0000000..07c59b2
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime_applications.html
@@ -0,0 +1,65 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">

+<html>

+<head>

+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

+   <title>Workbench Extension Points</title>

+</head>

+<body link="#0000FF" vlink="#800080">

+

+<center>

+<h1>

+Applications</h1></center>

+<b><i>Identifier: </i></b>org.eclipse.core.runtime.applications<p><b><i>Description:

+</i></b>Platform runtime supports plug-ins which would like to declare main

+entry points.&nbsp; That is, programs which would like to run using the platform

+runtime but yet control all aspects of execution can declare themselves as an <i>application</i>.&nbsp;

+Declared applications can be run directly from the main platform launcher by

+specifying the <i>-application</i> argument where the parameter is the id of an

+extension supplied to the applications extension point described here.&nbsp;

+This application is instantiated and run by the platform.&nbsp; Platform clients

+can also use the platform to lookup and run multiple applications.&nbsp;&nbsp;

+<p><b><i>Configuration Markup:</i></b>

+<p><tt>&nbsp;&nbsp; &lt;!ELEMENT application run?></tt>

+<p>

+<tt>&nbsp;&nbsp; &lt;!ELEMENT run parameter*></tt>

+<br><tt>&nbsp;&nbsp; &lt;!ATTLIST run</tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

+CDATA #REQUIRED</tt>

+<br><tt>&nbsp;&nbsp; ></tt>

+<ul>

+<li>

+<b>class -</b> the fully-qualified name of a class which implements&nbsp; <tt>org.eclipse.core.boot.IPlatformRunnable</tt>.</li>

+</ul>

+<tt>&nbsp;&nbsp; &lt;!ELEMENT parameter EMPTY></tt>

+<br><tt>&nbsp;&nbsp; &lt;!ATTLIST parameter</tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

+CDATA #REQUIRED</tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

+CDATA #REQUIRED</tt>

+<br><tt>&nbsp;&nbsp; ></tt>

+<ul>

+<li>

+<b>name</b> - the name of this parameter made available to instances of

+the specified application class</li>

+

+<li>

+<b>value</b> - an arbitrary value associated with the given name and made

+available to instances of the specified application class</li>

+</ul>

+<b><i>Examples:</i></b>

+<p>Following is an example of a builder configuration:

+<p><tt>&nbsp;&nbsp; &lt;extension id=&quot;coolApplication&quot; point=&quot;org.eclipse.core.runtime.applications&quot;&gt;</tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;application&gt;</tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;run class=&quot;com.xyz.applications.Cool&quot;&gt;</tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

+&lt;parameter name="optimize" value="true"/></tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/run></tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/application&gt;</tt>

+<br><tt>&nbsp;&nbsp; &lt;/extension></tt>

+<p><b><i>API Information</i>: </b>The value of the <tt>class</tt> attribute

+must represent an implementor of <tt>org.eclipse.core.boot.IPlatformRunnable</tt>.

+<p><b><i>Supplied Implementation:</i></b> The platform itself supplies a number

+of applications including the platform workbench itself.

+<p><a href="hglegal.htm"><img SRC="ngibmcpy.gif" ALT="Copyright IBM Corp. 2000, 2001.  All Rights Reserved." BORDER=0 height=12 width=195></a>

+</body>

+</html>

diff --git a/bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime_urlHandlers.html b/bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime_urlHandlers.html
new file mode 100644
index 0000000..b1931c0
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/doc/org_eclipse_core_runtime_urlHandlers.html
@@ -0,0 +1,45 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">

+<html>

+<head>

+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; U) [Netscape]">

+   <title>Workbench Extension Points</title>

+</head>

+<body link="#0000FF" vlink="#800080">

+

+<center>

+<h1>

+URL Stream Handlers</h1></center>

+<b><i>Identifier: </i></b>org.eclipse.core.runtime.urlHandlers

+<p><b><i>Description:

+</i></b>This extension point is used to register

+additional URL handlers to the platform search path. Note, that because

+of the platform class loader structure, URL handlers registered by a plug-in

+using the standard Java mechanisms will not be found.

+<p><b><i>Configuration Markup:</i></b>

+<p><tt>&nbsp;&nbsp; &lt;!ELEMENT handler EMPTY></tt>

+<p><tt>&nbsp;&nbsp; &lt;!ATTLIST handler</tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protocol&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

+CDATA #REQUIRED</tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

+CDATA #REQUIRED</tt>

+<br><tt>&nbsp;&nbsp; ></tt>

+<ul>

+<li>

+<b>protocol -</b> URL protocol</li>

+

+<li>

+<b>class</b> - URL stream handler contributed by plug-in</li>

+</ul>

+<b><i>Examples:</i></b>

+<p>Following is an example of a handler configuration:

+<p><tt>&nbsp;&nbsp; &lt;extension point="org.eclipse.core.runtime.urlHandlers"></tt>

+<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;handler protocol="foo" class="org.eclipse.handlers.FooHandler"/></tt>

+<br><tt>&nbsp;&nbsp; &lt;/extension></tt>

+<p><b><i>API Information</i>: </b>The value of the <tt>class</tt> attribute

+must represent an implementor of implementation of <tt>java.net.URLStreamHandler</tt>

+<p><b><i>Supplied Implementation:</i></b> The platform itself does not

+supply any URL handlers registered through this extension point..

+<p><a href="hglegal.htm"><img SRC="ngibmcpy.gif" ALT="Copyright IBM Corp. 2000, 2001.  All Rights Reserved." BORDER=0 height=12 width=195></a>

+</body>

+</html>

diff --git a/bundles/org.eclipse.core.runtime/plugin.jars b/bundles/org.eclipse.core.runtime/plugin.jars
new file mode 100644
index 0000000..5bfba12
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/plugin.jars
@@ -0,0 +1 @@
+runtime.jar=Eclipse Core Runtime

diff --git a/bundles/org.eclipse.core.runtime/plugin.properties b/bundles/org.eclipse.core.runtime/plugin.properties
new file mode 100644
index 0000000..e35523e
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/plugin.properties
@@ -0,0 +1,3 @@
+pluginName = Core Runtime

+applicationsName = Applications

+handlersName = URL Stream Handlers

diff --git a/bundles/org.eclipse.core.runtime/plugin.xml b/bundles/org.eclipse.core.runtime/plugin.xml
new file mode 100644
index 0000000..15ae645
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/plugin.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<plugin

+  name="%pluginName"

+  id="org.eclipse.core.runtime"

+  version="1.0"

+  provider-name="Object Technology International, Inc.">

+

+  <runtime>

+    <library name="runtime.jar">

+      <export name="*"/>

+    </library>

+  </runtime>

+

+  <requires>

+    <import plugin="org.apache.xerces"/>

+  </requires>

+

+  <extension-point name="%applicationsName" id="applications"/>

+  <extension-point name="%handlersName" id="urlHandlers"/>

+

+</plugin>

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ConfigurationElement.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ConfigurationElement.java
new file mode 100644
index 0000000..3256dfb
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ConfigurationElement.java
@@ -0,0 +1,156 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.internal.runtime.InternalPlatform;

+import org.eclipse.core.internal.runtime.Policy;

+import java.util.*;

+

+public class ConfigurationElement extends ConfigurationElementModel implements IConfigurationElement {

+  public ConfigurationElement()

+  {

+	super();

+  }  

+public Object createExecutableExtension(String attributeName) throws CoreException {

+	String prop = null;

+	String executable;

+	String pluginName = null;

+	String className = null;

+	Object initData = null;

+	int i;

+

+	if (attributeName != null)

+		prop = getAttribute(attributeName);

+	else {

+		// property not specified, try as element value

+		prop = getValue();

+		if (prop != null) {

+			prop = prop.trim();

+			if (prop.equals(""))

+				prop = null;

+		}

+	}

+

+	if (prop == null) {

+		// property not defined, try as a child element

+		IConfigurationElement[] exec;

+		IConfigurationElement[] parms;

+		IConfigurationElement element;

+		Hashtable initParms;

+		String pname;

+

+		exec = getChildren(attributeName);

+		if (exec.length != 0) {

+			element = exec[0]; // assumes single definition

+			pluginName = (String) element.getAttribute("plugin");

+			className = (String) element.getAttribute("class");

+			parms = element.getChildren("parameter");

+			if (parms != null) {

+				initParms = new Hashtable(parms.length + 1);

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

+					pname = (String) parms[i].getAttribute("name");

+					if (pname != null)

+						initParms.put(pname, parms[i].getAttribute("value"));

+				}

+				if (!initParms.isEmpty())

+					initData = initParms;

+			}

+		}

+

+		// specified name is not a simple attribute nor child element

+		else {

+			String message = Policy.bind("plugin.extDefNotFound", attributeName);

+			IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.PLUGIN_ERROR, message, null);

+			throw new CoreException(status);

+		}

+	} else {

+		// simple property or element value, parse it into its components

+		i = prop.indexOf(':');

+		if (i != -1) {

+			executable = prop.substring(0, i).trim();

+			initData = prop.substring(i + 1).trim();

+		} else

+			executable = prop;

+

+		i = executable.indexOf('/');

+		if (i != -1) {

+			pluginName = executable.substring(0, i).trim();

+			className = executable.substring(i + 1).trim();

+		} else

+			className = executable;

+	}

+

+	if (className == null || className.equals("")) {

+		String message = Policy.bind("plugin.extDefNoClass", attributeName );

+		IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.PLUGIN_ERROR, message, null);

+		logError(status);

+		throw new CoreException(status);

+	}

+

+	IPluginDescriptor plugin = getDeclaringExtension().getDeclaringPluginDescriptor();

+	return ((PluginDescriptor) plugin).createExecutableExtension(pluginName, className, initData, this, attributeName);

+}

+public String getAttribute(String name) {

+

+	String s = getAttributeAsIs(name);	

+	return s==null ? null : getDeclaringExtension().getDeclaringPluginDescriptor().getResourceString(s);

+}

+public String getAttributeAsIs(String name) {

+	ConfigurationPropertyModel[] list = (ConfigurationPropertyModel[]) getProperties();

+	if (list == null)

+		return null;

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

+		if (name.equals(list[i].getName()))

+			return list[i].getValue();

+	return null;

+}

+public String[] getAttributeNames() {

+	ConfigurationPropertyModel[] list = getProperties();

+	if (list == null)

+		return new String[0];

+	String[] result = new String[list.length];

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

+		result[i] = list[i].getName();

+	return result;

+}

+public IConfigurationElement[] getChildren() {

+	ConfigurationElementModel[] list = getSubElements();

+	if (list == null)

+		return new IConfigurationElement[0];

+	IConfigurationElement[] newValues = new IConfigurationElement[list.length];

+	System.arraycopy(list, 0, newValues, 0, list.length);

+	return newValues;

+}

+public IConfigurationElement[] getChildren(String name) {

+	ConfigurationElementModel[] list = getSubElements();

+	if (list == null)

+		return new IConfigurationElement[0];

+	ArrayList children = new ArrayList();

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

+		ConfigurationElementModel	element = list[i];

+		if (name.equals(element.getName()))

+			children.add(list[i]);

+	}

+	return (IConfigurationElement[]) children.toArray(new IConfigurationElement[children.size()]);

+}

+public IExtension getDeclaringExtension() {

+	return (IExtension) getParentExtension();

+}

+public String getValue() {

+	String s = getValueAsIs();

+	return s == null ? null : getDeclaringExtension().getDeclaringPluginDescriptor().getResourceString(s);

+}

+public String getValueAsIs() {

+	return super.getValue();

+}

+private void logError(IStatus status) {

+	InternalPlatform.getRuntimePlugin().getLog().log(status);

+	if (InternalPlatform.DEBUG)

+		System.out.println(status.getMessage());

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ConfigurationProperty.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ConfigurationProperty.java
new file mode 100644
index 0000000..20ba74d
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ConfigurationProperty.java
@@ -0,0 +1,16 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import java.io.PrintWriter;

+

+public class ConfigurationProperty extends ConfigurationPropertyModel {

+public ConfigurationProperty() {

+	super();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/DefaultPlugin.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/DefaultPlugin.java
new file mode 100644
index 0000000..e58798d
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/DefaultPlugin.java
@@ -0,0 +1,19 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * Dummy plugin runtime class implementation

+ */

+import org.eclipse.core.runtime.Plugin;

+import org.eclipse.core.runtime.IPluginDescriptor;

+

+public class DefaultPlugin extends Plugin {

+

+public DefaultPlugin(IPluginDescriptor descriptor) {

+	super(descriptor);

+}

+}

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
new file mode 100644
index 0000000..94b04d4
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Extension.java
@@ -0,0 +1,49 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.internal.plugins.IModel;

+import org.eclipse.core.internal.runtime.Policy;

+import java.util.*;

+

+public class Extension extends ExtensionModel implements IExtension {

+  public Extension()

+  {

+	super();

+  }  

+public IConfigurationElement[] getConfigurationElements() {

+	ConfigurationElementModel[] list = getSubElements();

+	if (list == null)

+		return new IConfigurationElement[0];

+	IConfigurationElement[] newValues = new IConfigurationElement[list.length];

+	System.arraycopy(list, 0, newValues, 0, list.length);

+	return newValues;

+}

+public IPluginDescriptor getDeclaringPluginDescriptor() {

+	return (IPluginDescriptor) getParentPluginDescriptor();

+}

+public String getExtensionPointUniqueIdentifier() {

+	return getExtensionPoint();

+}

+public String getLabel() {

+	String s = getName();

+	return s == null ? "" : ((PluginDescriptor) getDeclaringPluginDescriptor()).getResourceString(s);

+}

+public String getSimpleIdentifier() {

+	return getId();

+}

+public String getUniqueIdentifier() {

+	String simple = getSimpleIdentifier();

+	if (simple == null)

+		return null;

+	return getParentPluginDescriptor().getId() + "." + simple;

+}

+public String toString() {

+	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
new file mode 100644
index 0000000..2875189
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/ExtensionPoint.java
@@ -0,0 +1,72 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.internal.plugins.IModel;

+import java.util.*;

+import java.io.File;

+

+public class ExtensionPoint extends ExtensionPointModel implements IExtensionPoint {

+  public ExtensionPoint()

+  {

+	super();

+  }  

+public IConfigurationElement[] getConfigurationElements() {

+	ExtensionModel[] list = getDeclaredExtensions();

+	if (list == null)

+		return new IConfigurationElement[0];

+	ArrayList result = new ArrayList();

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

+		ConfigurationElementModel[] configs = list[i].getSubElements();

+		if (configs != null)

+			for (int j = 0; j < configs.length; j++)

+				result.add(configs[j]);

+	}

+	return (IConfigurationElement[]) result.toArray(new IConfigurationElement[result.size()]);

+}

+public IPluginDescriptor getDeclaringPluginDescriptor() {

+	return (IPluginDescriptor) getParentPluginDescriptor();

+}

+public IExtension getExtension(String id) {

+	if (id == null)

+		return null;

+	ExtensionModel[] list = getDeclaredExtensions();

+	if (list == null)

+		return null;

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

+		if (id.equals(((Extension) list[i]).getUniqueIdentifier()))

+			return (IExtension) list[i];

+	}

+	return null;

+}

+public IExtension[] getExtensions() {

+	ExtensionModel[] list = getDeclaredExtensions();

+	if (list == null)

+		return new IExtension[0];

+	IExtension[] newValues = new IExtension[list.length];

+	System.arraycopy(list, 0, newValues, 0, list.length);

+	return newValues;

+}

+public String getLabel() {

+	String s = getName();

+	return s == null ? "" : ((PluginDescriptor) getDeclaringPluginDescriptor()).getResourceString(s);

+}

+public java.lang.String getSchemaReference() {

+	String s = getSchema();

+	return s == null ? "" : s.replace(File.separatorChar, '/');

+}

+public String getSimpleIdentifier() {

+	return getId();

+}

+public String getUniqueIdentifier() {

+	return getParentPluginDescriptor().getId() + "." + getSimpleIdentifier();

+}

+public String toString() {

+	return getParent().getPluginId() + "." + getSimpleIdentifier();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/FragmentDescriptor.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/FragmentDescriptor.java
new file mode 100644
index 0000000..261af03
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/FragmentDescriptor.java
Binary files differ
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
new file mode 100644
index 0000000..d3f0db0
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IModel.java
@@ -0,0 +1,118 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+public interface IModel {

+

+	public static final int INDENT = 2;

+	public static final int RADIX = 36;

+

+	public static final String TRUE = "true";

+	public static final String FALSE = "false";

+

+	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_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";

+	public static final String PLUGIN_REQUIRES_MATCH_EXACT = "exact";

+	public static final String PLUGIN_REQUIRES_MATCH_COMPATIBLE = "compatible";

+

+	public static final String PLUGIN_KEY_VERSION_SEPARATOR = "_";

+

+	public static final String RUNTIME = "runtime";

+

+	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 EXTENSION_POINT = "extension-point";

+	public static final String EXTENSION_POINT_NAME = "name";

+	public static final String EXTENSION_POINT_ID = "id";

+	public static final String EXTENSION_POINT_SCHEMA = "schema";

+

+	public static final String EXTENSION = "extension";

+	public static final String EXTENSION_NAME = "name";

+	public static final String EXTENSION_ID = "id";

+	public static final String EXTENSION_TARGET = "point";

+

+	public static final String ELEMENT = "element";

+	public static final String ELEMENT_NAME = "name";

+	public static final String ELEMENT_VALUE = "value";

+

+	public static final String PROPERTY = "property";

+	public static final String PROPERTY_NAME = "name";

+	public static final String PROPERTY_VALUE = "value";

+

+	public static final String COMPONENT = "component";

+	public static final String COMPONENT_LABEL = "label";

+	public static final String COMPONENT_ID = "id";

+	public static final String COMPONENT_VERSION = "version";

+	public static final String COMPONENT_PROVIDER = "provider-name";

+

+	public static final String COMPONENT_DESCRIPTION = "description";

+

+	public static final String COMPONENT_URL = "url";

+

+	public static final String COMPONENT_PLUGIN = "plugin";

+	public static final String COMPONENT_PLUGIN_LABEL = "label";

+	public static final String COMPONENT_PLUGIN_ID = "id";

+	public static final String COMPONENT_PLUGIN_VERSION = "version";

+

+	public static final String COMPONENT_FRAGMENT = "fragment";

+	public static final String COMPONENT_FRAGMENT_LABEL = "label";

+	public static final String COMPONENT_FRAGMENT_ID = "id";

+	public static final String COMPONENT_FRAGMENT_VERSION = "version";

+

+	public static final String CONFIGURATION = "configuration";

+	public static final String CONFIGURATION_LABEL = "label";

+	public static final String CONFIGURATION_ID = "id";

+	public static final String CONFIGURATION_VERSION = "version";

+	public static final String CONFIGURATION_PROVIDER = "provider-name";

+	public static final String CONFIGURATION_APPLICATION = "application";

+

+	public static final String CONFIGURATION_DESCRIPTION = "description";

+

+	public static final String CONFIGURATION_URL = "url";

+

+	public static final String CONFIGURATION_COMPONENT = "component";

+	public static final String CONFIGURATION_COMPONENT_LABEL = "label";

+	public static final String CONFIGURATION_COMPONENT_ID = "id";

+	public static final String CONFIGURATION_COMPONENT_VERSION = "version";

+	public static final String CONFIGURATION_COMPONENT_ALLOW_UPGRADE = "allowUpgrade";

+	public static final String CONFIGURATION_COMPONENT_OPTIONAL = "optional";

+

+	public static final String URL_UPDATE = "update";

+	public static final String URL_DISCOVERY = "discovery";

+	public static final String URL_URL = "url";

+	public static final String URL_LABEL = "label";

+

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IPluginVisitor.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IPluginVisitor.java
new file mode 100644
index 0000000..2741aa7
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/IPluginVisitor.java
@@ -0,0 +1,12 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.IPluginDescriptor;

+

+public interface IPluginVisitor {

+public void visit(IPluginDescriptor descriptor);

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/InternalFactory.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/InternalFactory.java
new file mode 100644
index 0000000..dc17967
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/InternalFactory.java
@@ -0,0 +1,48 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.internal.runtime.InternalPlatform;

+

+public class InternalFactory extends Factory {

+public InternalFactory(MultiStatus status) {

+	super(status);

+}

+public ConfigurationElementModel createConfigurationElement() {

+	return new ConfigurationElement();

+}

+public ConfigurationPropertyModel createConfigurationProperty() {

+	return new ConfigurationProperty();

+}

+public ExtensionModel createExtension() {

+	return new Extension();

+}

+public ExtensionPointModel createExtensionPoint() {

+	return new ExtensionPoint();

+}

+

+

+

+public LibraryModel createLibrary() {

+	return new Library();

+}

+public PluginDescriptorModel createPluginDescriptor() {

+	return new PluginDescriptor();

+}

+

+public PluginFragmentModel createPluginFragment() {

+	return new FragmentDescriptor();

+}

+

+public PluginPrerequisiteModel createPluginPrerequisite() {

+	return new PluginPrerequisite();

+}

+public PluginRegistryModel createPluginRegistry() {

+	return new PluginRegistry();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Library.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Library.java
new file mode 100644
index 0000000..90e7346
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/Library.java
@@ -0,0 +1,25 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.internal.plugins.IModel;

+

+public class Library extends LibraryModel implements ILibrary {

+  public Library()

+  {

+	super();

+  }  

+public String[] getContentFilters() {

+	if (!isExported() || isFullyExported())

+		return null;

+	return getExports();

+}

+public IPath getPath() {

+	return new Path(getName());

+}

+}

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
new file mode 100644
index 0000000..caac29f
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginClassLoader.java
Binary files differ
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
new file mode 100644
index 0000000..7320ac4
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginDescriptor.java
Binary files differ
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
new file mode 100644
index 0000000..7936b71
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginParser.java
@@ -0,0 +1,957 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.internal.runtime.Policy;

+import org.apache.xerces.parsers.SAXParser;

+import java.util.Stack;

+import java.util.Vector;

+import org.xml.sax.*;

+import org.xml.sax.helpers.*;

+

+public class PluginParser extends DefaultHandler implements IModel {

+

+	// concrete object factory

+	Factory factory;

+

+	// Current State Information

+	Stack stateStack = new Stack();

+

+	// Current object stack (used to hold the current object we are

+	// populating in this plugin descriptor

+	Stack objectStack = new Stack();

+

+	// model parser

+	private static SAXParser parser;

+	

+	static {

+		initializeParser();

+	}

+

+	// Valid States

+	private final int IGNORED_ELEMENT_STATE = 0;

+	private final int INITIAL_STATE = 1;

+	private final int PLUGIN_STATE = 2;

+	private final int PLUGIN_RUNTIME_STATE = 3;

+	private final int PLUGIN_REQUIRES_STATE = 4;

+	private final int PLUGIN_EXTENSION_POINT_STATE = 5;

+	private final int PLUGIN_EXTENSION_STATE = 6;

+	private final int RUNTIME_LIBRARY_STATE = 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;

+	private final int CONFIGURATION_STATE = 12;

+	private final int COMPONENT_STATE = 13;

+	private final int DESCRIPTION_STATE = 14;

+	private final int URL_STATE = 15;

+

+	// Keep a group of vectors as a temporary scratch space.  These

+	// vectors will be used to populate arrays in the plugin descriptor

+	// once processing of the XML file is complete.

+	private final int EXTENSION_POINT_INDEX = 0;

+	private final int EXTENSION_INDEX = 1;

+	private final int LAST_INDEX = 1;

+	private Vector scratchVectors[] = new Vector[LAST_INDEX + 1];

+	

+public PluginParser(Factory factory) {

+	super();

+	this.factory = factory;

+	parser.setContentHandler(this);

+	parser.setDTDHandler(this);

+	parser.setEntityResolver(this);

+	parser.setErrorHandler(this);

+}

+

+private static void initializeParser() {

+	parser = new SAXParser();

+	try {

+	 	((SAXParser)parser).setFeature("http://xml.org/sax/features/string-interning", true);

+	} catch (SAXException e) {

+	}

+}

+

+public void characters(char[] ch, int start, int length) {

+	int state = ((Integer) stateStack.peek()).intValue();

+	if (state == CONFIGURATION_ELEMENT_STATE) {

+		// Accept character data within an element, is when it is

+		// part of a configuration element (i.e. an element within an EXTENSION element

+		ConfigurationElementModel currentConfigElement = (ConfigurationElementModel) objectStack.peek();

+		String value = new String(ch, start, length);

+		String newValue = value.trim();

+		if (!newValue.equals("") || newValue.length() != 0)

+			currentConfigElement.setValue(newValue);

+		return;

+	} 

+	if (state == DESCRIPTION_STATE) {

+		// Accept character data within an element, is when it is part of a component or configuration 

+		// description element (i.e. an element within a COMPONENT or CONFIGURATION element

+		InstallModel model = (InstallModel) objectStack.peek();

+		String value = new String(ch, start, length).trim();

+		if (!value.equals("") || value.length() != 0)

+			model.setDescription(value);

+		return;

+	} 		

+}

+public void endDocument() {

+}

+public void endElement(String uri, String elementName, String qName) {

+	switch (((Integer) stateStack.peek()).intValue()) {

+		case IGNORED_ELEMENT_STATE :

+			stateStack.pop();

+			break;

+		case INITIAL_STATE :

+			// shouldn't get here

+			internalError (Policy.bind("parse.internalStack", elementName));

+			break;

+		case PLUGIN_STATE :

+		case FRAGMENT_STATE :

+			if (elementName.equals(PLUGIN) || elementName.equals(FRAGMENT)) {

+				stateStack.pop();

+				PluginModel root = (PluginModel) objectStack.peek();

+

+				// Put the extension points into this plugin

+				Vector extPointVector = scratchVectors[EXTENSION_POINT_INDEX];

+				if (extPointVector.size() > 0) {

+					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) {

+					root.setDeclaredExtensions((ExtensionModel[]) extVector.toArray(new ExtensionModel[extVector.size()]));

+					scratchVectors[EXTENSION_INDEX].removeAllElements();

+				}

+			}

+			break;

+		case PLUGIN_RUNTIME_STATE :

+			if (elementName.equals(RUNTIME)) {

+				stateStack.pop();

+				// take the vector of library entries and put them into the plugin

+				// descriptor

+				Vector libVector = (Vector)objectStack.pop();

+				if (libVector.size() > 0) {

+					PluginModel model = (PluginModel) objectStack.peek();

+					model.setRuntime((LibraryModel[]) libVector.toArray(new LibraryModel[libVector.size()]));

+					}

+			}

+			break;

+		case PLUGIN_REQUIRES_STATE :

+			if (elementName.equals(PLUGIN_REQUIRES)) {

+				stateStack.pop();

+				// take the vector of prerequisites and put them into the plugin

+				// descriptor

+				Vector importVector = (Vector)objectStack.pop();

+				if (importVector.size() > 0) {

+					PluginModel parentDescriptor = (PluginModel) objectStack.peek();

+					parentDescriptor.setRequires((PluginPrerequisiteModel[]) importVector.toArray(new PluginPrerequisiteModel[importVector.size()]));

+				}

+			}

+			break;

+		case PLUGIN_EXTENSION_POINT_STATE :

+			if (elementName.equals(EXTENSION_POINT)) {

+				stateStack.pop();

+			}

+			break;

+		case PLUGIN_EXTENSION_STATE :

+			if (elementName.equals(EXTENSION)) {

+				stateStack.pop();

+				// Finish up extension object

+				ExtensionModel currentExtension = (ExtensionModel) objectStack.pop();

+				PluginModel parent = (PluginModel) objectStack.peek();

+				currentExtension.setParent(parent);

+				scratchVectors[EXTENSION_INDEX].addElement(currentExtension);

+			}

+			break;

+		case RUNTIME_LIBRARY_STATE :

+			if (elementName.equals(LIBRARY)) {

+				LibraryModel curLibrary = (LibraryModel) objectStack.pop();

+				// Clean up the exports for this library entry

+				Vector exportsVector = (Vector) objectStack.pop();

+				if (exportsVector.size() > 0) {

+					curLibrary.setExports((String[]) exportsVector.toArray(new String[exportsVector.size()]));

+				}

+

+				// Add this library element to the vector "runtime" on the stack

+				Vector libraryVector = (Vector) objectStack.peek();

+				libraryVector.addElement(curLibrary);

+				stateStack.pop();

+			}

+			break;

+		case LIBRARY_EXPORT_STATE :

+			if (elementName.equals(LIBRARY_EXPORT)) {

+				stateStack.pop();

+			}

+			break;

+		case PLUGIN_REQUIRES_IMPORT_STATE :

+			if (elementName.equals(PLUGIN_REQUIRES_IMPORT)) {

+				stateStack.pop();

+			}

+			break;

+		case CONFIGURATION_ELEMENT_STATE :

+			// We don't care what the element name was

+			stateStack.pop();

+			// Now finish up the configuration element object

+			ConfigurationElementModel currentConfigElement = (ConfigurationElementModel) objectStack.pop();

+			Object parent = objectStack.peek();

+			currentConfigElement.setParent(parent);

+			if (((Integer) stateStack.peek()).intValue() == PLUGIN_EXTENSION_STATE) {

+				// Want to add this configuration element to the subelements of an extension

+				ConfigurationElementModel[] oldValues = (ConfigurationElementModel[]) ((ExtensionModel) parent).getSubElements();

+				int size = (oldValues == null) ? 0 : oldValues.length;

+				ConfigurationElementModel[] newValues = new ConfigurationElementModel[size + 1];

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

+					newValues[i] = oldValues[i];

+				}

+				newValues[size] = currentConfigElement;

+				((ExtensionModel) parent).setSubElements(newValues);

+			} else {

+				ConfigurationElementModel[] oldValues = (ConfigurationElementModel[]) ((ConfigurationElementModel) parent).getSubElements();

+				int size = (oldValues == null) ? 0 : oldValues.length;

+				ConfigurationElementModel[] newValues = new ConfigurationElementModel[size + 1];

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

+					newValues[i] = oldValues[i];

+				}

+				newValues[size] = currentConfigElement;

+				((ConfigurationElementModel) parent).setSubElements(newValues);

+			}

+			break;

+		case DESCRIPTION_STATE:

+			if (elementName.equals(COMPONENT_DESCRIPTION) || elementName.equals(CONFIGURATION_DESCRIPTION))

+				stateStack.pop();

+			break;

+		case URL_STATE:

+			if (elementName.equals(COMPONENT_URL) || elementName.equals(CONFIGURATION_URL)) 

+				stateStack.pop();

+			break;

+	}

+}

+public void error(SAXParseException ex) {

+	logStatus(ex);

+}

+public void fatalError(SAXParseException ex) throws SAXException {

+	logStatus(ex);

+	throw ex;

+}

+

+public void handleComponentState(String elementName, Attributes attributes) {

+

+	if (elementName.equals(COMPONENT_DESCRIPTION)) {

+		stateStack.push(new Integer(DESCRIPTION_STATE));

+		return;

+	}

+	if (elementName.equals(COMPONENT_URL)) {

+		stateStack.push(new Integer(URL_STATE));

+		return;

+	}

+	if (elementName.equals(COMPONENT_PLUGIN)) {

+		parseComponentPluginAttributes(attributes);

+		return;

+	}

+	if (elementName.equals(COMPONENT_FRAGMENT)) {

+		parseComponentFragmentAttributes(attributes);

+		return;

+	}

+	// 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));

+	internalError(Policy.bind("parse.unknownElement", COMPONENT, elementName));

+}

+

+public void handleConfigurationState(String elementName, Attributes attributes) {

+

+	if (elementName.equals(CONFIGURATION_DESCRIPTION)) {

+		stateStack.push(new Integer(DESCRIPTION_STATE));

+		return;

+	}

+	if (elementName.equals(CONFIGURATION_URL)) {

+		stateStack.push(new Integer(URL_STATE));

+		return;

+	}

+	if (elementName.equals(CONFIGURATION_COMPONENT)) {

+		parseComponentAttributes(attributes);

+		ComponentModel component = (ComponentModel)objectStack.pop();

+		ConfigurationModel config = (ConfigurationModel)objectStack.peek();

+		Object components = addObject(component, config.getComponents());

+		config.setComponents((ComponentModel[])components);

+		return;

+	}

+	// 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));

+	internalError(Policy.bind("parse.unknownElement", CONFIGURATION, elementName));

+}

+

+

+public void handleDescriptionState(String elementName, Attributes attributes) {

+

+	// We ignore all elements (if there are any)

+	stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+	internalError(Policy.bind("parse.unknownElement", CONFIGURATION_DESCRIPTION, elementName));

+}

+

+public void handleExtensionPointState(String elementName, Attributes attributes) {

+

+	// We ignore all elements under extension points (if there are any)

+	stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+	internalError(Policy.bind("parse.unknownElement", EXTENSION_POINT, elementName));

+}

+public void handleExtensionState(String elementName, Attributes attributes) {

+

+	// You need to change the state here even though we will be executing the same

+	// code for ExtensionState and ConfigurationElementState.  We ignore the name

+	// of the element for ConfigurationElements.  When we are wrapping up, we will

+	// want to add each configuration element object to the subElements vector of

+	// its parent configuration element object.  However, the first configuration

+	// element object we created (the last one we pop off the stack) will need to

+	// be added to a vector in the extension object called _configuration.

+	stateStack.push(new Integer(CONFIGURATION_ELEMENT_STATE));

+

+	// create a new Configuration Element and push it onto the object stack

+	ConfigurationElementModel currentConfigurationElement = factory.createConfigurationElement();

+	objectStack.push(currentConfigurationElement);

+	currentConfigurationElement.setName(elementName);

+

+	// Processing the attributes of a configuration element involves creating

+	// a new configuration property for each attribute and populating the configuration

+	// property with the name/value pair of the attribute.  Note there will be one

+	// configuration property for each attribute

+	parseConfigurationElementAttributes(attributes);

+}

+public void handleInitialState(String elementName, Attributes attributes) {

+	if (elementName.equals(PLUGIN)) {

+		stateStack.push(new Integer(PLUGIN_STATE));

+		parsePluginAttributes(attributes);

+	} else

+		if (elementName.equals(FRAGMENT)) {

+			stateStack.push(new Integer(FRAGMENT_STATE));

+			parseFragmentAttributes(attributes);

+		} else

+			if (elementName.equals(COMPONENT)) {

+				stateStack.push(new Integer(COMPONENT_STATE));

+				parseComponentAttributes(attributes);

+			} else

+				if (elementName.equals(CONFIGURATION)) {

+					stateStack.push(new Integer(CONFIGURATION_STATE));

+					parseConfigurationAttributes(attributes);

+				} else {

+					stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+					internalError(Policy.bind("parse.unknownTopElement", elementName));

+				}

+}

+public void handleLibraryExportState(String elementName, Attributes attributes) {

+

+	// All elements ignored.

+	stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+	internalError(Policy.bind("parse.unknownElement", LIBRARY_EXPORT, elementName));

+}

+public void handleLibraryState(String elementName, Attributes attributes) {

+	// The only valid element at this stage is a export

+	if (!elementName.equals(LIBRARY_EXPORT)) {

+		stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+		internalError(Policy.bind("parse.unknownElement", LIBRARY, elementName));

+		return;

+	}

+

+	// Change State

+	stateStack.push(new Integer(LIBRARY_EXPORT_STATE));

+	// The top element on the stack much be a library element

+	LibraryModel currentLib = (LibraryModel) objectStack.peek();

+

+	if (attributes == null)

+		return;

+

+	String maskValue = null;

+

+	// Process Attributes

+	int len = attributes.getLength();

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		if (attrName.equals(LIBRARY_EXPORT_MASK))

+			maskValue = attrValue;

+		else 

+			internalError(Policy.bind("parse.unknownAttribute", LIBRARY, attrName));

+	}

+

+	// set up mask tables

+	// pop off the library - already in currentLib

+	objectStack.pop();

+	Vector exportMask = (Vector)objectStack.peek();

+	// push library back on

+	objectStack.push(currentLib);

+	if ((maskValue != null) && (!exportMask.contains(maskValue)))

+		exportMask.addElement(maskValue);

+}

+public void handlePluginState(String elementName, Attributes attributes) {

+

+	if (elementName.equals(RUNTIME)) {

+		// We should only have one Runtime element in a plugin or fragment

+		Object whatIsIt = objectStack.peek();

+		if ( ( (whatIsIt instanceof PluginDescriptorModel) && (((PluginDescriptorModel)objectStack.peek()).getRuntime() != null) ) ||

+		     ( (whatIsIt instanceof PluginFragmentModel) && (((PluginFragmentModel)objectStack.peek()).getRuntime() != null) ) ) {

+			// This is at least the 2nd Runtime element we have

+			// hit.  Ignore it and give an error.

+			stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+			return;

+		}

+		stateStack.push(new Integer(PLUGIN_RUNTIME_STATE));

+		// Push a new vector to hold all the library entries

+		objectStack.push(new Vector());

+		return;

+	}

+	if (elementName.equals(PLUGIN_REQUIRES)) {

+		stateStack.push(new Integer(PLUGIN_REQUIRES_STATE));

+		// Push a new vector to hold all the prerequisites

+		objectStack.push(new Vector());

+		parseRequiresAttributes(attributes);

+		return;

+	}

+	if (elementName.equals(EXTENSION_POINT)) {

+		stateStack.push(new Integer(PLUGIN_EXTENSION_POINT_STATE));

+		parseExtensionPointAttributes(attributes);

+		return;

+	}

+	if (elementName.equals(EXTENSION)) {

+		stateStack.push(new Integer(PLUGIN_EXTENSION_STATE));

+		parseExtensionAttributes(attributes);

+		return;

+	}

+

+	// 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));

+	internalError(Policy.bind("parse.unknownElement", PLUGIN + " / " + FRAGMENT, elementName));

+}

+public void handleRequiresImportState(String elementName, Attributes attributes) {

+

+	// All elements ignored.

+	stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+	internalError(Policy.bind("parse.unknownElement", PLUGIN_REQUIRES_IMPORT, elementName));

+}

+public void handleRequiresState(String elementName, Attributes attributes) {

+

+	if (elementName.equals(PLUGIN_REQUIRES_IMPORT)) {

+		parsePluginRequiresImport(attributes);

+		return;

+	}

+	// 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));

+	internalError(Policy.bind("parse.unknownElement", PLUGIN_REQUIRES, elementName));

+}

+public void handleRuntimeState(String elementName, Attributes attributes) {

+

+	if (elementName.equals(LIBRARY)) {

+		// Change State

+		stateStack.push(new Integer(RUNTIME_LIBRARY_STATE));

+		// Process library attributes

+		parseLibraryAttributes(attributes);

+		return;

+	}

+	// 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));

+	internalError(Policy.bind("parse.unknownElement", RUNTIME, elementName));

+}

+

+private Object addObject(Object newElement, Object[] container) {

+	Object[] result = new ComponentModel[container == null ? 1 : container.length + 1];

+	if (container != null) 

+		System.arraycopy(container, 0, result, 0, container.length);

+	result[result.length - 1] = newElement;

+	return result;

+}

+private URLModel[] addURLElement(URLModel newElement, URLModel[] container) {

+	URLModel[] result = new URLModel[container == null ? 1 : container.length + 1];

+	if (container != null) 

+		System.arraycopy(container, 0, result, 0, container.length);

+	result[result.length - 1] = newElement;

+	return result;

+}

+private PluginDescriptorModel[] addPluginDescriptorElement(PluginDescriptorModel newElement, PluginDescriptorModel[] container) {

+	PluginDescriptorModel[] result = new PluginDescriptorModel[container == null ? 1 : container.length + 1];

+	if (container != null) 

+		System.arraycopy(container, 0, result, 0, container.length);

+	result[result.length - 1] = newElement;

+	return result;

+}

+private PluginFragmentModel[] addPluginFragmentElement(PluginFragmentModel newElement, PluginFragmentModel[] container) {

+	PluginFragmentModel[] result = new PluginFragmentModel[container == null ? 1 : container.length + 1];

+	if (container != null) 

+		System.arraycopy(container, 0, result, 0, container.length);

+	result[result.length - 1] = newElement;

+	return result;

+}

+public void handleURLState(String elementName, Attributes attributes) {

+	URLModel url = null;

+	InstallModel model = (InstallModel)objectStack.peek();

+	if (elementName.equals(URL_UPDATE)) {

+		url = parseURLAttributes(attributes);

+		model.setUpdates((URLModel [])addURLElement(url, model.getUpdates()));

+		return; 

+	} else

+		if (elementName.equals(URL_DISCOVERY)) {

+			url = parseURLAttributes(attributes);

+			model.setDiscoveries((URLModel [])addURLElement(url, model.getDiscoveries()));

+			return; 

+		}

+	// We ignore all elements (if there are any)

+	stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+}

+public void ignoreableWhitespace(char[] ch, int start, int length) {

+}

+private void logStatus(SAXParseException ex) {

+	String name = ex.getSystemId();

+	if (name == null)

+		name = "";

+	else

+		name = name.substring(1 + name.lastIndexOf("/"));

+

+	String msg;

+	if (name.equals(""))

+		msg = Policy.bind("parse.error", ex.getMessage());

+	else

+		msg = Policy.bind("parse.errorNameLineColumn", 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));

+}

+synchronized public InstallModel parseInstall(InputSource in) throws Exception {

+	parser.parse(in);

+	return (InstallModel) objectStack.pop();

+}

+

+synchronized public PluginModel parsePlugin(InputSource in) throws Exception {

+	parser.parse(in);

+	return (PluginModel) objectStack.pop();

+}

+

+public void parseComponentAttributes(Attributes attributes) {

+

+	ComponentModel current = factory.createComponentModel();

+	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();

+

+		if (attrName.equals(COMPONENT_ID))

+			current.setId(attrValue);

+		else

+			if (attrName.equals(COMPONENT_LABEL))

+				current.setName(attrValue);

+			else

+				if (attrName.equals(COMPONENT_VERSION))

+					current.setVersion(attrValue);

+				else

+					if (attrName.equals(COMPONENT_PROVIDER))

+						current.setProviderName(attrValue);

+					else

+						internalError(Policy.bind("parse.unknownAttribute", COMPONENT, attrName));

+	}

+}

+

+public void parseComponentFragmentAttributes(Attributes attributes) {

+

+	PluginFragmentModel current = factory.createPluginFragment();

+

+	// process attributes

+	int len = attributes.getLength();

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		if (attrName.equals(COMPONENT_FRAGMENT_ID))

+			current.setId(attrValue);

+		else

+			if (attrName.equals(COMPONENT_FRAGMENT_LABEL))

+				current.setName(attrValue);

+			else

+				if (attrName.equals(COMPONENT_FRAGMENT_VERSION))

+					current.setVersion(attrValue);

+				else

+					internalError(Policy.bind("parse.unknownAttribute", COMPONENT_FRAGMENT, attrName));

+	}

+	

+	ComponentModel componentModel = (ComponentModel)objectStack.peek();

+	PluginFragmentModel fragments[] = componentModel.getFragments();

+	fragments = (PluginFragmentModel [])addPluginFragmentElement(current,fragments);

+	componentModel.setFragments(fragments);

+}

+

+public void parseComponentPluginAttributes(Attributes attributes) {

+

+	PluginDescriptorModel current = factory.createPluginDescriptor();

+

+	// process attributes

+	int len = attributes.getLength();

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		if (attrName.equals(COMPONENT_PLUGIN_ID))

+			current.setId(attrValue);

+		else

+			if (attrName.equals(COMPONENT_PLUGIN_LABEL))

+				current.setName(attrValue);

+			else

+				if (attrName.equals(COMPONENT_PLUGIN_VERSION))

+					current.setVersion(attrValue);

+				else

+					internalError(Policy.bind("parse.unknownAttribute", COMPONENT_PLUGIN, attrName));

+	}

+	

+	ComponentModel componentModel = (ComponentModel)objectStack.peek();

+	PluginDescriptorModel plugins[] = componentModel.getPlugins();

+	plugins = (PluginDescriptorModel [])addPluginDescriptorElement(current,plugins);

+	componentModel.setPlugins(plugins);

+}

+

+public void parseConfigurationAttributes(Attributes attributes) {

+

+	ConfigurationModel current = factory.createConfiguration();

+	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();

+

+		if (attrName.equals(CONFIGURATION_ID))

+			current.setId(attrValue);

+		else

+			if (attrName.equals(CONFIGURATION_LABEL))

+				current.setName(attrValue);

+			else

+				if (attrName.equals(CONFIGURATION_VERSION))

+					current.setVersion(attrValue);

+				else

+					if (attrName.equals(CONFIGURATION_PROVIDER))

+						current.setProviderName(attrValue);

+					else

+						if (attrName.equals(CONFIGURATION_APPLICATION))

+							current.setApplication(attrValue);

+					else

+						internalError(Policy.bind("parse.unknownAttribute", CONFIGURATION, attrName));

+	}

+}

+

+public void parseConfigurationElementAttributes(Attributes attributes) {

+

+	ConfigurationElementModel parentConfigurationElement = (ConfigurationElementModel) objectStack.peek();

+	Vector propVector = null;

+

+	// process attributes

+	int len = (attributes != null) ? attributes.getLength() : 0;

+	if (len == 0)

+		return;

+	propVector = new Vector();

+

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i);

+

+		ConfigurationPropertyModel currentConfigurationProperty = factory.createConfigurationProperty();

+		currentConfigurationProperty.setName(attrName);

+		currentConfigurationProperty.setValue(attrValue);

+		propVector.addElement(currentConfigurationProperty);

+	}

+	parentConfigurationElement.setProperties((ConfigurationPropertyModel[]) propVector.toArray(new ConfigurationPropertyModel[propVector.size()]));

+	propVector = null;

+}

+public void parseExtensionAttributes(Attributes attributes) {

+

+	PluginModel parent = (PluginModel) objectStack.peek();

+	ExtensionModel currentExtension = factory.createExtension();

+	objectStack.push(currentExtension);

+

+	// Process Attributes

+	int len = (attributes != null) ? attributes.getLength() : 0;

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		if (attrName.equals(EXTENSION_NAME))

+			currentExtension.setName(attrValue);

+		else

+			if (attrName.equals(EXTENSION_ID))

+				currentExtension.setId(attrValue);

+			else

+				if (attrName.equals(EXTENSION_TARGET)) {

+					// check if point is specified as a simple or qualified name

+					String targetName;

+					if (attrValue.lastIndexOf('.') == -1) {

+						String baseId = parent instanceof PluginDescriptorModel ? parent.getId() : ((PluginFragmentModel) parent).getPlugin();

+						targetName = baseId + "." + attrValue;

+					} else

+						targetName = attrValue;

+					currentExtension.setExtensionPoint(targetName);

+				}

+				else

+					internalError(Policy.bind("parse.unknownAttribute", EXTENSION, attrName));

+	}

+}

+public void parseExtensionPointAttributes(Attributes attributes) {

+

+	ExtensionPointModel currentExtPoint = factory.createExtensionPoint();

+

+	// Process Attributes

+	int len = (attributes != null) ? attributes.getLength() : 0;

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		if (attrName.equals(EXTENSION_POINT_NAME))

+			currentExtPoint.setName(attrValue);

+		else

+			if (attrName.equals(EXTENSION_POINT_ID))

+				currentExtPoint.setId(attrValue);

+			else

+				if (attrName.equals(EXTENSION_POINT_SCHEMA))

+					currentExtPoint.setSchema(attrValue);

+				else

+					internalError(Policy.bind("parse.unknownAttribute", EXTENSION_POINT, attrName));

+	}

+	// currentExtPoint contains a pointer to the parent plugin descriptor.

+	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 parseFragmentAttributes(Attributes attributes) {

+	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();

+

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

+							else

+								internalError(Policy.bind("parse.unknownAttribute", FRAGMENT, attrName));

+	}

+}

+

+public void parseLibraryAttributes(Attributes attributes) {

+	// Push a vector to hold the export mask 

+	objectStack.push (new Vector());

+	LibraryModel current = factory.createLibrary();

+	objectStack.push(current);

+	

+	// Now the objectStack should contain the following:

+	//	plugin descriptor or fragment (bottom of the stack)

+	//	vector to hold all the library entries

+	//  vector to hold the export mask for this library entry

+	//  this library entry (top of the stack)

+

+	// process attributes

+	int len = (attributes != null) ? attributes.getLength() : 0;

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		if (attrName.equals(LIBRARY_NAME))

+			current.setName(attrValue);

+		else

+			if (attrName.equals(LIBRARY_TYPE))

+				current.setType(attrValue.toLowerCase());

+			else

+				internalError(Policy.bind("parse.unknownAttribute", LIBRARY, attrName));

+	}

+}

+public void parsePluginAttributes(Attributes attributes) {

+

+	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();

+

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

+						else

+							internalError(Policy.bind("parse.unknownAttribute", PLUGIN, attrName));

+	}

+}

+

+public void parsePluginRequiresImport(Attributes attributes) {

+	PluginPrerequisiteModel current = factory.createPluginPrerequisite();

+

+	// process attributes

+	int len = (attributes != null) ? attributes.getLength() : 0;

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		if (attrName.equals(PLUGIN_REQUIRES_PLUGIN))

+			current.setPlugin(attrValue);

+		else

+			if (attrName.equals(PLUGIN_REQUIRES_PLUGIN_VERSION))

+				current.setVersion(attrValue);

+			else

+				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 (PLUGIN_REQUIRES_MATCH_COMPATIBLE.equals(attrValue))

+								current.setMatch(false);

+							else

+								internalError(Policy.bind("parse.validMatch", attrValue));

+					} else

+						if (attrName.equals(PLUGIN_REQUIRES_EXPORT)) {

+							if (TRUE.equals(attrValue))

+								current.setExport(true);

+							else

+								if (FALSE.equals(attrValue))

+									current.setExport(false);

+								else

+									internalError(Policy.bind("parse.validExport", attrValue));

+						} else

+							internalError(Policy.bind("parse.unknownAttribute", PLUGIN_REQUIRES_IMPORT, attrName));

+

+	}

+	// Populate the vector of prerequisites with this new element

+	((Vector)objectStack.peek()).addElement(current);

+}

+public void parseRequiresAttributes(Attributes attributes) {

+}

+

+public URLModel parseURLAttributes(Attributes attributes) {

+	URLModel current = factory.createURL();

+

+	// process attributes

+	int len = (attributes != null) ? attributes.getLength() : 0;

+	for (int i = 0; i < len; i++) {

+		String attrName = attributes.getLocalName(i);

+		String attrValue = attributes.getValue(i).trim();

+

+		if (attrName.equals(URL_URL))

+			current.setURL(attrValue);

+		else

+			if (attrName.equals(URL_LABEL))

+				current.setName(attrValue);

+	}

+	return current;

+}

+

+static String replace(String s, String from, String to) {

+	String str = s;

+	int fromLen = from.length();

+	int toLen = to.length();

+	int ix = str.indexOf(from);

+	while (ix != -1) {

+		str = str.substring(0, ix) + to + str.substring(ix + fromLen);

+		ix = str.indexOf(from, ix + toLen);

+	}

+	return str;

+}

+public void startDocument() {

+	stateStack.push(new Integer(INITIAL_STATE));

+	for (int i = 0; i <= LAST_INDEX; i++) {

+		scratchVectors[i] = new Vector();

+	}

+}

+public void startElement(String uri, String elementName, String qName, Attributes attributes) {

+	switch (((Integer) stateStack.peek()).intValue()) {

+		case INITIAL_STATE :

+			handleInitialState(elementName, attributes);

+			break;

+		case FRAGMENT_STATE :

+			handlePluginState(elementName, attributes);

+			break;

+		case PLUGIN_STATE :

+			handlePluginState(elementName, attributes);

+			break;

+		case PLUGIN_RUNTIME_STATE :

+			handleRuntimeState(elementName, attributes);

+			break;

+		case PLUGIN_REQUIRES_STATE :

+			handleRequiresState(elementName, attributes);

+			break;

+		case PLUGIN_EXTENSION_POINT_STATE :

+			handleExtensionPointState(elementName, attributes);

+			break;

+		case PLUGIN_EXTENSION_STATE :

+		case CONFIGURATION_ELEMENT_STATE :

+			handleExtensionState(elementName, attributes);

+			break;

+		case RUNTIME_LIBRARY_STATE :

+			handleLibraryState(elementName, attributes);

+			break;

+		case LIBRARY_EXPORT_STATE :

+			handleLibraryExportState(elementName, attributes);

+			break;

+		case PLUGIN_REQUIRES_IMPORT_STATE :

+			handleRequiresImportState(elementName, attributes);

+			break;

+		case COMPONENT_STATE:

+			handleComponentState(elementName, attributes);

+			break;

+		case CONFIGURATION_STATE :

+			handleConfigurationState(elementName, attributes);

+			break;

+		case DESCRIPTION_STATE :

+			handleDescriptionState(elementName, attributes);

+			break;

+		case URL_STATE :

+			handleURLState(elementName, attributes);

+			break;

+		default :

+			stateStack.push(new Integer(IGNORED_ELEMENT_STATE));

+			internalError (Policy.bind("parse.unknownTopElement", elementName));

+	}

+}

+public void warning(SAXParseException ex) {

+	logStatus(ex);

+}

+private void internalError(String message) {

+	factory.error(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, message, null));

+}

+}

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
new file mode 100644
index 0000000..9b5d01a
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginPrerequisite.java
@@ -0,0 +1,56 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+

+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/PluginRegistry.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginRegistry.java
new file mode 100644
index 0000000..739cb95
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/PluginRegistry.java
@@ -0,0 +1,272 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.internal.runtime.*;

+import java.io.*;

+import java.net.URL;

+import java.net.MalformedURLException;

+import java.util.*;

+

+public class PluginRegistry extends PluginRegistryModel implements IPluginRegistry {

+

+	private static final String URL_PROTOCOL_FILE = "file";

+	private static final String F_DEBUG_REGISTRY = ".debugregistry";

+

+	// lifecycle events

+	private static final int STARTUP = 0;

+	private static final int SHUTDOWN = 1;

+  public PluginRegistry()

+  {

+	super();

+  }  

+/**

+ * Iterate over the plug-ins in this registry.  Plug-ins are visited in dependent order.  That is, 

+ * a plug-in, A, which requires another plug-in, B, is visited before its dependents (i.e., A is 

+ * visited before B).  

+ */

+public void accept(IPluginVisitor visitor, boolean activeOnly) {

+	Map dependents = getDependentCounts(activeOnly);

+	// keep iterating until all have been visited.

+	while (!dependents.isEmpty()) {

+		// loop over the dependents list.  For each entry, if there are no dependents, visit

+		// the plugin and remove it from the list.  Make a copy of the keys so we don't end up

+		// with concurrent accesses (since we are deleting the values as we go)

+		PluginDescriptor[] keys = (PluginDescriptor[]) dependents.keySet().toArray(new PluginDescriptor[dependents.size()]);

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

+			PluginDescriptor descriptor = keys[i];

+			Integer entry = (Integer) dependents.get(descriptor);

+			if (entry != null && entry.intValue() <= 0) {

+				visitor.visit(descriptor);

+				dependents.remove(descriptor);

+				// decrement the dependent count for all of the prerequisites.

+				PluginPrerequisiteModel[] requires = descriptor.getRequires();

+				int reqSize = (requires == null) ? 0 : requires.length;

+				for (int j = 0; j < reqSize; j++) {

+					String id = ((PluginPrerequisite) requires[j]).getUniqueIdentifier();

+					PluginDescriptor prereq = (PluginDescriptor) getPlugin(id);

+					Integer count = (Integer) dependents.get(prereq);

+					if (count != null)

+						dependents.put(prereq, new Integer(count.intValue() - 1));

+				}

+			}

+		}

+	}

+}

+public IConfigurationElement[] getConfigurationElementsFor(String uniqueId) {

+	IExtensionPoint point = getExtensionPoint(uniqueId);

+	if (point == null)

+		return new IConfigurationElement[0];

+	IConfigurationElement[] result = point.getConfigurationElements();

+	return result == null ? new IConfigurationElement[0] : result;

+}

+public IConfigurationElement[] getConfigurationElementsFor(String pluginId, String pointId) {

+	IExtensionPoint point = getExtensionPoint(pluginId, pointId);

+	if (point == null)

+		return new IConfigurationElement[0];

+	IConfigurationElement[] result = point.getConfigurationElements();

+	return result == null ? new IConfigurationElement[0] : result;

+}

+public IConfigurationElement[] getConfigurationElementsFor(String pluginId, String pointId, String extensionId) {

+	IExtension extension = getExtension(pluginId, pointId, extensionId);

+	if (extension == null)

+		return new IConfigurationElement[0];

+	IConfigurationElement[] result = extension.getConfigurationElements();

+	return result == null ? new IConfigurationElement[0] : result;

+}

+/**

+ * Returns a map of the dependent counts for all plug-ins.  The map's

+ * keys are the plug-in descriptors and the values are an (<code>Integer</code>) count of

+ * descriptors which depend on that plug-in.

+ */

+private Map getDependentCounts(boolean activeOnly) {

+	IPluginDescriptor[] descriptors = getPluginDescriptors();

+	int descSize = (descriptors == null) ? 0 : descriptors.length;

+	Map dependents = new HashMap(5);

+	// build a table of all dependent counts.  The table is keyed by descriptor and

+	// the value the integer number of dependent plugins.

+	for (int i = 0; i < descSize; i++) {

+		if (activeOnly && !descriptors[i].isPluginActivated())

+			continue;

+		// ensure there is an entry for this descriptor (otherwise it will not be visited)

+		Integer entry = (Integer) dependents.get(descriptors[i]);

+		if (entry == null)

+			dependents.put(descriptors[i], new Integer(0));

+		PluginPrerequisiteModel[] requires = ((PluginDescriptor) descriptors[i]).getRequires();

+		int reqSize = (requires == null ? 0 : requires.length);

+		for (int j = 0; j < reqSize; j++) {

+			String id = ((PluginPrerequisite) requires[j]).getUniqueIdentifier();

+			PluginDescriptor prereq = (PluginDescriptor) getPlugin(id);

+			if (prereq == null || activeOnly && !prereq.isPluginActivated())

+				continue;

+			entry = (Integer) dependents.get(prereq);

+			entry = entry == null ? new Integer(1) : new Integer(entry.intValue() + 1);

+			dependents.put(prereq, entry);

+		}

+	}

+	return dependents;

+}

+public IExtension getExtension(String xptUniqueId, String extUniqueId) {

+

+	int lastdot = xptUniqueId.lastIndexOf('.');

+	if (lastdot == -1) return null;

+	return getExtension(xptUniqueId.substring(0,lastdot), xptUniqueId.substring(lastdot+1), extUniqueId); 

+	

+}

+public IExtension getExtension(String pluginId, String xptSimpleId, String extId) {

+

+	IExtensionPoint xpt = getExtensionPoint(pluginId, xptSimpleId);

+	if (xpt == null) return null;

+	return xpt.getExtension(extId);

+}

+public IExtensionPoint getExtensionPoint(String  xptUniqueId) {

+

+	int lastdot = xptUniqueId.lastIndexOf('.');

+	if (lastdot == -1) return null;

+	return getExtensionPoint(xptUniqueId.substring(0,lastdot), xptUniqueId.substring(lastdot+1)); 

+}

+public IExtensionPoint getExtensionPoint(String plugin, String xpt) {

+

+	IPluginDescriptor pd = getPluginDescriptor(plugin);

+	if (pd == null) return null;

+	return pd.getExtensionPoint(xpt);

+}

+public IExtensionPoint[] getExtensionPoints() {

+	PluginDescriptorModel[] list = getPlugins();

+	if (list == null)

+		return new IExtensionPoint[0];

+	ArrayList result = new ArrayList();

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

+		ExtensionPointModel[] pointList = list[i].getDeclaredExtensionPoints();

+		if (pointList != null) {

+			for (int j = 0; j < pointList.length; j++)

+				result.add(pointList[j]);

+		}

+	}

+	return (IExtensionPoint[]) result.toArray(new IExtensionPoint[result.size()]);

+}

+public IPluginDescriptor getPluginDescriptor(String plugin) {

+	return (IPluginDescriptor) getPlugin(plugin);

+}

+public IPluginDescriptor getPluginDescriptor(String pluginId, PluginVersionIdentifier version) {

+	PluginDescriptorModel[] plugins = getPlugins(pluginId);

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

+		return null;

+	if (version == null)

+		// Just return the first one in the list (random)

+		return (IPluginDescriptor) plugins[0];

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

+		IPluginDescriptor element = (IPluginDescriptor) plugins[i];

+		if (element.getVersionIdentifier().equals(version))

+			return element;

+	}

+	return null;

+}

+public IPluginDescriptor[] getPluginDescriptors() {

+	PluginDescriptorModel[] plugins = getPlugins();

+	if (plugins==null)

+		return new IPluginDescriptor[0];

+	IPluginDescriptor[] result = new IPluginDescriptor[plugins.length];

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

+		result[i] = (IPluginDescriptor) plugins[i];

+	return result;

+}

+public IPluginDescriptor[] getPluginDescriptors(String plugin) {

+	PluginDescriptorModel[] plugins = getPlugins(plugin);

+	if (plugins==null)

+		return new IPluginDescriptor[0];

+	IPluginDescriptor[] result = new IPluginDescriptor[plugins.length];

+	System.arraycopy(plugins, 0, result, 0, plugins.length);

+	return result;

+}

+void logError(IStatus status) {

+	InternalPlatform.getRuntimePlugin().getLog().log(status);

+	if (InternalPlatform.DEBUG)

+		System.out.println(status.getMessage());

+}

+public void saveRegistry() throws IOException {

+	IPath path = InternalPlatform.getMetaArea().getRegistryPath();

+	IPath tempPath = InternalPlatform.getMetaArea().getBackupFilePathFor(path);

+

+	DataOutputStream output = null;

+	try {

+		output = new DataOutputStream(new BufferedOutputStream(new SafeFileOutputStream(path.toOSString(),tempPath.toOSString())));

+	} catch (IOException ioe) {

+		String message = Policy.bind("meta.unableToCreateCache");

+		IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.PLUGIN_ERROR, message, ioe);

+		logError(status);

+	}

+	try {

+		long start = System.currentTimeMillis();

+		RegistryCacheWriter cacheWriter = new RegistryCacheWriter();

+		cacheWriter.writePluginRegistry(this, output);

+		if (InternalPlatform.DEBUG)

+			System.out.println("Wrote registry: " + (System.currentTimeMillis() - start) + "ms");

+	} finally {

+		output.close();

+	}

+}

+public void flushRegistry() {

+	IPath path = InternalPlatform.getMetaArea().getRegistryPath();

+	IPath tempPath = InternalPlatform.getMetaArea().getBackupFilePathFor(path);

+	path.toFile().delete();

+	tempPath.toFile().delete();

+}

+public void debugRegistry() {

+	IPath path = InternalPlatform.getMetaArea().getLocation().append(F_DEBUG_REGISTRY);

+

+	try {

+		FileOutputStream fs = new FileOutputStream(path.toOSString());

+		PrintWriter w = new PrintWriter(fs);

+		try {

+			RegistryWriter regWriter = new RegistryWriter();

+			regWriter.writePluginRegistry(this, w, 0);

+			w.flush();

+		} finally {

+			w.close();

+		}

+	} catch (IOException ioe) {

+		String message = Policy.bind("meta.unableToCreateRegDebug");

+		IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.PLUGIN_ERROR, message, ioe);

+		logError(status);

+	}

+}

+public void flushDebugRegistry() {

+	IPath path = InternalPlatform.getMetaArea().getLocation().append(F_DEBUG_REGISTRY);

+	path.toFile().delete();

+}

+public void shutdown(IProgressMonitor progress) {

+	shutdownPlugins();

+	if (progress != null)

+		progress.worked(1);

+}

+private void shutdownPlugins() {

+	IPluginVisitor visitor = new IPluginVisitor() {

+		public void visit(final IPluginDescriptor descriptor) {

+			ISafeRunnable code = new ISafeRunnable() {

+				public void run() throws Exception {

+					if (!descriptor.isPluginActivated())

+						return;

+					try {

+						Plugin plugin = descriptor.getPlugin();

+						plugin.shutdown();

+					} finally {

+						((PluginDescriptor) descriptor).doPluginDeactivation();

+					}

+				}

+				public void handleException(Throwable e) {

+					// do nothing as the exception has already been logged.

+				}

+			};

+			InternalPlatform.run(code);

+		}

+	};

+	accept(visitor, true);

+}

+public void startup(IProgressMonitor progress) {}

+}

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
new file mode 100644
index 0000000..9946daa
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheReader.java
@@ -0,0 +1,971 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.internal.plugins.*;

+import org.eclipse.core.internal.runtime.Policy;

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

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

+import java.io.*;

+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 MultiStatus cacheReadProblems = null;

+

+	public static final byte REGISTRY_CACHE_VERSION = 2;

+

+	public static final byte NONLABEL = 0;

+

+	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 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 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 byte FRAGMENT_INDEX_LABEL = 47;

+	public static final byte FRAGMENT_LABEL = 48;

+	public static final byte FRAGMENT_END_LABEL = 49;

+	public static final byte FRAGMENT_PLUGIN_LABEL = 50;

+	public static final byte FRAGMENT_PLUGIN_VERSION_LABEL = 51;

+

+	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 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 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_OPTIONAL_LABEL = 52;

+	public static final byte REQUIRES_PLUGIN_NAME_LABEL = 40;

+	public static final byte REQUIRES_RESOLVED_VERSION_LABEL = 41;

+	public static final byte SOURCE_LABEL = 53;

+	public static final byte SUBELEMENTS_LENGTH_LABEL = 42;

+	public static final byte TYPE_LABEL = 54;

+	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 static String decipherLabel(byte labelValue) {

+	switch (labelValue) {

+		case REGISTRY_LABEL:

+			return "<registry>";

+		case REGISTRY_RESOLVED_LABEL:

+			return "<resolved>";

+		case PLUGIN_LABEL:

+			return "<plugin>";

+		case REGISTRY_END_LABEL:

+			return "<endregistry>";

+		case READONLY_LABEL:

+			return "<readonly>";

+		case NAME_LABEL:

+			return "<name>";

+		case ID_LABEL:

+			return "<id>";

+		case PLUGIN_PROVIDER_NAME_LABEL:

+			return "<provider>";

+		case VERSION_LABEL:

+			return "<version>";

+		case PLUGIN_CLASS_LABEL:

+			return "<class>";

+		case PLUGIN_LOCATION_LABEL:

+			return "<location>";

+		case PLUGIN_ENABLED_LABEL:

+			return "<enabled>";

+		case PLUGIN_REQUIRES_LABEL:

+			return "<requires>";

+		case PLUGIN_LIBRARY_LABEL:

+			return "<library>";

+		case PLUGIN_EXTENSION_LABEL:

+			return "<extension>";

+		case PLUGIN_EXTENSION_POINT_LABEL:

+			return "<extensionPoint>";

+		case PLUGIN_END_LABEL:

+			return "<endplugin>";

+		case REQUIRES_MATCH_LABEL:

+			return "<match>";

+		case REQUIRES_EXPORT_LABEL:

+			return "<export>";

+		case REQUIRES_RESOLVED_VERSION_LABEL:

+			return "<resolved_version>";

+		case REQUIRES_PLUGIN_NAME_LABEL:

+			return "<requires_plugin_name>";

+		case REQUIRES_END_LABEL:

+			return "<endrequires>";

+		case LIBRARY_EXPORTS_LENGTH_LABEL:

+			return "<exports-length>";

+		case LIBRARY_EXPORTS_LABEL:

+			return "<exports>";

+		case LIBRARY_END_LABEL:

+			return "<endlibrary>";

+		case EXTENSION_POINT_SCHEMA_LABEL:

+			return "<schema>";

+		case EXTENSION_POINT_END_LABEL:

+			return "<endextensionPoint>";

+		case EXTENSION_EXT_POINT_NAME_LABEL:

+			return "<extension-extPt-name>";

+		case SUBELEMENTS_LENGTH_LABEL:

+			return "<subElements-length>";

+		case EXTENSION_END_LABEL:

+			return "<endextension>";

+		case CONFIGURATION_ELEMENT_LABEL:

+			return "<configuration-element>";

+		case VALUE_LABEL:

+			return "<value>";

+		case PROPERTIES_LENGTH_LABEL:

+			return "<properties-length>";

+		case CONFIGURATION_ELEMENT_END_LABEL:

+			return "<endconfiguration-element>";

+		case CONFIGURATION_PROPERTY_LABEL:

+			return "<configuration-property>";

+		case CONFIGURATION_PROPERTY_END_LABEL:

+			return "<endconfiguration-property>";

+		case PLUGIN_PARENT_LABEL:

+			return "<parentRegistry>";

+		case CONFIGURATION_ELEMENT_PARENT_LABEL:

+			return "<ConfigurationElementParent>";

+		case PLUGIN_INDEX_LABEL:

+			return "<pluginIndex>";

+		case EXTENSION_INDEX_LABEL:

+			return "<extensionIndex>";

+		case EXTENSION_POINT_PARENT_LABEL:

+			return "<ExtensionPointParent>";

+		case EXTENSION_POINT_EXTENSIONS_LENGTH_LABEL:

+			return "<extensionPointExtensionsLength>";

+		case EXTENSION_POINT_EXTENSIONS_LABEL:

+			return "<extensionPointExtensions>";

+		case EXTENSION_PARENT_LABEL:

+			return "<extensionParent>";

+		case CONFIGURATION_ELEMENT_INDEX_LABEL:

+			return "<configElementIndex>";

+		case REGISTRY_INDEX_LABEL:

+			return "<registryIndex>";

+	}

+

+	return "<unknown label>";

+}

+public boolean interpretHeaderInformation(DataInputStream in) {

+	try {

+		int version = in.readInt();

+		// install stamp

+		String installStamp = in.readUTF();

+		// OS stamp

+		String osStamp = in.readUTF();

+		// windows system stamp

+		String windowsStamp = in.readUTF();

+		// locale stamp

+		String localeStamp = in.readUTF();

+

+		return ((version == REGISTRY_CACHE_VERSION) &&

+			(installStamp.equals(LaunchInfo.getCurrent().getIdentifier())) &&

+			(osStamp.equals(BootLoader.getOS())) &&

+			(windowsStamp.equals(BootLoader.getWS())) &&

+			(localeStamp.equals(BootLoader.getNL())) );

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", "HeaderInformation"), ioe));

+		return false;

+	}

+}

+public ConfigurationElementModel readConfigurationElement(DataInputStream in) {

+	ConfigurationElementModel configurationElement = cacheFactory.createConfigurationElement();

+	// 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 {

+		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 NAME_LABEL :

+					configurationElement.setName(in.readUTF());

+					break;

+				case VALUE_LABEL :

+					configurationElement.setValue(in.readUTF());

+					break;

+				case PROPERTIES_LENGTH_LABEL :

+					int propertiesLength = in.readInt();

+					ConfigurationPropertyModel[] properties = new ConfigurationPropertyModel[propertiesLength];

+					for (int i = 0; i < propertiesLength; i++) {

+						properties[i] = readConfigurationProperty(in);

+					}

+					configurationElement.setProperties(properties);

+					properties = null;

+					break;

+				case SUBELEMENTS_LENGTH_LABEL :

+					int subElementsLength = in.readInt();

+					ConfigurationElementModel[] subElements = new ConfigurationElementModel[subElementsLength];

+					for (int i = 0; i < subElementsLength; i++) {

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

+			}

+		}

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", decipherLabel(CONFIGURATION_ELEMENT_LABEL)), ioe));

+		return null;

+	}

+	return configurationElement;

+}

+public ConfigurationPropertyModel readConfigurationProperty(DataInputStream in) {

+	ConfigurationPropertyModel configurationProperty = cacheFactory.createConfigurationProperty();

+	// 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 property.

+	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 NAME_LABEL :

+					configurationProperty.setName(in.readUTF());

+					break;

+				case VALUE_LABEL :

+					configurationProperty.setValue(in.readUTF());

+					break;

+				case CONFIGURATION_PROPERTY_END_LABEL :

+					done = true;

+			}

+		}

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", decipherLabel(CONFIGURATION_PROPERTY_LABEL)), ioe));

+		return null;

+	}

+	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 {

+		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 NAME_LABEL :

+					extension.setName(in.readUTF());

+					break;

+				case ID_LABEL :

+					extension.setId(in.readUTF());

+					break;

+				case EXTENSION_EXT_POINT_NAME_LABEL :

+					extension.setExtensionPoint(in.readUTF());

+					break;

+				case SUBELEMENTS_LENGTH_LABEL :

+					int subElementsLength = in.readInt();

+					ConfigurationElementModel[] subElements = new ConfigurationElementModel[subElementsLength];

+					for (int i = 0; i < subElementsLength; i++) {

+						// 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_PARENT_LABEL :

+					// Either there is a plugin or there is an index into the

+					// objectTable

+					switch (in.readByte()) {

+						case PLUGIN_LABEL :

+							extension.setParent((PluginModel)readPluginDescriptor(in));

+							break;

+						case PLUGIN_INDEX_LABEL :

+							extension.setParent((PluginModel)objectTable.get(in.readInt()));

+							break;

+						case FRAGMENT_LABEL :

+							extension.setParent((PluginModel)readPluginFragment(in));

+							break;

+						case FRAGMENT_INDEX_LABEL :

+							extension.setParent((PluginModel)objectTable.get(in.readInt()));

+							break;

+					}

+					break;

+				case EXTENSION_END_LABEL :

+					done = true;

+			}

+		}

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", decipherLabel(PLUGIN_EXTENSION_LABEL)), ioe));

+		return null;

+	}

+	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 {

+		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 NAME_LABEL :

+					extPoint.setName(in.readUTF());

+					break;

+				case ID_LABEL :

+					extPoint.setId(in.readUTF());

+					break;

+				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 :

+					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 or fragment is already in the objectTable

+					extPoint.setParent((PluginModel) objectTable.get(in.readInt()));

+					break;

+				case EXTENSION_POINT_END_LABEL :

+					done = true;

+			}

+		}

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", decipherLabel(PLUGIN_EXTENSION_POINT_LABEL)), ioe));

+		return null;

+	}

+	return extPoint;

+}

+public LibraryModel readLibrary(DataInputStream in) {

+	LibraryModel library = cacheFactory.createLibrary();

+	// 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

+	// library.

+	boolean setReadOnlyFlag = false;

+	int exportsLength = 0;

+	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 NAME_LABEL :

+					library.setName(in.readUTF());

+					break;

+				case LIBRARY_EXPORTS_LENGTH_LABEL :

+					exportsLength = in.readInt();

+					break;

+				case TYPE_LABEL :

+					library.setType(in.readUTF());

+					break;

+				case LIBRARY_EXPORTS_LABEL :

+					String[] exports = new String[exportsLength];

+					for (int i = 0; i < exportsLength; i++) {

+						exports[i] = in.readUTF();

+					}

+					library.setExports(exports);

+					exports = null;

+					break;

+				case LIBRARY_END_LABEL :

+					done = true;

+			}

+		}

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", decipherLabel(PLUGIN_LIBRARY_LABEL)), ioe));

+		return null;

+	}

+	return library;

+}

+public PluginDescriptorModel readPluginDescriptor(DataInputStream in) {

+	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 {

+		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 NAME_LABEL :

+					plugin.setName(in.readUTF());

+					break;

+				case ID_LABEL :

+					plugin.setId(in.readUTF());

+					break;

+				case PLUGIN_PROVIDER_NAME_LABEL :

+					plugin.setProviderName(in.readUTF());

+					break;

+				case VERSION_LABEL :

+					plugin.setVersion(in.readUTF());

+					break;

+				case PLUGIN_CLASS_LABEL :

+					plugin.setPluginClass(in.readUTF());

+					break;

+				case PLUGIN_LOCATION_LABEL :

+					plugin.setLocation(in.readUTF());

+					break;

+				case PLUGIN_ENABLED_LABEL :

+					plugin.setEnabled(in.readBoolean());

+					break;

+				case PLUGIN_REQUIRES_LABEL :

+					PluginPrerequisiteModel requires = readPluginPrerequisite(in);

+					// Add this prerequisite to the end of the requires list

+					PluginPrerequisiteModel[] requiresList = plugin.getRequires();

+					PluginPrerequisiteModel[] newRequiresValues = null;

+					if (requiresList == null) {

+						newRequiresValues = new PluginPrerequisiteModel[1];

+						newRequiresValues[0] = requires;

+					} else {

+						newRequiresValues = new PluginPrerequisiteModel[requiresList.length + 1];

+						System.arraycopy(requiresList, 0, newRequiresValues, 0, requiresList.length);

+						newRequiresValues[requiresList.length] = requires;

+					}

+					plugin.setRequires(newRequiresValues);

+					requires = null;

+					requiresList = newRequiresValues = null;

+					break;

+				case PLUGIN_LIBRARY_LABEL :

+					LibraryModel library = readLibrary(in);

+					// Add this library to the end of the runtime list

+					LibraryModel[] libraryList = plugin.getRuntime();

+					LibraryModel[] newLibraryValues = null;

+					if (libraryList == null) {

+						newLibraryValues = new LibraryModel[1];

+						newLibraryValues[0] = library;

+					} else {

+						newLibraryValues = new LibraryModel[libraryList.length + 1];

+						System.arraycopy(libraryList, 0, newLibraryValues, 0, libraryList.length);

+						newLibraryValues[libraryList.length] = library;

+					}

+					plugin.setRuntime(newLibraryValues);

+					library = null;

+					libraryList = newLibraryValues = null;

+					break;

+				case PLUGIN_EXTENSION_LABEL :

+					ExtensionModel extension = readExtension(in);

+					ExtensionModel[] extList = plugin.getDeclaredExtensions();

+					ExtensionModel[] 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 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

+					ExtensionPointModel[] extPointList = plugin.getDeclaredExtensionPoints();

+					ExtensionPointModel[] newExtPointValues = null;

+					if (extPointList == null) {

+						newExtPointValues = new ExtensionPointModel[1];

+						newExtPointValues[0] = extensionPoint;

+					} else {

+						newExtPointValues = new ExtensionPointModel[extPointList.length + 1];

+						System.arraycopy(extPointList, 0, newExtPointValues, 0, extPointList.length);

+						newExtPointValues[extPointList.length] = extensionPoint;

+					}

+					plugin.setDeclaredExtensionPoints(newExtPointValues);

+					extensionPoint = null;

+					extPointList = newExtPointValues = null;

+					break;

+				case FRAGMENT_LABEL :

+					PluginFragmentModel fragment = readPluginFragment(in);

+					// Add this fragment to the end of the fragment list

+					PluginFragmentModel[] fragmentList = plugin.getFragments();

+					PluginFragmentModel[] newFragmentValues = null;

+					if (fragmentList == null) {

+						newFragmentValues = new PluginFragmentModel[1];

+						newFragmentValues[0] = fragment;

+					} else {

+						newFragmentValues = new PluginFragmentModel[fragmentList.length + 1];

+						System.arraycopy(fragmentList, 0, newFragmentValues, 0, fragmentList.length);

+						newFragmentValues[fragmentList.length] = fragment;

+					}

+					plugin.setFragments(newFragmentValues);

+					fragment = null;

+					fragmentList = newFragmentValues = null;

+					break;

+				case FRAGMENT_INDEX_LABEL :

+					fragment = (PluginFragmentModel) objectTable.get(in.readInt());

+					fragmentList = plugin.getFragments();

+					newFragmentValues = null;

+					if (fragmentList == null) {

+						newFragmentValues = new PluginFragmentModel[1];

+						newFragmentValues[0] = fragment;

+					} else {

+						newFragmentValues = new PluginFragmentModel[fragmentList.length + 1];

+						System.arraycopy(fragmentList, 0, newFragmentValues, 0, fragmentList.length);

+						newFragmentValues[fragmentList.length] = fragment;

+					}

+					plugin.setFragments(newFragmentValues);

+					fragment = null;

+					fragmentList = newFragmentValues = null;

+					break;

+				case PLUGIN_PARENT_LABEL :

+					plugin.setRegistry((PluginRegistryModel) objectTable.get(in.readInt()));

+					break;

+				case PLUGIN_END_LABEL :

+					done = true;

+			}

+		}

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", decipherLabel(PLUGIN_LABEL)), ioe));

+		return null;

+	}

+	return plugin;

+}

+public PluginFragmentModel readPluginFragment(DataInputStream in) {

+	PluginFragmentModel fragment = cacheFactory.createPluginFragment();

+	addToObjectTable(fragment);

+	// 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 {

+		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 NAME_LABEL :

+					fragment.setName(in.readUTF());

+					break;

+				case ID_LABEL :

+					fragment.setId(in.readUTF());

+					break;

+				case PLUGIN_PROVIDER_NAME_LABEL :

+					fragment.setProviderName(in.readUTF());

+					break;

+				case VERSION_LABEL :

+					fragment.setVersion(in.readUTF());

+					break;

+				case PLUGIN_LOCATION_LABEL :

+					fragment.setLocation(in.readUTF());

+					break;

+				case FRAGMENT_PLUGIN_LABEL :

+					fragment.setPlugin(in.readUTF());

+					break;

+				case FRAGMENT_PLUGIN_VERSION_LABEL :

+					fragment.setPluginVersion(in.readUTF());

+					break;

+				case PLUGIN_REQUIRES_LABEL :

+					PluginPrerequisiteModel requires = readPluginPrerequisite(in);

+					// Add this prerequisite to the end of the requires list

+					PluginPrerequisiteModel[] requiresList = fragment.getRequires();

+					PluginPrerequisiteModel[] newRequiresValues = null;

+					if (requiresList == null) {

+						newRequiresValues = new PluginPrerequisiteModel[1];

+						newRequiresValues[0] = requires;

+					} else {

+						newRequiresValues = new PluginPrerequisiteModel[requiresList.length + 1];

+						System.arraycopy(requiresList, 0, newRequiresValues, 0, requiresList.length);

+						newRequiresValues[requiresList.length] = requires;

+					}

+					fragment.setRequires(newRequiresValues);

+					requires = null;

+					requiresList = newRequiresValues = null;

+					break;

+				case PLUGIN_LIBRARY_LABEL :

+					LibraryModel library = readLibrary(in);

+					// Add this library to the end of the runtime list

+					LibraryModel[] libraryList = fragment.getRuntime();

+					LibraryModel[] newLibraryValues = null;

+					if (libraryList == null) {

+						newLibraryValues = new LibraryModel[1];

+						newLibraryValues[0] = library;

+					} else {

+						newLibraryValues = new LibraryModel[libraryList.length + 1];

+						System.arraycopy(libraryList, 0, newLibraryValues, 0, libraryList.length);

+						newLibraryValues[libraryList.length] = library;

+					}

+					fragment.setRuntime(newLibraryValues);

+					library = null;

+					libraryList = newLibraryValues = null;

+					break;

+				case PLUGIN_EXTENSION_LABEL :

+					ExtensionModel extension = readExtension(in);

+					ExtensionModel[] extList = fragment.getDeclaredExtensions();

+					ExtensionModel[] 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;

+					}

+					fragment.setDeclaredExtensions(newExtValues);

+					extension = null;

+					extList = newExtValues = null;

+					break;

+				case EXTENSION_INDEX_LABEL :

+					extension = (ExtensionModel) objectTable.get(in.readInt());

+					extList = fragment.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;

+					}

+					fragment.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

+					ExtensionPointModel[] extPointList = fragment.getDeclaredExtensionPoints();

+					ExtensionPointModel[] newExtPointValues = null;

+					if (extPointList == null) {

+						newExtPointValues = new ExtensionPointModel[1];

+						newExtPointValues[0] = extensionPoint;

+					} else {

+						newExtPointValues = new ExtensionPointModel[extPointList.length + 1];

+						System.arraycopy(extPointList, 0, newExtPointValues, 0, extPointList.length);

+						newExtPointValues[extPointList.length] = extensionPoint;

+					}

+					fragment.setDeclaredExtensionPoints(newExtPointValues);

+					extensionPoint = null;

+					extPointList = newExtPointValues = null;

+					break;

+				case PLUGIN_PARENT_LABEL :

+					fragment.setRegistry((PluginRegistryModel) objectTable.get(in.readInt()));

+					break;

+				case FRAGMENT_END_LABEL :

+					done = true;

+			}

+		}

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", decipherLabel(FRAGMENT_LABEL)), ioe));

+		return null;

+	}

+	return fragment;

+}

+public PluginPrerequisiteModel readPluginPrerequisite(DataInputStream in) {

+	PluginPrerequisiteModel requires = cacheFactory.createPluginPrerequisite();

+	// 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

+	// prerequisite.

+	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 NAME_LABEL :

+					requires.setName(in.readUTF());

+					break;

+				case VERSION_LABEL :

+					requires.setVersion(in.readUTF());

+					break;

+				case REQUIRES_MATCH_LABEL :

+					requires.setMatch(in.readBoolean());

+					break;

+				case REQUIRES_EXPORT_LABEL :

+					requires.setExport(in.readBoolean());

+					break;

+				case REQUIRES_OPTIONAL_LABEL :

+					requires.setOptional(in.readBoolean());

+					break;

+				case REQUIRES_RESOLVED_VERSION_LABEL :

+					requires.setResolvedVersion(in.readUTF());

+					break;

+				case REQUIRES_PLUGIN_NAME_LABEL :

+					requires.setPlugin(in.readUTF());

+					break;

+				case REQUIRES_END_LABEL :

+					done = true;

+			}

+		}

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", decipherLabel(PLUGIN_REQUIRES_LABEL)), ioe));

+		return null;

+	}

+	return requires;

+}

+public PluginRegistryModel readPluginRegistry(DataInputStream in) {

+	if (cacheReadProblems == null) {

+		cacheReadProblems = new MultiStatus(Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind("meta.registryCacheReadProblems"), null);

+	}

+

+	if (!interpretHeaderInformation(in)) {

+		return null;

+	}

+	PluginRegistryModel cachedRegistry = cacheFactory.createPluginRegistry();

+	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 FRAGMENT_LABEL :

+					PluginFragmentModel fragment = null;

+					if ((fragment = readPluginFragment(in)) != null) {

+						cachedRegistry.addFragment(fragment);

+					}

+					break;

+				case FRAGMENT_INDEX_LABEL :

+					fragment = (PluginFragmentModel) objectTable.get(in.readInt());

+					cachedRegistry.addFragment(fragment);

+					break;

+				case REGISTRY_END_LABEL :

+					done = true;

+			}

+		}

+	} catch (IOException ioe) {

+		cacheReadProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", decipherLabel(REGISTRY_LABEL)), 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?

+	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
new file mode 100644
index 0000000..8d82062
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryCacheWriter.java
@@ -0,0 +1,609 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

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

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

+import org.eclipse.core.internal.runtime.Policy;

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

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

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

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

+import org.eclipse.core.runtime.model.*;

+import java.io.DataOutputStream;

+import java.io.IOException;

+import java.util.ArrayList;

+

+public class RegistryCacheWriter {

+	// 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 MultiStatus cacheWriteProblems = null;

+	

+	public static final boolean DEBUG_REGISTRY_CACHE = false;

+	

+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 writeLabel(byte labelValue, DataOutputStream out) {

+	try {

+		if (DEBUG_REGISTRY_CACHE) {

+			out.writeUTF (RegistryCacheReader.decipherLabel(labelValue));

+		} else {

+			out.writeByte(labelValue);

+		}

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(labelValue)), ioe));

+	}

+}

+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

+			writeLabel(RegistryCacheReader.CONFIGURATION_ELEMENT_INDEX_LABEL, out);

+			out.writeInt(configElementIndex);

+			return;

+		}

+

+		String outString;

+		// add this object to the object table first

+		addToObjectTable(configElement);

+

+		writeLabel(RegistryCacheReader.CONFIGURATION_ELEMENT_LABEL, out);

+

+		writeLabel(RegistryCacheReader.READONLY_LABEL, out);

+		out.writeBoolean(configElement.isReadOnly());

+

+		if ((outString = configElement.getName()) != null) {

+			writeLabel(RegistryCacheReader.NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		if ((outString = configElement.getValue()) != null) {

+			writeLabel(RegistryCacheReader.VALUE_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		ConfigurationPropertyModel[] properties = configElement.getProperties();

+		if (properties != null) {

+			writeLabel(RegistryCacheReader.PROPERTIES_LENGTH_LABEL, out);

+			out.writeInt(properties.length);

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

+				writeConfigurationProperty(properties[i], out);

+			}

+		}

+

+		ConfigurationElementModel[] subElements = configElement.getSubElements();

+		if (subElements != null) {

+			writeLabel(RegistryCacheReader.SUBELEMENTS_LENGTH_LABEL, out);

+			out.writeInt(subElements.length);

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

+				writeConfigurationElement(subElements[i], out);

+			}

+		}

+

+		// 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();

+		writeLabel(RegistryCacheReader.CONFIGURATION_ELEMENT_PARENT_LABEL, out);

+		out.writeInt(objectTable.indexOf(parent));

+

+		writeLabel(RegistryCacheReader.CONFIGURATION_ELEMENT_END_LABEL, out);

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(RegistryCacheReader.CONFIGURATION_ELEMENT_LABEL)), ioe));

+	}

+}

+public void writeConfigurationProperty(ConfigurationPropertyModel configProperty, DataOutputStream out) {

+	try {

+		String outString;

+

+		writeLabel(RegistryCacheReader.CONFIGURATION_PROPERTY_LABEL, out);

+

+		writeLabel(RegistryCacheReader.READONLY_LABEL, out);

+		out.writeBoolean(configProperty.isReadOnly());

+

+		if ((outString = configProperty.getName()) != null) {

+			writeLabel(RegistryCacheReader.NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		if ((outString = configProperty.getValue()) != null) {

+			writeLabel(RegistryCacheReader.VALUE_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		writeLabel(RegistryCacheReader.CONFIGURATION_PROPERTY_END_LABEL, out);

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(RegistryCacheReader.CONFIGURATION_PROPERTY_LABEL)), 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

+			writeLabel(RegistryCacheReader.EXTENSION_INDEX_LABEL, out);

+			out.writeInt(extensionIndex);

+			return;

+		}

+		// add this object to the object table first

+		addToObjectTable(extension);

+

+		String outString;

+

+		writeLabel(RegistryCacheReader.PLUGIN_EXTENSION_LABEL, out);

+

+		writeLabel(RegistryCacheReader.READONLY_LABEL, out);

+		out.writeBoolean(extension.isReadOnly());

+

+		if ((outString = extension.getName()) != null) {

+			writeLabel(RegistryCacheReader.NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		if ((outString = extension.getExtensionPoint()) != null) {

+			writeLabel(RegistryCacheReader.EXTENSION_EXT_POINT_NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		if ((outString = extension.getId()) != null) {

+			writeLabel(RegistryCacheReader.ID_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		ConfigurationElementModel[] subElements = extension.getSubElements();

+		if (subElements != null) {

+			writeLabel(RegistryCacheReader.SUBELEMENTS_LENGTH_LABEL, out);

+			out.writeInt(subElements.length);

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

+				writeConfigurationElement(subElements[i], out);

+			}

+		}

+

+		// Now worry about the parent plugin descriptor or plugin fragment

+		PluginModel parent = extension.getParent();

+		int parentIndex = objectTable.indexOf(parent);

+		writeLabel(RegistryCacheReader.EXTENSION_PARENT_LABEL, out);

+		if (parentIndex != -1) {

+			// We have already written this plugin or fragment.  Just use the index.

+			if (parent instanceof PluginDescriptorModel) {

+				writeLabel(RegistryCacheReader.PLUGIN_INDEX_LABEL, out);

+			} else /* must be a fragment */ {

+				writeLabel(RegistryCacheReader.FRAGMENT_INDEX_LABEL, out);

+			}

+			out.writeInt(parentIndex);

+		} else {

+			// We haven't visited this plugin or fragment yet, so write it explicitly

+			if (parent instanceof PluginDescriptorModel) {

+				writePluginDescriptor((PluginDescriptorModel)parent, out);

+			} else /* must be a fragment */ {

+				writePluginFragment((PluginFragmentModel)parent, out);

+			}

+		}

+

+		writeLabel(RegistryCacheReader.EXTENSION_END_LABEL, out);

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(RegistryCacheReader.PLUGIN_EXTENSION_LABEL)), ioe));

+	}

+}

+public void writeExtensionPoint(ExtensionPointModel extPoint, DataOutputStream out) {

+	// add this object to the object table first

+	addToObjectTable(extPoint);

+	try {

+		String outString;

+

+		writeLabel(RegistryCacheReader.PLUGIN_EXTENSION_POINT_LABEL, out);

+

+		writeLabel(RegistryCacheReader.READONLY_LABEL, out);

+		out.writeBoolean(extPoint.isReadOnly());

+

+		if ((outString = extPoint.getName()) != null) {

+			writeLabel(RegistryCacheReader.NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		if ((outString = extPoint.getId()) != null) {

+			writeLabel(RegistryCacheReader.ID_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		if ((outString = extPoint.getSchema()) != null) {

+			writeLabel(RegistryCacheReader.EXTENSION_POINT_SCHEMA_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		// Write out the parent's index.  We know we have

+		// already written this plugin or fragment to the cache

+		PluginModel parent = extPoint.getParent();

+		if (parent != null) {

+			int parentIndex = objectTable.indexOf(parent);

+			if (parentIndex != -1) {

+				writeLabel(RegistryCacheReader.EXTENSION_POINT_PARENT_LABEL, out);

+				out.writeInt(parentIndex);

+			}

+		}

+

+		// Now do the extensions.

+		ExtensionModel[] extensions = extPoint.getDeclaredExtensions();

+		int extLength = extensions == null ? 0 : extensions.length;

+		if (extLength != 0) {

+			writeLabel(RegistryCacheReader.EXTENSION_POINT_EXTENSIONS_LENGTH_LABEL, out);

+			out.writeInt(extLength);

+			writeLabel(RegistryCacheReader.EXTENSION_POINT_EXTENSIONS_LABEL, out);

+			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

+					writeLabel(RegistryCacheReader.EXTENSION_INDEX_LABEL, out);

+					out.writeInt(extensionIndex);

+				} else {

+					writeExtension(extensions[i], out);

+				}

+			}

+		}

+

+		writeLabel(RegistryCacheReader.EXTENSION_POINT_END_LABEL, out);

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(RegistryCacheReader.PLUGIN_EXTENSION_POINT_LABEL)), ioe));

+	}

+}

+public void writeHeaderInformation(DataOutputStream out) {

+	try {

+		out.writeInt(RegistryCacheReader.REGISTRY_CACHE_VERSION);

+		// install stamp

+		out.writeUTF(LaunchInfo.getCurrent().getIdentifier());

+		// OS stamp

+		out.writeUTF(BootLoader.getOS());

+		// windows system stamp

+		out.writeUTF(BootLoader.getWS());

+		// locale stamp

+		out.writeUTF(BootLoader.getNL());

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", "HeaderInformation"), ioe));

+	}

+}

+public void writeLibrary(LibraryModel library, DataOutputStream out) {

+	try {

+		String outString;

+

+		writeLabel(RegistryCacheReader.PLUGIN_LIBRARY_LABEL, out);

+

+		writeLabel(RegistryCacheReader.READONLY_LABEL, out);

+		out.writeBoolean(library.isReadOnly());

+

+		if ((outString = library.getName()) != null) {

+			writeLabel(RegistryCacheReader.NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = library.getType()) != null) {

+			writeLabel(RegistryCacheReader.TYPE_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		String[] exports = null;

+		if ((exports = library.getExports()) != null) {

+			writeLabel(RegistryCacheReader.LIBRARY_EXPORTS_LENGTH_LABEL, out);

+			out.writeInt(exports.length);

+			writeLabel(RegistryCacheReader.LIBRARY_EXPORTS_LABEL, out);

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

+				out.writeUTF(exports[i]);

+			}

+		}

+

+		// 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.

+		writeLabel(RegistryCacheReader.LIBRARY_END_LABEL, out);

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(RegistryCacheReader.PLUGIN_LIBRARY_LABEL)), 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

+			writeLabel(RegistryCacheReader.PLUGIN_INDEX_LABEL, out);

+			out.writeInt(pluginIndex);

+			return;

+		}

+

+		// add this object to the object table first

+		addToObjectTable(plugin);

+		String outString;

+

+		writeLabel(RegistryCacheReader.PLUGIN_LABEL, out);

+		writeLabel(RegistryCacheReader.READONLY_LABEL, out);

+		out.writeBoolean(plugin.isReadOnly());

+		if ((outString = plugin.getName()) != null) {

+			writeLabel(RegistryCacheReader.NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = plugin.getId()) != null) {

+			writeLabel(RegistryCacheReader.ID_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = plugin.getProviderName()) != null) {

+			writeLabel(RegistryCacheReader.PLUGIN_PROVIDER_NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = plugin.getVersion()) != null) {

+			writeLabel(RegistryCacheReader.VERSION_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = plugin.getPluginClass()) != null) {

+			writeLabel(RegistryCacheReader.PLUGIN_CLASS_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = plugin.getLocation()) != null) {

+			writeLabel(RegistryCacheReader.PLUGIN_LOCATION_LABEL, out);

+			out.writeUTF(outString);

+		}

+		writeLabel(RegistryCacheReader.PLUGIN_ENABLED_LABEL, out);

+		out.writeBoolean(plugin.getEnabled());

+

+		// write out prerequisites

+		PluginPrerequisiteModel[] requires = plugin.getRequires();

+		int reqSize = (requires == null) ? 0 : requires.length;

+		if (reqSize != 0) {

+			for (int i = 0; i < reqSize; i++)

+				writePluginPrerequisite(requires[i], out);

+		}

+

+		// write out library entries

+		LibraryModel[] runtime = plugin.getRuntime();

+		int runtimeSize = (runtime == null) ? 0 : runtime.length;

+		if (runtimeSize != 0) {

+			for (int i = 0; i < runtimeSize; i++) {

+				writeLibrary(runtime[i], out);

+			}

+		}

+

+		// need to worry about cross links here

+		// now do extension points

+		ExtensionPointModel[] extensionPoints = plugin.getDeclaredExtensionPoints();

+		int extPointsSize = (extensionPoints == null) ? 0 : extensionPoints.length;

+		if (extPointsSize != 0) {

+			for (int i = 0; i < extPointsSize; i++)

+				writeExtensionPoint(extensionPoints[i], out);

+		}

+

+		// and then extensions

+		ExtensionModel[] extensions = plugin.getDeclaredExtensions();

+		int extSize = (extensions == null) ? 0 : extensions.length;

+		if (extSize != 0) {

+			for (int i = 0; i < extSize; i++) {

+				writeExtension(extensions[i], out);

+			}

+		}

+

+		// and then fragments

+		PluginFragmentModel[] fragments = plugin.getFragments();

+		int fragmentSize = (fragments == null) ? 0 : fragments.length;

+		if (fragmentSize != 0) {

+			for (int i = 0; i < fragmentSize; i++) {

+				writePluginFragment(fragments[i], out);

+			}

+		}

+

+		// Add the index to the registry object for this plugin

+		PluginRegistryModel parentRegistry = plugin.getRegistry();

+		writeLabel(RegistryCacheReader.PLUGIN_PARENT_LABEL, out);

+		// We can assume that the parent registry is already written out.

+		out.writeInt(objectTable.indexOf(parentRegistry));

+

+		writeLabel(RegistryCacheReader.PLUGIN_END_LABEL, out);

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(RegistryCacheReader.PLUGIN_LABEL)), ioe));

+	}

+}

+public void writePluginFragment(PluginFragmentModel fragment, DataOutputStream out) {

+

+	try {

+		// Check to see if this fragment already exists in the objectTable.  If it is there,

+		// it has already been written to the cache so just write out the index.

+		int fragmentIndex = objectTable.indexOf(fragment);

+		if (fragmentIndex != -1) {

+			// this fragment is already there

+			writeLabel(RegistryCacheReader.FRAGMENT_INDEX_LABEL, out);

+			out.writeInt(fragmentIndex);

+			return;

+		}

+

+		// add this object to the object table first

+		addToObjectTable(fragment);

+		String outString;

+

+		writeLabel(RegistryCacheReader.FRAGMENT_LABEL, out);

+		writeLabel(RegistryCacheReader.READONLY_LABEL, out);

+		out.writeBoolean(fragment.isReadOnly());

+		if ((outString = fragment.getName()) != null) {

+			writeLabel(RegistryCacheReader.NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = fragment.getId()) != null) {

+			writeLabel(RegistryCacheReader.ID_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = fragment.getProviderName()) != null) {

+			writeLabel(RegistryCacheReader.PLUGIN_PROVIDER_NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = fragment.getVersion()) != null) {

+			writeLabel(RegistryCacheReader.VERSION_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = fragment.getLocation()) != null) {

+			writeLabel(RegistryCacheReader.PLUGIN_LOCATION_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = fragment.getPlugin()) != null) {

+			writeLabel(RegistryCacheReader.FRAGMENT_PLUGIN_LABEL, out);

+			out.writeUTF(outString);

+		}

+		if ((outString = fragment.getPluginVersion()) != null) {

+			writeLabel(RegistryCacheReader.FRAGMENT_PLUGIN_VERSION_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		// write out prerequisites

+		PluginPrerequisiteModel[] requires = fragment.getRequires();

+		int reqSize = (requires == null) ? 0 : requires.length;

+		if (reqSize != 0) {

+			for (int i = 0; i < reqSize; i++)

+				writePluginPrerequisite(requires[i], out);

+		}

+

+		// write out library entries

+		LibraryModel[] runtime = fragment.getRuntime();

+		int runtimeSize = (runtime == null) ? 0 : runtime.length;

+		if (runtimeSize != 0) {

+			for (int i = 0; i < runtimeSize; i++) {

+				writeLibrary(runtime[i], out);

+			}

+		}

+

+		// need to worry about cross links here

+		// now do extension points

+		ExtensionPointModel[] extensionPoints = fragment.getDeclaredExtensionPoints();

+		int extPointsSize = (extensionPoints == null) ? 0 : extensionPoints.length;

+		if (extPointsSize != 0) {

+			for (int i = 0; i < extPointsSize; i++)

+				writeExtensionPoint(extensionPoints[i], out);

+		}

+

+		// and then extensions

+		ExtensionModel[] extensions = fragment.getDeclaredExtensions();

+		int extSize = (extensions == null) ? 0 : extensions.length;

+		if (extSize != 0) {

+			for (int i = 0; i < extSize; i++) {

+				writeExtension(extensions[i], out);

+			}

+		}

+

+		// Add the index to the registry object for this plugin

+		PluginRegistryModel parentRegistry = fragment.getRegistry();

+		writeLabel(RegistryCacheReader.PLUGIN_PARENT_LABEL, out);

+		// We can assume that the parent registry is already written out.

+		out.writeInt(objectTable.indexOf(parentRegistry));

+

+		writeLabel(RegistryCacheReader.FRAGMENT_END_LABEL, out);

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(RegistryCacheReader.FRAGMENT_LABEL)), ioe));

+	}

+}

+public void writePluginPrerequisite(PluginPrerequisiteModel requires, DataOutputStream out) {

+	try {

+		String outString = null;

+

+		writeLabel(RegistryCacheReader.PLUGIN_REQUIRES_LABEL, out);

+

+		writeLabel(RegistryCacheReader.READONLY_LABEL, out);

+		out.writeBoolean(requires.isReadOnly());

+

+		if ((outString = requires.getName()) != null) {

+			writeLabel(RegistryCacheReader.NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		if ((outString = requires.getVersion()) != null) {

+			writeLabel(RegistryCacheReader.VERSION_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		writeLabel(RegistryCacheReader.REQUIRES_MATCH_LABEL, out);

+		out.writeBoolean(requires.getMatch());

+

+		writeLabel(RegistryCacheReader.REQUIRES_EXPORT_LABEL, out);

+		out.writeBoolean(requires.getExport());

+

+		writeLabel(RegistryCacheReader.REQUIRES_OPTIONAL_LABEL, out);

+		out.writeBoolean(requires.getOptional());

+

+		if ((outString = requires.getResolvedVersion()) != null) {

+			writeLabel(RegistryCacheReader.REQUIRES_RESOLVED_VERSION_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		if ((outString = requires.getPlugin()) != null) {

+			writeLabel(RegistryCacheReader.REQUIRES_PLUGIN_NAME_LABEL, out);

+			out.writeUTF(outString);

+		}

+

+		writeLabel(RegistryCacheReader.REQUIRES_END_LABEL, out);

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(RegistryCacheReader.PLUGIN_REQUIRES_LABEL)), ioe));

+	}

+}

+public void writePluginRegistry(PluginRegistryModel registry, DataOutputStream out) {

+	if (cacheWriteProblems == null) {

+		cacheWriteProblems = new MultiStatus(Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind("meta.registryCacheWriteProblems"), null);

+	}

+

+	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

+				writeLabel(RegistryCacheReader.REGISTRY_INDEX_LABEL, out);

+				out.writeInt(registryIndex);

+				return;

+			}

+		}

+

+		// add this object to the object table first

+		addToObjectTable(registry);

+		writeHeaderInformation(out);

+		String outString = null;

+

+		writeLabel(RegistryCacheReader.REGISTRY_LABEL, out);

+

+		writeLabel(RegistryCacheReader.READONLY_LABEL, out);

+		out.writeBoolean(registry.isReadOnly());

+

+		writeLabel(RegistryCacheReader.REGISTRY_RESOLVED_LABEL, out);

+		out.writeBoolean(registry.isResolved());

+		PluginDescriptorModel[] pluginList = registry.getPlugins();

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

+			writePluginDescriptor(pluginList[i], out);

+		PluginFragmentModel[] fragmentList = registry.getFragments();

+		int fragmentLength = (fragmentList == null) ? 0 : fragmentList.length;

+		for (int i = 0; i < fragmentLength; i++)

+			writePluginFragment(fragmentList[i], out);

+		writeLabel(RegistryCacheReader.REGISTRY_END_LABEL, out);

+	} catch (IOException ioe) {

+		cacheWriteProblems.add(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind ("meta.regCacheIOException", RegistryCacheReader.decipherLabel(RegistryCacheReader.REGISTRY_LABEL)), 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
new file mode 100644
index 0000000..37469b2
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryLoader.java
@@ -0,0 +1,129 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.internal.runtime.InternalPlatform;

+import org.eclipse.core.internal.runtime.Policy;

+import java.io.*;

+import java.net.URL;

+import java.net.MalformedURLException;

+import org.xml.sax.InputSource;

+import org.xml.sax.SAXParseException;

+

+public class RegistryLoader {

+	private Factory factory;

+

+	// debug support

+	private boolean debug = false;

+	private long startTick = (new java.util.Date()).getTime(); // used for performance timings

+	private long lastTick = startTick;

+private RegistryLoader(Factory factory, boolean debug) {

+	super();

+	this.debug = debug;

+	this.factory = factory;

+}

+private void debug(String msg) {

+	long thisTick = System.currentTimeMillis();

+	System.out.println("RegistryLoader: " + msg + " [+"+ (thisTick - lastTick) + "ms]");

+	lastTick = thisTick;

+}

+private String[] getPathMembers(URL path) {

+	String[] list = null;

+	String protocol = path.getProtocol();

+	if (protocol.equals("file") || (InternalPlatform.inVAJ() && protocol.equals("valoader"))) {

+		list = (new File(path.getFile())).list();

+	} else {

+		// XXX: attempt to read URL and see if we got html dir page

+	}

+	return list == null ? new String[0] : list;

+}

+private PluginRegistryModel parseRegistry(URL[] pluginPath) {

+	long startTick = System.currentTimeMillis();

+	PluginRegistryModel result = processManifestFiles(pluginPath);

+	if (InternalPlatform.DEBUG) {

+		long endTick = System.currentTimeMillis();

+		debug("Parsed Registry: " + (endTick - startTick) + "ms");

+	}

+	return result;

+}

+public static PluginRegistryModel parseRegistry(URL[] pluginPath, Factory factory, boolean debug) {

+	return new RegistryLoader(factory, debug).parseRegistry(pluginPath);

+}

+private PluginModel processManifestFile(URL manifest) {

+	InputStream is = null;

+	try {

+		is = manifest.openStream();

+	} catch (IOException e) {

+		if (debug)

+			debug("No plugin found for: " + manifest);

+		return null;

+	}

+	PluginModel result = null;

+	try {

+		try {

+			result = new PluginParser((Factory) factory).parsePlugin(new InputSource(is));

+		} finally {

+			is.close();

+		}

+	} catch (SAXParseException se) {

+		/* exception details logged by parser */

+		factory.error(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind("parse.errorProcessing", manifest.toString()), null));

+	} catch (Exception e) {

+		factory.error(new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind("parse.errorProcessing", manifest.toString()), null));

+	}

+	return result;

+}

+private PluginRegistryModel processManifestFiles(URL[] pluginPath) {

+	PluginRegistryModel result = factory.createPluginRegistry();

+	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 - " + members[j]);

+		}

+	} else {

+		// specific file entry - load the given file

+		boolean found = processPluginPathFile(registry, location);

+		if (debug)

+			debug("Processed - " + location);

+	}

+}

+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
new file mode 100644
index 0000000..22a97fd
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryResolver.java
@@ -0,0 +1,1063 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.util.*;

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.runtime.PluginVersionIdentifier;

+import org.eclipse.core.internal.runtime.InternalPlatform;

+import org.eclipse.core.internal.runtime.Policy;

+

+public class RegistryResolver {

+

+	private Map idmap;

+	private PluginRegistryModel reg;

+	private MultiStatus status;

+	private boolean trimPlugins = true;

+	private boolean crossLink = true;

+

+	public static final int MATCH_EXACT = 0;

+	public static final int MATCH_COMPATIBLE = 1;

+	public static final int MATCH_LATEST = 2;

+

+	private boolean DEBUG_RESOLVE = false;

+	private static final String OPTION_DEBUG_RESOLVE = "org.eclipse.core.runtime/registry/debug/resolve";

+

+	// constraint entry

+	private class Constraint {

+		private PluginDescriptorModel parent;

+		private PluginPrerequisiteModel prq;

+		private PluginVersionIdentifier ver;

+		private int type = MATCH_LATEST;

+		private ConstraintsEntry cEntry = null;

+

+		private Constraint(PluginDescriptorModel parent, PluginPrerequisiteModel prq) {

+			this.parent = parent;

+			this.prq = prq;

+			if (prq != null) {

+				ver = RegistryResolver.this.getVersionIdentifier(prq);

+				if (ver == null)

+					type = MATCH_LATEST;

+				else

+					if (prq.getMatch())

+						type = MATCH_EXACT;

+					else

+						type = MATCH_COMPATIBLE;

+			}

+		}

+

+		private int getMatchType() {

+			return type;

+		}

+

+		private ConstraintsEntry getConstraintsEntry() {

+			return cEntry;

+		}

+

+		private void setConstraintsEntry(ConstraintsEntry entry) {

+			cEntry = entry;

+		}

+

+		private PluginDescriptorModel getParent() {

+			return parent;

+		}

+

+		private PluginPrerequisiteModel getPrerequisite() {

+			return prq;

+		}

+

+		private PluginVersionIdentifier getVersionIdentifier() {

+			return ver;

+		}

+

+		public String toString() {

+			if (prq == null)

+				return "(null)";

+			String s = parent.toString() + "->" + prq.getPlugin();

+			String v = prq.getVersion();

+			s += v == null ? "(any)" : (prq.getMatch() ? "(" + v + ",exact)" : "(" + v + ",compatible)");

+			return s;

+		}

+	}

+

+	// constraint index structure

+	private class ConstraintsEntry {

+		private IndexEntry parent;

+		private List constraintList = new LinkedList();

+		private PluginDescriptorModel lastResolved = null;

+		private boolean isResolved = false;

+		private PluginDescriptorModel bestMatch = null;

+		private boolean bestMatchEnabled = false;

+

+		private ConstraintsEntry(IndexEntry parent) {

+			this.parent = parent;

+		}

+

+		private int constraintCount() {

+			return constraintList.size();

+		}

+

+		private PluginDescriptorModel addConstraint(Constraint c) {

+			constraintList.add(c);

+			c.setConstraintsEntry(this);

+			List constrained = getMatchingDescriptors();

+			if (constrained.size() <= 0) {

+				constraintList.remove(c);

+				c.setConstraintsEntry(null);

+				return null;

+			} else {

+				PluginDescriptorModel match = (PluginDescriptorModel) constrained.get(0);

+				if (!match.equals(lastResolved)) {

+					lastResolved = match;

+					isResolved = false;

+				}

+				return match;

+			}

+		}

+

+		private void removeConstraint(Constraint c) {

+			if (DEBUG_RESOLVE)

+				debug("removing constraint " + c.toString());

+			constraintList.remove(c);

+			c.setConstraintsEntry(null);

+			lastResolved = null;

+			isResolved = false;

+		}

+

+		private void removeConstraintFor(PluginPrerequisiteModel prereq) {

+			List remove = new ArrayList();

+			for (Iterator list = constraintList.iterator(); list.hasNext();) {

+				Constraint c = (Constraint) list.next();

+				if (c.getPrerequisite() == prereq)

+					remove.add(c);

+			}

+			for (Iterator list = remove.iterator(); list.hasNext();)

+				removeConstraint((Constraint) list.next());

+		}

+

+		private PluginDescriptorModel getMatchingDescriptor() {

+			List constrained = getMatchingDescriptors();

+			if (constrained.size() <= 0)

+				return null;

+			else

+				return (PluginDescriptorModel) constrained.get(0);

+		}

+

+		private List getMatchingDescriptors() {

+			List constrained = new LinkedList();

+

+			for (Iterator list = parent.versions().iterator(); list.hasNext();) {

+				PluginDescriptorModel pd = (PluginDescriptorModel) list.next();

+				if (pd.getEnabled())

+					constrained.add(pd);

+			}

+

+			for (Iterator list = constraintList.iterator(); list.hasNext();) {

+				Constraint c = (Constraint) list.next();

+				if (c.getMatchType() == MATCH_LATEST)

+					continue;

+				for (Iterator list2 = parent.versions().iterator(); list2.hasNext();) {

+					PluginDescriptorModel pd = (PluginDescriptorModel) list2.next();

+					if (!pd.getEnabled())

+						continue;

+					if (c.getMatchType() == MATCH_EXACT) {

+						if (!getVersionIdentifier(pd).isEquivalentTo(c.getVersionIdentifier()))

+							constrained.remove(pd);

+					} else {

+						if (!getVersionIdentifier(pd).isCompatibleWith(c.getVersionIdentifier()))

+							constrained.remove(pd);

+					}

+				}

+			}

+

+			return constrained;

+		}

+

+		private void preresolve(List roots) {

+

+			if (constraintList.size() <= 0) {

+				if (roots.contains(parent.getId())) {

+					bestMatch = (PluginDescriptorModel) parent.versions().get(0);

+					if (bestMatch == null) {

+						if (DEBUG_RESOLVE)

+							debug("*ERROR* no resolved descriptor for " + parent.getId());

+					} else

+						bestMatchEnabled = bestMatch.getEnabled();

+				}

+			} else {

+				bestMatch = getMatchingDescriptor();

+				if (bestMatch == null) {

+					if (DEBUG_RESOLVE)

+						debug("*ERROR* no resolved descriptor for " + parent.getId());

+				} else

+					bestMatchEnabled = true;

+			}

+		}

+

+		private void resolve() {

+			if (bestMatch != null) {

+				bestMatch.setEnabled(bestMatchEnabled);

+				if (bestMatchEnabled) {

+					if (DEBUG_RESOLVE)

+						debug("configured " + bestMatch.toString());

+					if (constraintList.size() > 0) {

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

+							PluginPrerequisiteModel prq = (PluginPrerequisiteModel) ((Constraint) constraintList.get(i)).getPrerequisite();

+							prq.setResolvedVersion(getVersionIdentifier(bestMatch).toString());

+						}

+					}

+				}

+			}

+		}

+

+		private boolean isResolved() {

+			return this.isResolved;

+		}

+		private void isResolved(boolean isResolved) {

+			this.isResolved = isResolved;

+		}

+	}

+

+	// plugin descriptor index structure

+	private class IndexEntry {

+		private String id;

+		private List verList = new LinkedList();

+		private List concurrentList = new ArrayList();

+

+		private IndexEntry(String id) {

+			this.id = id;

+			concurrentList.add(new ConstraintsEntry(this));

+		}

+

+		private String getId() {

+			return id;

+		}

+

+		private ConstraintsEntry getConstraintsEntryFor(Constraint c) {

+			ConstraintsEntry ce = c.getConstraintsEntry();

+			if (ce != null)

+				return ce;

+			ce = (ConstraintsEntry) concurrentList.get(0);

+			if (c.getPrerequisite() == null)

+				c.setConstraintsEntry(ce);

+			return ce;

+		}

+

+		private PluginDescriptorModel addConstraint(Constraint c) {

+			int concurrentCount = concurrentList.size();

+

+			// try to find constraits entry that can accommodate new constraint

+			for (Iterator list = concurrentList.iterator(); list.hasNext();) {

+				ConstraintsEntry cie = (ConstraintsEntry) list.next();

+				PluginDescriptorModel pd = cie.addConstraint(c);

+				if (pd != null) {

+

+					// constraint added OK and no concurrency

+					if (concurrentCount <= 1)

+						return pd;

+

+					// constraint added OK but have concurrency

+					if (allowConcurrencyFor(pd))

+						return pd;

+					else {

+						cie.removeConstraint(c); // cannot be concurrent

+						return null;

+					}

+				}

+			}

+

+			// attempt to create new constraints entry

+			ConstraintsEntry cie;

+			PluginDescriptorModel pd;

+

+			if (concurrentList.size() == 1) {

+				// ensure base entry allows concurrency

+				cie = (ConstraintsEntry) concurrentList.get(0);

+				pd = cie.getMatchingDescriptor();

+				if (!allowConcurrencyFor(pd))

+					return null;

+			}

+

+			cie = new ConstraintsEntry(this);

+			pd = cie.addConstraint(c);

+			if (pd == null) {

+				cie.removeConstraint(c); // no matching target

+				return null;

+			}

+			if (!allowConcurrencyFor(pd)) {

+				cie.removeConstraint(c); // cannot be concurrent

+				return null;

+			}

+			if (DEBUG_RESOLVE)

+				debug("creating new constraints list in " + id + " for " + c.toString());

+			concurrentList.add(cie);

+			return pd;

+		}

+

+		private boolean allowConcurrencyFor(PluginDescriptorModel pd) {

+			if (pd == null)

+				return false;

+			if (pd.getDeclaredExtensions() != null && pd.getDeclaredExtensions().length > 0)

+				return false;

+			if (pd.getDeclaredExtensionPoints() != null && pd.getDeclaredExtensionPoints().length > 0)

+				return false;

+			return true;

+		}

+

+		private void removeConstraint(Constraint c) {

+			ConstraintsEntry cie = getConstraintsEntryFor(c);

+			cie.removeConstraint(c);

+			if (concurrentList.get(0) != cie && cie.constraintCount() == 0)

+				concurrentList.remove(cie);

+		}

+

+		private void removeConstraintFor(PluginPrerequisiteModel prereq) {

+			for (Iterator list = concurrentList.iterator(); list.hasNext();)

+				 ((ConstraintsEntry) list.next()).removeConstraintFor(prereq);

+		}

+

+		private PluginDescriptorModel getMatchingDescriptorFor(Constraint c) {

+			ConstraintsEntry cie = getConstraintsEntryFor(c);

+			return cie.getMatchingDescriptor();

+		}

+

+		private void disableAllDescriptors() {

+			for (Iterator list = verList.iterator(); list.hasNext();) {

+				PluginDescriptorModel pd = (PluginDescriptorModel) list.next();

+				pd.setEnabled(false);

+			}

+		}

+

+		private void resolveDependencies(List roots) {

+			for (Iterator list = concurrentList.iterator(); list.hasNext();)

+				 ((ConstraintsEntry) list.next()).preresolve(roots);

+			disableAllDescriptors();

+			for (Iterator list = concurrentList.iterator(); list.hasNext();)

+				 ((ConstraintsEntry) list.next()).resolve();

+		}

+

+		private List versions() {

+			return verList;

+		}

+

+		private boolean isResolvedFor(Constraint c) {

+			ConstraintsEntry cie = getConstraintsEntryFor(c);

+			return cie.isResolved();

+		}

+

+		private void isResolvedFor(Constraint c, boolean value) {

+			ConstraintsEntry cie = getConstraintsEntryFor(c);

+			cie.isResolved(value);

+		}

+

+	}

+

+	// subtree resolution "cookie" (composite change list)

+	private class Cookie {

+		private boolean ok = true;

+		private List changes = new ArrayList();

+

+		private Cookie() {

+		}

+

+		private boolean addChange(Constraint c) {

+			PluginPrerequisiteModel prereq = c.getPrerequisite();

+			for (Iterator list = changes.iterator(); list.hasNext();)

+				if (prereq == ((Constraint)list.next()).getPrerequisite())

+					return false; // prereq loop

+			changes.add(c);

+			return true;

+		}

+

+		private List getChanges() {

+			return changes;

+		}

+

+		private void clearChanges() {

+			if (changes.size() >= 0)

+				changes = new ArrayList();

+		}

+

+		private boolean isOk() {

+			return ok;

+		}

+

+		private void isOk(boolean value) {

+			ok = value;

+		}

+	}

+public RegistryResolver() {	

+	String debug = Platform.getDebugOption(OPTION_DEBUG_RESOLVE);

+	DEBUG_RESOLVE = debug==null ? false : ( debug.equalsIgnoreCase("true") ? true : false );

+}

+private void add(PluginDescriptorModel pd) {

+

+	String key = pd.getId();

+	List verList;

+	IndexEntry ix = (IndexEntry) idmap.get(key);

+

+	// create new index entry if one does not exist for plugin

+	if (ix == null) {

+		ix = new IndexEntry(key);

+		idmap.put(key, ix);

+	}

+

+	// insert plugin into list maintaining version order

+	verList = ix.versions();

+	int i = 0;

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

+		PluginDescriptorModel element = (PluginDescriptorModel) verList.get(i);

+		if (getVersionIdentifier(pd).equals(getVersionIdentifier(element)))

+			return; // ignore duplicates

+		if (getVersionIdentifier(pd).isGreaterThan(getVersionIdentifier(element)))

+			break;

+	}

+	verList.add(i, pd);

+}

+private void addAll(Collection c) {

+	for (Iterator list = c.iterator(); list.hasNext();)

+		add((PluginDescriptorModel) list.next());

+}

+private void addExtensions(ExtensionModel[] extensions, PluginDescriptorModel plugin) {

+	int extLength = extensions.length;

+	for (int i = 0; i < extLength; i++) {

+		extensions[i].setParentPluginDescriptor (plugin);

+	}

+	ExtensionModel[] list = plugin.getDeclaredExtensions();

+	int listLength = (list == null ? 0 : list.length);

+	ExtensionModel[] result = null;

+	if (list == null)

+		result = new ExtensionModel[extLength];

+	else {

+		result = new ExtensionModel[list.length + extLength];

+		System.arraycopy(list, 0, result, 0, list.length);

+	}

+	System.arraycopy(extensions, 0, result, listLength, extLength); 

+	plugin.setDeclaredExtensions(result);

+}

+private void addExtensionPoints(ExtensionPointModel[] extensionPoints, PluginDescriptorModel plugin) {

+	int extPtLength = extensionPoints.length;

+	for (int i = 0; i < extPtLength; i++) {

+		extensionPoints[i].setParentPluginDescriptor (plugin);

+	}

+	ExtensionPointModel[] list = plugin.getDeclaredExtensionPoints();

+	int listLength = (list == null ? 0 : list.length);

+	ExtensionPointModel[] result = null;

+	if (list == null)

+		result = new ExtensionPointModel[extPtLength];

+	else {

+		result = new ExtensionPointModel[list.length + extPtLength];

+		System.arraycopy(list, 0, result, 0, list.length);

+	}

+	System.arraycopy(extensionPoints, 0, result, listLength, extPtLength); 

+	plugin.setDeclaredExtensionPoints(result);

+}

+private void addLibraries(LibraryModel[] libraries, PluginDescriptorModel plugin) {

+	int libLength = libraries.length;

+	LibraryModel[] list = plugin.getRuntime();

+	LibraryModel[] result = null;

+	int listLength = (list == null ? 0 : list.length);

+	if (list == null)

+		result = new LibraryModel[libLength];

+	else {

+		result = new LibraryModel[list.length + libLength];

+		System.arraycopy(list, 0, result, 0, list.length);

+	}

+	System.arraycopy(libraries, 0, result, listLength, libLength); 

+	plugin.setRuntime(result);

+}

+private void addPrerequisites(PluginPrerequisiteModel[] prerequisites, PluginDescriptorModel plugin) {

+	int reqLength = prerequisites.length;

+	PluginPrerequisiteModel[] list = plugin.getRequires();

+	PluginPrerequisiteModel[] result = null;

+	int listLength = (list == null ? 0 : list.length);

+	if (list == null)

+		result = new PluginPrerequisiteModel[reqLength];

+	else {

+		result = new PluginPrerequisiteModel[list.length + reqLength];

+		System.arraycopy(list, 0, result, 0, list.length);

+	}

+	System.arraycopy(prerequisites, 0, result, listLength, reqLength); 

+	plugin.setRequires(result);

+}

+private void debug(String s) {

+	System.out.println("Registry Resolve: "+s);

+}

+private void error(String message) {

+	Status error = new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, message, null);

+	status.add(error);

+	if (InternalPlatform.DEBUG && DEBUG_RESOLVE)

+		System.out.println(error.toString());

+}

+public IExtensionPoint getExtensionPoint(PluginDescriptorModel plugin, String extensionPointId) {

+	if (extensionPointId == null)

+		return null;

+	ExtensionPointModel[] list = plugin.getDeclaredExtensionPoints();

+	if (list == null)

+		return null;

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

+		if (extensionPointId.equals(list[i].getId()))

+			return (IExtensionPoint) list[i];

+	}

+	return null;

+}

+private PluginVersionIdentifier getVersionIdentifier(PluginDescriptorModel descriptor) {

+	String version = descriptor.getVersion();

+	if (version == null)

+		return new PluginVersionIdentifier("1.0.0");

+	try {

+		return new PluginVersionIdentifier(version);

+	} catch (Throwable e) {

+		return new PluginVersionIdentifier("1.0.0");

+	}

+}

+private PluginVersionIdentifier getVersionIdentifier(PluginPrerequisiteModel prereq) {

+	String version = prereq.getVersion();

+	return version == null ? null : new PluginVersionIdentifier(version);

+}

+private void linkFragments() {

+	/* For each fragment, find out which plugin descriptor it belongs

+	 * to and add it to the list of fragments in this plugin.

+	 */

+	PluginFragmentModel[] fragments = reg.getFragments();

+	HashSet seen = new HashSet(5);

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

+		PluginFragmentModel fragment = fragments[i];

+		if (!requiredFragment(fragment)) {

+			// There is a required field missing on this fragment, so 

+			// ignore it.

+			String id, name;

+			if ((id = fragment.getId()) != null)

+				error (Policy.bind("parse.fragmentMissingAttr", id));

+			else if ((name = fragment.getName()) != null)

+				error (Policy.bind("parse.fragmentMissingAttr", name));

+			else

+				error (Policy.bind("parse.fragmentMissingIdName"));

+			continue;

+		}

+		if (seen.contains(fragment.getId()))

+			continue;

+		seen.add(fragment.getId());

+		PluginDescriptorModel plugin = reg.getPlugin(fragment.getPluginId(), fragment.getPluginVersion());

+		if (plugin == null) {

+			// We couldn't find this fragment's plugin

+			error (Policy.bind("parse.missingFragmentPd", fragment.getPluginId(), fragment.getId()));

+			continue;

+		}

+		// Soft prereq's ???

+		// PluginFragmentModel[] list = reg.getFragments(fragment.getId());

+		// resolvePluginFragments(list, plugin);

+		

+		// Add this fragment to the list of fragments for this plugin descriptor

+		PluginFragmentModel[] list = plugin.getFragments();

+		PluginFragmentModel[] newList;

+		if (list == null) {

+			newList = new PluginFragmentModel[1];

+			newList[0] = fragment;

+		} else {

+			newList = new PluginFragmentModel[list.length + 1];

+			System.arraycopy(list, 0, newList, 0, list.length);

+			newList[list.length] = fragment;

+		}

+		plugin.setFragments(newList);

+	}

+}

+private void removeConstraintFor(PluginPrerequisiteModel prereq) {

+

+	String id = prereq.getPlugin();

+	IndexEntry ix = (IndexEntry) idmap.get(id);

+	if (ix == null) {

+		if (DEBUG_RESOLVE)

+			debug("unable to locate index entry for " + id);

+		return;

+	}

+	ix.removeConstraintFor(prereq);

+}

+private void resolve() {

+

+	// Add all the fragments to their associated plugin

+	linkFragments();

+	PluginDescriptorModel[] pluginList = reg.getPlugins();

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

+		if (pluginList[i].getFragments() != null) {

+			// Take all the information in each fragment and

+			// embed it in the plugin descriptor

+			resolvePluginFragments(pluginList[i]);

+		}

+	}

+	

+	// Walk through the registry and ensure that all structures

+	// have all their 'required' fields.  Do this now as

+	// the resolve assumes required field exist.  

+	resolveRequiredComponents();

+

+	// resolve root descriptors

+	List rd = resolveRootDescriptors();

+	if (rd.size() == 0) {

+		// no roots ... quit

+		idmap = null;

+		reg = null;

+		error(Policy.bind("plugin.unableToResolve"));

+		return;

+	}

+

+	// sort roots

+	Object[] a = rd.toArray();

+	Arrays.sort(a);

+	ArrayList roots = new ArrayList(Arrays.asList(a));

+	

+	// walk the dependencies and setup constraints

+	ArrayList orphans = new ArrayList();

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

+		resolveNode((String) roots.get(i), null, null, null, orphans);

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

+		if (!roots.contains(orphans.get(i))) {

+			roots.add(orphans.get(i));

+			if (DEBUG_RESOLVE)

+				debug("orphan " + orphans.get(i));

+		}

+	}

+

+	// resolve dependencies

+	Iterator plugins = idmap.entrySet().iterator();

+	while (plugins.hasNext()) {

+		IndexEntry ix = (IndexEntry) ((Map.Entry) plugins.next()).getValue();

+		ix.resolveDependencies(roots);

+	}

+

+	// walk down the registry structure and resolve links

+	resolvePluginRegistry();

+	

+	// unhook registry and index

+	idmap = null;

+	reg = null;

+}

+public IStatus resolve(PluginRegistryModel registry) {

+	status = new MultiStatus(Platform.PI_RUNTIME, IStatus.OK, "", null);

+	if (registry.isResolved())

+		return status;

+	reg = registry;

+	idmap = new HashMap();

+	// Need to pick up the fragments before calling

+	// addAll.  Currently we do this in resolve().

+	addAll(Arrays.asList(reg.getPlugins()));

+	resolve();

+	registry.markResolved();

+	return status;

+}

+private void resolveExtension(ExtensionModel ext) {

+

+	String target = ext.getExtensionPoint();

+	int ix = target.lastIndexOf(".");

+	String pluginId = target.substring(0, ix);

+	String extPtId = target.substring(ix + 1);

+	String message;

+

+	PluginDescriptorModel plugin = (PluginDescriptorModel) reg.getPlugin(pluginId);

+	if (plugin == null) {

+		message = Policy.bind("parse.extPointUnknown", target, ext.getParentPluginDescriptor().getId());

+		error(message);

+		return;

+	}

+	if (!plugin.getEnabled()) {

+		message = Policy.bind("parse.extPointDisabled", target, ext.getParentPluginDescriptor().getId());

+		error(message);

+		return;

+	}

+

+	ExtensionPointModel extPt = (ExtensionPointModel) getExtensionPoint(plugin, extPtId);

+	if (extPt == null) {

+		message = Policy.bind("parse.extPointUnknown", target, ext.getParentPluginDescriptor().getId());

+		error(message);

+		return;

+	}

+

+	ExtensionModel[] oldValues = extPt.getDeclaredExtensions();

+	ExtensionModel[] newValues = null;

+	if (oldValues == null)

+		newValues = new ExtensionModel[1];

+	else {

+		newValues = new ExtensionModel[oldValues.length + 1];

+		System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);

+	}

+	newValues[newValues.length - 1] = ext;

+	extPt.setDeclaredExtensions(newValues);

+}

+private void resolveFragments() {

+	PluginFragmentModel[] fragments = reg.getFragments();

+	HashSet seen = new HashSet(5);

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

+		PluginFragmentModel fragment = fragments[i];

+		if (!requiredFragment(fragment))

+			continue;

+		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(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.

+

+	if (DEBUG_RESOLVE)

+		debug("PUSH> " + child);

+

+	if (cookie == null)

+		cookie = new Cookie();

+

+	// lookup child entry

+	IndexEntry ix = (IndexEntry) idmap.get(child);

+	if (ix == null) {

+		if (parent != null)

+			error(Policy.bind("parse.prereqDisabled", new String[] { parent.getId(), child }));

+		if (DEBUG_RESOLVE)

+			debug("<POP  " + child + " not found");

+		cookie.isOk(false);

+		return cookie;

+	}

+

+	// try to add new dependency constraint

+	Constraint currentConstraint = new Constraint(parent, prq);

+	PluginDescriptorModel childPd = null;

+	if (parent != null) {

+		childPd = ix.addConstraint(currentConstraint);

+		if (childPd == null) {

+			String message = Policy.bind("parse.unsatisfiedPrereq", parent.getId(), child);

+			error(message);

+			if (DEBUG_RESOLVE)

+				debug("<POP  " + child + " unable to satisfy constraint");

+			cookie.isOk(false);

+			return cookie;

+		} else

+			if (!cookie.addChange(currentConstraint)) {

+				String message = Policy.bind("parse.prereqLoop", parent.getId(), child);

+				error(message);

+				if (DEBUG_RESOLVE)

+					debug("<POP  " + child + " prerequisite loop");

+				cookie.isOk(false);

+				return cookie;

+			}

+	} else {

+		childPd = ix.getMatchingDescriptorFor(currentConstraint);

+		if (childPd == null) {

+			if (DEBUG_RESOLVE)

+				debug("<POP  " + child + " not found (missing descriptor entry)");

+			cookie.isOk(false);

+			return cookie;

+		}

+	}

+

+	// check to see if subtree is already resolved

+	if (ix.isResolvedFor(currentConstraint)) {

+		if (DEBUG_RESOLVE)

+			debug("<POP  " + child + " already resolved");

+		return cookie;

+	}

+

+	// select the subtree to resolve

+	PluginPrerequisiteModel[] prereqs = childPd.getRequires();

+	PluginPrerequisiteModel prereq;

+	prereqs = prereqs == null ? new PluginPrerequisiteModel[0] : prereqs;

+	for (int i = 0; cookie.isOk() && i < prereqs.length; i++) {

+		prereq = (PluginPrerequisiteModel) prereqs[i];

+		cookie = resolveNode(prereq.getPlugin(), childPd, prereq, cookie, orphans);

+	}

+

+	// if we failed, remove any constraints we added

+	if (!cookie.isOk()) {

+		Constraint cookieConstraint;

+		for (Iterator change = cookie.getChanges().iterator(); change.hasNext();) {

+			cookieConstraint = (Constraint) change.next();

+			if (childPd == cookieConstraint.getParent()) {

+				prereq = cookieConstraint.getPrerequisite();

+				removeConstraintFor(prereq);

+				if (!orphans.contains(prereq.getPlugin())) // keep track of orphaned subtrees

+					orphans.add(prereq.getPlugin());

+			}

+		}

+		if (parent != null)

+			error(Policy.bind("parse.prereqDisabled", parent.getId(), child));

+		childPd.setEnabled(false);

+		if (DEBUG_RESOLVE)

+			debug("<POP  " + child + " failed to resolve subtree");

+		return cookie;

+	} else {

+		// we're done

+		ix.isResolvedFor(currentConstraint, true);

+		if (DEBUG_RESOLVE)

+			debug("<POP  " + child + " " + getVersionIdentifier(childPd));

+		return cookie;

+	}

+}

+private void resolvePluginDescriptor(PluginDescriptorModel pd) {

+	ExtensionModel[] list = pd.getDeclaredExtensions();

+	if (list == null || list.length == 0 || !pd.getEnabled())

+		// Can be disabled if all required attributes not present

+		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)

+		// Add all the fragment extensions to the plugin

+		addExtensions(extensions, plugin);

+

+	ExtensionPointModel[] points = fragment.getDeclaredExtensionPoints();

+	if (points != null)

+		// Add all the fragment extension points to the plugin

+		addExtensionPoints(points, plugin);

+

+	LibraryModel[] libraries = fragment.getRuntime();

+	if (libraries != null)

+		// Add all the fragment library entries to the plugin

+		addLibraries(libraries, plugin);

+			

+	PluginPrerequisiteModel[] prerequisites = fragment.getRequires();

+	if (prerequisites != null)

+		// Add all the fragment prerequisites to the plugin

+		addPrerequisites(prerequisites, plugin);

+}

+private void resolvePluginFragments(PluginDescriptorModel plugin) {

+	/* For each fragment contained in the fragment list of this plugin, 

+	 * apply all the fragment bits to the plugin (e.g. all of the fragment's

+	 * extensions are added to the list of extensions in the plugin).  Be

+	 * sure to use only the latest version of any given fragment (in case

+	 * there are multiple versions of a given fragment id).  So note that,

+	 * if there are multiple versions of a given fragment id, all but the

+	 * latest version will be discarded.

+	 */

+	PluginFragmentModel[] fragmentList = plugin.getFragments();

+	while (fragmentList != null) {

+		ArrayList fragmentsWithId = new ArrayList();

+		ArrayList fragmentsToProcessLater = new ArrayList();

+		String currentFragmentId = fragmentList[0].getId();

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

+			// Find all the fragments with a given id.

+			if (currentFragmentId.equals(fragmentList[i].getId())) {

+				fragmentsWithId.add(fragmentList[i]);

+			} else {

+				fragmentsToProcessLater.add(fragmentList[i]);

+			}

+		}

+		

+		PluginFragmentModel[] fragments;

+		if (fragmentsWithId.isEmpty())

+			fragments = null;

+		else

+			fragments = (PluginFragmentModel[]) fragmentsWithId.toArray(new PluginFragmentModel[fragmentsWithId.size()]);

+		

+		if (fragmentsToProcessLater.isEmpty())

+			fragmentList = null;

+		else

+			fragmentList = (PluginFragmentModel[]) fragmentsToProcessLater.toArray(new PluginFragmentModel[fragmentsToProcessLater.size()]);

+			

+		if (fragments != null) {

+			// Now find the latest version of the fragment with the chosen id

+			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) {

+				// For the latest version of this fragment id only, apply

+				// all the fragment bits to the plugin.  

+				resolvePluginFragment(latestFragment, plugin);

+			}

+		}

+	}

+}

+private void resolvePluginRegistry() {

+	// filter out disabled plugins from "live" registry

+	if (trimPlugins)

+		trimRegistry();

+

+	// resolve relationships

+	if (crossLink) {

+		// 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 void resolveRequiredComponents() {

+	PluginDescriptorModel[] pluginList = reg.getPlugins();

+	// Only worry about the enabled plugins as we are going

+	// to disable any plugins that don't have all the 

+	// required bits.

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

+		if (pluginList[i].getEnabled()) {

+			if (!requiredPluginDescriptor(pluginList[i])) {

+				pluginList[i].setEnabled(false);

+				String id, name;

+				if ((id = pluginList[i].getId()) != null)

+					error (Policy.bind("parse.pluginMissingAttr", id));

+				else if ((name = pluginList[i].getName()) != null)

+					error (Policy.bind("parse.pluginMissingAttr", name));

+				else

+					error (Policy.bind("parse.pluginMissingIdName"));

+			}

+		}

+	}

+	// Don't worry about the fragments.  They were done already.

+}

+private boolean requiredPluginDescriptor(PluginDescriptorModel plugin) {

+	boolean retValue = true;

+	retValue = plugin.getName() != null &&

+		plugin.getId() != null &&

+		plugin.getVersion() != null;

+	if (!retValue) 

+		return retValue;

+		

+	PluginPrerequisiteModel[] requiresList = plugin.getRequires();

+	ExtensionModel[] extensions = plugin.getDeclaredExtensions();

+	ExtensionPointModel[] extensionPoints = plugin.getDeclaredExtensionPoints();

+	LibraryModel[] libraryList = plugin.getRuntime();

+	PluginFragmentModel[] fragments = plugin.getFragments();

+	

+	if (requiresList != null) {

+		for (int i = 0; i < requiresList.length && retValue; i++) {

+			retValue = retValue && requiredPrerequisite(requiresList[i]);

+		}

+	}

+	if (extensions != null) {

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

+			retValue = retValue && requiredExtension(extensions[i]);

+		}

+	}

+	if (extensionPoints != null) {

+		for (int i = 0; i < extensionPoints.length && retValue; i++) {

+			retValue = retValue && requiredExtensionPoint(extensionPoints[i]);

+		}

+	}

+	if (libraryList != null) {

+		for (int i = 0; i < libraryList.length && retValue; i++) {

+			retValue = retValue && requiredLibrary(libraryList[i]);

+		}

+	}

+	if (fragments != null) {

+		for (int i = 0; i < fragments.length && retValue; i++) {

+			retValue = retValue && requiredFragment(fragments[i]);

+		}

+	}

+	

+	return retValue;

+}

+private boolean requiredPrerequisite (PluginPrerequisiteModel prerequisite) {

+	return ((prerequisite.getPlugin() != null));

+}

+private boolean requiredExtension (ExtensionModel extension) {

+	return (extension.getExtensionPoint() != null);

+}

+private boolean requiredExtensionPoint (ExtensionPointModel extensionPoint) {

+	return ((extensionPoint.getName() != null) &&

+		(extensionPoint.getId() != null));

+}

+private boolean requiredLibrary (LibraryModel library) {

+	return (library.getName() != null);

+}

+private boolean requiredFragment (PluginFragmentModel fragment) {

+	return ((fragment.getName() != null) &&

+		(fragment.getId() != null) &&

+		(fragment.getPlugin() != null) &&

+		(fragment.getPluginVersion() != null) &&

+		(fragment.getVersion() != null));

+}

+private List resolveRootDescriptors() {

+

+	// Determine the roots of the dependency tree. Disable all

+	// but one versions of the root descriptors.

+

+	// get list of all plugin identifiers in the registry

+	List ids = new ArrayList();

+	ids.addAll(idmap.keySet());

+

+	// iterate over the list eliminating targets of <requires> entries

+	Iterator p = idmap.entrySet().iterator();

+	while (p.hasNext()) {

+		IndexEntry ix = (IndexEntry) ((Map.Entry) p.next()).getValue();

+		if (ix != null) {

+			List list = ix.versions();

+			if (list.size() > 0) {

+				PluginDescriptorModel pd = (PluginDescriptorModel) list.get(0);

+				PluginPrerequisiteModel[] prereqs = pd.getRequires();

+				for (int i = 0; prereqs != null && i < prereqs.length; i++) {

+					ids.remove(prereqs[i].getPlugin());

+				}

+			}

+		}

+	}

+

+	if (ids.size() > 0) {

+		// disable all but the most recent version of root descriptors

+		String id;

+		p = ids.iterator();

+		while (p.hasNext()) {

+			id = (String) p.next();

+			IndexEntry ix = (IndexEntry) idmap.get(id);

+			if (ix != null) {

+				List list = ix.versions();

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

+					PluginDescriptorModel pd = (PluginDescriptorModel) list.get(i);

+					if (i == 0) {

+						if (DEBUG_RESOLVE)

+							debug("root " + pd);

+					} else {

+						if (DEBUG_RESOLVE)

+							debug("     " + pd + " disabled");

+						pd.setEnabled(false);

+					}

+				}

+			}

+		}

+	} else {

+		if (DEBUG_RESOLVE)

+			debug("NO ROOTS");

+	}

+

+	return ids;

+}

+/**

+ * Specifies whether extensions and extension points should be cross 

+ * linked during the resolve process.

+ */

+public void setCrossLink(boolean value) {

+	crossLink = value;

+}

+/**

+ * Specified whether disabled plugins should to be removed when the resolve

+ * is completed.

+ */

+public void setTrimPlugins(boolean value) {

+	trimPlugins = value;

+}

+private void trimRegistry() {

+	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/plugins/RegistryWriter.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryWriter.java
new file mode 100644
index 0000000..cd1d220
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/plugins/RegistryWriter.java
@@ -0,0 +1,324 @@
+package org.eclipse.core.internal.plugins;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.model.*;

+import java.io.PrintWriter;

+

+public class RegistryWriter {

+public RegistryWriter() {

+	super();

+}

+public void writeConfigurationElement(ConfigurationElementModel configElement, PrintWriter w, int indent) {

+	String element = configElement.getName();

+	if (element == null)

+		return;

+

+	String gap1 = "";

+	for (int i = 0; i < indent; i++)

+		gap1 += " ";

+	String gap2 = gap1;

+	for (int i = 0; i < IModel.INDENT; i++)

+		gap2 += " ";

+

+	w.print(gap1 + "<" + element);

+	ConfigurationPropertyModel[] propList = configElement.getProperties();

+	int propSize = (propList == null) ? 0 : propList.length;

+	for (int i = 0; i < propSize; i++) 

+		writeConfigurationProperty(propList[i], w, indent + IModel.INDENT);

+

+	ConfigurationElementModel[] subElementList = configElement.getSubElements();

+	int subElementSize = (subElementList == null) ? 0 : subElementList.length;

+	if (configElement.getValue() == null && subElementSize == 0) {

+		w.println("/>");

+		return;

+	}

+	w.println(">");

+

+	if (configElement.getValue() != null)

+		w.println(gap2 + xmlSafe(configElement.getValue()));

+	for (int i = 0; i < subElementSize; i++) 

+		writeConfigurationElement(subElementList[i], w, indent + IModel.INDENT);

+

+	w.println(gap1 + "</" + element + ">");

+}

+public void writeConfigurationProperty(ConfigurationPropertyModel configProp, PrintWriter w, int indent) {

+	if (configProp.getName() == null)

+		return;

+	w.print(" " + xmlSafe(configProp.getName()) + "=\"");

+	if (configProp.getValue() != null)

+		w.print(xmlSafe(configProp.getValue()));

+	w.print("\"");

+}

+public void writeExtension(ExtensionModel extension, PrintWriter w, int indent) {

+	String gap1 = "";

+	for (int i = 0; i < indent; i++)

+		gap1 += " ";

+

+	w.print(gap1 + "<" + IModel.EXTENSION);

+	if (extension.getExtensionPoint() != null)

+		w.print(" " + IModel.EXTENSION_TARGET + "=\"" + xmlSafe(extension.getExtensionPoint()) + "\"");

+	if (extension.getId() != null)

+		w.print(" " + IModel.EXTENSION_ID + "=\"" + xmlSafe(extension.getId()) + "\"");

+	if (extension.getName() != null)

+		w.print(" " + IModel.EXTENSION_NAME + "=\"" + xmlSafe(extension.getName()) + "\"");

+

+	ConfigurationElementModel[] subElements = extension.getSubElements();

+	int size = (subElements == null) ? 0 : subElements.length;

+	if (size == 0) {

+		w.println("/>");

+		return;

+	}

+	w.println(">");

+

+	for (int i = 0; i < size; i++) 

+		writeConfigurationElement(subElements[i], w, indent + IModel.INDENT);

+

+	w.println(gap1 + "</" + IModel.EXTENSION + ">");

+}

+public void writeExtensionPoint(ExtensionPointModel extPt, PrintWriter w, int indent) {

+	String gap1 = "";

+	for (int i = 0; i < indent; i++)

+		gap1 += " ";

+

+	w.print(gap1 + "<" + IModel.EXTENSION_POINT);

+	if (extPt.getId() != null)

+		w.print(" " + IModel.EXTENSION_POINT_ID + "=\"" + xmlSafe(extPt.getId()) + "\"");

+	if (extPt.getName() != null)

+		w.print(" " + IModel.EXTENSION_POINT_NAME + "=\"" + xmlSafe(extPt.getName()) + "\"");

+	if (extPt.getSchema() != null)

+		w.print(" " + IModel.EXTENSION_POINT_SCHEMA + "=\"" + xmlSafe(extPt.getSchema()) + "\"");

+	w.println("/>");

+}

+public void writeLibrary(LibraryModel library, PrintWriter w, int indent) {

+	String gap1 = "";

+	for (int i = 0; i < indent; i++)

+		gap1 += " ";

+	String gap2 = gap1;

+	for (int i = 0; i < IModel.INDENT; i++)

+		gap2 += " ";

+

+	w.print(gap1 + "<" + IModel.LIBRARY);

+	if (library.getName() != null)

+		w.print(" " + IModel.LIBRARY_NAME + "=\"" + xmlSafe(library.getName()) + "\"");

+	if (library.getType() != null)

+		w.print(" " + IModel.LIBRARY_TYPE + "=\"" + xmlSafe(library.getType()) + "\"");

+	if (!library.isExported())

+		w.println("/>");

+	else {

+		w.println(">");

+		String[] exports = library.getExports();

+		int size = (exports == null) ? 0 : exports.length;

+		for (int i = 0; i < size; i++)

+			w.println(gap2 + "<" + IModel.LIBRARY_EXPORT + " " + IModel.LIBRARY_EXPORT_MASK + "=\"" + xmlSafe(exports[i]) + "\"/>");

+		w.println(gap1 + "</" + IModel.LIBRARY + ">");

+	}

+}

+public void writePluginDescriptor(PluginDescriptorModel plugin, PrintWriter w, int indent) {

+

+	String gap1 = "";

+	for (int i = 0; i < indent; i++)

+		gap1 += " ";

+	String gap2 = gap1;

+	for (int i = 0; i < IModel.INDENT; i++)

+		gap2 += " ";

+

+	w.println("");

+	w.print(gap1 + "<" + IModel.PLUGIN);

+	if (plugin.getId() != null)

+		w.print(" " + IModel.PLUGIN_ID + "=\"" + xmlSafe(plugin.getId()) + "\"");

+	if (plugin.getName() != null)

+		w.print(" " + IModel.PLUGIN_NAME + "=\"" + xmlSafe(plugin.getName()) + "\"");

+	if (plugin.getProviderName() != null)

+		w.print(" " + IModel.PLUGIN_PROVIDER + "=\"" + xmlSafe(plugin.getProviderName()) + "\"");

+	if (plugin.getVersion() != null)

+		w.print(" " + IModel.PLUGIN_VERSION + "=\"" + xmlSafe(plugin.getVersion()) + "\"");

+	if (plugin.getPluginClass() != null)

+		w.print(" " + IModel.PLUGIN_CLASS + "=\"" + xmlSafe(plugin.getPluginClass()) + "\"");

+	w.println(">");

+

+	PluginPrerequisiteModel[] requires = plugin.getRequires();

+	int reqSize = (requires == null) ? 0 : requires.length;

+	if (reqSize != 0) {

+		w.print(gap2 + "<" + IModel.PLUGIN_REQUIRES);

+		w.println(">");

+		for (int i = 0; i < reqSize; i++) 

+			writePluginPrerequisite(requires[i], w, indent + 2 * IModel.INDENT);

+		w.println(gap2 + "</" + IModel.PLUGIN_REQUIRES + ">");

+	}

+

+	LibraryModel[] runtime = plugin.getRuntime();

+	int runtimeSize = (runtime == null) ? 0 : runtime.length;

+	if (runtimeSize != 0) {

+		w.println(gap2 + "<" + IModel.RUNTIME + ">");

+		for (int i = 0; i < runtimeSize; i++) {

+			writeLibrary(runtime[i], w, indent + 2 * IModel.INDENT);

+		}

+		w.println(gap2 + "</" + IModel.RUNTIME + ">");

+	}

+

+	ExtensionPointModel[] extensionPoints = plugin.getDeclaredExtensionPoints();

+	int extPointsSize = (extensionPoints == null) ? 0 : extensionPoints.length;

+	if (extPointsSize != 0) {

+		w.println("");

+		for (int i = 0; i < extPointsSize; i++)

+			writeExtensionPoint(extensionPoints[i], w, indent + IModel.INDENT);

+	}

+

+	ExtensionModel[] extensions = plugin.getDeclaredExtensions();

+	int extSize = (extensions == null) ? 0 : extensions.length;

+	if (extSize != 0) {

+		for (int i = 0; i < extSize; i++) {

+			w.println("");

+			writeExtension(extensions[i], w, indent + IModel.INDENT);

+		}

+	}

+	

+	// Don't write fragments here.  If we do, XML won't be

+	// able to parse what we write out.  Fragments must be

+	// entities separate from plugins.

+	w.println(gap1 + "</" + IModel.PLUGIN + ">");

+}

+public void writePluginFragment(PluginFragmentModel fragment, PrintWriter w, int indent) {

+

+	String gap1 = "";

+	for (int i = 0; i < indent; i++)

+		gap1 += " ";

+	String gap2 = gap1;

+	for (int i = 0; i < IModel.INDENT; i++)

+		gap2 += " ";

+

+	w.println("");

+	w.print(gap1 + "<" + IModel.FRAGMENT);

+	if (fragment.getId() != null)

+		w.print(" " + IModel.FRAGMENT_ID + "=\"" + xmlSafe(fragment.getId()) + "\"");

+	if (fragment.getName() != null)

+		w.print(" " + IModel.FRAGMENT_NAME + "=\"" + xmlSafe(fragment.getName()) + "\"");

+	if (fragment.getProviderName() != null)

+		w.print(" " + IModel.FRAGMENT_PROVIDER + "=\"" + xmlSafe(fragment.getProviderName()) + "\"");

+	if (fragment.getVersion() != null)

+		w.print(" " + IModel.FRAGMENT_VERSION + "=\"" + xmlSafe(fragment.getVersion()) + "\"");

+	if (fragment.getPluginId() != null)

+		w.print(" " + IModel.FRAGMENT_PLUGIN_ID + "=\"" + xmlSafe(fragment.getPluginId()) + "\"");

+	if (fragment.getPluginVersion() != null)

+		w.print(" " + IModel.FRAGMENT_PLUGIN_VERSION + "=\"" + xmlSafe(fragment.getPluginVersion()) + "\"");

+	w.println(">");

+

+	PluginPrerequisiteModel[] requires = fragment.getRequires();

+	int reqSize = (requires == null) ? 0 : requires.length;

+	if (reqSize != 0) {

+		w.print(gap2 + "<" + IModel.PLUGIN_REQUIRES);

+		w.println(">");

+		for (int i = 0; i < reqSize; i++) 

+			writePluginPrerequisite(requires[i], w, indent + 2 * IModel.INDENT);

+		w.println(gap2 + "</" + IModel.PLUGIN_REQUIRES + ">");

+	}

+

+	LibraryModel[] runtime = fragment.getRuntime();

+	int runtimeSize = (runtime == null) ? 0 : runtime.length;

+	if (runtimeSize != 0) {

+		w.println(gap2 + "<" + IModel.RUNTIME + ">");

+		for (int i = 0; i < runtimeSize; i++) {

+			writeLibrary(runtime[i], w, indent + 2 * IModel.INDENT);

+		}

+		w.println(gap2 + "</" + IModel.RUNTIME + ">");

+	}

+

+	ExtensionPointModel[] extensionPoints = fragment.getDeclaredExtensionPoints();

+	int extPointsSize = (extensionPoints == null) ? 0 : extensionPoints.length;

+	if (extPointsSize != 0) {

+		w.println("");

+		for (int i = 0; i < extPointsSize; i++)

+			writeExtensionPoint(extensionPoints[i], w, indent + IModel.INDENT);

+	}

+

+	ExtensionModel[] extensions = fragment.getDeclaredExtensions();

+	int extSize = (extensions == null) ? 0 : extensions.length;

+	if (extSize != 0) {

+		for (int i = 0; i < extSize; i++) {

+			w.println("");

+			writeExtension(extensions[i], w, indent + IModel.INDENT);

+		}

+	}

+

+	w.println(gap1 + "</" + IModel.FRAGMENT + ">");

+}

+public void writePluginPrerequisite(PluginPrerequisiteModel req, PrintWriter w, int indent) {

+	String gap1 = "";

+	for (int i = 0; i < indent; i++)

+		gap1 += " ";

+

+	w.print(gap1 + "<" + IModel.PLUGIN_REQUIRES_IMPORT);

+	if (req.getPlugin() != null)

+		w.print(" " + IModel.PLUGIN_REQUIRES_PLUGIN + "=\"" + xmlSafe(req.getPlugin()) + "\"");

+	if (req.getVersion() != null)

+		w.print(" " + IModel.PLUGIN_REQUIRES_PLUGIN_VERSION + "=\"" + xmlSafe(req.getVersion()) + "\"");

+	if (req.getExport())

+		w.print(" " + IModel.PLUGIN_REQUIRES_EXPORT + "=\"" + IModel.TRUE + "\"");

+	if (req.getOptional())

+		w.print(" " + IModel.PLUGIN_REQUIRES_OPTIONAL + "=\"" + IModel.TRUE + "\"");

+	if (req.getMatch())

+		w.print(" " + IModel.PLUGIN_REQUIRES_MATCH + "=\"" + IModel.PLUGIN_REQUIRES_MATCH_EXACT + "\"");

+	else

+		w.print(" " + IModel.PLUGIN_REQUIRES_MATCH + "=\"" + IModel.PLUGIN_REQUIRES_MATCH_COMPATIBLE + "\"");

+	w.println("/>");

+}

+public void writePluginRegistry(PluginRegistryModel registry, PrintWriter w, int indent) {

+	String gap1 = "";

+	for (int i = 0; i < indent; i++)

+		gap1 += " ";

+	w.println(gap1 + "<" + IModel.REGISTRY + ">");

+	PluginDescriptorModel[] pluginList = registry.getPlugins();

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

+		writePluginDescriptor(pluginList[i], w, indent + IModel.INDENT);

+	

+	PluginFragmentModel[] fragmentList = registry.getFragments();

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

+		writePluginFragment(fragmentList[i], w, indent + IModel.INDENT);

+

+	w.println(gap1 + "</" + IModel.REGISTRY + ">");

+

+}

+private static void appendEscapedChar(StringBuffer buffer, char c) {

+	String replacement = getReplacement(c);

+	if (replacement != null) {

+		buffer.append('&');

+		buffer.append(replacement);

+		buffer.append(';');

+	} else {

+		if ((c >= ' ' && c <= 0x7E) || c == '\n' || c == '\r' || c == '\t') {

+			buffer.append(c);

+		} else {

+			buffer.append("&#");

+			buffer.append(Integer.toString(c));

+			buffer.append(';');

+		}

+	}

+}

+public static String xmlSafe(String s) {

+	StringBuffer result = new StringBuffer(s.length() + 10);

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

+		appendEscapedChar(result, s.charAt(i));

+	return result.toString();

+}

+private static String getReplacement(char c) {

+	// Encode special XML characters into the equivalent character references.

+	// These five are defined by default for all XML documents.

+	switch (c) {

+		case '<' :

+			return "lt";

+		case '>' :

+			return "gt";

+		case '"' :

+			return "quot";

+		case '\'' :

+			return "apos";

+		case '&' :

+			return "amp";

+	}

+	return null;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AdapterManager.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AdapterManager.java
new file mode 100644
index 0000000..9d01cda
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AdapterManager.java
@@ -0,0 +1,211 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.util.*;

+import org.eclipse.core.runtime.IAdaptable;

+import org.eclipse.core.runtime.IAdapterManager;

+import org.eclipse.core.runtime.IAdapterFactory;

+

+/**

+ * This class is a default implementation of <code>IExtenderManager</code>.

+ * It provides fast lookup of property values with the following semantics:

+ * <ul>

+ * <li> At most one extender will be invoked per property lookup

+ * <li> If multiple installed extenders provide the same property, only 

+ *		the first found in the search order is said to <i>define</i> the property 

+ *		as it is the only extender which will be invoked..

+ * <li> The search order from a class with the definition<br>

+ *			<code>class X extends Y implements A, B</code><br>

+ *		is as follows:

+ * 		<il>

+ *			<li>the target's class: X

+ *			<li>X's superclasses in order to <code>Object</code>

+ *			<li>a depth-first traversal of the target class's interaces in the order 

+ *				returned by <code>getInterfaces</code> (in the example, A and 

+ *				its superinterfaces then B and its superinterfaces)

+ *		</il>

+ * </ul>

+ *

+ * @see IAdapter

+ * @see IAdapterManager

+ */

+public final class AdapterManager implements IAdapterManager {

+

+	/** Table of factories, keyed by <code>Class</code>. */

+	protected Hashtable factories;

+

+	/** Cache of adapter search paths; <code>null</code> if none. */

+	protected Hashtable lookup;

+/** Constructs a new extender manager.

+ */

+public AdapterManager() {

+	factories = new Hashtable(5);

+	lookup = null;

+}

+/**

+ * Given a list of types, add all of the property entries for the installed

+ * extenders into the lookupTable.  Each entry will be keyed by the property

+ * identifier (supplied in IExtender.getPropertyList) and the extender

+ * supplying that property.

+ */

+private void addFactoriesFor(Vector types, Hashtable lookupTable) {

+	for (Enumeration classes = types.elements(); classes.hasMoreElements();) {

+		Class clazz = (Class) classes.nextElement();

+		Vector factoryList = (Vector) factories.get(clazz);

+		if (factoryList == null)

+			continue;

+		for (Enumeration list = factoryList.elements(); list.hasMoreElements();) {

+			IAdapterFactory factory = (IAdapterFactory) list.nextElement();

+			Object[] adapters = factory.getAdapterList();

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

+				Object adapter = adapters[i];

+				if (lookupTable.get(adapter) == null)

+					lookupTable.put(adapter, factory);

+			}

+		}

+	}

+}

+/**

+ * Returns the class search order starting with <code>extensibleClass</code>.

+ * The search order is defined in this class' comment.

+ */

+private Vector computeClassOrder(Class extensibleClass) {

+	Vector result = new Vector(4);

+	Class clazz = extensibleClass;

+	while (clazz != null) {

+		result.addElement(clazz);

+		clazz = clazz.getSuperclass();

+	}

+	return result;

+}

+/**

+ * Returns the interface search order for the class hierarchy described

+ * by <code>classList</code>.

+ * The search order is defined in this class' comment.

+ */

+private Vector computeInterfaceOrder(Vector classList) {

+	Vector result = new Vector(4);

+	Hashtable seen = new Hashtable(4);

+	for (Enumeration list = classList.elements(); list.hasMoreElements();) {

+		Class[] interfaces = ((Class) list.nextElement()).getInterfaces();

+		internalComputeInterfaceOrder(interfaces, result, seen);

+	}

+	return result;

+}

+/**

+ * Flushes the cache of extender search paths.  This is generally required

+ * whenever an extender is added or removed.  

+ * <p>

+ * It is likely easier to just toss the whole cache rather than trying to be

+ * smart and remove only those entries affected.

+ * </p>

+ */

+public void flushLookup() {

+	lookup = null;

+}

+/*

+ * @see IAdapterManager#getAdapter

+ */

+public Object getAdapter(Object object, Class target) {

+	IAdapterFactory factory = getFactory(object.getClass(), target);

+	Object result = null;

+	if (factory != null)

+		result = factory.getAdapter(object, target);

+	if (result == null && target.isInstance(object))

+		return object;

+	return result;

+}

+/**

+ * Gets the extender installed for objects of class <code>extensibleClass</code>

+ * which defines the property identified by <code>key</code>.  If no such

+ * extender exists, returns null.

+ */

+private IAdapterFactory getFactory(Class extensibleClass, Class adapter) {

+	Hashtable table;

+	// check the cache first.

+	if (lookup != null) {

+		table = (Hashtable) lookup.get(extensibleClass);

+		if (table != null)

+			return (IAdapterFactory) table.get(adapter);

+	}

+	// Its not in the cache so we have to build the extender table for this class.

+	// The table is keyed by property identifier.  The 

+	// value is the <b>sole<b> extender which defines that property.  Note that if

+	// if multiple extenders technically define the same property, only the first found

+	// in the search order is considered.

+	table = new Hashtable(4);

+	// get the list of all superclasses and add the extenders installed for each 

+	// of those classes to the table.  

+	Vector classList = computeClassOrder(extensibleClass);

+	addFactoriesFor(classList, table);

+	// get the ordered set of all interfaces for the extensible class and its 

+	// superclasses and add the extenders installed for each 

+	// of those interfaces to the table.  

+	classList = computeInterfaceOrder(classList);

+	addFactoriesFor(classList, table);

+	// If there is still nothing, give up

+	if (table.isEmpty())

+		return null;

+	// otherwise, cache the table and do the lookup again.

+	if (lookup == null)

+		lookup = new Hashtable(5);

+	lookup.put(extensibleClass, table);

+	return (IAdapterFactory) table.get(adapter);

+}

+private void internalComputeInterfaceOrder(Class[] interfaces, Vector result, Hashtable seen) {

+	Vector newInterfaces = new Vector(seen.size());

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

+		Class interfac = interfaces[i];

+		if (seen.get(interfac) == null) {

+			result.addElement(interfac);

+			seen.put(interfac, interfac);

+			newInterfaces.addElement(interfac);

+		}

+	}

+	for (Enumeration newList = newInterfaces.elements(); newList.hasMoreElements();)

+		internalComputeInterfaceOrder(((Class) newList.nextElement()).getInterfaces(), result, seen);

+}

+/*

+ * @see IAdapterManager#registerAdapters

+ */

+public void registerAdapters(IAdapterFactory factory, Class extensibleType) {

+	Vector list = (Vector) factories.get(extensibleType);

+	if (list == null) {

+		list = new Vector(5);

+		factories.put(extensibleType, list);

+	}

+	list.addElement(factory);

+	flushLookup();

+}

+/*

+ * @see IAdapterManager#unregisterAdapters

+ */

+public void unregisterAdapters(IAdapterFactory factory) {

+	for (Enumeration enum = factories.elements(); enum.hasMoreElements();) {

+		Vector list = (Vector) enum.nextElement();

+		list.removeElement(factory);

+	}

+	flushLookup();

+}

+/*

+ * @see IAdapterManager#unregisterAdapters

+ */

+public void unregisterAdapters(IAdapterFactory factory, Class extensibleType) {

+	Vector factoryList = (Vector) factories.get(extensibleType);

+	if (factoryList == null)

+		return;

+	factoryList.removeElement(factory);

+	flushLookup();

+}

+/*

+ * @see IAdapterManager#unregisterAllAdapters

+ */

+public void unregisterAllAdapters() {

+	factories = new Hashtable(5);

+	flushLookup();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Assert.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Assert.java
new file mode 100644
index 0000000..38b14f7
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Assert.java
@@ -0,0 +1,98 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * <code>Assert</code> is useful for for embedding runtime sanity checks

+ * in code.

+ * The predicate methods all test a condition and throw some

+ * type of unchecked exception if the condition does not hold.

+ * <p>

+ * Assertion failure exceptions, like most runtime exceptions, are

+ * thrown when something is misbehaving. Assertion failures are invariably

+ * unspecified behavior; consequently, clients should never rely on

+ * these being thrown (and certainly should not being catching them

+ * specifically).

+ * </p>

+ */

+public final class Assert {

+/* This class is not intended to be instantiated. */

+private Assert() {

+}

+/** Asserts that an argument is legal. If the given boolean is

+ * not <code>true</code>, an <code>IllegalArgumentException</code>

+ * is thrown.

+ *

+ * @param expression the outcode of the check

+ * @return <code>true</code> if the check passes (does not return

+ *    if the check fails)

+ * @exception IllegalArgumentException if the legality test failed

+ */

+public static boolean isLegal(boolean expression) {

+	return isLegal(expression, "");

+}

+/** Asserts that an argument is legal. If the given boolean is

+ * not <code>true</code>, an <code>IllegalArgumentException</code>

+ * is thrown.

+ * The given message is included in that exception, to aid debugging.

+ *

+ * @param expression the outcode of the check

+ * @param message the message to include in the exception

+ * @return <code>true</code> if the check passes (does not return

+ *    if the check fails)

+ * @exception IllegalArgumentException if the legality test failed

+ */

+public static boolean isLegal(boolean expression, String message) {

+	if (!expression)

+		throw new IllegalArgumentException(message);

+	return expression;

+}

+/** Asserts that the given object is not <code>null</code>. If this

+ * is not the case, some kind of unchecked exception is thrown.

+ * 

+ * @param object the value to test

+ * @exception IllegalArgumentException if the object is <code>null</code>

+ */

+public static void isNotNull(Object object) {

+	isNotNull(object, "");

+}

+/** Asserts that the given object is not <code>null</code>. If this

+ * is not the case, some kind of unchecked exception is thrown.

+ * The given message is included in that exception, to aid debugging.

+ *

+ * @param object the value to test

+ * @param message the message to include in the exception

+ * @exception IllegalArgumentException if the object is <code>null</code>

+ */

+public static void isNotNull(Object object, String message) {

+	if (object == null)

+		throw new AssertionFailedException("null argument:" + message);

+}

+/** Asserts that the given boolean is <code>true</code>. If this

+ * is not the case, some kind of unchecked exception is thrown.

+ *

+ * @param expression the outcode of the check

+ * @return <code>true</code> if the check passes (does not return

+ *    if the check fails)

+ */

+public static boolean isTrue(boolean expression) {

+	return isTrue(expression, "");

+}

+/** Asserts that the given boolean is <code>true</code>. If this

+ * is not the case, some kind of unchecked exception is thrown.

+ * The given message is included in that exception, to aid debugging.

+ *

+ * @param expression the outcode of the check

+ * @param message the message to include in the exception

+ * @return <code>true</code> if the check passes (does not return

+ *    if the check fails)

+ */

+public static boolean isTrue(boolean expression, String message) {

+	if (!expression)

+		throw new AssertionFailedException("assertion failed: "+message);

+	return expression;

+}

+}

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

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * <code>AssertionFailedException</code> is a runtime exception thrown

+ * by some of the methods in <code>Assert</code>.

+ * <p>

+ * This class is not declared public to prevent some misuses; programs that catch 

+ * or otherwise depend on assertion failures are susceptible to unexpected

+ * breakage when assertions in the code are added or removed.

+ * </p>

+ */

+/* package */

+class AssertionFailedException extends RuntimeException {

+/** Constructs a new exception.

+ */

+public AssertionFailedException() {

+}

+/** Constructs a new exception with the given message.

+ */

+public AssertionFailedException(String detail) {

+	super(detail);

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AuthorizationDatabase.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AuthorizationDatabase.java
new file mode 100644
index 0000000..d99ddda
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AuthorizationDatabase.java
@@ -0,0 +1,292 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import java.io.*;

+import java.net.*;

+import java.util.*;

+

+/**

+ * A database that remembers information, such as usernames and

+ * passwords.  The information is stored in memory and can be saved

+ * to disk in an encrypted format.  While the API is phrased in terms of

+ * URLs, realms and authentication schemes, not all of these must have

+ * significant values.  For example, if "realm" is not relevant to a

+ * particular application, it can be left blank (though not

+ * <code>null</code>).

+ */

+public class AuthorizationDatabase {

+	/**

+	 * A nested hashtable that stores authorization information. The

+	 * table maps server URLs to realms to authentication schemes to

+	 * authorization information.

+	 */

+	private Hashtable authorizationInfo = new Hashtable(5);

+

+	/**

+	 * A hashtable mapping resource URLs to realms.

+	 */

+	private Hashtable protectionSpace = new Hashtable(5);

+

+	private File file = null;

+	private String password = null;

+	private boolean needsSaving = true;

+/**

+ * Creates a new authorization database whose data cannot be saved to

+ * disk.

+ */

+public AuthorizationDatabase() {

+}

+/**

+ * Creates a new authorization database, or opens an existing one, whose

+ * data is, or can be, saved to a file with the given filename. A

+ * password must be given to create a new database and an existing

+ * database is opened by supplying the password that was given to create

+ * it.

+ *

+ * @param filename the location of the database on disk. For example,

+ *		"c:/temp/database"

+ * @param password the password to access the database. For example,

+ *		"secret"

+ * @exception Exception if there are problems creating the database.

+ *		Reasons include:

+ * <ul>

+ * <li>The database could not be opened because the wrong password was given.

+ * <li>The database could not be opened because the specified file is corrupt.

+ * </ul>

+ */

+public AuthorizationDatabase(String filename, String password) throws CoreException {

+	Assert.isNotNull(filename);

+	Assert.isNotNull(password);

+	this.password = password;

+	file = new File(filename);

+	load();

+}

+/**

+ * Adds the given authorization information to the database. The

+ * information is relevant for the specified protection space and the

+ * given authorization scheme. The protection space is defined by the

+ * combination of the given server URL and realm. The authorization 

+ * scheme determines what the authorization information contains and how 

+ * it should be used. The authorization information is a <code>Map</code> 

+ * of <code>String</code> to <code>String</code> and typically

+ * contain information such as usernames and passwords.

+ *

+ * @param serverUrl the URL identifying the server for this authorization

+ *		information. For example, "http://www.hostname.com/".

+ * @param realm the subsection of the given server to which this

+ *		authorization information applies.  For example,

+ *		"realm1@hostname.com" or "" for no realm.

+ * @param authScheme the scheme for which this authorization information

+ *		applies. For example, "Basic" or "" for no authorization scheme

+ * @param info a <code>Map</code> containing authorization information 

+ *		such as usernames and passwords

+ */

+public void addAuthorizationInfo(URL serverUrl, String realm, String authScheme, Map info){

+	Assert.isNotNull(serverUrl);

+	Assert.isNotNull(realm);

+	Assert.isNotNull(authScheme);

+	Assert.isNotNull(info);

+

+	String url = serverUrl.toString();

+	Hashtable realmToAuthScheme = (Hashtable)authorizationInfo.get(url);

+	if(realmToAuthScheme == null){

+		realmToAuthScheme = new Hashtable(5);

+		authorizationInfo.put(url, realmToAuthScheme);

+	}

+

+	Hashtable authSchemeToInfo = (Hashtable)realmToAuthScheme.get(realm);

+	if(authSchemeToInfo == null){

+		authSchemeToInfo = new Hashtable(5);

+		realmToAuthScheme.put(realm, authSchemeToInfo);

+	}

+

+	authSchemeToInfo.put(authScheme.toLowerCase(), info);

+	needsSaving = true;

+}

+/**

+ * Adds the specified resource to the protection space specified by the

+ * given realm. All resources at or deeper than the depth of the last

+ * symbolic element in the path of the given resource URL are assumed to

+ * be in the same protection space.

+ *

+ * @param resourceUrl the URL identifying the resources to be added to

+ *		the specified protection space. For example,

+ *		"http://www.hostname.com/folder/".

+ * @param realm the name of the protection space. For example,

+ *		"realm1@hostname.com"

+ */

+public void addProtectionSpace(URL resourceUrl, String realm){

+	Assert.isNotNull(resourceUrl);

+	Assert.isNotNull(realm);

+

+	String file = resourceUrl.getFile();

+	if(!file.endsWith("/")){

+		resourceUrl = URLTool.getParent(resourceUrl);

+	}

+

+	String oldRealm = getProtectionSpace(resourceUrl);

+	if(oldRealm != null && oldRealm.equals(realm)){

+		return;

+	}

+

+	String url1 = resourceUrl.toString();

+	Enumeration urls = protectionSpace.keys();

+	while(urls.hasMoreElements()){

+		String url2 = (String)urls.nextElement();

+		if(url1.startsWith(url2) || url2.startsWith(url1)){

+			protectionSpace.remove(url2);

+			break;

+		}

+	}

+

+	protectionSpace.put(url1, realm);

+	needsSaving = true;

+}

+/**

+ * Removes the authorization information for the specified protection

+ * space and given authorization scheme. The protection space is defined

+ * by the given server URL and realm.

+ *

+ * @param serverUrl the URL identifying the server to remove the

+ *		authorization information for. For example,

+ *		"http://www.hostname.com/".

+ * @param realm the subsection of the given server to remove the

+ *		authorization information for. For example,

+ *		"realm1@hostname.com" or "" for no realm.

+ * @param authScheme the scheme for which the authorization information

+ *		to remove applies. For example, "Basic" or "" for no

+ *		authorization scheme.

+ */

+public void flushAuthorizationInfo(URL serverUrl, String realm, String authScheme) {

+	Hashtable realmToAuthScheme = (Hashtable)authorizationInfo.get(serverUrl.toString());

+

+	if(realmToAuthScheme == null){

+		return;

+	}

+

+	Hashtable authSchemeToInfo = (Hashtable)realmToAuthScheme.get(realm);

+

+	if(authSchemeToInfo == null){

+		return;

+	}

+

+	authSchemeToInfo.remove(authScheme.toLowerCase());

+

+	needsSaving = true;

+}

+/**

+ * Returns the authorization information for the specified protection

+ * space and given authorization scheme. The protection space is defined

+ * by the given server URL and realm. Returns <code>null</code> if no

+ * such information exists.

+ *

+ * @param serverUrl the URL identifying the server for the authorization

+ *		information. For example, "http://www.hostname.com/".

+ * @param realm the subsection of the given server to which the

+ *		authorization information applies.  For example,

+ *		"realm1@hostname.com" or "" for no realm.

+ * @param authScheme the scheme for which the authorization information

+ *		applies. For example, "Basic" or "" for no authorization scheme

+ * @return the authorization information for the specified protection

+ *		space and given authorization scheme, or <code>null</code> if no

+ *		such information exists

+ */

+public Map getAuthorizationInfo(URL serverUrl, String realm, String authScheme){

+	Hashtable realmToAuthScheme = (Hashtable)authorizationInfo.get(serverUrl.toString());

+	if(realmToAuthScheme == null){

+		return null;

+	}

+

+	Hashtable authSchemeToInfo = (Hashtable)realmToAuthScheme.get(realm);

+	if(authSchemeToInfo == null){

+		return null;

+	}

+

+	return (Map)authSchemeToInfo.get(authScheme.toLowerCase());

+}

+/**

+ * Returns the protection space (realm) for the specified resource, or

+ * <code>null</code> if the realm is unknown.

+ *

+ * @param resourceUrl the URL of the resource whose protection space is

+ *		returned. For example, "http://www.hostname.com/folder/".

+ * @return the protection space (realm) for the specified resource, or

+ *		<code>null</code> if the realm is unknown

+ */

+public String getProtectionSpace(URL resourceUrl){

+	while(resourceUrl != null){

+		String realm = (String)protectionSpace.get(resourceUrl.toString());

+		if(realm != null){

+			return realm;

+		}

+		resourceUrl = URLTool.getParent(resourceUrl);

+	}

+

+	return null;

+}

+private void load() throws CoreException {

+	if (file == null)

+		return;

+	if (!file.exists()) {

+		save();

+		return;

+	}

+	try {

+		InputStream input = new FileInputStream(file);

+		try {

+			load(input);

+		} finally {

+			input.close();

+		}

+	} catch (IOException e) {

+		throw new CoreException(new Status(IStatus.ERROR,Platform.PI_RUNTIME,13,Policy.bind("meta.unableToReadAuthorization",file.toString()),e));

+	} catch (ClassNotFoundException e) {

+		throw new CoreException(new Status(IStatus.ERROR,Platform.PI_RUNTIME,13,Policy.bind("meta.unableToReadAuthorization",file.toString()),e));

+	}

+}

+private void load(InputStream is) throws IOException, ClassNotFoundException {

+	CipherInputStream cis = new CipherInputStream(is, password);

+	ObjectInputStream ois = new ObjectInputStream(cis);

+	authorizationInfo = (Hashtable) ois.readObject();

+	protectionSpace = (Hashtable) ois.readObject();

+	ois.close();

+}

+/**

+ * Saves the authorization database to disk.

+ */

+public void save() throws CoreException {

+	if (!needsSaving || file == null)

+		return;

+	try {

+		file.delete();

+		file.createNewFile();

+		save(new FileOutputStream(file));

+	} catch (IOException e) {

+		throw new CoreException(new Status(IStatus.ERROR,Platform.PI_RUNTIME,13,Policy.bind("meta.unableToWriteAuthorization",file.toString()),e));

+	}

+	needsSaving = false;

+}

+private void save(OutputStream os) throws IOException {

+	CipherOutputStream cos = new CipherOutputStream(os, password);

+	ObjectOutputStream oos = new ObjectOutputStream(cos);

+	oos.writeObject(authorizationInfo);

+	oos.writeObject(protectionSpace);

+	oos.close();

+}

+/**

+ * Sets the password to use for accessing this database.  If the database

+ * is subsequently saved, this new password is used.

+ */

+public boolean setPassword(String oldValue, String newValue) {

+	if (!oldValue.equals(password))

+		return false;

+	password = newValue;

+	needsSaving = true;

+	return true;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Cipher.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Cipher.java
new file mode 100644
index 0000000..5ad3974
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Cipher.java
@@ -0,0 +1,106 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.security.MessageDigest;

+import java.security.SecureRandom;

+

+/**

+ * <P>Encrypts or decrypts a sequence of bytes. The bytes are decrypted

+ * by supplying the same password that was given when the bytes were

+ * encrypted.

+ * <P>Here is an example showing how to encrypt and then decrypt the

+ * string "Hello, world!" using the password "music":

+ * <pre>

+ *     String password = "music";

+ *     byte[] data = "Hello, world!".getBytes("UTF8");

+ *

+ *     // Encrypt

+ *     Cipher cipher = new Cipher(ENCRYPT_MODE, password);

+ *     byte[] encrypted = cipher.update(data);

+ *

+ *     // Decrypt

+ *     cipher = new Cipher(DECRYPT_MODE, password);

+ *     byte[] decrypted = cipher.update(encrypted);

+ * </pre>

+ */

+public class Cipher {

+	public static final int DECRYPT_MODE = -1;

+	public static final int ENCRYPT_MODE = 1;

+

+	private int mode = 0;

+	private String password = null;

+	private SecureRandom secureRandom = null;

+/**

+ * Initializes the cipher with the given mode and password. This method

+ * must be called first (before any encryption of decryption takes

+ * place) to specify whether the cipher should be in encrypt or decrypt

+ * mode and to set the password.

+ *

+ * @param mode

+ * @param password

+ */

+public Cipher (int mode, String password){

+	this.mode = mode;

+	this.password = password;

+	this.secureRandom = null;

+}

+/**

+ * Encrypts or decrypts (depending on which mode the cipher is in) the

+ * given data and returns the result.

+ *

+ * @param data

+ * @return     the result of encrypting or decrypting the given data

+ */

+public byte[] cipher(byte[] data) throws Exception {

+	return transform(data, 0, data.length, mode);

+}

+/**

+ * Encrypts or decrypts (depending on which mode the cipher is in) the

+ * given data and returns the result.

+ *

+ * @param data the byte array containg the given data

+ * @param off  the index of the first byte in the given byte array

+ *             to be transformed

+ * @param len  the index after the last byte in the given byte array

+ *             to be transformed

+ * @return     the result of encrypting or decrypting the given data

+ */

+public byte[] cipher(byte[] data, int off, int len) throws Exception {

+	return transform(data, off, len, mode);

+}

+/**

+ * Encrypts or decrypts (depending on which mode the cipher is in) the

+ * given byte and returns the result.

+ *

+ * @param datum the given byte

+ * @return      the result of encrypting or decrypting the given byte

+ */

+public byte cipher(byte datum) throws Exception {

+	byte[] data = { datum };

+	return cipher(data)[0];

+}

+private byte[] getSeed() throws Exception {

+	MessageDigest messageDigest = MessageDigest.getInstance("SHA");

+	return messageDigest.digest(password.getBytes("UTF8"));

+}

+private byte[] nextRandom(int length) throws Exception {

+	if (secureRandom == null) {

+		secureRandom = SecureRandom.getInstance("SHA1PRNG");

+		secureRandom.setSeed(getSeed());

+	}

+	byte[] nextRandom = new byte[length];

+	secureRandom.nextBytes(nextRandom);

+	return nextRandom;

+}

+private byte[] transform(byte[] data, int off, int len, int mode) throws Exception {

+	byte[] result = nextRandom(len);

+	for (int i = 0; i < len; ++i) {

+		result[i] = (byte) (data[i + off] + mode * result[i]);

+	}

+	return result;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/CipherInputStream.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/CipherInputStream.java
new file mode 100644
index 0000000..505f31a
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/CipherInputStream.java
@@ -0,0 +1,86 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.io.*;

+

+/**

+ * Decrypts a stream of data that was encrypted using the

+ * <code>Cipher</code> or <code>CipherOutputStream</code>.

+ *

+ * @see Cipher

+ * @see CipherOutputStream

+ */

+public class CipherInputStream extends FilterInputStream {

+	private static final int SKIP_BUFFER_SIZE = 2048;

+	private Cipher cipher;

+/**

+ * Constructs a new <code>CipherInputStream</code> that decrypts the

+ * data in the given <code>InputStream</code>.  The data can only be

+ * decrypted if the given password is the same as that which was used

+ * to encrypt it.

+ *

+ * @param is

+ * @param password

+ */

+public CipherInputStream(InputStream is, String password) {

+	super(is);

+	cipher = new Cipher(Cipher.DECRYPT_MODE, password);

+}

+/**

+ * @see InputStream#markSupported

+ */

+public boolean markSupported() {

+	return false;

+}

+/**

+ * @see InputStream#read

+ */

+public int read() throws IOException {

+	int b = super.read();

+	if (b == -1)

+		return -1;

+	try {

+		return ((int) cipher.cipher((byte) b)) & 0x00ff;

+	} catch (Exception e) {

+		throw new IOException(e.getMessage());

+	}

+}

+/**

+ * @see InputStream#read(byte, int, int)

+ */

+public int read(byte b[], int off, int len) throws IOException {

+	int bytesRead = in.read(b, off, len);

+	if (bytesRead == -1)

+		return -1;

+	try {

+		byte[] result = cipher.cipher(b, off, bytesRead);

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

+			b[i + off] = result[i];

+		return bytesRead;

+	} catch (Exception e) {

+		throw new IOException(e.getMessage());

+	}

+}

+/**

+ * @see InputStream#skip(long)

+ */

+public long skip(long n) throws IOException {

+	byte[] buffer = new byte[SKIP_BUFFER_SIZE];

+

+	int bytesRead = 0;

+	long bytesRemaining = n;

+

+	while(bytesRead != -1 && bytesRemaining > 0){

+		bytesRead = read(buffer, 0, (int)Math.min(SKIP_BUFFER_SIZE, bytesRemaining));

+		if(bytesRead > 0){

+			bytesRemaining -= bytesRead;

+		}

+	}

+

+	return n - bytesRemaining;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/CipherOutputStream.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/CipherOutputStream.java
new file mode 100644
index 0000000..c48c0fb
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/CipherOutputStream.java
@@ -0,0 +1,43 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.io.*;

+

+/**

+ * Encrypts a stream of data that can be decrypted using the

+ * <code>Cipher</code> or <code>CipherInputStream</code>.

+ *

+ * @see Cipher

+ * @see CipherInputStream

+ */

+public class CipherOutputStream extends FilterOutputStream {

+	private Cipher cipher;

+/**

+ * Constructs a new <code>CipherOutputStream</code> that encrypts the

+ * data in the given <code>OutputStream</code>.  Once the data is

+ * encrypted it can be decrypted by suppying the encrupted data and

+ * given password to a <code>Cipher</code> or

+ * <code>CipherInputStream</code>.

+ *

+ * @param os

+ * @param password

+ */

+public CipherOutputStream(OutputStream os, String password) {

+	super(os);

+	cipher = new Cipher(Cipher.ENCRYPT_MODE, password);

+}

+/**

+ * @see OutputStream#write(int)

+ */

+public void write(int b) throws IOException {

+	try {

+		out.write(cipher.cipher((byte) b));

+	} catch (Exception e) {

+		throw new IOException(e.getMessage());

+	}

+}

+}

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
new file mode 100644
index 0000000..14b0091
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java
@@ -0,0 +1,795 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

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

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

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

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.internal.runtime.*;

+import org.eclipse.core.internal.plugins.*;

+import java.io.*;

+import java.net.*;

+import java.util.*;

+

+/**

+ * Bootstrap class for the platform. It is responsible for setting up the

+ * platform class loader and passing control to the actual application class

+ */

+public final class InternalPlatform {

+	private static IAdapterManager adapterManager;

+	private static PluginRegistry registry;

+	private static Set logListeners = new HashSet(5);

+	private static Map logs = new HashMap(5);

+	private static PlatformLogListener platformLog = null;

+	private static PlatformMetaArea metaArea;

+	private static boolean initialized;

+	private static IPath location;

+	private static PluginClassLoader xmlClassLoader = null;

+

+	private static boolean debugEnabled = false;

+	private static boolean consoleLogEnabled = false;

+	private static ILogListener consoleLog = null;

+	private static Properties options = null;

+	private static AuthorizationDatabase keyring = null;

+	private static String keyringFile = null;

+	private static String password = "";

+	private static boolean inDevelopmentMode = false;

+	private static boolean splashDown = false;

+	private static boolean cacheRegistry = false;

+

+	// default plugin data

+	private static final String PI_XML = "org.apache.xerces";

+	private static final String PLUGINSDIR = "plugins/";

+	private static final String XML_VERSION = "1.2.1";

+	private static final String XML_JAR = "xerces.jar";

+	private static final String XML_LOCATION = "plugins/" + PI_XML + "/";

+

+	// execution options

+	private static final String OPTION_DEBUG = Platform.PI_RUNTIME + "/debug";

+	private static final String OPTION_DEBUG_PLUGINS = Platform.PI_RUNTIME + "/registry/debug";

+

+	// command line options

+	private static final String LOG = "-consolelog";

+	private static final String KEYRING = "-keyring";

+	private static final String PASSWORD = "-password";

+	private static final String DEV = "-dev";

+	private static final String ENDSPLASH = "-endsplash";

+	private static final String REGISTRYCACHE = "-registrycache";

+

+	// debug support:  set in loadOptions()

+	public static boolean DEBUG = false;

+	public static boolean DEBUG_PLUGINS = false;

+

+	private static boolean inVAJ;

+	static {

+		try {

+			Class.forName("com.ibm.uvm.lang.ProjectClassLoader");

+			inVAJ = true;

+		} catch (Exception e) {

+			inVAJ = false;

+		}

+	}

+	private static boolean inVAME;

+	static {

+		try {

+			Class.forName("com.ibm.eclipse.core.VAME");

+			inVAME = true;

+		} catch (Exception e) {

+			inVAME = false;

+		}

+	}

+/**

+ * Private constructor to block instance creation.

+ */

+private InternalPlatform() {

+}

+/**

+ * The runtime plug-in is not totally real due to bootstrapping problems.

+ * This method builds the required constructs to activate and install

+ * the runtime plug-in.

+ */

+private static void activateDefaultPlugins() throws CoreException {

+	// for now, simply do the default activation.  This does not do the right thing

+	// wrt the plugin class loader.

+	PluginDescriptor descriptor = (PluginDescriptor) registry.getPluginDescriptor(Platform.PI_RUNTIME);

+	descriptor.setPluginClassLoader(PlatformClassLoader.getDefault());

+	descriptor.getPlugin();

+

+	descriptor = (PluginDescriptor) registry.getPluginDescriptor(PI_XML);

+	descriptor.setPluginClassLoader(xmlClassLoader);

+	xmlClassLoader.setPluginDescriptor(descriptor);

+	descriptor.getPlugin();

+}

+/**

+ * @see Platform

+ */

+public static void addAuthorizationInfo(URL serverUrl, String realm, String authScheme, Map info) throws CoreException {

+	keyring.addAuthorizationInfo(serverUrl, realm, authScheme, new HashMap(info));

+	keyring.save();

+}

+/**

+ * @see Platform#addLogListener

+ */

+public static void addLogListener(ILogListener listener) {

+	assertInitialized();

+	synchronized (logListeners) {

+		logListeners.add(listener);

+	}

+}

+/**

+ * @see Platform

+ */

+public static void addProtectionSpace(URL resourceUrl, String realm) throws CoreException {

+	keyring.addProtectionSpace(resourceUrl, realm);

+	keyring.save();

+}

+/**

+ * @see Platform

+ */

+public static URL asLocalURL(URL url) throws IOException {

+	URLConnection connection = url.openConnection();

+	if (!(connection instanceof PlatformURLConnection))

+		return url;

+	String file = connection.getURL().getFile();

+	if (file.endsWith("/") && !file.endsWith(PlatformURLHandler.JAR_SEPARATOR))

+		throw new IOException();

+	return ((PlatformURLConnection) connection).getURLAsLocal();

+}

+private static void assertInitialized() {

+	Assert.isTrue(initialized, "meta.appNotInit");

+}

+private static String findPlugin(LaunchInfo.VersionedIdentifier[] list, String name, String version) {

+	LaunchInfo.VersionedIdentifier result = null;

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

+		if (list[i].getIdentifier().equals(name)) {

+			if (version != null)

+				// we are looking for a particular version, compare.  If the current element 

+				// has no version, save it for later in case we don't fine what we are looking for.

+				if (list[i].getVersion().equals(version))

+					return list[i].toString();

+				else

+					if (result == null && list[i].getVersion().length() == 0)

+						result = list[i];

+			else 

+				// remember the element with the latest version number.

+				if (result == null)

+					result = list[i];

+				else 

+					if (result.getVersion().compareTo(list[i].getVersion()) == -1)

+						result = list[i];

+		}

+	}

+	return result == null ? null : result.toString();

+}

+

+/**

+ * Creates and remembers a spoofed up class loader which loads the

+ * classes from a predefined XML plugin.

+ */

+private static void createXMLClassLoader() {

+	// create a plugin descriptor which is sufficient to be able to create

+	// the class loader through the normal channels.

+	Factory factory = new InternalFactory(null);

+	PluginDescriptor descriptor = (PluginDescriptor) factory.createPluginDescriptor();

+	descriptor.setEnabled(true);

+	descriptor.setId(PI_XML);

+	descriptor.setVersion(XML_VERSION);

+

+	try {

+		LaunchInfo launch = LaunchInfo.getCurrent();

+		String plugin = findPlugin(launch.getPlugins(), PI_XML, XML_VERSION);

+		URL url = null;

+		if (plugin == null)

+			url = new URL(BootLoader.getInstallURL(), XML_LOCATION);

+		else

+			url = new URL(BootLoader.getInstallURL(), PLUGINSDIR + plugin + "/");

+		descriptor.setLocation(url.toExternalForm());

+	} catch (MalformedURLException e) {

+		// ISSUE: What to do when this fails.  It's pretty serious

+	}

+

+	LibraryModel lib = factory.createLibrary();

+	lib.setName(XML_JAR);

+	lib.setExports(new String[] { "*" });

+	descriptor.setRuntime(new LibraryModel[] { lib });

+

+	// use the fake plugin descriptor to create the desired class loader.

+	// Since this class loader will be used before the plugin registry is installed,

+	// ensure that the URLs on its class path are raw as opposed to eclipse:

+	xmlClassLoader = (PluginClassLoader) descriptor.getPluginClassLoader(false);

+}

+/**

+ * @see Platform

+ */

+public static void endSplash() {

+	if (DEBUG) {

+		String startString = Platform.getDebugOption(Platform.OPTION_STARTTIME);

+		if (startString != null) 

+			try {

+				long start = Long.parseLong(startString);

+				long end = System.currentTimeMillis();

+				System.out.println("Startup complete: " + (end - start) + "ms");

+			} catch (NumberFormatException e) {

+			}

+	}	

+	if (splashDown) 

+		return;

+	String[] args = BootLoader.getCommandLineArgs();

+	String splash = null;

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

+        if (args[i].equalsIgnoreCase(ENDSPLASH) && (i + 1) < args.length)

+            splash = args[i + 1];

+	if (splash != null)

+	try {

+		splashDown = true;

+		Runtime.getRuntime().exec(splash);

+	} catch (Exception e) {

+	}

+}

+

+/**

+ * @see Platform

+ */

+public static void flushAuthorizationInfo(URL serverUrl, String realm, String authScheme) throws CoreException {

+	keyring.flushAuthorizationInfo(serverUrl, realm, authScheme);

+	keyring.save();

+}

+/**

+ * @see Platform#getAdapterManager

+ */

+public static IAdapterManager getAdapterManager() {

+	assertInitialized();

+	return adapterManager;

+}

+

+/**

+ * Augments the plugin path with extra entries.

+ */

+private static URL[] getAugmentedPluginPath(URL[] pluginPath) {

+	

+	// ISSUE: this code needs to be reworked so that the platform

+	//        does not have logical reference to plug-in-specific

+	//        function

+		

+	IPath result = metaArea.getLocation().append(PlatformMetaArea.F_PLUGIN_DATA).append("org.eclipse.scripting").append("plugin.xml");

+	String userScriptName = result.toString();

+	URL userScriptUrl = null;

+	try {

+		userScriptUrl = new URL("file",null,0,userScriptName);

+	} catch(MalformedURLException e) {

+		return pluginPath;

+	}

+		

+	URL[] newPath = new URL[pluginPath.length+1];

+	System.arraycopy(pluginPath,0,newPath,0, pluginPath.length);

+	newPath[newPath.length-1] = userScriptUrl;	

+	return newPath;

+}

+/**

+ * @see Platform

+ */

+public static Map getAuthorizationInfo(URL serverUrl, String realm, String authScheme) {

+	Map info = keyring.getAuthorizationInfo(serverUrl, realm, authScheme);

+	return info == null ? null : new HashMap(info);

+}

+public static boolean getBooleanOption(String option, boolean defaultValue) {

+	String optionValue = options.getProperty(option);

+	return (optionValue != null && optionValue.equalsIgnoreCase("true"))  || defaultValue;

+}

+/**

+ * @see Platform

+ */

+public static String getDebugOption(String option) {

+	return debugEnabled ? options.getProperty(option) : null;

+}

+public static int getIntegerOption(String option, int defaultValue) {

+	String value = getDebugOption(option);

+	try {

+		return value == null ? defaultValue : Integer.parseInt(value);

+	} catch (NumberFormatException e) {

+		return defaultValue;

+	}

+}

+/**

+ * @see Platform#getLocation

+ */

+public static IPath getLocation() {

+	assertInitialized();

+	return location;

+}

+/**

+ * Returns a log for the given plugin or <code>null</code> if none exists.

+ */

+public static ILog getLog(Plugin plugin) {

+	ILog result = (ILog) logs.get(plugin);

+	if (result != null)

+		return result;

+	result = new Log(plugin);

+	logs.put(plugin, result);

+	return result;

+}

+/**

+ * Returns the object which defines the location and organization

+ * of the platform's meta area.

+ */

+public static PlatformMetaArea getMetaArea() {

+	return metaArea;

+}

+/**

+ * @see Platform#getPlugin

+ */

+public static Plugin getPlugin(String id) {

+	assertInitialized();

+	IPluginDescriptor descriptor = getPluginRegistry().getPluginDescriptor(id);

+	if (descriptor == null)

+		return null;

+	try {

+		return descriptor.getPlugin();

+	} catch (CoreException e) {

+		return null;

+	}

+}

+/**

+ * @see Platform#getPluginRegistry

+ */

+public static IPluginRegistry getPluginRegistry() {

+	assertInitialized();

+	return registry;

+}

+/**

+ * @see Platform#getPluginStateLocation

+ */

+public static IPath getPluginStateLocation(Plugin plugin) {

+	assertInitialized();

+	IPath result = metaArea.getPluginStateLocation(plugin);

+	result.toFile().mkdirs();

+	return result;

+}

+/**

+ * @see Platform

+ */

+public static String getProtectionSpace(URL resourceUrl) {

+	return keyring.getProtectionSpace(resourceUrl);

+}

+public static Plugin getRuntimePlugin() {

+	try {

+		return getPluginRegistry().getPluginDescriptor(Platform.PI_RUNTIME).getPlugin();

+	} catch (CoreException e) {

+		return null;

+	}

+}

+private static void handleException(ISafeRunnable code, Throwable e) {

+	if (!(e instanceof OperationCanceledException)) {

+		// try to figure out which plugin caused the problem.  Derive this from the class

+		// of the code arg.  Attribute to the Runtime plugin if we can't figure it out.

+		Plugin plugin = getRuntimePlugin();

+		try {

+			plugin = ((PluginClassLoader)code.getClass().getClassLoader()).getPluginDescriptor().getPlugin();

+		} catch (ClassCastException e1) {

+		} catch (CoreException e1) {

+		}

+		String pluginId =  plugin.getDescriptor().getUniqueIdentifier();

+		String message = Policy.bind("meta.pluginProblems", pluginId);

+		IStatus status = new Status(Status.WARNING, pluginId, Platform.PLUGIN_ERROR, message, e);

+		plugin.getLog().log(status);

+	}

+	code.handleException(e);

+}

+/**

+ * Returns true if the platform is currently running in Development Mode.  If it is, there are 

+ * special procedures that should be taken when defining plug-in class paths.

+ */

+public static boolean inDevelopmentMode() {

+	return inDevelopmentMode || inVAJ() || inVAME();

+}

+/**

+ * Returns true if the platform is currently running in  VA/Java.  If it is, there are 

+ * typically some special procedures

+ * that should be taken when dealing with plug-in activation and class loading.

+ */

+public static boolean inVAJ() {

+	return inVAJ;

+}

+/**

+ * Returns true if the platform is currently running in  VA/ME.  If it is, there are 

+ * typically some special procedures

+ * that should be taken when dealing with plug-in activation and class loading.

+ */

+public static boolean inVAME() {

+	return inVAME;

+}

+/**

+ * Internal method for finding and returning a runnable instance of the 

+ * given class as defined in the specified plug-in.

+ * The returned object is initialized with the supplied arguments.

+ * <p>

+ * This method is used by the platform boot loader; is must

+ * not be called directly by client code.

+ * </p>

+ * @see BootLoader

+ */

+public static IPlatformRunnable loaderGetRunnable(String applicationName) {

+	assertInitialized();

+	IExtension extension = registry.getExtension(Platform.PI_RUNTIME, Platform.PT_APPLICATIONS, applicationName);

+	if (extension == null)

+		return null;

+	IConfigurationElement[] configs = extension.getConfigurationElements();

+	if (configs.length == 0)

+		return null;

+	try {

+		IConfigurationElement config = configs[0];

+		return (IPlatformRunnable) config.createExecutableExtension("run");

+	} catch (CoreException e) {

+		if (DEBUG)

+			getRuntimePlugin().getLog().log(e.getStatus());

+		return null;

+	}

+}

+/**

+ * Internal method for finding and returning a runnable instance of the 

+ * given class as defined in the specified plug-in.

+ * The returned object is initialized with the supplied arguments.

+ * <p>

+ * This method is used by the platform boot loader; is must

+ * not be called directly by client code.

+ * </p>

+ * @see BootLoader

+ */

+public static IPlatformRunnable loaderGetRunnable(String pluginId, String className, Object args) {

+	assertInitialized();

+	PluginDescriptor descriptor = (PluginDescriptor) registry.getPluginDescriptor(pluginId);

+	try {

+		return (IPlatformRunnable) descriptor.createExecutableExtension(className, args, null, null);

+	} catch (CoreException e) {

+		if (DEBUG)

+			getRuntimePlugin().getLog().log(e.getStatus());

+		return null;

+	}

+}

+/**

+ * Internal method for shutting down the platform.  All active plug-ins 

+ * are notified of the impending shutdown. 

+ * The exact order of notification is unspecified;

+ * however, each plug-in is assured that it will be told to shut down

+ * before any of its prerequisites.  Plug-ins are expected to free any

+ * shared resources they manage.  Plug-ins should not store state at

+ * this time; a separate <b>save</b> lifecycle event preceding the

+ * shutdown notice tells plug-ins the right time to be saving their state.

+ * <p>

+ * On exit, the platform will no longer be initialized and any objects derived from

+ * or based on the running platform are invalidated.

+ * </p>

+ * <p>

+ * This method is used by the platform boot loader; is must

+ * not be called directly by client code.

+ * </p>

+ * @see BootLoader

+ */

+public static void loaderShutdown() {

+	assertInitialized();

+	registry.shutdown(null);

+	if (DEBUG_PLUGINS) {

+		// We are debugging so output the registry in XML

+		// format.

+		registry.debugRegistry();

+	} else {

+		// get rid of the debug file if it exists

+		registry.flushDebugRegistry();

+	}

+	

+	if (cacheRegistry) {

+		// Write the registry in cache format

+		try {

+			registry.saveRegistry();

+		} catch (IOException e) {

+			String message = Policy.bind("meta.unableToWriteRegistry");

+			IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.PLUGIN_ERROR, message, e);

+			getRuntimePlugin().getLog().log(status);

+			if (DEBUG)

+				System.out.println(status.getMessage());

+		}

+	} else {

+		// get rid of the cache file if it exists

+		registry.flushRegistry();

+	}

+	if (platformLog != null)

+		platformLog.shutdown();

+	initialized = false;

+}

+/**

+ * Internal method for starting up the platform.  The platform is started at the 

+ * given location.  The plug-ins found at the supplied 

+ * collection of plug-in locations are loaded into the newly started platform.

+ * <p>

+ * This method is used by the platform boot loader; is must

+ * not be called directly by client code.

+ * </p>

+ * @param pluginPath the list of places to look for plug-in specifications.  This may

+ *		identify individual plug-in files or directories containing directories which contain

+ *		plug-in files.

+ * @param location the local filesystem location at which the newly started platform

+ *		should be started.  If the location does not contain the saved state of a platform,

+ *		the appropriate structures are created on disk (if required).

+ * @param bootOptions the debug options loaded by the boot loader.  If the argument

+ *		is <code>null</code> then debugging enablement was not requested by the

+ *		person starting the platform.

+ * @see BootLoader

+ */

+public static void loaderStartup(URL[] pluginPath, String locationString, Properties bootOptions, String[] args) throws CoreException {

+	processCommandLine(args);

+	setupMetaArea(locationString);

+	adapterManager = new AdapterManager();

+	loadOptions(bootOptions);

+	createXMLClassLoader();

+	MultiStatus problems = loadRegistry(pluginPath);

+	initialized = true;

+	// can't register url handlers until after the plugin registry is loaded

+	PlatformURLPluginHandlerFactory.startup();

+	activateDefaultPlugins();

+	// can't install the log or log problems until after the platform has been initialized.

+	platformLog = new PlatformLogListener();

+	addLogListener(platformLog);

+	if (consoleLogEnabled) {

+		consoleLog = new PlatformLogListener(System.out);

+		addLogListener(consoleLog);

+	}

+	if (!problems.isOK())

+		getRuntimePlugin().getLog().log(problems);

+	loadKeyring();

+}

+/**

+ * Opens the password database (if any) initally provided to the platform at startup.

+ */

+private static void loadKeyring() {

+	if (keyringFile != null)

+		try {

+			keyring = new AuthorizationDatabase(keyringFile, password);

+		} catch (CoreException e) {

+			log(e.getStatus());

+		}

+	if (keyring == null)

+		keyring = new AuthorizationDatabase();

+}

+static void loadOptions(Properties bootOptions) {

+	// If the boot loader passed <code>null</code> for the boot options, the user

+	// did not specify debug options so no debugging should be enabled.

+	if (bootOptions == null) {

+		debugEnabled = false;

+		return;

+	}

+	debugEnabled = true;

+	options = new Properties(bootOptions);

+	try {

+		InputStream input = new FileInputStream(InternalPlatform.getMetaArea().getOptionsLocation().toFile());

+		try {

+			options.load(input);

+		} finally {

+			input.close();

+		}

+	} catch (FileNotFoundException e) {

+		//	Its not an error to not find the options file

+	} catch (IOException e) {

+		//	Platform.RuntimePlugin.getLog().log();

+	}

+		// trim off all the blanks since properties files don't do that.

+	for (Iterator i = options.keySet().iterator(); i.hasNext();) {

+		Object key = i.next();

+		options.put(key, ((String) options.get(key)).trim());

+	}

+	DEBUG = getBooleanOption(OPTION_DEBUG, false);

+	DEBUG_PLUGINS = getBooleanOption(OPTION_DEBUG_PLUGINS, false);

+	InternalBootLoader.setupOptions();

+}

+/**

+ * Parses, resolves and rememberhs the plugin registry.  The multistatus returned

+ * details any problems/issues encountered during this process.

+ */

+private static MultiStatus loadRegistry(URL[] pluginPath) {

+	MultiStatus problems = new MultiStatus(Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, Policy.bind("parse.registryProblems"), null);

+	InternalFactory factory = new InternalFactory(problems);

+

+	IPath path = getMetaArea().getRegistryPath();

+	IPath tempPath = getMetaArea().getBackupFilePathFor(path);

+	DataInputStream input = null;

+	registry = null;

+	if (cacheRegistry) {

+		try {

+			input = new DataInputStream(new BufferedInputStream(new SafeFileInputStream(path.toOSString(), tempPath.toOSString())));

+			try {

+				long start = System.currentTimeMillis();

+				RegistryCacheReader cacheReader = new RegistryCacheReader(factory);

+				registry = (PluginRegistry)cacheReader.readPluginRegistry(input);

+				if (DEBUG)

+					System.out.println("Read registry cache: " + (System.currentTimeMillis() - start) + "ms");

+			} finally {

+				input.close();

+			}

+		} catch (IOException ioe) {

+			IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.PLUGIN_ERROR, Policy.bind("meta.unableToReadCache"), ioe);

+			problems.merge(status);

+		}

+	}

+	if (registry == null) {

+		URL[] augmentedPluginPath = getAugmentedPluginPath(pluginPath);	// augment the plugin path with any additional platform entries	(eg. user scripts)

+		registry = (PluginRegistry) parsePlugins(augmentedPluginPath, factory, DEBUG && DEBUG_PLUGINS);

+		IStatus resolveStatus = registry.resolve(true, true);

+		problems.merge(resolveStatus);

+		registry.markReadOnly();

+	}

+	registry.startup(null);

+	return problems;

+}

+/**

+ * @see Platform#log

+ */

+public static void log(final IStatus status) {

+	assertInitialized();

+	// create array to avoid concurrent access

+	ILogListener[] listeners;

+	synchronized (logListeners) {

+		listeners = (ILogListener[]) logListeners.toArray(new ILogListener[logListeners.size()]);

+	}

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

+		try {

+			listeners[i].logging(status, Platform.PI_RUNTIME);

+		} catch (Exception e) {

+		} // no chance of exceptions for log listeners

+	}

+}

+/**

+ * @see Platform#parsePlugins

+ */

+public static PluginRegistryModel parsePlugins(URL[] pluginPath, Factory factory) {

+	return parsePlugins(pluginPath, factory, false);

+}

+/**

+ * @see Platform#parsePlugins

+ */

+public synchronized static PluginRegistryModel parsePlugins(URL[] pluginPath, Factory factory, boolean debug) {

+	// If the platform is not running then simply parse the registry.  We don't need to play

+	// any funny class loader games as we assume the XML classes are on the class path

+	// This happens when we are running this code as part of a utility (as opposed to starting

+	// or inside the platform).

+	if (!(InternalBootLoader.isRunning() || InternalBootLoader.isStarting()))

+		return RegistryLoader.parseRegistry(pluginPath, factory, debug);

+

+	// If we are running the platform, we want to conserve class loaders.  

+	// Temporarily install the xml class loader as a prerequisite of the platform class loader

+	// This allows us to find the xml classes.  Be sure to reset the prerequisites after loading.

+	PlatformClassLoader.getDefault().setImports(new DelegatingURLClassLoader[] { xmlClassLoader });

+	try {

+		return RegistryLoader.parseRegistry(pluginPath, factory, debug);

+	} finally {

+		PlatformClassLoader.getDefault().setImports(null);

+	}

+}

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

+	int[] configArgs = new int[100];

+	configArgs[0] = -1; // need to initialize the first element to something that could not be an index.

+	int configArgIndex = 0;

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

+		boolean found = false;

+		// check for args without parameters (i.e., a flag arg)

+

+		// look for the log flag

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

+			consoleLogEnabled = true;

+			found = true;

+		}

+

+		// look for the development mode flag

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

+			inDevelopmentMode = true;

+			found = true;

+		}

+

+		// look for the registry cache flag

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

+			cacheRegistry = true;

+			found = true;

+		}

+

+		// done checking for args.  Remember where an arg was found 

+		if (found) {

+			configArgs[configArgIndex++] = i;

+			continue;

+		}

+		// check for args with parameters

+		if (i == args.length - 1 || args[i + 1].startsWith("-")) 

+			continue;

+		String arg = args[++i];

+

+		// look for the keyring file

+		if (args[i - 1].equalsIgnoreCase(KEYRING)) {

+			keyringFile = arg;

+			found = true;

+		}

+

+		// look for the user password.  

+		if (args[i - 1].equalsIgnoreCase(PASSWORD)) {

+			password = arg;

+			found = true;

+		}

+

+		// done checking for args.  Remember where an arg was found 

+		if (found) {

+			configArgs[configArgIndex++] = i - 1;

+			configArgs[configArgIndex++] = i;

+		}

+	}

+	// remove all the arguments consumed by this argument parsing

+	if (configArgIndex == 0)

+		return args;

+	String[] passThruArgs = new String[args.length - configArgIndex];

+	configArgIndex = 0;

+	int j = 0;

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

+		if (i == configArgs[configArgIndex])

+			configArgIndex++;

+		else

+			passThruArgs[j++] = args[i];

+	}

+	return passThruArgs;

+}

+/**

+ * @see Platform#removeLogListener

+ */

+public static void removeLogListener(ILogListener listener) {

+	assertInitialized();

+	synchronized (logListeners) {

+		logListeners.remove(listener);

+	}

+}

+/**

+ * @see Platform

+ */

+public static URL resolve(URL url) throws IOException {

+	URLConnection connection = url.openConnection();

+	if (connection instanceof PlatformURLConnection)

+		return ((PlatformURLConnection) connection).getResolvedURL();

+	else

+		return url;

+}

+public static void run(ISafeRunnable code) {

+	Assert.isNotNull(code);

+	try {

+		code.run();

+	} catch (Exception e) {

+		handleException(code, e);

+	} catch (LinkageError e) {

+		handleException(code, e);

+	}

+}

+public static void setDebugOption(String option, String value) {

+	if (debugEnabled)

+		options.setProperty(option, value);

+}

+/**

+ * Sets the plug-in registry for the platform to the given value.

+ * This method should only be called by the registry loader

+ */

+public static void setPluginRegistry(IPluginRegistry value) {

+	registry = (PluginRegistry) value;

+}

+private static void setupMetaArea(String locationString) throws CoreException {

+	location = new Path(locationString);

+	if (!location.isAbsolute())

+		location = new Path(System.getProperty("user.dir")).append(location);

+	// must create the meta area first as it defines all the other locations.

+	if (location.toFile().exists()) {

+		if (!location.toFile().isDirectory()) {

+			String message = Policy.bind("meta.notDir", location.toString());

+			throw new CoreException(new Status(IStatus.ERROR, Platform.PI_RUNTIME, 13, message, null));

+		}

+	}

+	metaArea = new PlatformMetaArea(location);

+	metaArea.createLocation();

+	if (keyringFile == null)

+		keyringFile = metaArea.getLocation().append(PlatformMetaArea.F_KEYRING).toOSString();

+}

+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Log.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Log.java
new file mode 100644
index 0000000..bffaa91
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Log.java
@@ -0,0 +1,73 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import java.util.*;

+

+/**

+ * 

+ */

+public class Log implements ILog{

+	Plugin plugin;

+	Set logListeners = new HashSet(5);

+Log(Plugin plugin) {

+	this.plugin = plugin;

+}

+/**

+ * Adds the given log listener to this log.  Subsequently the log listener will

+ * receive notification of all log events passing through this log.

+ *

+ * @see Platform#addLogListener

+ */

+public void addLogListener(ILogListener listener) {

+	synchronized (logListeners) {

+		logListeners.add(listener);

+	}

+}

+/**

+ * Returns the plug-in with which this log is associated.

+ */

+public Plugin getPlugin() {

+	return plugin;

+}

+/**

+ * Logs the given status.  The status is distributed to the log listeners

+ * installed on this log and then to the log listeners installed on the platform.

+ *

+ * @see Plugin#getLogMask

+ */

+public void log(final IStatus status) {

+	// create array to avoid concurrent access

+	ILogListener[] listeners;

+	synchronized (logListeners) {

+		listeners = (ILogListener[]) logListeners.toArray(new ILogListener[logListeners.size()]);

+	}

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

+		final ILogListener listener = listeners[i];

+		ISafeRunnable code = new ISafeRunnable() {

+			public void run() throws Exception {

+				listener.logging(status, plugin.getDescriptor().getUniqueIdentifier());

+			}

+			public void handleException(Throwable e) {

+			}

+		};

+		InternalPlatform.run(code);

+	}

+	InternalPlatform.log(status);

+}

+/**

+ * Removes the given log listener to this log.  Subsequently the log listener will

+ * no longer receive notification of log events passing through this log.

+ *

+ * @see Platform#removeLogListener

+ */

+public void removeLogListener(ILogListener listener) {

+	synchronized (logListeners) {

+		logListeners.remove(listener);

+	}

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Messages.properties b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Messages.properties
new file mode 100644
index 0000000..4e27253
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Messages.properties
@@ -0,0 +1,64 @@
+### Runtime plugin message catalog

+

+ok = OK

+

+### plugins

+plugin.extDefNotFound = Executable extension definition for {0} not found.

+plugin.extDefNoClass = Executable extension definition {0} does not specify a class name.

+plugin.deactivatedLoad = Attempt to load class {0} from deactivated plug-in {1}.

+plugin.loadClassError = Plug-in {0} was unable to load class {1}.

+plugin.instantiateClassError = Plugin {0} was unable to instantiate class {1}.

+plugin.initObjectError = Plugin {0} was unable to execute setInitializationData on an instance of {1}.

+plugin.bundleNotFound = Plugin {0} could not find resource bundle {1}.

+plugin.notPluginClass = Supplied runtime class {0} does not extend class Plugin.

+plugin.startupProblems = Problems encountered starting up plug-in: {0}.

+plugin.pluginDisabled = Attempt to activate a disabled plug-in: {0}.

+plugin.unableToResolve = Unable to resolve plug-in registry.

+plugin.mismatchRuntime = Runtime class declaration mismatch for plug-in: {0}.

+

+### parsing/resolve

+parse.error = Parsing error: {0}.

+parse.errorProcessing = Error while processing {0}.

+parse.errorNameLineColumn = Parsing error in {0} [line {1}, column {2}]: {3}.

+parse.extPointUnknown = Unknown extension point {0} specified in plug-in {1}.

+parse.extPointDisabled = Extension point {0} specified in plug-in {1} is disabled.

+parse.prereqDisabled = Plug-in {0} was disabled due to missing or disabled prerequisite plug-in {1}.

+parse.unsatisfiedPrereq = Unable to satisfy prerequisite constraint from {0} to {1}.

+parse.prereqLoop = Detected prerequisite loop from {0} to {1}.

+parse.registryProblems = Problems encountered loading the plug-in registry.

+parse.fragmentMissingAttr = Fragment {0} ignored due to missing attributes.

+parse.fragmentMissingIdName = Fragment ignored due to missing attributes (including name and id).

+parse.pluginMissingAttr = Plugin {0} disabled due to missing attributes.

+parse.pluginMissingIdName = Plugin disabled due to missing attributes (including name and id).

+parse.unknownElement = Unknown element {1}, found within a {0}, ignored.

+parse.unknownTopElement = Unknown element {0}, found at the top level, ignored.

+parse.initializationTrouble = Parser initialization using setFeature failed.

+parse.internalStack = Element/end element mismatch for element {0}.

+parse.validMatch = {0} is not a valid value for the attribute "match".   Use "exact" or "compatible".

+parse.validExport = {0} is not a valid value for the attribute "export".   Use "true" or "false".

+parse.unknownAttribute = Unknown attribute {1} for element {0} ignored.

+parse.missingFragmentPd = Plugin descriptor {0} not found for fragment {0}.  Fragment ignored.

+

+### metadata

+meta.unableToWriteRegistry = Unable to write plug-in registry to cache.

+meta.appNotInit = The application has not been initialized.

+meta.pluginProblems = Problems occurred when invoking code from plug-in: {0}.

+meta.notDir = Specified platform location {0} is not a directory.

+meta.readPlatformMeta = Could not read platform metadata: {0}.

+meta.writePlatformMeta = Could not write platform metadata: {0}.

+meta.couldNotCreate = Error trying to create the platform metadata area: {0}.

+meta.readonly = The platform metadata area could not be written: {0}.

+meta.unableToCreateCache = Unable to create output stream for registry cache.

+meta.unableToReadCache = Unable to create input stream for registry cache.

+meta.unableToCreateRegDebug = Unable to create output stream for registry debug information.

+meta.unableToWriteDebugRegistry = Unable to write plug-in registry to debug file.

+meta.unableToReadAuthorization = Unable to read authorization database: {0}.

+meta.unableToWriteAuthorization = Unable to write to authorization database: {0}.

+meta.registryCacheWriteProblems = Trouble writing to the registry cache file.

+meta.registryCacheReadProblems = Trouble reading from the registry cache file.

+meta.regCacheIOException = IOException encountered while writing {0}.

+

+### URL

+url.badVariant=Unsupported "platform:" protocol variation {0}.

+url.resolveFragment=Unable to resolve fragment {0}.

+url.resolvePlugin=Unable to resolve plug-in {0}.

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
new file mode 100644
index 0000000..9f8acf7
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformLogListener.java
@@ -0,0 +1,103 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import java.io.*;

+import java.util.Date;

+

+class PlatformLogListener implements ILogListener {

+	private PrintWriter log = null;

+	private boolean usingLogFile = false;

+PlatformLogListener() {

+	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");

+}

+private void logging(IStatus status, int nesting) {

+	indent(nesting);

+	log.print(status.getSeverity());

+	log.print(" ");

+	log.print(status.getPlugin());

+	log.print(" ");

+	log.print(status.getCode());

+	log.print(" ");

+	log.println(status.getMessage());

+	Throwable throwable = status.getException();

+	if (throwable != null) {

+		throwable.printStackTrace(log);

+		if (throwable instanceof CoreException) {

+			CoreException ex = (CoreException) throwable;

+			IStatus s = ex.getStatus();

+			if (s != null)

+				logging(s, nesting + 1);

+		}

+	}

+	if (status.isMultiStatus()) {

+		indent(nesting + 1);

+		log.print(nesting + 1);

+		log.println("=============<children>=============");

+		IStatus[] children = status.getChildren();

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

+			logging(children[i], nesting + 1);

+		indent(nesting + 1);

+		log.print(nesting + 1);

+		log.println("=============</children>=============");

+	}

+	log.flush();

+}

+public synchronized void logging(IStatus status, String plugin) {

+	// thread safety: (Concurrency003)

+	if (usingLogFile)

+		openLogFile();

+	if (log == null)

+		return;

+	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) {

+		// there was a problem opening the log file so log to the console

+		log = new PrintWriter(System.out);

+	}

+}

+/**

+ * @see ILogListener

+ */

+public synchronized void shutdown() {

+	if (log == null)

+		return;

+	PrintWriter old = log;

+	log = null;

+	old.flush();

+	old.close();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformMetaArea.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformMetaArea.java
new file mode 100644
index 0000000..2ba0f02
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformMetaArea.java
@@ -0,0 +1,160 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import java.util.*;

+import java.io.*;

+

+public class PlatformMetaArea {

+	IPath location;

+	

+	/* package */ static final String F_DESCRIPTION = ".platform";

+	/* package */ static final String F_META_AREA = ".metadata";

+	/* package */ static final String F_PLUGIN_PATH = ".plugin-path";

+	/* package */ static final String F_PLUGIN_DATA = ".plugins";

+	/* package */ static final String F_REGISTRY = ".registry";

+	/* package */ static final String F_SNAP = ".snap";

+	/* package */ static final String F_LOG = ".log";

+	/* package */ static final String F_BACKUP = ".bak";

+	/* package */ static final String F_OPTIONS = ".options";	

+	/* package */ static final String F_KEYRING = ".keyring";	

+/**

+ * 

+ */

+public PlatformMetaArea(IPath location) {

+	super();

+	this.location = location;

+}

+private Properties buildPathProperties(Hashtable paths) {

+	Properties result = new Properties();

+	for (Enumeration keys = paths.keys(); keys.hasMoreElements();) {

+		String key = (String) keys.nextElement();

+		StringBuffer entry = new StringBuffer(100);

+		IPath[] list = (IPath[]) paths.get(key);

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

+			entry.append(list[i].toOSString());

+			entry.append(";");

+		}

+		result.put(key, entry.toString());

+	}

+	return result;

+}

+/**

+ * 

+ */

+public void createLocation() throws CoreException {

+	File file = getLocation().toFile();

+	try {

+		file.mkdirs();

+	} catch (Exception e) {

+		String message = Policy.bind("meta.couldNotCreate", file.getAbsolutePath());

+		throw new CoreException(new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.FAILED_WRITE_METADATA, message, e));

+	}

+	if (!file.canWrite()) {

+		String message = Policy.bind("meta.readonly", file.getAbsolutePath());

+		throw new CoreException(new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.FAILED_WRITE_METADATA, message, null));

+	}

+}

+public IPath getBackupFilePathFor(IPath file) {

+	return file.removeLastSegments(1).append(file.lastSegment() + F_BACKUP);

+}

+/**

+ * Returns the location of the platform's meta area.

+ */

+public IPath getLocation() {

+	return location.append(F_META_AREA);

+}

+/**

+ * 

+ */

+public IPath getLogLocation() {

+	return getLocation().append(F_LOG);

+}

+/**

+ * 

+ */

+public IPath getOptionsLocation() {

+	return getLocation().append(F_OPTIONS);

+}

+/**

+ * Returns the read/write location in which the given plugin can manage

+ * private state.  

+ */

+public IPath getPluginStateLocation(Plugin plugin) {

+	IPath result = getLocation().append(F_PLUGIN_DATA);

+	String id = plugin.getDescriptor().getUniqueIdentifier();

+	return result.append(id);

+}

+/**

+ * 

+ */

+public IPath getRegistryPath() {

+	return getLocation().append(F_REGISTRY);

+}

+/**

+ * 

+ */

+public IPath getSnapshotPath() {

+	return getLocation().append(F_SNAP);

+}

+private Hashtable parsePathProperties(Properties props) {

+	Hashtable result = new Hashtable(5);

+	for (Enumeration keys = props.propertyNames(); keys.hasMoreElements();) {

+		String key = (String) keys.nextElement();

+		String entry = props.getProperty(key);

+		Vector list = new Vector(4);

+		for (StringTokenizer tokens = new StringTokenizer(entry, ";"); tokens.hasMoreTokens();)

+			list.addElement(new Path(tokens.nextToken()));

+		IPath[] paths = new IPath[list.size()];

+		list.copyInto(paths);

+		result.put(key, paths);

+	}

+	return result;

+}

+public Hashtable readPluginPath(IPath location) throws CoreException {

+	Properties props = new Properties();

+	location = location.append(F_PLUGIN_PATH);

+	IPath tempLocation = getBackupFilePathFor(location);

+	SafeFileInputStream stream = null;

+	try {

+		try {

+			stream = new SafeFileInputStream(location.toOSString(), tempLocation.toOSString());

+			props.load(stream);

+		} finally {

+			if (stream != null)

+				stream.close();

+		}

+	} catch (IOException e) {

+		String message = Policy.bind("meta.readPlatformMeta", location.toString());

+		IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.FAILED_READ_METADATA, message, e);

+		throw new CoreException (status);

+}

+	return parsePathProperties(props);

+}

+/**

+ * @see IWorkbenchProtected#setPluginPath

+ */

+public void writePluginPath(Hashtable paths, IPath location) throws CoreException {

+	Properties props = buildPathProperties(paths);

+	location = location.append(F_PLUGIN_PATH);

+	IPath tempLocation = getBackupFilePathFor(location);

+	SafeFileOutputStream stream = null;

+	try {

+		try {

+			stream = new SafeFileOutputStream(location.toOSString(), tempLocation.toOSString());

+			props.store(stream, null);

+		} finally {

+			if (stream != null)

+				stream.close();

+		}

+	} catch (IOException e) {

+		String message = Policy.bind("meta.writePlatformMeta", location.toString());

+		IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, Platform.FAILED_WRITE_METADATA, message, e);

+		throw new CoreException (status);

+	}

+}

+}

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..811561a
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLFragmentConnection.java
@@ -0,0 +1,62 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * Platform URL support

+ * platform:/fragment/<fragmentId>/		maps to fragmentDescriptor.getInstallURLInternal()

+ */

+

+import java.io.IOException;

+import java.net.URL;

+

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

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

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

+import org.eclipse.core.runtime.model.PluginFragmentModel;

+import org.eclipse.core.runtime.model.PluginRegistryModel;

+ 

+public class PlatformURLFragmentConnection extends PlatformURLConnection {

+

+	// fragment/ protocol

+	private PluginFragmentModel 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);

+	if (!spec.startsWith(FRAGMENT)) 

+		throw new IOException(Policy.bind("url.badVariant", url.toString()));

+	int ix = spec.indexOf("/",FRAGMENT.length()+1);

+	String ref = ix==-1 ? spec.substring(FRAGMENT.length()+1) : spec.substring(FRAGMENT.length()+1,ix);

+	String id = getId(ref);

+	String vid = getVersion(ref);

+	PluginRegistryModel registry = (PluginRegistryModel)Platform.getPluginRegistry();

+	fd = vid==null ? registry.getFragment(id) : registry.getFragment(id,vid);

+	if (fd == null)

+		throw new IOException(Policy.bind("url.resolveFragment", url.toString()));

+	URL result = new URL (fd.getLocation());

+	if (ix == -1 || (ix + 1) >= spec.length()) 

+		return result;

+	else

+		return new URL(result, spec.substring(ix+1));

+}

+

+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/PlatformURLPluginConnection.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginConnection.java
new file mode 100644
index 0000000..defd664
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginConnection.java
Binary files differ
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginHandlerFactory.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginHandlerFactory.java
new file mode 100644
index 0000000..548828f
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PlatformURLPluginHandlerFactory.java
@@ -0,0 +1,49 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.net.*;

+import java.util.*;

+import org.eclipse.core.runtime.*;

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

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

+ 

+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 PlatformURLPluginHandlerFactory(IConfigurationElement ce) {

+	super();

+	this.ce = ce;	

+}

+public URLStreamHandler createURLStreamHandler(String protocol) {

+

+	URLStreamHandler handler = null;

+	try {

+		handler = (URLStreamHandler)ce.createExecutableExtension(HANDLER);

+	} catch (CoreException e) {}

+	return handler;

+}

+public static void startup() {

+

+	// register URL handler extensions

+	IPluginRegistry r = Platform.getPluginRegistry();

+	IConfigurationElement[] ce = r.getConfigurationElementsFor(URL_HANDLERS_POINT);

+	String protocol;

+	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) PlatformURLHandlerFactory.register(protocol,new PlatformURLPluginHandlerFactory(ce[i]));

+	}

+

+	// initialize plugin and fragment connection support

+	PlatformURLPluginConnection.startup();

+	PlatformURLFragmentConnection.startup();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PluginStats.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PluginStats.java
new file mode 100644
index 0000000..6159b3c
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/PluginStats.java
@@ -0,0 +1,60 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

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

+import java.util.*;

+/**

+ * A placeholder for statistics about the runtime behaviour

+ * of a particular plugin.  PluginStats objects are used internally

+ * by the CoreStats mechanism.

+ */

+class PluginStats {

+	protected String pluginID;

+	protected long notificationRunningTime = 0;

+	protected long buildRunningTime = 0;

+	protected int notificationCount = 0;

+	protected int buildCount = 0;

+	protected Vector exceptions = new Vector();

+/**

+ * PluginStats constructor comment.

+ */

+PluginStats(String pluginID) {

+	this.pluginID = pluginID;

+}

+void addException(Exception e) {

+	exceptions.addElement(e);

+}

+Enumeration getCoreExceptions() {

+	Vector runtime = new Vector();

+	for (Enumeration e = exceptions.elements(); e.hasMoreElements();) {

+		Exception next = (Exception)e.nextElement();

+		if (next instanceof CoreException) {

+			runtime.addElement(next);

+		}

+	}

+	return runtime.elements();

+}

+int getExceptionCount() {

+	return exceptions.size();

+}

+String getName() {

+	return pluginID;

+}

+Enumeration getRuntimeExceptions() {

+	Vector runtime = new Vector();

+	for (Enumeration e = exceptions.elements(); e.hasMoreElements();) {

+		Exception next = (Exception) e.nextElement();

+		if (next instanceof RuntimeException) {

+			runtime.addElement(next);

+		}

+	}

+	return runtime.elements();

+}

+long getTotalRunningTime() {

+	return notificationRunningTime + buildRunningTime;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Policy.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Policy.java
new file mode 100644
index 0000000..90f32b1
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/Policy.java
@@ -0,0 +1,109 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import java.util.*;

+

+public class Policy {

+	private static ResourceBundle bundle;

+	private static String bundleName = "org.eclipse.core.internal.runtime.messages";

+

+	static {

+		relocalize();

+	}

+/**

+ * Lookup the message with the given ID in this catalog 

+ */

+public static String bind(String id) {

+	return bind(id, (String[])null);

+}

+/**

+ * Lookup the message with the given ID in this catalog and bind its

+ * substitution locations with the given string.

+ */

+public static String bind(String id, String binding) {

+	return bind(id, new String[] {binding});

+}

+/**

+ * Lookup the message with the given ID in this catalog and bind its

+ * substitution locations with the given strings.

+ */

+public static String bind(String id, String binding1, String binding2) {

+	return bind(id, new String[] {binding1, binding2});

+}

+

+/**

+ * Lookup the message with the given ID in this catalog and bind its

+ * substitution locations with the given string values.

+ */

+public static String bind(String id, String[] bindings) {

+	if (id == null)

+		return "No message available";

+	String message = null;

+	try {

+		message = bundle.getString(id);

+	} catch (MissingResourceException e) {

+		// If we got an exception looking for the message, fail gracefully by just returning

+		// the id we were looking for.  In most cases this is semi-informative so is not too bad.

+		return "Missing message: " + id + " in: " + bundleName;

+	}

+	if (bindings == null)

+		return message;

+	int length = message.length();

+	int start = -1;

+	int end = length;

+	StringBuffer output = new StringBuffer(80);

+	while (true) {

+		if ((end = message.indexOf('{', start)) > -1) {

+			output.append(message.substring(start + 1, end));

+			if ((start = message.indexOf('}', end)) > -1) {

+				int index = -1;

+				try {

+					index = Integer.parseInt(message.substring(end + 1, start));

+					output.append(bindings[index]);

+				} catch (NumberFormatException nfe) {

+					output.append(message.substring(end + 1, start + 1));

+				} catch (ArrayIndexOutOfBoundsException e) {

+					output.append("{missing " + Integer.toString(index) + "}");

+				}

+			} else {

+				output.append(message.substring(end, length));

+				break;

+			}

+		} else {

+			output.append(message.substring(start + 1, length));

+			break;

+		}

+	}

+	return output.toString();

+}

+public static IProgressMonitor monitorFor(IProgressMonitor monitor) {

+	if (monitor == null)

+		return new NullProgressMonitor();

+	return monitor;

+}

+/**

+ * Creates a NLS catalog for the given locale.

+ */

+public static void relocalize() {

+	bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());

+}

+public static IProgressMonitor subMonitorFor(IProgressMonitor monitor, int ticks) {

+	if (monitor == null)

+		return new NullProgressMonitor();

+	if (monitor instanceof NullProgressMonitor)

+		return monitor;

+	return new SubProgressMonitor(monitor, ticks);

+}

+public static IProgressMonitor subMonitorFor(IProgressMonitor monitor, int ticks, int style) {

+	if (monitor == null)

+		return new NullProgressMonitor();

+	if (monitor instanceof NullProgressMonitor)

+		return monitor;

+	return new SubProgressMonitor(monitor, ticks, style);

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/RuntimeStats.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/RuntimeStats.java
new file mode 100644
index 0000000..ee2fdda
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/RuntimeStats.java
@@ -0,0 +1,92 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.io.*;

+import java.util.*;

+/**

+ * This class is used to gather stats on various aspects of

+ * core and plugin behaviour.  The Policy class determines whether

+ * stats are gathered or not, so that instrumentation can be turned

+ * off during production builds.

+ */

+public class RuntimeStats {

+	/**

+	 * If this flag is true, CoreStats prints debug info

+	 * to the console.  If false, it fails silently.

+	 */

+	public static boolean DEBUG = false;

+	/** Table mapping plugin identifiers (Strings) to PluginStats objects.

+	 */

+	private static Hashtable pluginTable = new Hashtable(10);

+

+	/** The start time of the current build or notification

+	 */

+	private static long currentStart;

+

+	/** Plugin statistics

+	 */

+	private static int snapshotCount = 0;

+	private static long snapshotTime = 0;

+	

+/**

+ * CoreStats cannot be instantiated.

+ */

+private RuntimeStats() {

+	super();

+}

+public static void dumpStats() {

+	dumpStats(System.out);

+}

+public static void dumpStats(PrintStream out) {

+	dumpStats(new PrintWriter(out));

+

+}

+public static void dumpStats(PrintWriter out) {

+	/* gather totals */

+	int totalExceptions = 0;

+

+	for (Enumeration e = pluginTable.elements(); e.hasMoreElements();) {

+		PluginStats stats = (PluginStats) e.nextElement();

+		totalExceptions += stats.getExceptionCount();

+	}

+	//dump stats

+	out.println(Integer.toString(snapshotCount) + " snapshots took: " + snapshotTime + "ms");

+	for (Enumeration e = pluginTable.elements(); e.hasMoreElements();) {

+		PluginStats stats = (PluginStats) e.nextElement();

+		out.println("Stats for: " + stats.getName());

+

+		int exceptions = stats.getExceptionCount();

+		if (exceptions > 0) {

+			out.println("  Exceptions: " + exceptions + " (" + (int) ((float) exceptions * 100.0 / (float) totalExceptions) + "% of total)");

+		}

+		out.println("");

+	}

+}

+public static void endSnapshot() {

+	snapshotTime += System.currentTimeMillis() - currentStart;

+	snapshotCount++;

+	currentStart = -1;

+}

+public static int getSnapcount() {

+	return snapshotCount;

+}

+/**

+ * Returns the plug-in stats object for the given plug-in id.

+ * If one does not currently exist, one is created, remembered and returned.

+ */

+private static PluginStats getStats(String pluginID) {

+	PluginStats stats = (PluginStats) pluginTable.get(pluginID);

+	if (stats == null) {

+		stats = new PluginStats(pluginID);

+		pluginTable.put(pluginID, stats);

+	}

+	return stats;

+}

+public static void startSnapshot() {

+	currentStart = System.currentTimeMillis();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/SafeFileInputStream.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/SafeFileInputStream.java
new file mode 100644
index 0000000..e4e5ccc
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/SafeFileInputStream.java
@@ -0,0 +1,39 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.io.*;

+/**

+ * Given a target and a temporary locations, it tries to read the contents

+ * from the target. If a file does not exist at the target location, it tries

+ * to read the contents from the temporary location.

+ *

+ * @see SafeFileOutputStream

+ */

+public class SafeFileInputStream extends FilterInputStream {

+	protected static final String EXTENSION = ".bak";

+public SafeFileInputStream(File file) throws IOException {

+	this(file.getAbsolutePath(), null);

+}

+public SafeFileInputStream(String targetName) throws IOException {

+	this(targetName, null);

+}

+/**

+ * If targetPath is null, the file will be created in the default-temporary directory.

+ */

+public SafeFileInputStream(String targetPath, String tempPath) throws IOException {

+	super(getInputStream(targetPath, tempPath));

+}

+private static InputStream getInputStream(String targetPath, String tempPath) throws IOException {

+	File target = new File(targetPath);

+	if (!target.exists()) {

+		if (tempPath == null)

+			tempPath = target.getAbsolutePath() + EXTENSION;

+		target = new File(tempPath);

+	}

+	return new BufferedInputStream(new FileInputStream(target));

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/SafeFileOutputStream.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/SafeFileOutputStream.java
new file mode 100644
index 0000000..2c949bc
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/SafeFileOutputStream.java
Binary files differ
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/URLTool.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/URLTool.java
new file mode 100644
index 0000000..79951f7
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/URLTool.java
@@ -0,0 +1,482 @@
+package org.eclipse.core.internal.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.Vector;

+

+/**

+ * A utility for manipulating <code>URL</code>s.

+ */

+public class URLTool {

+/**

+ * Returns the given URL with a trailing slash appended to it. If the URL

+ * already has a trailing slash the URL is returned unchanged.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Returned URL</th>

+ * <tr>

+ *   <td>"http://hostname/folder"</td>

+ *   <td>"http://hostname/folder/"</td>

+ * <tr>

+ *   <td>"http://hostname/folder/</td>

+ *   <td>"http://hostname/folder/"</td>

+ * </table>

+ *

+ * @param url a URL

+ * @return    the given URL with a trailing slash

+ * @throws    MalformedURLException if the given URL is malformed

+ */

+public static URL appendTrailingSlash(String url) throws MalformedURLException {

+	return appendTrailingSlash(new URL(url));

+}

+/**

+ * Returns the given <code>URL</code> with a trailing slash appended to

+ * it. If the <code>URL</code> already has a trailing slash the

+ * <code>URL</code> is returned unchanged.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Returned URL</th>

+ * <tr>

+ *   <td>"http://hostname/folder"</td>

+ *   <td>"http://hostname/folder/"</td>

+ * <tr>

+ *   <td>"http://hostname/folder/</td>

+ *   <td>"http://hostname/folder/"</td>

+ * </table>

+ *

+ * @param url a URL

+ * @return    the given URL with a trailing slash

+ */

+public static URL appendTrailingSlash(URL url){

+	String file = url.getFile();

+	if (file.endsWith("/"))

+		return url;

+	try {

+		return new URL(url.getProtocol(), url.getHost(), url.getPort(), file + "/");

+	} catch(MalformedURLException e){

+		Assert.isTrue(false, "internal error");

+	}

+	return null;

+}

+/**

+ * Returns the child URL formed by joining the given member with the

+ * given parent URL.

+ *

+ * @return a child URL of the given parent

+ * @throws MalformedURLException if the given parent is malformed

+ */

+public static URL getChild(String parent, String member) throws MalformedURLException {

+	return getChild(new URL(parent), member);

+}

+/**

+ * Returns the child URL formed by joining the given member with the

+ * given parent URL.

+ *

+ * @return a child URL of the given parent

+ */

+public static URL getChild(URL parent, String member){

+	String file = parent.getFile();

+	if (!file.endsWith("/"))

+		file = file + "/";

+	try {

+		return new URL(parent.getProtocol(), parent.getHost(), parent.getPort(), file + member);

+	} catch(MalformedURLException e){

+		Assert.isTrue(false, "internal error");

+	}

+	return null;

+}

+/**

+ * Returns all elements in the given URLs path.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Element</th>

+ * <tr>

+ *   <td>"http://hostname/"</td>

+ *   <td>[]</td>

+ * <tr>

+ *   <td>"http://hostname/folder/</td>

+ *   <td>[folder]</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file</td>

+ *   <td>[folder, file]</td>

+ * </table>

+ * @param url a URL

+ * @return    all elements in the given URLs path

+ * @throws    MalformedURLException if the given URL is malformed

+ */

+public static Vector getElements(String url) throws MalformedURLException {

+	return getElements(new URL(url));

+}

+/**

+ * Returns all elements in the given URLs path.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Element</th>

+ * <tr>

+ *   <td>"http://hostname/"</td>

+ *   <td>[]</td>

+ * <tr>

+ *   <td>"http://hostname/folder/</td>

+ *   <td>[folder]</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file</td>

+ *   <td>[folder, file]</td>

+ * </table>

+ * @param url a URL

+ * @return    all elements in the given URLs path

+ */

+public static Vector getElements(URL url){

+	Vector result = new Vector(5);

+	String lastElement = null;

+	while((lastElement = getLastElement(url)) != null){

+		result.insertElementAt(lastElement, 0);

+		url = getParent(url);

+	}

+	return result;

+}

+/**

+ * Returns the last element in the given URLs path, or <code>null</code>

+ * if the URL is the root.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Last Element</th>

+ * <tr>

+ *   <td>"http://hostname/"</td>

+ *   <td>null</td>

+ * <tr>

+ *   <td>"http://hostname/folder/</td>

+ *   <td>folder</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file</td>

+ *   <td>file</td>

+ * </table>

+ * @param url a URL

+ * @return    the last element in the given URLs path, or

+ *            <code>null</code> if the URL is the root

+ * @throws    MalformedURLException if the given URL is malformed

+ */

+public static String getLastElement(String url) throws MalformedURLException {

+	return getLastElement(new URL(url));

+}

+/**

+ * Returns the last element in the given URLs path, or <code>null</code>

+ * if the URL is the root.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Last Element</th>

+ * <tr>

+ *   <td>"http://hostname/"</td>

+ *   <td>null</td>

+ * <tr>

+ *   <td>"http://hostname/folder/</td>

+ *   <td>folder</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file</td>

+ *   <td>file</td>

+ * </table>

+ * @param url a URL

+ * @return    the last element in the given URLs path, or

+ *            <code>null</code> if the URL is the root

+ */

+public static String getLastElement(URL url){

+	String file = url.getFile();

+	int len = file.length();

+	if (len == 0 || len == 1 && file.charAt(0) == '/')

+		return null;

+

+	int lastSlashIndex = -1;

+	for(int i = len - 2; lastSlashIndex == -1 && i >= 0; --i) {

+		if (file.charAt(i) == '/')

+			lastSlashIndex = i;

+	}

+	boolean isDirectory = file.charAt(len - 1) == '/';

+	if (lastSlashIndex == -1) {

+		if (isDirectory){

+			return file.substring(0, len - 1);

+		} else {

+			return file;

+		}

+	} else {

+		if (isDirectory) {

+			return file.substring(lastSlashIndex + 1, len - 1);

+		} else {

+			return file.substring(lastSlashIndex + 1, len);

+		}

+	}

+}

+/**

+ * Returns the parent URL of the given URL, or <code>null</code> if the

+ * given URL is the root.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Parent URL</th>

+ * <tr>

+ *   <td>"http://hostname/"</td>

+ *   <td>null</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file</td>

+ *   <td>"http://hostname/folder/</td>

+ * </table>

+ *

+ * @param url a URL

+ * @return    the parent of the given URL

+ * @throws    MalformedURLException if the given URL is malformed

+ */

+public static URL getParent(String url) throws MalformedURLException {

+	return getParent(new URL(url));

+}

+/**

+ * Returns the parent URL of the given URL, or <code>null</code> if the

+ * given URL is the root.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Parent URL</th>

+ * <tr>

+ *   <td>"http://hostname/"</td>

+ *   <td>null</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file</td>

+ *   <td>"http://hostname/folder/</td>

+ * </table>

+ *

+ * @param url a URL

+ * @return    the parent of the given URL

+ */

+public static URL getParent(URL url) {

+	String file = url.getFile();

+	int len = file.length();

+	if (len == 0 || len == 1 && file.charAt(0) == '/')

+		return null;

+	int lastSlashIndex = -1;

+	for (int i = len - 2; lastSlashIndex == -1 && i >= 0; --i){

+		if (file.charAt(i) == '/')

+			lastSlashIndex = i;

+	}

+	if (lastSlashIndex == -1)

+		file = "";

+	else

+		file = file.substring(0, lastSlashIndex + 1);

+

+	try {

+		url = new URL(url.getProtocol(), url.getHost(), url.getPort(), file);

+	} catch(MalformedURLException e){

+		Assert.isTrue(false, e.getMessage());

+	}

+	return url;

+}

+/**

+ * Returns the root URL of the given URL.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Root URL</th>

+ * <tr>

+ *   <td>"http://hostname/"</td>

+ *   <td>"http://hostname/"</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file</td>

+ *   <td>"http://hostname/"</td>

+ * </table>

+ *

+ * @param urlString a URL

+ * @return          the root url of the given URL

+ * @throws          MalformedURLException if the given URL is malformed

+ */

+public static URL getRoot(String urlString) throws MalformedURLException {

+	return getRoot(new URL(urlString));

+}

+/**

+ * Returns the root URL of the given URL.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Root URL</th>

+ * <tr>

+ *   <td>"http://hostname/"</td>

+ *   <td>"http://hostname/"</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file</td>

+ *   <td>"http://hostname/"</td>

+ * </table>

+ *

+ * @param url a URL

+ * @return    the root URL of the given URL

+ */

+public static URL getRoot(URL url) {

+	try {

+		return new URL(url.getProtocol(), url.getHost(), url.getPort(), "/");

+	} catch(MalformedURLException e){

+		Assert.isTrue(false, "internal error");

+	}

+

+	return null;

+}

+/**

+ * Returns the given URL with its trailing slash removed. If the URL has

+ * no trailing slash, the URL is returned unchanged.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Returned URL</th>

+ * <tr>

+ *   <td>"http://hostname/folder"</td>

+ *   <td>"http://hostname/folder"</td>

+ * <tr>

+ *   <td>"http://hostname/folder/</td>

+ *   <td>"http://hostname/folder"</td>

+ * </table>

+ *

+ * @param url a URL

+ * @return    the given URL with its last slash removed

+ * @throws    MalformedURLException if the given URL is malformed

+ */

+public static URL removeTrailingSlash(String url) throws MalformedURLException {

+	return removeTrailingSlash(new URL(url));

+}

+/**

+ * Returns the given URL with its trailing slash removed. If the URL has

+ * no trailing slash, the URL is returned unchanged.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>Given URL</th>

+ *   <th>Returned URL</th>

+ * <tr>

+ *   <td>"http://hostname/folder"</td>

+ *   <td>"http://hostname/folder"</td>

+ * <tr>

+ *   <td>"http://hostname/folder/</td>

+ *   <td>"http://hostname/folder"</td>

+ * </table>

+ *

+ * @param url a URL

+ * @return    the given URL with its last slash removed

+ */

+public static URL removeTrailingSlash(URL url) {

+	String file = url.getFile();

+

+	if(file.endsWith("/")){

+		file = file.substring(0, file.length() - 1);

+		try {

+			return new URL(

+				url.getProtocol(),

+				url.getHost(),

+				url.getPort(),

+				file);

+		} catch(MalformedURLException e){

+			Assert.isTrue(false, e.getMessage());

+		}

+	} else {

+		return url;

+	}

+

+	return null;

+}

+/**

+ * Returns a boolean indicating whether the given URLs overlap.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>First URL</th>

+ *   <th>Second URL</th>

+ *   <th>Do they overlap</th>

+ * <tr>

+ *   <td>"http://hostname/folder/"</td>

+ *   <td>"http://hostname/folder/"</td>

+ *   <td>true</td>

+ * <tr>

+ *   <td>"http://hostname/folder/"</td>

+ *   <td>"http://hostname/folder/file"</td>

+ *   <td>true</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file"</td>

+ *   <td>"http://hostname/folder/"</td>

+ *   <td>true</td>

+ * <tr>

+ *   <td>"http://hostname/folder1/"</td>

+ *   <td>"http://hostname/folder2/"</td>

+ *   <td>false</td>

+ * </table>

+ * @param  url1 firt URL

+ * @param  url2 second URL

+ * @return a boolean indicating whether the given URLs overlap

+ */

+public static boolean urlsOverlap(String url1, String url2) throws MalformedURLException {

+	return urlsOverlap(new URL(url1), new URL(url2));

+}

+/**

+ * Returns a boolean indicating whether the given URLs overlap.

+ * <table>

+ * <caption>Example</caption>

+ * <tr>

+ *   <th>First URL</th>

+ *   <th>Second URL</th>

+ *   <th>Do they overlap</th>

+ * <tr>

+ *   <td>"http://hostname/folder/"</td>

+ *   <td>"http://hostname/folder/"</td>

+ *   <td>true</td>

+ * <tr>

+ *   <td>"http://hostname/folder/"</td>

+ *   <td>"http://hostname/folder/file"</td>

+ *   <td>true</td>

+ * <tr>

+ *   <td>"http://hostname/folder/file"</td>

+ *   <td>"http://hostname/folder/"</td>

+ *   <td>true</td>

+ * <tr>

+ *   <td>"http://hostname/folder1/"</td>

+ *   <td>"http://hostname/folder2/"</td>

+ *   <td>false</td>

+ * <tr>

+ *   <td>"http://hostname1/folder/"</td>

+ *   <td>"http://hostname2/folder/"</td>

+ *   <td>false</td>

+ * </table>

+ * @param  url1 firt URL

+ * @param  url2 second URL

+ * @return a boolean indicating whether the given URLs overlap

+ */

+public static boolean urlsOverlap(URL url1, URL url2){

+	if(!getRoot(url1).equals(getRoot(url2))){

+		return false;

+	}

+

+	Vector elements1 = URLTool.getElements(url1);

+	Vector elements2 = URLTool.getElements(url2);

+

+	for(int i = 0; i < elements1.size() && i < elements2.size(); ++i){

+		String element1 = (String)elements1.elementAt(i);

+		String element2 = (String)elements2.elementAt(i);

+		if(!element1.equals(element2)){

+			return false;

+		}

+	}

+

+	return true;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/messages.properties b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/messages.properties
new file mode 100644
index 0000000..edd0d4f
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/messages.properties
@@ -0,0 +1,53 @@
+### Runtime plugin message catalog

+

+ok = OK

+

+### plugins

+plugin.extDefNotFound = Executable extension definition for {0} not found.

+plugin.extDefNoClass = Executable extension definition {0} does not specify a class name.

+plugin.deactivatedLoad = Attempt to load class {0} from deactivated plug-in {1}.

+plugin.loadClassError = Plug-in {0} was unable to load class {1}.

+plugin.instantiateClassError = Plugin {0} was unable to instantiate class {1}.

+plugin.initObjectError = Plugin {0} was unable to execute setInitializationData on an instance of {1}.

+plugin.bundleNotFound = Plugin {0} could not find resource bundle {1}.

+plugin.notPluginClass = Supplied runtime class {0} does not extend class Plugin.

+plugin.startupProblems = Problems encountered starting up plug-in: {0}.

+plugin.pluginDisabled = Attempt to activate a disabled plug-in: {0}.

+plugin.unableToResolve = Unable to resolve plug-in registry.

+plugin.mismatchRuntime = Runtime class declaration mismatch for plug-in: {0}.

+

+### parsing/resolve

+parse.error = Parsing error: {0}.

+parse.errorProcessing = Error while processing {0}.

+parse.errorNameLineColumn = Parsing error in {0} [line {1}, column {2}]: {3}.

+parse.extPointUnknown = Unknown extension point {0} specified in plug-in {1}.

+parse.extPointDisabled = Extension point {0} specified in plug-in {1} is disabled.

+parse.prereqDisabled = Plug-in {0} was disabled due to missing or disabled prerequisite plug-in {1}.

+parse.unsatisfiedPrereq = Unable to satisfy prerequisite constraint from {0} to {1}.

+parse.prereqLoop = Detected prerequisite loop from {0} to {1}.

+parse.registryProblems = Problems encountered loading the plug-in registry.

+parse.fragmentMissingAttr = Fragment {0} ignored due to missing attributes.

+parse.fragmentMissingIdName = Fragment ignored due to missing attributes (including name and id).

+parse.pluginMissingAttr = Plugin {0} disabled due to missing attributes.

+parse.pluginMissingIdName = Plugin disabled due to missing attributes (including name and id).

+

+### metadata

+meta.unableToWriteRegistry = Unable to write plug-in registry to cache.

+meta.appNotInit = The application has not been initialized.

+meta.pluginProblems = Problems occurred when invoking code from plug-in: {0}.

+meta.notDir = Specified platform location {0} is not a directory.

+meta.readPlatformMeta = Could not read platform metadata: {0}.

+meta.writePlatformMeta = Could not write platform metadata: {0}.

+meta.couldNotCreate = Error trying to create the platform metadata area: {0}.

+meta.readonly = The platform metadata area could not be written: {0}.

+meta.unableToCreateCache = Unable to create output stream for registry cache.

+meta.unableToReadCache = Unable to create input stream for registry cache.

+meta.unableToCreateRegDebug = Unable to create output stream for registry debug information.

+meta.unableToWriteDebugRegistry = Unable to write plug-in registry to debug file.

+meta.unableToReadAuthorization = Unable to read authorization database: {0}.

+meta.unableToWriteAuthorization = Unable to write to authorization database: {0}.

+

+### URL

+url.badVariant=Unsupported "platform:" protocol variation {0}.

+url.resolveFragment=Unable to resolve fragment {0}.

+url.resolvePlugin=Unable to resolve plug-in {0}.

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/CoreException.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/CoreException.java
new file mode 100644
index 0000000..95342cd
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/CoreException.java
@@ -0,0 +1,78 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.io.PrintStream;

+import java.io.PrintWriter;

+/**

+ * A checked expection representing a failure.

+ * <p>

+ * Core exceptions contain a status object describing the 

+ * cause of the exception.

+ * </p>

+ *

+ * @see IStatus

+ */

+public class CoreException extends Exception {

+

+	/** Status object. */

+	private IStatus status;

+/**

+ * Creates a new exception with the given status object.  The message

+ * of the given status is used as the exception message.

+ *

+ * @param status the status object to be associated with this exception

+ */

+public CoreException(IStatus status) {

+	super(status.getMessage());

+	this.status = status;

+}

+/**

+ * Returns the status object for this exception.

+ *

+ * @return a status object

+ */

+public final IStatus getStatus() {

+	return status;

+}

+/**

+ * Prints a stack trace out for the exception, and

+ * any nested exception that it may have embedded in

+ * its Status object.

+ */

+public void printStackTrace() {

+	printStackTrace(System.err);

+}

+/**

+ * Prints a stack trace out for the exception, and

+ * any nested exception that it may have embedded in

+ * its Status object.

+ */

+public void printStackTrace(PrintStream output) {

+	synchronized (output) {

+		if (status.getException() != null) {

+			output.print(getClass().getName() + "[" + status.getCode() + "]: ");

+			status.getException().printStackTrace(output);

+		} else

+			super.printStackTrace(output);

+	}

+}

+/**

+ * Prints a stack trace out for the exception, and

+ * any nested exception that it may have embedded in

+ * its Status object.

+ */

+public void printStackTrace(PrintWriter output) {

+	synchronized (output) {

+		if (status.getException() != null) {

+			output.print(getClass().getName() + "[" + status.getCode() + "]: ");

+			status.getException().printStackTrace(output);

+		} else

+			super.printStackTrace(output);

+	}

+}

+

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdaptable.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdaptable.java
new file mode 100644
index 0000000..002968d
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdaptable.java
@@ -0,0 +1,40 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An interface for an adaptable object.

+ * <p>

+ * Adaptable objects can be dynamically extended to provide different 

+ * interfaces (or "adapters").  Adapters are created by adapter 

+ * factories, which are in turn managed by type by adapter managers.

+ * </p>

+ * For example,

+ * <pre>

+ *     IAdaptable a = [some adaptable];

+ *     IFoo x = (IFoo)a.getAdapter(IFoo.class);

+ *     if (x != null)

+ *         [do IFoo things with x]

+ * </pre>

+ * <p>

+ * Clients may implement this interface.

+ * </p>

+ * @see IAdapterFactory

+ * @see IAdapterManager

+ */

+public interface IAdaptable {

+/**

+ * Returns an object which is an instance of the given class

+ * associated with this object. Returns <code>null</code> if

+ * no such object can be found.

+ *

+ * @param adapter the adapter class to look up

+ * @return a object castable to the given class, 

+ *    or <code>null</code> if this object does not

+ *    have an adapter for the given class

+ */

+public Object getAdapter(Class adapter);

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdapterFactory.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdapterFactory.java
new file mode 100644
index 0000000..fa978b9
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdapterFactory.java
@@ -0,0 +1,47 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An adapter factory defines behavioral extensions for

+ * one or more classes that implements the <code>IAdaptable</code>

+ * interface. Adapter factories are registered with an

+ * adapter manager.

+ * <p>

+ * Clients may implement this interface.

+ * </p>

+ *

+ * @see IAdapterManager

+ * @see IAdaptable

+ */

+public interface IAdapterFactory {

+/**

+ * Returns an object which is an instance of the given class

+ * associated with the given object. Returns <code>null</code> if

+ * no such object can be found.

+ *

+ * @param adaptableObject the adaptable object being queried

+ *   (usually an instance of <code>IAdaptable</code>)

+ * @param adapterType the type of adapter to look up

+ * @return a object castable to the given adapter type, 

+ *    or <code>null</code> if this adapter factory 

+ *    does not have an adapter of the given type for the

+ *    given object

+ */

+public Object getAdapter(Object adaptableObject, Class adapterType);

+/**

+ * Returns the collection of adapter types handled by this

+ * factory.

+ * <p>

+ * This method is generally used by an adapter manager

+ * to discover which adapter types are supported, in advance

+ * of dispatching any actual <code>getAdapter</code> requests.

+ * </p>

+ *

+ * @return the collection of adapter types

+ */

+public Class[] getAdapterList();

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdapterManager.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdapterManager.java
new file mode 100644
index 0000000..40ddadb
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IAdapterManager.java
@@ -0,0 +1,107 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An adapter manager maintains a registry of adapter factories.

+ * Clients directly invoke methods on an adapter manager to register

+ * and unregister adapters.

+ * All adaptable objects (that is, objects that implement the 

+ * <code>IAdaptable</code> interface) funnel 

+ * <code>IAdaptable.getAdapter</code> invocations to their

+ * adapter manager's <code>IAdapterManger.getAdapter</code>

+ * method. The adapter manager then forwards this request

+ * unmodified to the <code>IAdapterFactory.getAdapter</code> 

+ * method on one of the registered adapter factories.

+ * <p>

+ * The following code snippet shows how one might register

+ * an adapter of type <code>com.example.acme.Sticky</code>

+ * on resources in the workspace.

+ * <p>

+ * <pre>

+ * IAdapterFactory pr = new IAdapterFactory() {

+ *     public Class[] getAdapterList() {

+ *         return new Class[] { com.example.acme.Sticky.class };

+ *     }

+ *     public Object getAdapter(Object adaptableObject, adapterType) {

+ *         IResource res = (IResource) adaptableObject;

+ *         QualifiedName key = new QualifiedName("com.example.acme", "sticky-note");

+ *         try {

+ *             com.example.acme.Sticky v = (com.example.acme.Sticky) res.getSessionProperty(key);

+ *             if (v == null) {

+ *                 v = new com.example.acme.Sticky();

+ *                 res.setSessionProperty(key, v);

+ *             }

+ *         } catch (CoreException e) {

+ *             // unable to access session property - ignore

+ *         }

+ *         return v;

+ *     }

+ * }

+ * Platform.getAdapterManager().registerAdapters(pr, IResource.class);

+</pre>

+ * </p>

+ * <p>

+ * This interface is not intended to be implemented by clients.

+ * </p>

+ *

+ * @see IAdaptable

+ * @see IAdapterFactory

+ */

+public interface IAdapterManager {

+/**

+ * Returns an object which is an instance of the given class

+ * associated with the given object. Returns <code>null</code> if

+ * no such object can be found.

+ *

+ * @param adaptable the adaptable object being queried

+ *   (usually an instance of <code>IAdaptable</code>)

+ * @param adapterType the type of adapter to look up

+ * @return a object castable to the given adapter type, 

+ *    or <code>null</code> if the given adaptable object does not

+ *    have an adapter of the given type

+ */

+public Object getAdapter(Object adaptable, Class adapterType);

+/**

+ * Registers the given adapter factory as extending objects of

+ * the given type.

+ * <p>

+ * If the type being extended is a class,

+ * the given factory's adapters are available on instances

+ * of that class and any of its subclasses.  If it is an interface, 

+ * the adapters are available to all classes that directly 

+ * or indirectly implement that interface.

+ * </p>

+ *

+ * @param factory the adapter factory

+ * @param adaptable the type being extended

+ * @see #unregisterAdapters

+ */

+public void registerAdapters(IAdapterFactory factory, Class adaptable);

+/**

+ * Removes the given adapter factory completely from the list of 

+ * registered factories. Equivalent to calling

+ * <code>unregisterAdapters(IAdapterFactory,Class)</code>

+ * on all classes against which it had been explicitly registered.

+ * Does nothing if the given factory is not currently registered.

+ *

+ * @param factory the adapter factory to remove

+ * @see #registerAdapters

+ */

+public void unregisterAdapters(IAdapterFactory factory);

+/**

+ * Removes the given adapter factory from the list of factories

+ * registered as extending the given class.

+ * Does nothing if the given factory and type combination is not

+ * registered.

+ *

+ * @param factory the adapter factory to remove

+ * @param adaptable one of the types against which the given

+ *    factory is registered

+ * @see #registerAdapters

+ */

+public void unregisterAdapters(IAdapterFactory factory, Class adaptable);

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IConfigurationElement.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IConfigurationElement.java
new file mode 100644
index 0000000..9a9423f
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IConfigurationElement.java
@@ -0,0 +1,203 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * A configuration element, with its attributes and children, 

+ * directly reflects the content and structure of the extension section

+ * within the declaring plug-in's manifest (<code>plugin.xml</code>) file.

+ * <p>

+ * This interface also provides a way to create executable extension

+ * objects.

+ * </p>

+ * <p>

+ * This interface is not intended to be implemented by clients.

+ * </p>

+ */

+public interface IConfigurationElement {

+/**

+ * Creates and returns a new instance of the executable extension 

+ * identified by the named attribute of this configuration element.

+ * The named attribute value must contain a fully qualified name

+ * of a Java class implementing the executable extension.

+ * <p>

+ * The specified class is instantiated using its 0-argument public 

+ * constructor. If the specified class implements the

+ * <code>IExecutableExtension</code> interface, the method

+ * <code>setInitializationData</code> is called, passing to the object

+ * the configuration information that was used to create it. 

+ * </p>

+ * <p>

+ * Unlike other methods on this object, invoking this method may activate 

+ * the plug-in.

+ * </p>

+ *

+ * @param propertyName the name of the property

+ * @return the executable instance

+ * @exception CoreException if an instance of the executable extension

+ *   could not be created for any reason.

+ * @see IExecutableExtension#setInitializationData

+ */

+public Object createExecutableExtension(String propertyName) throws CoreException;

+/**

+ * Returns the named attribute of this configuration element, or

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

+ * <p>

+ * The names of configuration element attributes

+ * are the same as the attribute names of the corresponding XML element.

+ * For example, the configuration markup 

+ * <pre>

+ * &lt;bg pattern="stripes"/&gt;

+ * </pre>

+ * corresponds to a configuration element named <code>"bg"</code>

+ * with an attribute named <code>"pattern"</code>

+ * with attribute value <code>"stripes"</code>.

+ * </p>

+ * <p> Note that any translation specified in the plug-in manifest

+ * file is automatically applied.

+ * </p>

+ *

+ * @see IPluginDescriptor#getResourceString 

+ *

+ * @param name the name of the attribute

+ * @return attribute value, or <code>null</code> if none

+ */

+public String getAttribute(String name);

+/**

+ * Returns the named attribute of this configuration element, or

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

+ * <p>

+ * The names of configuration element attributes

+ * are the same as the attribute names of the corresponding XML element.

+ * For example, the configuration markup 

+ * <pre>

+ * &lt;bg pattern="stripes"/&gt;

+ * </pre>

+ * corresponds to a configuration element named <code>"bg"</code>

+ * with an attribute named <code>"pattern"</code>

+ * with attribute value <code>"stripes"</code>.

+ * </p>

+ * <p>

+ * Note that any translation specified in the plug-in manifest

+ * file for this attribute is <b>not</b> automatically applied.

+ * </p>

+ *

+ * @param name the name of the attribute

+ * @return attribute value, or <code>null</code> if none

+ */

+public String getAttributeAsIs(String name);

+/**

+ * Returns the names of the attributes of this configuration element.

+ * Returns an empty array if this configuration element has no attributes.

+ * <p>

+ * The names of configuration element attributes

+ * are the same as the attribute names of the corresponding XML element.

+ * For example, the configuration markup 

+ * <pre>

+ * &lt;bg color="blue" pattern="stripes"/&gt;

+ * </pre>

+ * corresponds to a configuration element named <code>"bg"</code>

+ * with attributes named <code>"color"</code>

+ * and <code>"pattern"</code>.

+ * </p>

+ *

+ * @return the names of the attributes 

+ */

+public String[] getAttributeNames();

+/**

+ * Returns all configuration elements that are children of this

+ * configuration element. 

+ * Returns an empty array if this configuration element has no children.

+ * <p>

+ * Each child corresponds to a nested

+ * XML element in the configuration markup.

+ * For example, the configuration markup 

+ * <pre>

+ * &lt;view&gt;

+ * &nbsp&nbsp&nbsp&nbsp&lt;verticalHint&gt;top&lt;/verticalHint&gt;

+ * &nbsp&nbsp&nbsp&nbsp&lt;horizontalHint&gt;left&lt;/horizontalHint&gt;

+ * &lt;/view&gt;

+ * </pre>

+ * corresponds to a configuration element, named <code>"view"</code>,

+ * with two children.

+ * </p>

+ *

+ * @return the child configuration elements

+ */

+public IConfigurationElement[] getChildren();

+/**

+ * Returns all child configuration elements with the given name. 

+ * Returns an empty array if this configuration element has no children

+ * with the given name.

+ *

+ * @param name the name of the child configuration element

+ * @return the child configuration elements with that name

+ * @see #getChildren

+ */

+public IConfigurationElement[] getChildren(String name);

+/** 

+ * Returns the extension that declares this configuration element.

+ *

+ * @return the extension

+ */

+public IExtension getDeclaringExtension();

+/**

+ * Returns the name of this configuration element. 

+ * The name of a configuration element is the same as

+ * the XML tag of the corresponding XML element. 

+ * For example, the configuration markup 

+ * <pre>

+ * &lt;wizard name="Create Project"/&gt; 

+ * </pre>

+ * corresponds to a configuration element named <code>"wizard"</code>.

+ *

+ * @return the name of this configuration element

+ */

+public String getName();

+/**

+ * Returns the text value of this configuration element.

+ * For example, the configuration markup 

+ * <pre>

+ * &lt;script lang="javascript"&gt;.\scripts\cp.js&lt;/script&gt;

+ * </pre>

+ * corresponds to a configuration element <code>"script"</code>

+ * with value <code>".\scripts\cp.js"</code>.

+ * <p> Values may span multiple lines (i.e., contain carriage returns

+ * and/or line feeds).

+ * <p> Note that any translation specified in the plug-in manifest

+ * file is automatically applied.

+ * </p>

+ *

+ * @see IPluginDescriptor#getResourceString 

+ *

+ * @return the text value of this configuration element or <code>null</code>

+ */

+public String getValue();

+/**

+ * Returns the untranslated text value of this configuration element.

+ * For example, the configuration markup 

+ * <pre>

+ * &lt;script lang="javascript"&gt;.\scripts\cp.js&lt;/script&gt;

+ * </pre>

+ * corresponds to a configuration element <code>"script"</code>

+ * with value <code>".\scripts\cp.js"</code>.

+ * <p> Values may span multiple lines (i.e., contain carriage returns

+ * and/or line feeds).

+ * <p>

+ * Note that translation specified in the plug-in manifest

+ * file is <b>not</b> automatically applied.

+ * For example, the configuration markup 

+ * <pre>

+ * &lt;tooltip&gt;#hattip&lt;/tooltip&gt;

+ * </pre>

+ * corresponds to a configuration element, named <code>"tooltip"</code>,

+ * with value <code>"#hattip"</code>.

+ * </p>

+ *

+ * @return the untranslated text value of this configuration element or <code>null</code>

+ */

+public String getValueAsIs();

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExecutableExtension.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExecutableExtension.java
new file mode 100644
index 0000000..e5445da
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExecutableExtension.java
@@ -0,0 +1,113 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * Interface for executable extension classes that require access to 

+ * their configuration element, or implement an extension adapter.

+ * <p>

+ * Extension adapters are typically required in cases where the extension

+ * implementation does not follow the interface rules specified

+ * by the provider of the extension point. In these

+ * cases, the role of the adapter is to map between the extension point

+ * interface, and the actual extension implementation. In general, adapters

+ * are used when attempting to plug-in existing Java implementations, or

+ * non-Java implementations (e.g., external executables).

+ * </p>

+ * <p>

+ * Clients may implement this interface.

+ * </p>

+ * 

+ * @see IConfigurationElement#createExecutableExtension 

+ */

+public interface IExecutableExtension {

+/**

+ * This method is called by the implementation of the method

+ * <code>IConfigurationElement.createExecutableExtension</code>

+ * on a newly constructed extension, passing it its relevant configuration 

+ * information. Most executable extensions only make use of the first 

+ * two call arguments.

+ * <p>

+ * Regular executable extensions specify their Java implementation 

+ * class name as an attribute of the configuration element for the 

+ * extension. For example

+ * <pre>

+ *     &lt;action run="com.example.BaseAction"/&gt;

+ * </pre>

+ * In the above example, this method would be called with a reference

+ * to the <code>&lt;action&gt;</code> element (first argument), and

+ * <code>"run"</code> as the name of the attribute that defined

+ * this executable extension (second argument).

+ * </p>

+ * <p>

+ * The last parameter is for the specific use of extension adapters

+ * and is typically not used by regular executable extensions.

+ * </p>

+ * <p>

+ * There are two supported ways of associating additional

+ * adapter-specific data with the configuration in a way that

+ * is transparent to the extension point implementor:

+ * </p>

+ * <p>

+ * (1) by specifying adapter data as part of the implementation

+ * class attribute value. The Java class name can be followed

+ * by a ":" separator, followed by any adapter data in string

+ * form. For example, if the extension point specifies an attribute

+ * <code>"run"</code> to contain the name of the extension implementation,

+ * an adapter can be configured as

+ * <pre>

+ *     &lt;action run="com.example.ExternalAdapter:./cmds/util.exe -opt 3"/&gt;

+ * </pre>

+ * </p>

+ * <p>

+ * (2) by converting the attribute used to specify the executable

+ * extension to a child element of the original configuration element,

+ * and specifying the adapter data in the form of xml markup.

+ * Using this form, the example above would become

+ * <pre>

+ *     &lt;action&gt;

+ *         &lt;<it>run</it> class="com.xyz.ExternalAdapter"&gt;

+ *             &lt;parameter name="exec" value="./cmds/util.exe"/&gt;

+ *             &lt;parameter name="opt"  value="3"/&gt;

+ *         &lt;/<it>run</it>&gt;

+ *     &lt;/action&gt;

+ * </pre>

+ * </p>

+ * <p>

+ * Form (2) will typically only be

+ * used for extension points that anticipate the majority of

+ * extensions configured into it will in fact be in the form

+ * of adapters.

+ * </p>

+ * <p>

+ * In either case, the specified adapter class is instantiated using its

+ * 0-argument public constructor. The adapter data is passed as the

+ * last argument of this method. The data argument is defined as Object.

+ * It can have the following values:

+ * <ul>

+ * <li><code>null</code>, if no adapter data was supplied</li>

+ * <li>in case (1), the initialization data

+ *		string is passed as a <code>String</code></li>

+ * <li>in case (2), the initialization data is passed

+ *		as a <code>Hashtable</code> containing the actual

+ *		parameter names and values (both <code>String</code>s)</li>

+ * </ul>

+ * </p>

+ *

+ * @param config the configuration element used to trigger this execution. 

+ *		It can be queried by the executable extension for specific

+ *		configuration properties

+ * @param propertyName the name of an attribute of the configuration element

+ *		used on the <code>createExecutableExtension(String)</code> call. This

+ *		argument can be used in the cases where a single configuration element

+ *		is used to define multiple executable extensions.

+ * @param data adapter data in the form of a <code>String</code>, 

+ *		a <code>Hashtable</code>, or <code>null</code>.

+ * @exception CoreException if error(s) detected during initialization processing

+ * @see IConfigurationElement#createExecutableExtension

+ */

+public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException;

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExtension.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExtension.java
new file mode 100644
index 0000000..3fb6469
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExtension.java
@@ -0,0 +1,77 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An extension declared in a plug-in.

+ * All information is obtained from the declaring plug-in's 

+ * manifest (<code>plugin.xml</code>) file. 

+ * <p>

+ * This interface is not intended to be implemented by clients.

+ * </p>

+ */

+public interface IExtension {

+/**

+ * Returns all configuration elements declared by this extension.

+ * These elements are a direct reflection of the configuration 

+ * markup supplied in the manifest (<code>plugin.xml</code>)

+ * file for the plug-in that declares this extension.

+ * Returns an empty array if this extension does not declare any

+ * configuration elements.

+ *

+ * @return the configuration elements declared by this extension 

+ */

+public IConfigurationElement[] getConfigurationElements();

+/** 

+ * Returns the descriptor of the plug-in that declares this extension.

+ *

+ * @return the plug-in that declares this extension

+ */

+public IPluginDescriptor getDeclaringPluginDescriptor();

+/**

+ * Returns the unique identifier of the extension point

+ * that this extension gets plugged into.

+ *

+ * @return the unique identifier of the relevant extension point

+ */

+public String getExtensionPointUniqueIdentifier();

+/**

+ * Returns a displayable label for this extension.

+ * Returns the empty string if no label for this extension

+ * is specified in the plug-in manifest file.

+ * <p> Note that any translation specified in the plug-in manifest

+ * file is automatically applied.

+ * <p>

+ *

+ * @see IPluginDescriptor#getResourceString 

+ *

+ * @return a displayable string label for this extension,

+ *    possibly the empty string

+ */

+public String getLabel();

+/**

+ * Returns the simple identifier of this extension, or <code>null</code>

+ * if this extension does not have an identifier.

+ * This identifier is specified in the plug-in manifest (<code>plugin.xml</code>) 

+ * file as a non-empty string containing no period characters 

+ * (<code>'.'</code>) and must be unique within the defining plug-in.

+ *

+ * @return the simple identifier of the extension (e.g. <code>"main"</code>)

+ *  or <code>null</code>

+ */

+public String getSimpleIdentifier();

+/**

+ * Returns the unique identifier of this extension, or <code>null</code>

+ * if this extension does not have an identifier.

+ * If available, this identifier is unique within the plug-in registry, and

+ * is composed of the identifier of the plug-in that declared

+ * this extension and this extension's simple identifier.

+ *

+ * @return the unique identifier of the extension

+ *    (e.g. <code>"com.example.acme.main"</code>), or <code>null</code>

+ */

+public String getUniqueIdentifier();

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExtensionPoint.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExtensionPoint.java
new file mode 100644
index 0000000..fa11bc7
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IExtensionPoint.java
@@ -0,0 +1,95 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An extension point declared in a plug-in.

+ * Except for the list of extensions plugged in to it, the information 

+ * available for an extension point is obtained from the declaring plug-in's 

+ * manifest (<code>plugin.xml</code>) file.

+ * <p>

+ * This interface is not intended to be implemented by clients.

+ * </p>

+ */

+public interface IExtensionPoint {

+/**

+ * Returns all configuration elements from all extensions configured

+ * into this extension point. Returns an empty array if this extension 

+ * point has no extensions configured, or none of the extensions 

+ * contain configuration elements.

+ *

+ * @return the configuration elements for all extension configured 

+ *   into this extension point

+ */

+public IConfigurationElement[] getConfigurationElements();

+/** 

+ * Returns the descriptor of the plug-in that declares this extension point.

+ *

+ * @return the plug-in that declares this extension point

+ */

+public IPluginDescriptor getDeclaringPluginDescriptor();

+/**

+ * Returns the extension with the given unique identifier configured into

+ * this extension point, or <code>null</code> if there is no such extension.

+ * Since an extension might not have an identifier, some extensions

+ * can only be found via the <code>getExtensions</code> method.

+ *

+ * @param extensionId the unique identifier of an extension 

+ *		(e.g. <code>"com.example.acme.main"</code>).

+ * @return an extension, or <code>null</code>

+ */

+public IExtension getExtension(String extensionId) ;

+/**

+ * Returns all extensions configured into this extension point.

+ * Returns an empty array if this extension point has no extensions.

+ *

+ * @return the extensions configured into this extension point

+ */

+public IExtension[] getExtensions();

+/**

+ * Returns a displayable label for this extension point.

+ * Returns the empty string if no label for this extension point

+ * is specified in the plug-in manifest file.

+ * <p> Note that any translation specified in the plug-in manifest

+ * file is automatically applied.

+ * </p>

+ *

+ * @return a displayable string label for this extension point,

+ *    possibly the empty string

+ * @see IPluginDescriptor#getResourceString 

+ */

+public String getLabel();

+/**

+ * Returns reference to the extension point schema. The schema 

+ * reference is returned as a URL path relative to the plug-in 

+ * installation URL. 

+ * Returns the empty string if no schema for this extension point

+ * is specified in the plug-in manifest file.

+ *

+ * @return a relative URL path, or an empty string

+ * @see IPluginDescriptor#getInstallURL

+ */

+public String getSchemaReference();

+/**

+ * Returns the simple identifier of this extension point.

+ * This identifier is a non-empty string containing no

+ * period characters (<code>'.'</code>) and is guaranteed

+ * to be unique within the defining plug-in.

+ *

+ * @return the simple identifier of the extension point (e.g. <code>"builders"</code>)

+ */

+public String getSimpleIdentifier();

+/**

+ * Returns the unique identifier of this extension point.

+ * This identifier is unique within the plug-in registry, and

+ * is composed of the identifier of the plug-in that declared

+ * this extension point and this extension point's simple identifier.

+ *

+ * @return the unique identifier of the extension point

+ *    (e.g. <code>"org.eclipse.core.resources.builders"</code>)

+ */

+public String getUniqueIdentifier();

+}

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
new file mode 100644
index 0000000..2518f30
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILibrary.java
@@ -0,0 +1,85 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+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> and

+ * <code>RESOURCE</code>.  

+ * </p>

+ * <p>

+ * This interface is not intended to be implemented by clients.

+ * </p>

+ *

+ * @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;

+	

+/**

+ * Returns the content filters, or <code>null</code>.

+ * Each content filter identifies a specific class, or

+ * a group of classes, using a notation and matching rules

+ * equivalent to Java <code>import</code> declarations

+ * (e.g., "java.io.File", or "java.io.*"). Returns <code>null</code>

+ * if the library is not exported, or it is fully exported

+ * (no filtering).

+ *

+ * @return the content filters, or <code>null</codel> if none

+ */

+public String[] getContentFilters();

+/**

+ * Returns the path of this runtime library, relative to the

+ * installation location.

+ *

+ * @return the path of the library

+ * @see IPluginDescriptor#getInstallURL

+ */

+public IPath getPath();

+/**

+ * Returns this library's type.

+ *

+ * @return the type of this library.   The valid types are: <code>CODE</code> and <code>RESOURCE</code>.

+ * @see #CODE

+ * @see #RESOURCE

+ */

+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.

+ * Libraries that are not exported are entirely private to the declaring

+ * plug-in.

+ *

+ * @return <code>true</code> if the library is exported, <code>false</code>

+ *    if it is private

+ */

+public boolean isExported();

+/**

+ * Returns whether this library is fully exported. A library is considered

+ * fully exported iff it is exported and has no content filters.

+ *

+ * @return <code>true</code> if the library is fully exported, and

+ *    <code>false</code> if it is private or has filtered content

+ */

+public boolean isFullyExported();

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILog.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILog.java
new file mode 100644
index 0000000..3f83326
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILog.java
@@ -0,0 +1,47 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * A log to which status events can be written.  Logs appear on individual

+ * plug-ins and on the platform itself.  Clients can register log listeners which

+ * will receive notification of all log events as the come in.

+ * <p>

+ * This interface is not intended to be implemented by clients.

+ * </p>

+ */

+public interface ILog {

+/**

+ * Adds the given log listener to this log.  Subsequently the log listener will

+ * receive notification of all log events passing through this log.

+ * This method has no affect if the identical listener is already registered on this log.

+ *

+ * @param listener the listener to add to this log

+ * @see Platform#addLogListener

+ */

+public void addLogListener(ILogListener listener);

+/**

+ * Returns the plug-in with which this log is associated.

+ *

+ * @return the plug-in with which this log is associated

+ */

+public Plugin getPlugin();

+/**

+ * Logs the given status.  The status is distributed to the log listeners

+ * installed on this log and then to the log listeners installed on the platform.

+ *

+ * @param status the status to log

+ */

+public void log(IStatus status);

+/**

+ * Removes the given log listener to this log.  Subsequently the log listener will

+ * no longer receive notification of log events passing through this log.  

+ * This method has no affect if the identical listener is not registered on this log.

+ *

+ * @see Platform#removeLogListener

+ */

+public void removeLogListener(ILogListener listener);

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILogListener.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILogListener.java
new file mode 100644
index 0000000..40b3f0a
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ILogListener.java
@@ -0,0 +1,28 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.util.EventListener;

+

+/**

+ * A log listener is notified of entries added to a plug-in's log.

+ * <p>

+ * Clients may implement this interface.

+ * </p>

+ *

+ * @see ILog#addLogListener

+ * @see Platform#addLogListener

+ */

+public interface ILogListener extends EventListener {

+/**

+ * Notifies this listener that given status has been logged by

+ * a plug-in.  The listener is free to retain or ignore this status.

+ * 

+ * @param status the status being logged

+ * @param plugin the plugin of the log which generated this event

+ */

+public void logging(IStatus status, String plugin);

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPath.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPath.java
new file mode 100644
index 0000000..2ae456c
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPath.java
@@ -0,0 +1,449 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.io.File;

+

+/**

+ * A path is an ordered collection of string segments,

+ * separated by a standard separator character, "/".

+ * A path may also have a leading and/or a trailing separator.

+ * Paths also be prefixed by an optional device id, which includes

+ * the character(s) which separate the device id from the rest 

+ * of the path. For example, "C:" and "Server/Volume:" are typical

+ * device ids.

+ * A device independent path has <code>null</code> for a device id.

+ * <p>

+ * Note that paths are value objects; all operations on paths 

+ * return a new path; the receiver is unscathed.

+ * </p>

+ * <p>

+ * UNC paths are denoted by leading double-slashes such 

+ * as <code>//Server/Volume/My/Path</code>. When a new path

+ * is constructed all double-slashes are removed except those

+ * appearing at the beginning of the path.

+ * </p>

+ * <p>

+ * This interface is not intended to be implemented by clients.

+ * </p>

+ * 

+ * @see Path

+ */

+public interface IPath extends Cloneable {

+

+	/**

+	 * Path separator character constant "/" used in paths.

+	 */

+	public static final char SEPARATOR = '/';

+	

+	/** 

+	 * Device separator character constant ":" used in paths.

+	 */

+	public static final char DEVICE_SEPARATOR = ':';

+/**

+ * Returns a new path which is the same as this path but with

+ * the given file extension added.  If this path is empty, root or has a 

+ * trailing separator, this path is returned.  If this path already

+ * has an extension, the existing extension is left and the given

+ * extension simply appended.  Clients wishing to replace

+ * the current extension should first remove the extension and

+ * then add the desired one.

+ * <p>

+ * The file extension portion is defined as the string

+ * following the last period (".") character in the last segment.

+ * The given extension should not include a leading ".".

+ * </p>

+ *

+ * @param extension the file extension to append

+ * @return the new path

+ */

+public IPath addFileExtension(String extension);

+/**

+ * Returns a path with the same segments as this path

+ * but with a trailing separator added.

+ * This path must have at least one segment.

+ * <p>

+ * If this path already has a trailing separator,

+ * this path is returned.

+ * </p>

+ *

+ * @return the new path

+ * @see #hasTrailingSeparator

+ * @see #removeTrailingSeparator

+ */

+public IPath addTrailingSeparator();

+/**

+ * Returns the canonicalized path obtained from the

+ * concatenation of the given string path to the

+ * end of this path. The given string path must be a valid

+ * path. If it has a trailing separator, 

+ * the result will have a trailing separator.

+ * The device id of this path is preserved (the one

+ * of the given string is ignored). Duplicate slashes

+ * are removed from the path except at the beginning

+ * where the path is considered to be UNC.

+ * 

+ * @param path the string path to concatenate

+ * @return the new path

+ * @see #isValidPath 

+ */

+public IPath append(String path);

+/**

+ * Returns the canonicalized path obtained from the 

+ * concatenation of the given path's segments to the

+ * end of this path.  If the given path has a trailing

+ * separator, the result will have a trailing separator.

+ * The device id of this path is preserved (the one

+ * of the given path is ignored). Duplicate slashes

+ * are removed from the path except at the beginning

+ * where the path is considered to be UNC.

+ *

+ * @param path the path to concatenate

+ * @return the new path

+ */

+public IPath append(IPath path);

+/**

+ * Returns a copy of this path.

+ *

+ * @return the cloned path

+ */

+public Object clone();

+/**

+ * Returns whether this path equals the given object.

+ * <p>

+ * Equality for paths is defined to be: same sequence of segments,

+ * same absolute/relative status, and same device.

+ * Trailing separators are disregarded.

+ * Paths are not generally considered equal to objects other than paths.

+ * </p>

+ *

+ * @param obj the other object

+ * @return <code>true</code> if the paths are equivalent,

+ *    and <code>false</code> if they are not

+ */

+public boolean equals(Object obj);

+/**

+ * Returns the device id for this path, or <code>null</code> if this

+ * path has no device id. Note that the result will end in ':'.

+ *

+ * @return the device id, or <code>null</code>

+ * @see #setDevice

+ */

+public String getDevice();

+/**

+ * Returns the file extension portion of this path, 

+ * or <code>null</code> if there is none.

+ * <p>

+ * The file extension portion is defined as the string

+ * following the last period (".") character in the last segment.

+ * If there is no period in the last segment, the path has no

+ * file extension portion. If the last segment ends in a period,

+ * the file extension portion is the empty string.

+ * </p>

+ *

+ * @return the file extension or <code>null</code>

+ */

+public String getFileExtension();

+/**

+ * Returns whether this path has a trailing separator.

+ * <p>

+ * Note: In the root path ("/"), the separator is considered to

+ * be leading rather than trailing.

+ * </p>

+ *

+ * @return <code>true</code> if this path has a trailing

+ *    separator, and <code>false</code> otherwise

+ * @see #addTrailingSeparator

+ * @see #removeTrailingSeparator

+ */

+public boolean hasTrailingSeparator();

+/**

+ * Returns whether this path is an absolute path (ignoring

+ * any device id).

+ * <p>

+ * Absolute paths start with a path separator.

+ * A root path, like <code>/</code> or <code>C:/</code>, 

+ * is considered absolute.

+ * </p>

+ *

+ * @return <code>true</code> if this path is an absolute path,

+ *    and <code>false</code> otherwise

+ */

+public boolean isAbsolute();

+/**

+ * Returns whether this path has no segments and is not

+ * a root path.

+ *

+ * @return <code>true</code> if this path is empty,

+ *    and <code>false</code> otherwise

+ */

+public boolean isEmpty();

+/**

+ * Returns whether this path is a prefix of the given path.

+ * To be a prefix, this path's segments must

+ * appear in the argument path in the same order,

+ * and their device ids must match.

+ * <p>

+ * Modulo device ids, an empty path is a prefix of all paths;

+ * a root path is a prefix of all absolute paths.

+ * </p>

+ *

+ * @param anotherPath the other path

+ * @return <code>true</code> if this path is a prefix of the given path,

+ *    and <code>false</code> otherwise

+ */

+public boolean isPrefixOf(IPath anotherPath);

+/**

+ * Returns whether this path is a root path.

+ * <p>

+ * The root path is the absolute path with zero segments; 

+ * e.g., <code>/</code> or <code>C:/</code>.

+ * The separator is considered a leading separator, not a trailing one.

+ * </p>

+ *

+ * @return <code>true</code> if this path is a root path,

+ *    and <code>false</code> otherwise

+ */

+public boolean isRoot();

+/**

+ * Returns a boolean value indicating whether or not this path

+ * is considered to be in UNC form. Return false if this path

+ * has a device set or if the first 2 characters of the path string

+ * are not <code>Path.SEPARATOR</code>.

+ * 

+ * @return boolean indicating if this path is UNC

+ */

+public boolean isUNC();

+/**

+ * Returns whether the given string is syntactically correct as

+ * a path.  The device id is the prefix up to and including the first ":";

+ * the path proper is everything to the right of it, or the entire string

+ * if there is no ":". The device id is not checked for validity;

+ * the path proper is correct if each of the segments in its canonicalized

+ * form is valid.

+ *

+ * @return <code>true</code> if the given string is a valid path,

+ *    and <code>false</code> otherwise

+ * @see #isValidSegment

+ */

+public boolean isValidPath(String path);

+/**

+ * Returns whether the given string is valid as a segment in 

+ * a path. The rules for valid segments are as follows:

+ * <ul>

+ * <li> the empty string is not valid

+ * <li> any string containing the colon character (":") is not valid

+ * <li> any string containing the slash character ("/") is not valid

+ * <li> any string containing the backslash character ("\") is not valid

+ * <li> any string starting or ending with a whitespace character is not valid

+ * <li> all other strings are valid

+ * </ul>

+ *

+ * @param segment the path segment to check

+ * @return <code>true</code> if the given path segment is valid,

+ *    and <code>false</code> otherwise

+ * @see java.lang.Character#isWhitespace

+ */

+public boolean isValidSegment(String segment);

+/**

+ * Returns the last segment of this path, or

+ * <code>null</code> if it does not have any segments.

+ *

+ * @return the last segment of this path, or <code>null</code> 

+ */

+public String lastSegment();

+/**

+ * Returns an absolute path with the segments and device id of this path.

+ * If this path is absolute, it is simply returned.

+ *

+ * @return the new path

+ */

+public IPath makeAbsolute();

+/**

+ * Returns a relative path with the segments and device id of this path.

+ * If this path is relative, it is simply returned.

+ *

+ * @return the new path

+ */

+public IPath makeRelative();

+/**

+ * Return a new path which is the equivalent of this path converted to UNC

+ * form (if the given boolean is true) or this path not as a UNC path (if the given

+ * boolean is false). If UNC, the returned path will not have a device and the 

+ * first 2 characters of the path string will be <code>Path.SEPARATOR</code>. If not UNC, the

+ * 	first 2 characters of the returned path string will not be <code>Path.SEPARATOR</code>.

+ * 

+ * @param toUNC true if converting to UNC, false otherwise

+ * @return the new path, either in UNC form or not depending on the boolean parm

+ */

+public IPath makeUNC(boolean toUNC);

+/**

+ * Returns a count of the number of segments which match in

+ * this path and the given path (device ids are ignored),

+ * comparing in increasing segment number order.

+ *

+ * @param anotherPath the other path

+ * @return the number of matching segments

+ */

+public int matchingFirstSegments(IPath anotherPath);

+/**

+ * Returns a new path which is the same as this path but with

+ * the file extension removed.  If this path does not have an 

+ * extension, this path is returned.

+ * <p>

+ * The file extension portion is defined as the string

+ * following the last period (".") character in the last segment.

+ * If there is no period in the last segment, the path has no

+ * file extension portion. If the last segment ends in a period,

+ * the file extension portion is the empty string.

+ * </p>

+ *

+ * @return the new path

+ */

+public IPath removeFileExtension();

+/**

+ * Returns a copy of this path with the given number of segments

+ * removed from the beginning. The device id is preserved. 

+ * The number must be greater or equal zero.

+ * If the count is zero, this path is returned.

+ * The resulting path will always be a relative path with respect

+ * to this path.  If the number equals or exceeds the number

+ * of segments in this path, an empty relative path is returned.

+ *

+ * @return the new path

+ */

+public IPath removeFirstSegments(int count);

+/**

+ * Returns a copy of this path with the given number of segments

+ * removed from the end. The device id is preserved.

+ * The number must be greater or equal zero.

+ * If the count is zero, this path is returned.

+ * <p>

+ * If this path has a trailing separator, it will still

+ * have a trailing separator after the last segments are removed

+ * (assuming there are some segments left).  If there is no

+ * trailing separator, the result will not have a trailing

+ * separator.

+ * If the number equals or exceeds the number

+ * of segments in this path, an empty path is returned.

+ * </p>

+ *

+ * @return the new path

+ */

+public IPath removeLastSegments(int count);

+/**

+ * Returns a path with the same segments as this path

+ * but with a trailing separator removed.

+ * Does nothing if this path does not have at least one segment.

+ * The device id is preserved.

+ * <p>

+ * If this path does not have a trailing separator,

+ * this path is returned.

+ * </p>

+ *

+ * @return the new path

+ * @see #addTrailingSeparator

+ * @see #hasTrailingSeparator

+ */

+public IPath removeTrailingSeparator();

+/**

+ * Returns the specified segment of this path, or

+ * <code>null</code> if the path does not have such a segment.

+ *

+ * @param index the 0-based segment index

+ * @return the specified segment, or <code>null</code> 

+ */

+public String segment(int index);

+/**

+ * Returns the number of segments in this path.

+ * <p> 

+ * Note that both root and empty paths have 0 segments.

+ * </p>

+ *

+ * @return the number of segments

+ */

+public int segmentCount();

+/**

+ * Returns the segments in this path in order.

+ *

+ * @return an array of string segments

+ */

+public String[] segments();

+/**

+ * Returns a new path which is the same as this path but with 

+ * the given device id.  The device id must end with a ":".

+ * A device independent path is obtained by passing <code>null</code>.

+ * <p>

+ * For example, "C:" and "Server/Volume:" are typical device ids.

+ * </p>

+ *

+ * @param device the device id or <code>null</code>

+ * @return a new path

+ * @see #getDevice

+ */

+public IPath setDevice(String device);

+/**

+ * Returns a <code>java.io.File</code> corresponding to this path.

+ *

+ * @return the file corresponding to this path

+ */

+public java.io.File toFile();

+/**

+ * Returns a string representation of this path which uses the

+ * platform-dependent path separator defined by <code>java.io.File</code>.

+ * This method is like <code>toString()</code> except that the

+ * latter always uses the same separator (<code>/</code>) regardless of platform.

+ * <p>

+ * This string is suitable for passing to <code>java.io.File(String)</code>.

+ * </p>

+ *

+ * @return a platform-dependent string representation of this path

+ */

+public String toOSString();

+/**

+ * Returns a string representation of this path, including its

+ * device id.  The same separator, "/", is used on all platforms.

+ * <p>

+ * Example result strings (without and with device id):

+ * <pre>

+ * "/foo/bar.txt"

+ * "bar.txt"

+ * "/foo/"

+ * "foo/"

+ * ""

+ * "/"

+ * "C:/foo/bar.txt"

+ * "C:bar.txt"

+ * "C:/foo/"

+ * "C:foo/"

+ * "C:"

+ * "C:/"

+ * </pre>

+ * This string is suitable for passing to <code>Path(String)</code>.

+ * </p>

+ *

+ * @return a string representation of this path

+ * @see Path

+ */

+public String toString();

+/**

+ * Returns a copy of this path truncated after the

+ * given number of segments. The number must not be negative.

+ * The device id is preserved.

+ * <p>

+ * If this path has a trailing separator, the result will too

+ * (assuming there are some segments left). If there is no

+ * trailing separator, the result will not have a trailing

+ * separator.

+ * Copying up to segment zero simply means making an copy with

+ * no path segments.

+ * </p>

+ *

+ * @param count the segment number at which to truncate the path

+ * @return the new path

+ */

+public IPath uptoSegment(int count);

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginDescriptor.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginDescriptor.java
new file mode 100644
index 0000000..aafde0b
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginDescriptor.java
@@ -0,0 +1,257 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.util.MissingResourceException;

+import java.util.ResourceBundle;

+import java.net.URL;

+

+/**

+ * A plug-in descriptor contains information about a plug-in

+ * obtained from the plug-in's manifest (<code>plugin.xml</code>) file.

+ * <p>

+ * Plug-in descriptors are platform-defined objects that exist

+ * in the plug-in registry independent of whether a plug-in has

+ * been started. In contrast, a plug-in's runtime object 

+ * (<code>getPlugin</code>) generally runs plug-in-defined code.

+ * </p>

+ * <p>

+ * This interface is not intended to be implemented by clients.

+ * </p>

+ *

+ * @see #getPlugin

+ */

+public interface IPluginDescriptor {

+/**

+ * Returns the extension with the given simple identifier declared in

+ * this plug-in, or <code>null</code> if there is no such extension.

+ * Since an extension might not have an identifier, some extensions

+ * can only be found via the <code>getExtensions</code> method.

+ *

+ * @param extensionName the simple identifier of the extension (e.g. <code>"main"</code>).

+ * @return the extension, or <code>null</code>

+ */

+public IExtension getExtension(String extensionName);

+/**

+ * Returns the extension point with the given simple identifier

+ * declared in this plug-in, or <code>null</code> if there is no such extension point.

+ *

+ * @param extensionPointId the simple identifier of the extension point (e.g. <code>"wizard"</code>).

+ * @return the extension point, or <code>null</code>

+ */

+public IExtensionPoint getExtensionPoint(String extensionPointId);

+/**

+ * Returns all extension points declared by this plug-in.

+ * Returns an empty array if this plug-in does not declare any extension points.

+ *

+ * @return the extension points declared by this plug-in

+ */

+public IExtensionPoint[] getExtensionPoints();

+/**

+ * Returns all extensions declared by this plug-in.

+ * Returns an empty array if this plug-in does not declare any extensions.

+ *

+ * @return the extensions declared by this plug-in

+ */

+public IExtension[] getExtensions();

+/**

+ * Returns the URL of this plug-in's install directory. 

+ * This is the directory containing

+ * the plug-in manifest file, resource bundle, runtime libraries,

+ * and any other files supplied with this plug-in.

+ *

+ * @return the URL of this plug-in's install directory

+ */

+public URL getInstallURL() ;

+/**

+ * Returns a displayable label for this plug-in.

+ * Returns the empty string if no label for this plug-in

+ * is specified in the plug-in manifest file.

+ * <p> Note that any translation specified in the plug-in manifest

+ * file is automatically applied.

+ * </p>

+ *

+ * @return a displayable string label for this plug-in,

+ *    possibly the empty string

+ * @see #getResourceString 

+ */

+public String getLabel();

+/**

+ * Returns the plug-in runtime object corresponding to this

+ * plug-in descriptor. Unlike other methods on this object,

+ * invoking this method may activate the plug-in.

+ * The returned object is an instance of the plug-in runtime class

+ * specified in the plug-in's manifest file;

+ * if a class is not specified there, the returned object

+ * is an internally-supplied one that does not react to life cycle requests.

+ *

+ * @return the plug-in runtime object

+ * @exception CoreException 

+ *   if this plug-in's runtime object could not be created.

+ * @see #isPluginActivated

+ */

+public Plugin getPlugin() throws CoreException;

+/**

+ * Returns the plug-in class loader used to load classes and resources

+ * for this plug-in. The class loader can be used to directly access

+ * plug-in resources and classes. Note that accessing a resource will

+ * <b>not activate</b> the corresponding plug-in. Successfully loading 

+ * a class will <b>always activate</b> the corresponding plug-in.

+ * <p> 

+ * The following examples illustrate the direct use of the plug-in class

+ * loader and its effect on plug-in activation (example ignores error

+ * handling).

+ *

+ * <pre>

+ *     ClassLoader loader = descriptor.getPluginClassLoader();

+ *

+ *     // Load resource by name. Will not activate the plug-in.

+ *     URL res = loader.getResource("com/example/Foo/button.gif");

+ *     InputStream is = loader.getResourceAsStream("splash.jpg");

+ *

+ *     // Load resource for class. Will activate the plug-in because

+ *     // the referenced class is loaded first and triggers activation.

+ *     URL u = com.example.Foo.class.getResource("button.gif");

+ *

+ *     // Load class by name. Will activate the plug-in.

+ *     Class c = loader.loadClass("com.example.Bar");

+ *

+ *     // Load a resource bundle. May, or may not activate the plug-in, depending

+ *     // on the bundle implementation. If implemented as a class, the plug-in

+ *     // will be activated. If implemented as a properties file, the plug-in will

+ *     // not be activated.

+ *     ResourceBundle b = 

+ *         ResourceBundle.getBundle("bundle", Locale.getDefault(), loader);

+ * </pre>

+ *

+ * @return the plug-in class loader

+ * @see IConfigurationElement#createExecutableExtension

+ * @see #isPluginActivated

+ * @see #getResourceBundle

+ */

+public ClassLoader getPluginClassLoader();

+ /**

+ * Returns a list of plug-in prerequisites required

+ * for correct execution of this plug-in.

+ *

+ * @return an array of plug-in prerequisites, or an empty array

+ * if no prerequisites were specified

+ */

+public IPluginPrerequisite[] getPluginPrerequisites() ;

+/**

+ * Returns the name of the provider of this plug-in.

+ * Returns the empty string if no provider name is specified in 

+ * the plug-in manifest file.

+ * <p> Note that any translation specified in the plug-in manifest

+ * file is automatically applied.

+ * </p>

+ *

+ * @see #getResourceString 

+ *

+ * @return the name of the provider, possibly the empty string

+ */

+public String getProviderName();

+/**

+ * Returns this plug-in's resource bundle for the current locale. 

+ * <p>

+ * The bundle is stored as the <code>plugin.properties</code> file 

+ * in the plug-in install directory, and contains any translatable

+ * strings used in the plug-in manifest file (<code>plugin.xml</code>)

+ * along with other resource strings used by the plug-in implementation.

+ * </p>

+ *

+ * @return the resource bundle

+ * @exception MissingResourceException if the resource bundle was not found

+ */

+public ResourceBundle getResourceBundle() throws MissingResourceException;

+/**

+ * Returns a resource string corresponding to the given argument value.

+ * If the argument value specifies a resource key, the string

+ * is looked up in the default resource bundle. If the argument does not

+ * specify a valid key, the argument itself is returned as the

+ * resource string. The key lookup is performed in the

+ * plugin.properties resource bundle. If a resource string 

+ * corresponding to the key is not found in the resource bundle

+ * the key value, or any default text following the key in the

+ * argument value is returned as the resource string.

+ * A key is identified as a string begining with the "%" character.

+ * Note, that the "%" character is stripped off prior to lookup

+ * in the resource bundle.

+ * <p>

+ * Equivalent to <code>getResourceString(value, getBundle())</code>

+ * </p>

+ *

+ * @param value the value

+ * @return the resource string

+ * @see #getResourceBundle

+ */

+public String getResourceString(String value);

+/**

+ * Returns a resource string corresponding to the given argument 

+ * value and bundle.

+ * If the argument value specifies a resource key, the string

+ * is looked up in the given resource bundle. If the argument does not

+ * specify a valid key, the argument itself is returned as the

+ * resource string. The key lookup is performed against the

+ * specified resource bundle. If a resource string 

+ * corresponding to the key is not found in the resource bundle

+ * the key value, or any default text following the key in the

+ * argument value is returned as the resource string.

+ * A key is identified as a string begining with the "%" character.

+ * Note that the "%" character is stripped off prior to lookup

+ * in the resource bundle.

+ * <p>

+ * For example, assume resource bundle plugin.properties contains

+ * name = Project Name

+ * <pre>

+ *     getResourceString("Hello World") returns "Hello World"</li>

+ *     getResourceString("%name") returns "Project Name"</li>

+ *     getResourceString("%name Hello World") returns "Project Name"</li>

+ *     getResourceString("%abcd Hello World") returns "Hello World"</li>

+ *     getResourceString("%abcd") returns "%abcd"</li>

+ *     getResourceString("%%name") returns "%name"</li>

+ * </pre>

+ * </p>

+ *

+ * @param value the value

+ * @param bundle the resource bundle

+ * @return the resource string

+ * @see #getResourceBundle

+ */

+public String getResourceString(String value, ResourceBundle bundle);

+/**

+ * Returns all runtime libraries declared by this plug-in.

+ * Returns an empty array if this plug-in has no runtime libraries.

+ *

+ * @return the runtime libraries declared by this plug-in

+ */

+public ILibrary[] getRuntimeLibraries();

+/**

+ * Returns the unique identifier of this plug-in.

+ * 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>"org.eclipse.core.runtime"</code>)

+ */

+public String getUniqueIdentifier();

+/**

+ * Returns the version identifier of this plug-in.

+ *

+ * @return the plug-in version identifier

+ */

+public PluginVersionIdentifier getVersionIdentifier();

+/**

+ * Returns whether the plug-in described by this descriptor

+ * has been activated. Invoking this method will not cause the

+ * plug-in to be activated.

+ *

+ * @return <code>true</code> if this plug-in is activated, and

+ *   <code>false</code> otherwise

+ * @see #getPlugin

+ */

+public boolean isPluginActivated();

+}

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
new file mode 100644
index 0000000..55fd77b
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginPrerequisite.java
@@ -0,0 +1,79 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * A prerequisite entry declared by a plug-in. The declaration causes

+ * classes defined by the prerequisite plug-in to be visible

+ * to the plug-in that declared the dependency.

+ * <p>

+ * This interface is not intended to be implemented by developers.

+ * </p>

+ *

+ * @see IPluginDescriptor#getPluginPrerequisites

+ */

+public interface IPluginPrerequisite {

+/**

+ * Returns the actual version identifier that is used

+ * at runtime to resolve this prerequisite dependency,

+ * or null, if the dependency is not resolved.

+ * 

+ * @return the plug-in version identifier, or null

+ */

+public PluginVersionIdentifier getResolvedVersionIdentifier();

+/**

+ * Returns the plug-in identifier of the prerequisite plug-in.

+ * 

+ * @return the plug-in identifier

+ */

+public String getUniqueIdentifier();

+/**

+ * Returns the version identifier of the prerequisite plug-in,

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

+ * 

+ * @return the plug-in version identifier, or <code>null</code> if 

+ *    none was specified

+ */

+public PluginVersionIdentifier getVersionIdentifier();

+/**

+ * Indicates whether this prerequisite plug-in is further exposed to any

+ * plug-ins that declare a dependency on this plug-in. This allows

+ * for chaining of dependencies. For example, if plug-in A depends

+ * on plug-in B which depends on plug-in C, the classes from C 

+ * are typically visible to B, but not to A.  A can get around this 

+ * if either B explicitly exports its dependency on C, or 

+ * A explicitly declares C as a prerequisite in addition to B.

+ * 

+ * @return <code>true</code> if this prerequisite plug-in is exposed,

+ *    <code>false</code> otherwise

+ */

+public boolean isExported();

+/**

+ * Indicates that this plug-in prerequisite can be resolved

+ * against a configured plug-in with a compatible identifier.

+ *

+ * @return <code>true</code> if compatible match is allowed,

+ *   <code>false</code> if exact match is required.

+ */

+public boolean isMatchedAsCompatible();

+/**

+ * Indicates that this plug-in prerequisite can only be resolved

+ * against a configured plug-in with exactly the same plug-in 

+ * identifier.

+ *

+ * @return <code>true</code> if only exact identifier match

+ * satisfies this dependency, <code>false</code> if compatible

+ * 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/IPluginRegistry.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginRegistry.java
new file mode 100644
index 0000000..a84ad3d
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IPluginRegistry.java
@@ -0,0 +1,157 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.net.URL;

+

+/**

+ * The plug-in registry holds the master list of all

+ * discovered plug-ins, extension points, and extensions.

+ * <p>

+ * The plug-in registry can be queried, by name, for 

+ * plug-ins, extension points, and extensions.

+ * </p>

+ * <p>

+ * This interface is not intended to be implemented by clients.

+ * </p>

+ */

+public interface IPluginRegistry {

+/**

+ * Returns all configuration elements from all extensions configured

+ * into the identified extension point. Returns an empty array if the extension 

+ * point does not exist, has no extensions configured, or none of the extensions 

+ * contain configuration elements.

+ *

+ * @param extensionPointId the unique identifier of the extension point

+ *		(e.g. <code>"org.eclipse.core.resources.builders"</code>)

+ * @return the configuration elements

+ */

+public IConfigurationElement[] getConfigurationElementsFor(String extensionPointId);

+/**

+ * Returns all configuration elements from all extensions configured

+ * into the identified extension point. Returns an empty array if the extension 

+ * point does not exist, has no extensions configured, or none of the extensions 

+ * contain configuration elements.

+ *

+ * @param pluginId the unique identifier of the plug-in 

+ *		(e.g. <code>"org.eclipse.core.resources"</code>)

+ * @param extensionPointName the simple identifier of the 

+ *		extension point (e.g. <code>"builders"</code>)

+ * @return the configuration elements

+ */

+public IConfigurationElement[] getConfigurationElementsFor(String pluginId, String extensionPointName);

+/**

+ * Returns all configuration elements from the identified extension.

+ * Returns an empty array if the extension does not exist or 

+ * contains no configuration elements.

+ *

+ * @param pluginId the unique identifier of the plug-in 

+ *		(e.g. <code>"org.eclipse.core.resources"</code>)

+ * @param extensionPointName the simple identifier of the 

+ *		extension point (e.g. <code>"builders"</code>)

+ * @param extensionId the unique identifier of the extension 

+ *		(e.g. <code>"com.example.acme.coolbuilder</code>)

+ * @return the configuration elements

+ */

+public IConfigurationElement[] getConfigurationElementsFor(String pluginId, String extensionPointName, String extensionId);

+/**

+ * Returns the specified extension in this plug-in registry, 

+ * or <code>null</code> if there is no such extension.

+ * The first parameter identifies the extension point, and the second

+ * parameter identifies an extension plugged in to that extension point.

+ *

+ * @param extensionPointId the unique identifier of the extension point

+ *		(e.g. <code>"org.eclipse.core.resources.builders"</code>)

+ * @param extensionId the unique identifier of the extension 

+ *		(e.g. <code>"com.example.acme.coolbuilder"</code>)

+ * @return the extension, or <code>null</code>

+ */

+public IExtension getExtension(String extensionPointId, String extensionId);

+/**

+ * Returns the specified extension in this plug-in registry, 

+ * or <code>null</code> if there is no such extension.

+ * The first two parameters identify the extension point, and the third

+ * parameter identifies an extension plugged in to that extension point.

+ *

+ * @param pluginId the unique identifier of the plug-in 

+ *		(e.g. <code>"org.eclipse.core.resources"</code>)

+ * @param extensionPointName the simple identifier of the 

+ *		extension point (e.g. <code>"builders"</code>)

+ * @param extensionId the unique identifier of the extension 

+ *		(e.g. <code>"com.example.acme.coolbuilder"</code>)

+ * @return the extension, or <code>null</code>

+ */

+public IExtension getExtension(String pluginId, String extensionPointName, String extensionId);

+/**

+ * Returns the extension point with the given extension point identifier

+ * in this plug-in registry, or <code>null</code> if there is no such

+ * extension point.

+ *

+ * @param extensionPointId the unique identifier of the extension point 

+ *    (e.g., <code>"org.eclipse.core.resources.builders"</code>)

+ * @return the extension point, or <code>null</code>

+ */

+public IExtensionPoint getExtensionPoint(String extensionPointId);

+/**

+ * Returns the extension point in this plug-in registry

+ * with the given plug-in identifier and extension point simple identifier,

+ * or <code>null</code> if there is no such extension point.

+ *

+ * @param pluginId the unique identifier of the plug-in 

+ *		(e.g. <code>"org.eclipse.core.resources"</code>)

+ * @param extensionPointName the simple identifier of the 

+ *		extension point (e.g. <code>" builders"</code>)

+ * @return the extension point, or <code>null</code>

+ */

+public IExtensionPoint getExtensionPoint(String pluginId, String extensionPointName);

+/**

+ * Returns all extension points known to this plug-in registry.

+ * Returns an empty array if there are no extension points.

+ *

+ * @return the extension points known to this plug-in registry

+ */

+public IExtensionPoint[] getExtensionPoints();

+/**

+ * 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,

+ * one will be non-deterministically choosen and returned.  

+ *

+ * @param pluginId the unique identifier of the plug-in 

+ *		(e.g. <code>"com.example.acme"</code>).

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

+ */

+public IPluginDescriptor getPluginDescriptor(String pluginId);

+/**

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

+ * and version in this plug-in registry, or <code>null</code> if 

+ * there is no such plug-in.

+ *

+ * @param pluginId the unique identifier of the plug-in 

+ *		(e.g. <code>"org.eclipse.core.resources"</code>).

+ * @param version plug-in version identifier

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

+ */

+public IPluginDescriptor getPluginDescriptor(String pluginId, PluginVersionIdentifier version);

+/**

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

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

+ *

+ * @return the plug-in descriptors known to this plug-in registry

+ */

+public IPluginDescriptor[] getPluginDescriptors();

+/**

+ * Returns all versions of the identified plug-in descriptor

+ * known to this plug-in registry.

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

+ * with the specified identifier.

+ *

+ * @param pluginId the unique identifier of the plug-in 

+ *		(e.g. <code>"org.eclipse.core.resources"</code>).

+ * @return the plug-in descriptors known to this plug-in registry

+ */

+public IPluginDescriptor[] getPluginDescriptors(String pluginId);

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IProgressMonitor.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IProgressMonitor.java
new file mode 100644
index 0000000..467fc36
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IProgressMonitor.java
@@ -0,0 +1,115 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * The <code>IProgressMonitor</code> interface is implemented

+ * by objects that monitor the progress of an activity; the methods

+ * in this interface are invoked by code that performs the activity.

+ * <p>

+ * All activity is broken down into a linear sequence of tasks against

+ * which progress is reported. When a task begins, a <code>beginTask(String, int)

+ * </code> notification is reported, followed by any number and mixture of 

+ * progress reports (<code>worked()</code>) and subtask notifications 

+ * (<code>subTask(String)</code>).  When the task is eventually completed, a 

+ * <code>done()</code> notification is reported.  After the <code>done()</code>

+ * notification, the progress monitor cannot be reused;  i.e., <code>

+ * beginTask(String, int)</code> cannot be called again after the call to 

+ * <code>done()</code>.

+ * </p>

+ * <p>

+ * A request to cancel an operation can be signaled using the 

+ * <code>setCanceled</code> method.  Operations taking a progress

+ * monitor are expected to poll the monitor (using <code>isCanceled</code>)

+ * periodically and abort at their earliest convenience.  Operation can however 

+ * choose to ignore cancelation requests.

+ * </p>

+ * <p>

+ * Since notification is synchronous with the activity itself, the listener should 

+ * provide a fast and robust implementation. If the handling of notifications would 

+ * involve blocking operations, or operations which might throw uncaught exceptions, 

+ * the notifications should be queued, and the actual processing deferred (or perhaps

+ * delegated to a separate thread).

+ * </p>

+ * <p>

+ * Clients may implement this interface.

+ * </p>

+ */

+public interface IProgressMonitor {

+

+	/** Constant indicating an unknown amount of work.

+	 */

+	public final static int UNKNOWN = -1;

+	

+/**

+ * Notifies that the main task is beginning.  This must only be called once

+ * on a given progress monitor instance.

+ * 

+ * @param name the name (or description) of the main task

+ * @param totalWork the total number of work units into which

+ *  the main task is been subdivided. If the value is <code>UNKNOWN</code> 

+ *  the implemenation is free to indicate progress in a way which 

+ *  doesn't require the total number of work units in advance.

+ */

+public void beginTask(String name, int totalWork);

+/**

+ * Notifies that the work is done; that is, either the main task is completed 

+ * or the user canceled it. This method may be called more than once 

+ * (implementations should be prepared to handle this case).

+ */

+public void done();

+/**

+ * Internal method to handle scaling correctly. This method

+ * must not be called by a client. Clients should 

+ * always use the method </code>worked(int)</code>.

+ */

+public void internalWorked(double work);

+/**

+ * Returns whether cancelation of current operation has been requested.

+ * Long-running operations should poll to see if cancelation

+ * has been requested.

+ *

+ * @return <code>true</code> if cancellation has been requested,

+ *    and <code>false</code> otherwise

+ * @see #setCanceled

+ */

+public boolean isCanceled();

+/**

+ * Sets the cancel state to the given value.

+ * 

+ * @param value <code>true</code> indicates that cancelation has

+ *     been requested (but not necessarily acknowledged);

+ *     <code>false</code> clears this flag

+ *

+ * @see #isCanceled

+ */

+public void setCanceled(boolean value);

+/**

+ * Sets the task name to the given value. This method is used to 

+ * restore the task label after a nested operation was executed. 

+ * Normally there is no need for clients to call this method.

+ *

+ * @param name the name (or description) of the main task

+ * @see #beginTask(java.lang.String, int)

+ */

+public void setTaskName(String name);

+/**

+ * Notifies that a subtask of the main task is beginning.

+ * Subtasks are optional; the main task might not have subtasks.

+ *

+ * @param name the name (or description) of the subtask

+ */

+public void subTask(String name);

+/**

+ * Notifies that a given number of work unit of the main task

+ * has been completed. Note that this amount represents an

+ * installment, as opposed to a cumulative amount of work done

+ * to date.

+ *

+ * @param work the number of work units just completed

+ */

+public void worked(int work);

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ISafeRunnable.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ISafeRunnable.java
new file mode 100644
index 0000000..c098b92
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ISafeRunnable.java
@@ -0,0 +1,42 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * Safe runnables represent blocks of code and associated exception

+ * handlers.  They are typically used when a plug-in needs to call some

+ * untrusted code (e.g., code contributed by another plug-in via an

+ * extension).

+* <p>

+ * Clients may implement this interface.

+ * </p>

+ * 

+ * @see Platform#run

+ */

+public interface ISafeRunnable {

+/**

+ * Handles an exception thrown by this runnable's <code>run</code>

+ * method.  The processing done here should be specific to the

+ * particular usecase for this runnable.  Generalized exception

+ * processing (e.g., logging in the platform's log) is done by the

+ * Platform's run mechanism.

+ *

+ * @param exception an exception which occurred during processing

+ *		the body of this runnable (i.e., in <code>run()</code>)

+ * @see Platform#run

+ */

+public void handleException(Throwable exception);

+/**

+ * Runs this runnable.  Any exceptions thrown from this method will

+ * be passed to this runnable's <code>handleException</code>

+ * method.

+ *

+ * @exception Exception if a problem occurred while running this method.

+ *		The exception will be processed by <code>handleException</code>

+ * @see Platform#run

+ */

+public void run() throws Exception;

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IStatus.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IStatus.java
new file mode 100644
index 0000000..8efcd52
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/IStatus.java
@@ -0,0 +1,158 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * A status object represents the outcome of an operation.

+ * All <code>CoreException</code>s carry a status object to indicate 

+ * what went wrong. Status objects are also returned by methods needing 

+ * to provide details of failures (e.g., validation methods).

+ * <p>

+ * A status carries the following information:

+ * <ul>

+ * <li> plug-in identifier (required)</li>

+ * <li> severity (required)</li>

+ * <li> status code (required)</li>

+ * <li> message (required) - localized to current locale</li>

+ * <li> exception (optional) - for problems stemming from a failure at

+ *    a lower level</li>

+ * </ul>

+ * Some status objects, known as multi-statuses, have other status objects 

+ * as children.

+ * </p>

+ * <p>

+ * The class <code>Status</code> is the standard public implementation

+ * of status objects; the subclass <code>MultiStatus</code> is the

+ * implements multi-status objects.

+ * </p>

+ * @see MultiStatus

+ * @see Status

+ */

+public interface IStatus {

+	

+	/** Status severity constant (value 0) indicating this status represents the nominal case.

+	 * This constant is also used as the status code representing the nominal case.

+	 * @see #getSeverity

+	 * @see #isOK

+ 	 */

+	public static final int OK = 0;

+

+	/** Status type severity (bit mask, value 1) indicating this status is informational only.

+	 * @see #getSeverity

+	 * @see #matches

+ 	 */

+	public static final int INFO = 1;

+

+	/** Status type severity (bit mask, value 2) indicating this status represents a warning.

+	 * @see #getSeverity

+	 * @see #matches

+ 	 */

+	public static final int WARNING = 2;

+

+	/** Status type severity (bit mask, value 4) indicating this status represents an error.

+	 * @see #getSeverity

+	 * @see #matches

+ 	 */

+	public static final int ERROR = 4;

+/**

+ * Returns a list of status object immediately contained in this

+ * multi-status, or an empty list if this is not a multi-status.

+ *

+ * @return an array of status objects

+ * @see #isMultiStatus

+ */

+public IStatus[] getChildren();

+/**

+ * Returns the plug-in-specific status code describing the outcome.

+ *

+ * @return plug-in-specific status code

+ */

+public int getCode();

+/**

+ * Returns the relevant low-level exception, or <code>null</code> if none. 

+ * For example, when an operation fails because of a network communications

+ * failure, this might return the <code>java.io.IOException</code>

+ * describing the exact nature of that failure.

+ *

+ * @return the relevant low-level exception, or <code>null</code> if none

+ */

+public Throwable getException();

+/**

+ * Returns the message describing the outcome.

+ * The message is localized to the current locale.

+ *

+ * @return a localized message

+ */

+public String getMessage();

+/**

+ * Returns the unique identifier of the plug-in associated with this status

+ * (this is the plug-in that defines the meaning of the status code).

+ *

+ * @return the unique identifier of the relevant plug-in

+ */

+public String getPlugin();

+/**

+ * Returns the severity. The severities are as follows (in

+ * descending order):

+ * <ul>

+ * <li><code>ERROR</code> - a serious error (most severe)</li>

+ * <li><code>WARNING</code> - a warning (less severe)</li>

+ * <li><code>INFO</code> - an informational ("fyi") message (least severe)</li>

+ * <li><code>OK</code> - everything is just fine</li>

+ * </ul>

+ * <p>

+ * The severity of a multi-status is defined to be the maximum

+ * severity of any of its children, or <code>OK</code> if it has

+ * no children.

+ * </p>

+ *

+ * @return the severity: one of <code>OK</code>,

+ *   <code>ERROR</code>, <code>INFO</code>, or <code>WARNING</code>

+ * @see #matches

+ */

+public int getSeverity();

+/**

+ * Returns whether this status is a multi-status.

+ * A multi-status describes the outcome of an operation

+ * involving multiple operands.

+ * <p>

+ * The severity of a multi-status is derived from the severities

+ * of its children; a multi-status with no children is

+ * <code>OK</code> by definition.

+ * A multi-status carries a plug-in identifier, a status code,

+ * a message, and an optional exception. Clients may treat

+ * multi-status objects in a multi-status unaware way.

+ * </p>

+ *

+ * @return <code>true</code> for a multi-status, 

+ *    <code>false</code> otherwise

+ * @see #getChildren

+ */

+public boolean isMultiStatus();

+/**

+ * Returns whether this status indicates everything is okay

+ * (neither info, warning, nor error).

+ *

+ * @return <code>true</code> if this status has severity

+ *    <code>OK</code>, and <code>false</code> otherwise

+ */

+public boolean isOK();

+/**

+ * Returns whether the severity of this status matches the given

+ * specification.

+ *

+ * @param severityMask a mask formed by bitwise or'ing severity mask

+ *    constants (<code>ERROR</code>, <code>WARNING</code>,

+ *    <code>INFO</code>)

+ * @return <code>true</code> if there is at least one match, 

+ *    <code>false</code> if there are no matches

+ * @see #getSeverity

+ * @see #ERROR

+ * @see #WARNING

+ * @see #INFO

+ */

+public boolean matches(int severityMask);

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/MultiStatus.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/MultiStatus.java
new file mode 100644
index 0000000..d671d10
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/MultiStatus.java
@@ -0,0 +1,129 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.internal.runtime.Assert;

+

+/**

+ * A concrete multi-status implementation, 

+ * suitable either for instantiating or subclassing.

+ */

+public class MultiStatus extends Status {

+

+	/** List of child statuses.

+	 */

+	private IStatus[] children;

+/**

+ * Creates and returns a new multi-status object with the given children.

+ *

+ * @param pluginId the unique identifier of the relevant plug-in

+ * @param code the plug-in-specific status code

+ * @param children the list of children status objects

+ * @param message a human-readable message, localized to the

+ *    current locale

+ * @param exception a low-level exception, or <code>null</code> if not

+ *    applicable 

+ */

+public MultiStatus(String pluginId, int code, IStatus[] children, String message, Throwable exception) {

+	this(pluginId, code, message, exception);

+	Assert.isLegal(children != null);

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

+		Assert.isLegal(children[i] != null);

+		add(children[i]);

+	}

+}

+/**

+ * Creates and returns a new multi-status object with no children.

+ *

+ * @param pluginId the unique identifier of the relevant plug-in

+ * @param code the plug-in-specific status code

+ * @param message a human-readable message, localized to the

+ *    current locale

+ * @param exception a low-level exception, or <code>null</code> if not

+ *    applicable 

+ */

+public MultiStatus(String pluginId, int code, String message, Throwable exception) {

+	super(OK, pluginId, code, message, exception);

+	children = new IStatus[0];

+}

+/**

+ * Adds the given status to this multi-status.

+ *

+ * @param status the new child status

+ */

+public void add(IStatus status) {

+	Assert.isLegal(status != null);

+	IStatus[] result = new IStatus[children.length + 1];

+	System.arraycopy(children, 0, result, 0, children.length);

+	result[result.length - 1] = status;

+	children = result;

+	int newSev = status.getSeverity();

+	if (newSev > getSeverity()) {

+		setSeverity(newSev);

+	}

+}

+/**

+ * Adds all of the children of the given status to this multi-status.

+ * Does nothing if the given status has no children (which includes

+ * the case where it is not a multi-status).

+ *

+ * @param status the status whose children are to be added to this one

+ */

+public void addAll(IStatus status) {

+	Assert.isLegal(status != null);

+	IStatus[] statuses = status.getChildren();

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

+		add(statuses[i]);

+	}

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public IStatus[] getChildren() {

+	return children;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public boolean isMultiStatus() {

+	return true;

+}

+/**

+ * Merges the given status into this multi-status.

+ * Equivalent to <code>add(status)</code> if the

+ * given status is not a multi-status. 

+ * Equivalent to <code>addAll(status)</code> if the

+ * given status is a multi-status. 

+ *

+ * @param status the status to merge into this one

+ * @see #add

+ * @see #addAll

+ */

+public void merge(IStatus status) {

+	Assert.isLegal(status != null);

+	if (!status.isMultiStatus()) {

+		add(status);

+	} else {

+		addAll(status);

+	}

+}

+/**

+ * Returns a string representation of the status, suitable 

+ * for debugging purposes only.

+ */

+public String toString() {

+	StringBuffer buf = new StringBuffer(super.toString());

+	buf.append(" children=[");

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

+		if (i != 0) {

+			buf.append(" ");

+		}

+		buf.append(children[i].toString());

+	}

+	buf.append("]");

+	return buf.toString();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/NullProgressMonitor.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/NullProgressMonitor.java
new file mode 100644
index 0000000..4f140f1
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/NullProgressMonitor.java
@@ -0,0 +1,103 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * A default progress monitor implementation suitable for

+ * subclassing.

+ * <p>

+ * This implementation supports cancelation. The default

+ * implementations of the other methods do nothing.

+ * </p>

+ */

+public class NullProgressMonitor implements IProgressMonitor {

+

+	/**

+	 * Indicates whether cancel has been requested.

+	 */

+	private boolean cancelled = false;

+/**

+ * Constructs a new progress monitor.

+ */

+public NullProgressMonitor() {

+}

+/**

+ * This implementation does nothing. 

+ * Subclasses may override this method to do interesting

+ * processing when a task begins.

+ * 

+ * @see IProgressMonitor#beginTask

+ */

+public void beginTask(String name, int totalWork) {

+}

+/**

+ * This implementation does nothing.

+ * Subclasses may override this method to do interesting

+ * processing when a task is done.

+ * 

+ * @see IProgressMonitor#done

+ */

+public void done() {

+}

+/**

+ * This implementation does nothing.

+ * Subclasses may override this method.

+ * 

+ * @see IProgressMonitor#internalWorked

+ */

+public void internalWorked(double work) {

+}

+/**

+ * This implementation returns the value of the internal 

+ * state variable set by <code>setCanceled</code>.

+ * Subclasses which override this method should

+ * override <code>setCanceled</code> as well.

+ *

+ * @see IProgressMonitor#isCanceled

+ * @see IProgressMonitor#setCanceled

+ */

+public boolean isCanceled() {

+	return cancelled;

+}

+/**

+ * This implementation sets the value of an internal state variable.

+ * Subclasses which override this method should override 

+ * <code>isCanceled</code> as well.

+ *

+ * @see IProgressMonitor#isCanceled

+ * @see IProgressMonitor#setCanceled

+ */

+public void setCanceled(boolean cancelled) {

+	this.cancelled = cancelled;

+}

+/**

+ * This implementation does nothing.

+ * Subclasses may override this method to do something

+ * with the name of the task.

+ * 

+ * @see IProgressMonitor#setTaskName

+ */

+public void setTaskName(String name) {

+}

+/**

+ * This implementation does nothing.

+ * Subclasses may override this method to do interesting

+ * processing when a subtask begins.

+ * 

+ * @see IProgressMonitor#subTask

+ */

+public void subTask(String name) {

+}

+/**

+ * This implementation does nothing.

+ * Subclasses may override this method to do interesting

+ * processing when some work has been completed.

+ * 

+ * @see IProgressMonitor#worked

+ */

+public void worked(int work) {

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/OperationCanceledException.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/OperationCanceledException.java
new file mode 100644
index 0000000..1a7dc9e
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/OperationCanceledException.java
@@ -0,0 +1,25 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * This exception is thrown to blow out of a long-running method 

+ * when the user cancels it.

+ */

+public final class OperationCanceledException extends RuntimeException {

+/**

+ * Creates a new exception.

+ */

+public OperationCanceledException() {

+	super();

+}

+/**

+ * Creates a new exception with the given message.

+ */

+public OperationCanceledException(String message) {

+	super(message);

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Path.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Path.java
new file mode 100644
index 0000000..6b5f799
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Path.java
@@ -0,0 +1,827 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+import org.eclipse.core.internal.runtime.Assert;

+import java.util.*;

+import java.io.File;

+

+/** 

+ * The standard implementation of the <code>IPath</code> interface.

+ * Paths are always maintained in canonicalized form.  That is, parent

+ * references (i.e., <code>../../</code>) and duplicate separators are 

+ * resolved.  For example,

+ * <pre>     new Path("/a/b").append("../foo/bar")</pre>

+ * will yield the path

+ * <pre>     /a/foo/bar</pre>

+ * <p>

+ * This class is not intended to be subclassed by clients but

+ * may be instantiated.

+ * </p>

+ * @see IPath

+ */

+public class Path implements IPath, Cloneable {

+	

+	/** The path segments */

+	private String[] segments;

+

+	/** The device id string. May be null if there is no device. */

+	private String device = null;

+	

+	/** flags indicating separators (has leading, is UNC, has trailing) */

+	private int separators;

+	

+	/** masks for separator values */

+	private static final int HAS_LEADING = 1;

+	private static final int IS_UNC = 2;

+	private static final int HAS_TRAILING = 4;

+	

+	/** Constant value indicating no segments */

+	private static final String[] NO_SEGMENTS = new String[0];

+

+	/** Constant root path string (<code>"/"</code>). */

+	private static final String ROOT_STRING = "/";

+

+	/** Constant value containing the root path with no device. */

+	public static final Path ROOT = new Path(ROOT_STRING);

+

+	/** Constant empty string value. */

+	private static final String EMPTY_STRING = "";

+

+	/** Constant value containing the empty path with no device. */

+	public static final Path EMPTY = new Path(EMPTY_STRING);

+

+	//Private implementation note: the segments and separators 

+	//arrays are never modified, so that they can be shared between 

+	//path instances

+	

+/* (Intentionally not included in javadoc)

+ * Private constructor.

+ */

+private Path() {

+	super();

+}

+/* (Intentionally not included in javadoc)

+ * Private constructor.

+ */

+private Path(String device, String[] segments, int separators) {

+	this.segments = segments;

+	this.device = device;

+	this.separators = separators;

+}

+

+/** 

+ * Constructs a new path from the given string path.

+ * The given string path must be valid.

+ * The path is canonicalized and double slashes are removed

+ * except at the beginning. (to handle UNC paths) All backslashes ('\')

+ * are replaced with forward slashes. ('/')

+ *

+ * @param fullPath the string path

+ * @see #isValidPath

+ */

+public Path(String fullPath) {

+	super();

+	initialize(null, fullPath);

+}

+/** 

+ * Constructs a new path from the given device id and string path.

+ * The given string path must be valid.

+ * The path is canonicalized and double slashes are removed except

+ * at the beginning (to handle UNC paths). All backslashes ('\')

+ * are replaced with forward slashes. ('/')

+ *

+ * @param device the device id

+ * @param path the string path

+ * @see #isValidPath

+ * @see #setDevice

+ */

+public Path(String device, String path) {

+	super();

+	initialize(device, path);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#addFileExtension

+ */

+public IPath addFileExtension(String extension) {

+	if (isRoot() || isEmpty() || hasTrailingSeparator())

+		return this;

+	int len = segments.length;

+	String[] newSegments = new String[len];

+	System.arraycopy(segments, 0, newSegments, 0, len-1);

+	newSegments[len-1] = segments[len-1] + "." + extension;

+	return new Path(device, newSegments, separators);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#addTrailingSeparator

+ */

+public IPath addTrailingSeparator() {

+	if (hasTrailingSeparator() || isRoot()) {

+		return this;

+	}

+	//XXX workaround, see 1GIGQ9V

+	if (isEmpty()) {

+		return new Path(device, segments, HAS_LEADING);

+	}

+	return new Path(device, segments, separators | HAS_TRAILING);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#append(java.lang.String)

+ */

+public IPath append(String tail) {

+	//optimize addition of a single segment

+	if (tail.indexOf(SEPARATOR) == -1) {

+		int tailLength = tail.length();

+		if (tailLength < 3) {

+			//some special cases

+			if (tailLength == 0 || ".".equals(tail)) {

+				return this;

+			}

+			if ("..".equals(tail))

+				return removeLastSegments(1);

+		}

+		//just add the segment

+		int myLen = segments.length;

+		String[] newSegments = new String[myLen+1];

+		System.arraycopy(segments, 0, newSegments, 0, myLen);

+		newSegments[myLen] = tail;

+		return new Path(device, newSegments, separators);

+	}

+	//go with easy implementation for now

+	return append(new Path(tail));

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#append(IPath)

+ */

+public IPath append(IPath tail) {

+	//optimize some easy cases

+	if (tail == null || tail.isEmpty() || tail.isRoot())

+		return this;

+	if (this.isEmpty())

+		return tail.makeRelative();

+	if (this.isRoot())

+		return tail.makeAbsolute();

+	

+	//concatenate the two segment arrays

+	int myLen = segments.length;

+	int tailLen = tail.segmentCount();

+	String[] newSegments = new String[myLen+tailLen];

+	System.arraycopy(segments, 0, newSegments, 0, myLen);

+	for (int i = 0; i < tailLen; i++) {

+		newSegments[myLen+i] = tail.segment(i);

+	}

+	//use my leading separators and the tail's trailing separator

+	Path result = new Path(device, newSegments, 

+		(separators & (HAS_LEADING | IS_UNC)) | (tail.hasTrailingSeparator() ? HAS_TRAILING : 0));

+	String tailFirstSegment = newSegments[myLen];

+	if (tailFirstSegment.equals("..") || tailFirstSegment.equals(".")) {

+		result.canonicalize();

+	}

+	return result;

+}

+/**

+ * Destructively converts this path to its canonical form.

+ * <p>

+ * In its canonical form, a path does not have any

+ * "." segments, and parent references ("..") are collapsed

+ * where possible.

+ * </p>

+ * @return the canonicalized path

+ */

+private void canonicalize() {

+	//look for segments that need canonicalizing

+	for (int i = 0, max = segments.length; i < max; i++) {

+		String segment = segments[i];

+		if (segment.charAt(0) == '.' && (segment.equals("..") || segment.equals("."))) {

+			//path needs to be canonicalized

+			collapseParentReferences();

+			return;

+		}

+	}

+}

+/* (Intentionally not included in javadoc)

+ * Clones this object.

+ */

+public Object clone() {

+	try {

+		return super.clone();

+	} catch (CloneNotSupportedException e) {

+		return null;

+	}

+}

+/**

+ * Destructively removes all occurrences of ".." segments from this path.

+ */

+private void collapseParentReferences() {

+	int segmentCount = segments.length;

+	String[] stack = new String[segmentCount];

+	int stackPointer = 0;

+	for (int i = 0; i < segmentCount; i++) {

+		String segment = segments[i];

+		if (segment.equals("..")) {

+			if (stackPointer==0) {

+				// if the stack is empty we are going out of our scope 

+				// so we need to accumulate segments.  But only if the original

+				// path is relative.  If it is absolute then we can't go any higher than

+				// root so simply toss the .. references.

+				if (!isAbsolute())					

+					stack[stackPointer++] = segment;//stack push

+			} else {

+				// if the top is '..' then we are accumulating segments so don't pop

+				if ("..".equals(stack[stackPointer-1]))

+					stack[stackPointer++] = "..";

+				else

+					stackPointer--;//stack pop

+			}

+			//collapse current references

+		} else

+			if (!segment.equals(".") || (i == 0 && !isAbsolute()))

+				stack[stackPointer++] = segment;//stack push

+	}

+	//if the number of segments hasn't changed, then no modification needed

+	if (stackPointer== segmentCount)

+		return;

+	//build the new segment array backwards by popping the stack

+	String[] newSegments = new String[stackPointer];

+	System.arraycopy(stack, 0, newSegments, 0, stackPointer);

+	this.segments = newSegments;

+}

+/**

+ * Removes duplicate slashes from the given path, with the exception

+ * of leading double slash which represents a UNC path.

+ */

+private String collapseSlashes(String path) {

+	int length = path.length();

+	// if the path is only 0, 1 or 2 chars long then it could not possibly have illegal

+	// duplicate slashes.

+	if (length < 3)

+		return path;

+	// check for an occurence of // in the path.  Start at index 1 to ensure we skip leading UNC //

+	// If there are no // then there is nothing to collapse so just return.

+	if (path.indexOf("//", 1) == -1)

+		return path;

+	// We found an occurence of // in the path so do the slow collapse.

+	char[] result = new char[path.length()];

+	int count = 0;

+	boolean hasPrevious = false;

+	char[] characters = path.toCharArray();

+	for (int index = 0; index < characters.length; index++) {

+		char c = characters[index];

+		if (c == SEPARATOR) {

+			if (hasPrevious) {

+				// skip double slashes, except for beginning of UNC.

+				// note that a UNC path can't have a device.

+				if (device == null && index == 1) {

+					result[count] = c;

+					count++;

+				}

+			} else {

+				hasPrevious = true;

+				result[count] = c;

+				count++;

+			}

+		} else {

+			hasPrevious = false;

+			result[count] = c;

+			count++;

+		}

+	}

+	return new String(result, 0, count);

+}

+/* (Intentionally not included in javadoc)

+ * Returns the size of the string that will be created by toString or toOSString.

+ */

+private int computeLength() {

+	int length = 0;

+	if (device != null)

+		length += device.length();

+	if ((separators & HAS_LEADING) != 0) 

+		length ++;

+	if ((separators & IS_UNC) != 0)

+		length++;

+	//add the segment lengths

+	int max = segments.length;

+	if (max > 0) {

+		for (int i = 0; i < max; i++) {

+			length += segments[i].length();

+		}

+		//add the separator lengths

+		length += max-1;

+	}

+	if ((separators & HAS_TRAILING) != 0) 

+		length++;

+	return length;

+}

+/* (Intentionally not included in javadoc)

+ * Returns the number of segments in the given path

+ */

+private int computeSegmentCount(String path) {

+	int len = path.length();

+	if (len == 0 || (len == 1 && path.charAt(0) == SEPARATOR)) {

+		return 0;

+	}

+	int count = 1;

+	int prev = -1;

+	int i;

+	while ((i = path.indexOf(SEPARATOR, prev + 1)) != -1) {

+		if (i != prev + 1 && i != len) {

+			++count;

+		}

+		prev = i;

+	}

+	if (path.charAt(len - 1) == SEPARATOR) {

+		--count;

+	}

+	return count;

+}

+/**

+ * Computes the segment array for the given canonicalized path.

+ */

+private String[] computeSegments(String path) {

+	// performance sensitive --- avoid creating garbage

+	int segmentCount = computeSegmentCount(path);

+	String[] newSegments = new String[segmentCount];

+	if (segmentCount == 0) {

+		return NO_SEGMENTS;

+	}

+	int len = path.length();

+	// check for initial slash

+	int firstPosition = (path.charAt(0) == SEPARATOR) ? 1 : 0;

+	// check for UNC

+	if (firstPosition == 1 && isUNC())

+		firstPosition = 2;

+	int lastPosition = (path.charAt(len - 1) != SEPARATOR) ? len - 1 : len - 2;

+	// for non-empty paths, the number of segments is 

+	// the number of slashes plus 1, ignoring any leading

+	// and trailing slashes

+	int next = firstPosition;

+	for (int i = 0; i < segmentCount; i++) {

+		int start = next;

+		int end = path.indexOf(SEPARATOR, next);

+		if (end == -1) {

+			newSegments[i] = path.substring(start, lastPosition + 1);

+		} else {

+			newSegments[i] = path.substring(start, end);

+		}

+		next = end + 1;

+	}

+	return newSegments;

+}

+/* (Intentionally not included in javadoc)

+ * Compares objects for equality.

+ */

+public boolean equals(Object obj) {

+	if (this == obj) {

+		return true;

+	}

+	if (!(obj instanceof Path)) {

+		return false;

+	}

+	Path target = (Path)obj;

+	//check leading separators

+	int mask = HAS_LEADING | IS_UNC;

+	if ((separators & mask) != (target.separators & mask)) {

+		return false;

+	}

+	//check segment count

+	int segmentCount = segments.length;

+	if (segmentCount != target.segmentCount()) {

+		return false;

+	}

+	//check device

+	if (device == null) {

+		if (target.device != null) {

+			return false;

+		}

+	} else {

+		if (!device.equals(target.device)) {

+			return false;

+		}

+	}

+	//check segments

+	for (int i = 0; i < segmentCount; i++) {

+		if (!segments[i].equals(target.segment(i))) {

+			return false;

+		}

+	}

+	//they're the same!

+	return true;

+}

+

+/* (Intentionally not included in javadoc)

+ * @see IPath#getDevice

+ */

+public String getDevice() {

+	return device;

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#getFileExtension

+ */

+public String getFileExtension() {

+	if (hasTrailingSeparator()) {

+		return null;

+	}

+	String lastSegment = lastSegment();

+	if (lastSegment == null) {

+		return null;

+	}

+	int index = lastSegment.lastIndexOf(".");

+	if (index == -1) {

+		return null;

+	}

+	return lastSegment.substring(index + 1);

+}

+/* (Intentionally not included in javadoc)

+ * Computes the hash code for this object.

+ */

+public int hashCode() {

+	int hash = device == null ? 0 : device.hashCode();

+	int segmentCount = segments.length;

+	for (int i = 0; i < segmentCount; i++) {

+		hash += segments[i].hashCode();

+	}

+	return hash;

+}

+

+/* (Intentionally not included in javadoc)

+ * @see IPath#hasTrailingSeparator

+ */

+public boolean hasTrailingSeparator() {

+	return (separators & HAS_TRAILING) != 0;

+}

+/*

+ * Initialize the current path with the given string.

+ */

+private void initialize(String device, String fullPath) {

+	Assert.isNotNull(fullPath);

+	this.device = device;

+

+	String path = fullPath.replace('\\', SEPARATOR);

+	int i = path.indexOf(DEVICE_SEPARATOR);

+	if (i != -1) {

+		// if the specified device is null then set it to

+		// be whatever is defined in the path string

+		if (device == null)

+			this.device = path.substring(0, i + 1);

+		path = path.substring(i + 1, path.length());

+	}

+	path = collapseSlashes(path);

+

+	//compute the separators array

+	if (path.length() < 2) {

+		if (path.length() == 1 && path.charAt(0) == SEPARATOR) {

+			this.separators = HAS_LEADING;

+		} else {

+			this.separators = 0;

+		}

+	} else {

+		boolean hasLeading = path.charAt(0) == SEPARATOR;

+		boolean isUNC = hasLeading && path.charAt(1) == SEPARATOR;

+		//UNC path of length two has no trailing separator

+		boolean hasTrailing = !(isUNC && path.length() == 2) && path.charAt(path.length()-1) == SEPARATOR;

+		separators = hasLeading ? HAS_LEADING : 0;

+		if (isUNC) separators |= IS_UNC;

+		if (hasTrailing) separators |= HAS_TRAILING;

+	}

+	//compute segments and ensure canonical form

+	segments = computeSegments(path);

+	canonicalize();

+

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#isAbsolute

+ */

+public boolean isAbsolute() {

+	//it's absolute if it has a leading separator

+	return (separators & HAS_LEADING) != 0;

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#isEmpty

+ */

+public boolean isEmpty() {

+	//true if no segments and no leading prefix

+	return segments.length == 0 && ((separators & HAS_LEADING) == 0);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#isPrefixOf

+ */

+public boolean isPrefixOf(IPath anotherPath) {

+	Assert.isNotNull(anotherPath);

+	if (device == null) {

+		if (anotherPath.getDevice() != null) {

+			return false;

+		}

+	} else {

+		if (!device.equalsIgnoreCase(anotherPath.getDevice())) {

+			return false;

+		}

+	}

+	if (isEmpty() || (isRoot() && anotherPath.isAbsolute())) {

+		return true;

+	}

+	int len = segments.length;

+	if (len > anotherPath.segmentCount()) {

+		return false;

+	}

+	for (int i = 0; i < len; i++) {

+		if (!segments[i].equals(anotherPath.segment(i)))

+			return false;

+	}

+	return true;

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#isRoot

+ */

+public boolean isRoot() {

+	//must have no segments, a leading separator, and not be a UNC path.

+	return this == ROOT || (segments.length == 0 && isAbsolute() && ((separators & IS_UNC) == 0));

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#isUNC

+ */

+public boolean isUNC() {

+	if (device != null) 

+		return false;

+	return (separators & IS_UNC) != 0;

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#isValidPath

+ */

+public boolean isValidPath(String path) {

+	// We allow "//" at the beginning for UNC paths

+	if (path.indexOf("//") > 0) {

+		return false;

+	}

+	Path test = new Path(path);

+	int segmentCount = test.segmentCount();

+	for (int i = 0; i < segmentCount; i++) {

+		if (!test.isValidSegment(test.segment(i))) {

+			return false;

+		}

+	}

+	return true;

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#isValidSegment

+ */

+public boolean isValidSegment(String segment) {

+	int size = segment.length();

+	if (size == 0) {

+		return false;

+	}

+	if (Character.isWhitespace(segment.charAt(0)) || Character.isWhitespace(segment.charAt(size - 1))) {

+		return false;

+	}

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

+		char c = segment.charAt(i);

+		if (c == '/' || c == '\\' || c == ':') {

+			return false;

+		}

+	}

+	return true;

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#lastSegment

+ */

+public String lastSegment() {

+	int len = segments.length;

+	return len == 0 ? null : segments[len-1];

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#makeAbsolute

+ */

+public IPath makeAbsolute() {

+	if (isAbsolute()) {

+		return this;

+	}

+	Path result = new Path(device, segments, separators | HAS_LEADING);

+	//may need canonicalizing if it has leading ".." or "." segments

+	if (result.segmentCount() > 0) {

+		String first = result.segment(0);

+		if (first.equals("..") || first.equals(".")) {

+			result.canonicalize();

+		}

+	}

+	return result;

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#makeRelative

+ */

+public IPath makeRelative() {

+	if (!isAbsolute()) {

+		return this;

+	}

+	return new Path(device, segments, separators & HAS_TRAILING);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#makeUNC

+ */

+public IPath makeUNC(boolean toUNC) {

+	// if we are already in the right form then just return

+	if (!(toUNC ^ isUNC()))

+		return this;

+

+	int newSeparators = this.separators;

+	if (toUNC) {

+		newSeparators |= HAS_LEADING | IS_UNC;

+	} else {

+		//mask out the UNC bit

+		newSeparators &= HAS_LEADING | HAS_TRAILING;

+	}

+	return new Path(toUNC ? null : device, segments, newSeparators);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#matchingFirstSegments

+ */

+public int matchingFirstSegments(IPath anotherPath) {

+	Assert.isNotNull(anotherPath);

+	String[] argument = anotherPath.segments();

+	int max = Math.min(segments.length, argument.length);

+	int count = 0;

+	for (int i = 0; i < max; i++) {

+		if (!segments[i].equals(argument[i])) {

+			return count;

+		}

+		count++;

+	}

+	return count;

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#removeFileExtension

+ */

+public IPath removeFileExtension() {

+	String extension = getFileExtension();

+	if (extension == null || extension.equals("")) {

+		return this;

+	}

+	String lastSegment = lastSegment();

+	int index = lastSegment.lastIndexOf(extension) - 1;

+	return removeLastSegments(1).append(lastSegment.substring(0, index));

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#removeFirstSegments

+ */

+public IPath removeFirstSegments(int count) {

+	if (count == 0)

+		return this;

+	if (count >= segments.length) {

+		return new Path(device, NO_SEGMENTS, 0);

+	}

+	Assert.isLegal(count > 0);

+	int newSize = segments.length - count;

+	String[] newSegments = new String[newSize];

+	System.arraycopy(this.segments, count, newSegments, 0, newSize);

+

+	//result is always a relative path

+	return new Path(device, newSegments, separators & HAS_TRAILING);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#removeLastSegments

+ */

+public IPath removeLastSegments(int count) {

+	if (count == 0)

+		return this;

+	if (count >= segments.length) {

+		return new Path(device, NO_SEGMENTS, separators);

+	}

+	Assert.isLegal(count > 0);

+	int newSize = segments.length - count;

+	String[] newSegments = new String[newSize];

+	System.arraycopy(this.segments, 0, newSegments,0, newSize);

+	return new Path(device, newSegments, separators);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#removeTrailingSeparator

+ */

+public IPath removeTrailingSeparator() {

+	if (!hasTrailingSeparator()) {

+		return this;

+	}

+	return new Path(device, segments, separators & (HAS_LEADING | IS_UNC));

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#segment

+ */

+public String segment(int index) {

+	if (index >= segments.length)

+		return null;

+	return segments[index];

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#segmentCount

+ */

+public int segmentCount() {

+	return segments.length;

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#segments

+ */

+public String[] segments() {

+	return (String[])segments.clone();

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#setDevice

+ */

+public IPath setDevice(String value) {

+	if (value != null) {

+		Assert.isTrue(value.indexOf(IPath.DEVICE_SEPARATOR) == (value.length() - 1), "Last character should be the device separator");

+	}

+	return new Path(value, segments, separators);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#toFile

+ */

+public File toFile() {

+	return new File(toOSString());

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#toOSString

+ */

+public String toOSString() {

+	//Note that this method is identical to toString except

+	//it uses the OS file separator instead of the path separator

+	int resultSize = computeLength();

+	if (resultSize <= 0)

+		return EMPTY_STRING;

+	char FILE_SEPARATOR = File.separatorChar;

+	char[] result = new char[resultSize];

+	int offset = 0;

+	if (device != null) {

+		int size = device.length();

+		device.getChars(0, size, result, offset);

+		offset += size;

+	}

+	if ((separators & HAS_LEADING) != 0) 

+		result[offset++] = FILE_SEPARATOR;

+	if ((separators & IS_UNC) != 0)

+		result[offset++] = FILE_SEPARATOR;

+	int len = segments.length-1;

+	if (len>=0) {

+		//append all but the last segment, with separators

+		for (int i = 0; i < len; i++) {

+			int size = segments[i].length();

+			segments[i].getChars(0, size, result, offset);

+			offset += size;

+			result[offset++] = FILE_SEPARATOR;

+		}

+		//append the last segment

+		int size = segments[len].length();

+		segments[len].getChars(0, size, result, offset);

+		offset += size;

+	}

+	if ((separators & HAS_TRAILING) != 0) 

+		result[offset++] = FILE_SEPARATOR;

+	return new String(result);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#toString

+ */

+public String toString() {

+	int resultSize = computeLength();

+	if (resultSize <= 0)

+		return EMPTY_STRING;

+	char[] result = new char[resultSize];

+	int offset = 0;

+	if (device != null) {

+		int size = device.length();

+		device.getChars(0, size, result, offset);

+		offset += size;

+	}

+	if ((separators & HAS_LEADING) != 0) 

+		result[offset++] = SEPARATOR;

+	if ((separators & IS_UNC) != 0)

+		result[offset++] = SEPARATOR;

+	int len = segments.length-1;

+	if (len>=0) {

+		//append all but the last segment, with separators

+		for (int i = 0; i < len; i++) {

+			int size = segments[i].length();

+			segments[i].getChars(0, size, result, offset);

+			offset += size;

+			result[offset++] = SEPARATOR;

+		}

+		//append the last segment

+		int size = segments[len].length();

+		segments[len].getChars(0, size, result, offset);

+		offset += size;

+	}

+	if ((separators & HAS_TRAILING) != 0) 

+		result[offset++] = SEPARATOR;

+	return new String(result);

+}

+/* (Intentionally not included in javadoc)

+ * @see IPath#uptoSegment

+ */

+public IPath uptoSegment(int count) {

+	if (count == 0)

+		return Path.EMPTY;

+	if (count >= segments.length)

+		return this;

+	Assert.isTrue(count > 0, "Invalid parameter to Path.uptoSegment");

+	String[] newSegments = new String[count];

+	System.arraycopy(segments, 0, newSegments, 0, count);

+	return new Path(device, newSegments, separators);

+}

+}
\ No newline at end of file
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
new file mode 100644
index 0000000..e943e78
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Platform.java
@@ -0,0 +1,397 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

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

+import org.eclipse.core.runtime.model.Factory;

+import org.eclipse.core.runtime.model.PluginRegistryModel;

+import org.eclipse.core.internal.plugins.PluginClassLoader;

+import org.eclipse.core.internal.plugins.PluginDescriptor;

+import org.eclipse.core.internal.runtime.*;

+import java.io.IOException;

+import java.lang.reflect.Constructor;

+import java.net.URL;

+import java.net.URLConnection;

+import java.util.Map;

+

+/**

+ * The central class of the Eclipse Platform Runtime. This class cannot

+ * be instantiated or subclassed by clients; all functionality is provided 

+ * by static methods.  Features include:

+ * <ul>

+ * <li>the platform registry of installed plug-ins</li>

+ * <li>the platform adapter manager</li>

+ * <li>the platform log</li>

+ * <li>the authorization info management</li>

+ * </ul>

+ * <p>

+ * The platform is in one of two states, running or not running, at all

+ * times. The only ways to start the platform running, or to shut it down,

+ * are on the bootstrap <code>BootLoader</code> class. Code in plug-ins will

+ * only observe the platform in the running state. The platform cannot

+ * be shutdown from inside (code in plug-ins have no access to

+ * <code>BootLoader</code>).

+ * </p>

+ */

+public final class Platform {

+	/**

+	 * The unique identifier constant (value "<code>org.eclipse.core.runtime</code>")

+	 * of the Core Runtime (pseudo-) plug-in.

+	 */

+	public static final String PI_RUNTIME = "org.eclipse.core.runtime";

+

+	/** 

+	 * The simple identifier constant (value "<code>applications</code>") of

+	 * the extension point of the Core Runtime plug-in where plug-ins declare

+	 * the existence of runnable applications. A plug-in may define any

+	 * number of applications; however, the platform is only capable

+	 * of running one application at a time.

+	 * 

+	 * @see org.eclipse.core.boot.BootLoader#run

+	 */

+	public static final String PT_APPLICATIONS = "applications";	

+	

+	/** 

+	 * Debug option value denoting the time at which the platform runtime

+	 * was started.  This constant can be used in conjunction with

+	 * <code>getDebugOption</code> to find the string value of

+	 * <code>System.currentTimeMillis()</code> when the platform was started.

+ 	 */

+	public static final String OPTION_STARTTIME = PI_RUNTIME + "/starttime";

+

+	/** 

+	 * Status code constant (value 1) indicating a problem in a plug-in

+	 * manifest (<code>plugin.xml</code>) file.

+ 	 */

+	public static final int PARSE_PROBLEM = 1;

+

+	/**

+	 * Status code constant (value 2) indicating an error occurred while running a plug-in.

+ 	 */

+	public static final int PLUGIN_ERROR = 2;

+

+	/**

+	 * Status code constant (value 3) indicating an error internal to the

+	 * platform has occurred.

+ 	 */

+	public static final int INTERNAL_ERROR = 3;

+	

+	/**

+	 * Status code constant (value 4) indicating the platform could not read

+	 * some of its metadata.

+ 	 */

+	public static final int FAILED_READ_METADATA = 4;

+	

+	/**

+	 * Status code constant (value 5) indicating the platform could not write

+	 * some of its metadata.

+ 	 */

+	public static final int FAILED_WRITE_METADATA = 5;

+	

+	/**

+	 * Status code constant (value 6) indicating the platform could not delete

+	 * some of its metadata.

+ 	 */

+	public static final int FAILED_DELETE_METADATA = 6;

+/**

+ * Private constructor to block instance creation.

+ */

+private Platform() {

+}

+/**

+ * Adds the given authorization information to the keyring. The

+ * information is relevant for the specified protection space and the

+ * given authorization scheme. The protection space is defined by the

+ * combination of the given server URL and realm. The authorization 

+ * scheme determines what the authorization information contains and how 

+ * it should be used. The authorization information is a <code>Map</code> 

+ * of <code>String</code> to <code>String</code> and typically

+ * contains information such as usernames and passwords.

+ *

+ * @param serverUrl the URL identifying the server for this authorization

+ *		information. For example, "http://www.example.com/".

+ * @param realm the subsection of the given server to which this

+ *		authorization information applies.  For example,

+ *		"realm1@example.com" or "" for no realm.

+ * @param authScheme the scheme for which this authorization information

+ *		applies. For example, "Basic" or "" for no authorization scheme

+ * @param info a <code>Map</code> containing authorization information 

+ *		such as usernames and passwords (key type : <code>String</code>, 

+ *		value type : <code>String</code>)

+ * @exception CoreException if there are problems setting the

+ *		authorization information. Reasons include:

+ * <ul>

+ * <li>The keyring could not be saved.</li>

+ * </ul>

+ */

+public static void addAuthorizationInfo(URL serverUrl, String realm, String authScheme, Map info) throws CoreException {

+	InternalPlatform.addAuthorizationInfo(serverUrl, realm, authScheme, info);

+}

+/** 

+ * Adds the given log listener to the notification list of the platform.

+ * <p>

+ * Once registered, a listener starts receiving notification as entries

+ * are added to plug-in logs via <code>ILog.log()</code>. The listener continues to

+ * receive notifications until it is replaced or removed.

+ * </p>

+ *

+ * @param listener the listener to register

+ * @see ILog#addLogListener

+ * @see #removeLogListener

+ */

+public static void addLogListener(ILogListener listener) {

+	InternalPlatform.addLogListener(listener);

+}

+/**

+ * Adds the specified resource to the protection space specified by the

+ * given realm. All targets at or deeper than the depth of the last

+ * symbolic element in the path of the given resource URL are assumed to

+ * be in the same protection space.

+ *

+ * @param resourceUrl the URL identifying the resources to be added to

+ *		the specified protection space. For example,

+ *		"http://www.example.com/folder/".

+ * @param realm the name of the protection space. For example,

+ *		"realm1@example.com"

+ * @exception CoreException if there are problems setting the

+ *		authorization information. Reasons include:

+ * <ul>

+ * <li>The keyring could not be saved.</li>

+ * </ul>

+ */

+public static void addProtectionSpace(URL resourceUrl, String realm) throws CoreException {

+	InternalPlatform.addProtectionSpace(resourceUrl, realm);

+}

+/**

+ * Returns a URL which is the local equivalent of the

+ * supplied URL. This method is expected to be used with 

+ * plug-in-relative URLs returned by IPluginDescriptor.

+ * If the specified URL is not a plug-in-relative URL, it 

+ * is returned asis. If the specified URL is a plug-in-relative

+ * URL of a file (incl. .jar archive), it is returned as 

+ * a locally-accessible URL using "file:" or "jar:file:" protocol

+ * (caching the file locally, if required). If the specified URL

+ * is a plug-in-relative URL of a directory,

+ * an exception is thrown.

+ *

+ * @param url original plug-in-relative URL.

+ * @return the resolved URL

+ * @exception IOException if unable to resolve URL

+ * @see #resolve

+ * @see IPluginDescriptor#getInstallURL

+ */

+public static URL asLocalURL(URL url) throws IOException {

+	return InternalPlatform.asLocalURL(url);

+}

+

+/**

+ * Takes down the splash screen if one was put up.

+ */

+public static void endSplash() {

+	InternalPlatform.endSplash();

+}

+

+/**

+ * Removes the authorization information for the specified protection

+ * space and given authorization scheme. The protection space is defined

+ * by the given server URL and realm.

+ *

+ * @param serverUrl the URL identifying the server to remove the

+ *		authorization information for. For example,

+ *		"http://www.example.com/".

+ * @param realm the subsection of the given server to remove the

+ *		authorization information for. For example,

+ *		"realm1@example.com" or "" for no realm.

+ * @param authScheme the scheme for which the authorization information

+ *		to remove applies. For example, "Basic" or "" for no

+ *		authorization scheme.

+ * @exception CoreException if there are problems removing the

+ *		authorization information. Reasons include:

+ * <ul>

+ * <li>The keyring could not be saved.</li>

+ * </ul>

+ */

+public static void flushAuthorizationInfo(URL serverUrl, String realm, String authScheme) throws CoreException {

+	InternalPlatform.flushAuthorizationInfo(serverUrl, realm, authScheme);

+}

+/**

+ * Returns the adapter manager used for extending

+ * <code>IAdaptable</code> objects.

+ *

+ * @return the adapter manager for this platform

+ * @see IAdapterManager

+ */

+public static IAdapterManager getAdapterManager() {

+	return InternalPlatform.getAdapterManager();

+}

+/**

+ * Returns the authorization information for the specified protection

+ * space and given authorization scheme. The protection space is defined

+ * by the given server URL and realm. Returns <code>null</code> if no

+ * such information exists.

+ *

+ * @param serverUrl the URL identifying the server for the authorization

+ *		information. For example, "http://www.example.com/".

+ * @param realm the subsection of the given server to which the

+ *		authorization information applies.  For example,

+ *		"realm1@example.com" or "" for no realm.

+ * @param authScheme the scheme for which the authorization information

+ *		applies. For example, "Basic" or "" for no authorization scheme

+ * @return the authorization information for the specified protection

+ *		space and given authorization scheme, or <code>null</code> if no

+ *		such information exists

+ */

+public static Map getAuthorizationInfo(URL serverUrl, String realm, String authScheme) {

+	return InternalPlatform.getAuthorizationInfo(serverUrl, realm, authScheme);

+}

+/**

+ * Returns the command line args provided to the platform when it was first run.

+ * Note that individual platform runnables may be provided with different arguments

+ * if they are being run individually rather than with <code>Platform.run()</code>.

+ * 

+ * @return the command line used to start the platform

+ */

+public static String[] getCommandLineArgs() {

+	return BootLoader.getCommandLineArgs();

+}

+/**

+ * Returns the identified option.  <code>null</code>

+ * is returned if no such option is found.   Options are specified

+ * in the general form <i>&ltplug-in id&gt/&ltoption-path&gt</i>.  

+ * For example, <code>org.eclipse.core.runtime/debug</code>

+ *

+ * @param option the name of the option to lookup

+ * @return the value of the requested debug option or <code>null</code>

+ */

+public static String getDebugOption(String option) {

+	return InternalPlatform.getDebugOption(option);

+}

+/**

+ * Returns the location of the platform working directory.  This 

+ * corresponds to the <i>-platform</i> command line argument if

+ * present or, if not, the current working directory when the platform

+ * was started.

+ *

+ * @return the location of the platform

+ */

+public static IPath getLocation() {

+	return InternalPlatform.getLocation();

+}

+/**

+ * Returns the plug-in runtime object for the identified plug-in

+ * or <code>null</code> if no such plug-in can be found.  If

+ * the plug-in is defined but not yet activated, the plug-in will

+ * be activated before being returned.

+ *

+ * @param id the unique identifier of the desired plug-in 

+ *		(e.g., <code>"com.example.acme"</code>).

+ * @return the plug-in runtime object, or <code>null</code>

+ */

+public static Plugin getPlugin(String id) {

+	return InternalPlatform.getPlugin(id);

+}

+/**

+ * Returns the plug-in registry for this platform.

+ *

+ * @return the plug-in registry

+ * @see IPluginRegistry

+ */

+public static IPluginRegistry getPluginRegistry() {

+	return InternalPlatform.getPluginRegistry();

+}

+/**

+ * Returns the location in the local file system of the plug-in 

+ * state area for the given plug-in.

+ * The platform must be running.

+ * <p>

+ * The plug-in state area is a file directory within the

+ * platform's metadata area where a plug-in is free to create files.

+ * The content and structure of this area is defined by the plug-in,

+ * and the particular plug-in is solely responsible for any files

+ * it puts there. It is recommended for plug-in preference settings.

+ * </p>

+ *

+ * @param plugin the plug-in whose state location is returned

+ * @return a local file system path

+ */

+public static IPath getPluginStateLocation(Plugin plugin) {

+	return InternalPlatform.getPluginStateLocation(plugin);

+}

+/**

+ * Returns the protection space (realm) for the specified resource, or

+ * <code>null</code> if the realm is unknown.

+ *

+ * @param resourceUrl the URL of the resource whose protection space is

+ *		returned. For example, "http://www.example.com/folder/".

+ * @return the protection space (realm) for the specified resource, or

+ *		<code>null</code> if the realm is unknown

+ */

+public static String getProtectionSpace(URL resourceUrl) {

+	return InternalPlatform.getProtectionSpace(resourceUrl);

+}

+/**

+ * Returns a plug-in registry containing all of the plug-ins discovered

+ * on the given plug-in path.  Any problems encountered are added to

+ * the status managed by the supplied factory.

+ * <p>

+ * The given plug-in path is the list of locations in which to look for plug-ins.

+ * If an entry identifies a directory (i.e., ends in a '/'), this method

+ * attempts to scan all sub-directories for plug-ins.  Alternatively, an

+ * entry may identify a particular plug-in manifest (<code>plugin.xml</code>) file.

+ * </p>

+ * <p>

+ * <b>Note:</b> this method does not affect the running platform.  It is intended

+ * for introspecting installed plug-ins on this and other platforms.  The returned

+ * registry is <b>not</b> the same as the platform's registry.

+ * </p>

+ *

+ * @param pluginPath the list of locations in which to look for plug-ins

+ * @param factory the factory to use to create runtime model objects

+ * @return the registry of parsed plug-ins

+ */

+public static PluginRegistryModel parsePlugins(URL[] pluginPath, Factory factory) {

+	return InternalPlatform.parsePlugins(pluginPath, factory);

+}

+/** 

+ * Removes the indicated (identical) log listener from the notification list

+ * of the platform.  If no such listener exists, no action is taken.

+ *

+ * @param listener the listener to deregister

+ * @see ILog#removeLogListener

+ * @see #addLogListener

+ */

+public static void removeLogListener(ILogListener listener) {

+	InternalPlatform.removeLogListener(listener);

+}

+/**

+ * Returns a URL which is the resolved equivalent of the

+ * supplied URL. This method is expected to be used with 

+ * plug-in-relative URLs returned by IPluginDescriptor.

+ * If the specified URL is not a plug-in-relative URL, it is returned

+ * asis. If the specified URL is a plug-in-relative URL, it is

+ * resolved to a URL using the actuall URL protocol

+ * (eg. file, http, etc)

+ *

+ * @param url original plug-in-relative URL.

+ * @return the resolved URL

+ * @exception IOException if unable to resolve URL

+ * @see #asLocalURL

+ * @see IPluginDescriptor#getInstallURL

+ */

+public static URL resolve(URL url) throws java.io.IOException {

+	return InternalPlatform.resolve(url);

+}

+/**

+ * Runs the given runnable in a protected mode.   Exceptions

+ * thrown in the runnable are logged and passed to the runnable's

+ * exception handler.  Such exceptions are not rethrown by this method.

+ *

+ * @param code the runnable to run

+ */

+public static void run(ISafeRunnable runnable) {

+	InternalPlatform.run(runnable);

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/PlatformObject.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/PlatformObject.java
new file mode 100644
index 0000000..4e83261
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/PlatformObject.java
@@ -0,0 +1,55 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An abstract superclass implementing the <code>IAdaptable</code>

+ * interface. <code>getAdapter</code> invocations are directed

+ * to the platform's adapter manager.

+ * <p>

+ * Note: In situations where it would be awkward to subclass this

+ * class, the same affect can be achieved simply by implementing

+ * the <code>IAdaptable</code> interface and explicitly forwarding

+ * the <code>getAdapter</code> request to the platform's 

+ * adapater manager. The method would look like:

+ * <pre>

+ *     public Object getAdapter(Class adapter) {

+ *         return Platform.getAdapterManager().getAdapter(this, adapter);

+ *     }

+ * </pre>

+ * </p>

+ * <p>

+ * Clients may subclass.

+ * </p>

+ *

+ * @see Platform#getAdapterManager

+ */

+public abstract class PlatformObject implements IAdaptable {

+/**

+ * Constructs a new platform object.

+ */

+public PlatformObject() {

+}

+/**

+ * Returns an object which is an instance of the given class

+ * associated with this object. Returns <code>null</code> if

+ * no such object can be found.

+ * <p>

+ * This implementation of the method declared by <code>IAdaptable</code>

+ * passes the request along to the platform's adapter manager; roughly

+ * <code>Platform.getAdapterManager().getAdapter(this, adapter)</code>.

+ * Subclasses may override this method (however, if they do so, they

+ * should invoke the method on their superclass to ensure that the

+ * Platform's adapter manager is consulted).

+ * </p>

+ *

+ * @see IAdaptable#getAdapter

+ * @see Platform#getAdapterManager

+ */

+public Object getAdapter(Class adapter) {

+	return Platform.getAdapterManager().getAdapter(this, adapter);

+}

+}

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
new file mode 100644
index 0000000..160b66f
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java
@@ -0,0 +1,463 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.internal.plugins.DefaultPlugin;

+import org.eclipse.core.internal.plugins.PluginDescriptor;

+import org.eclipse.core.internal.runtime.*;

+import org.eclipse.core.runtime.model.PluginFragmentModel;

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

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

+import java.util.StringTokenizer;

+import java.util.Vector;

+import java.net.*;

+import java.io.*;

+

+/**

+ * The abstract superclass of all plug-in runtime class

+ * implementations. A plug-in subclasses this class and overrides

+ * the <code>startup</code> and <code>shutdown</code> methods 

+ * in order to react to life cycle requests automatically issued

+ * by the platform.

+ * <p>

+ * Conceptually, the plug-in runtime class represents the entire plug-in

+ * rather than an implementation of any one particular extension the

+ * plug-in declares. A plug-in is not required to explicitly

+ * specify a plug-in runtime class; if none is specified, the plug-in

+ * will be given a default plug-in runtime object that ignores all life 

+ * cycle requests (it still provides access to the corresponding

+ * plug-in descriptor).

+ * </p>

+ * <p>

+ * In the case of more complex plug-ins, it may be desireable

+ * to define a concrete subclass of <code>Plugin</code>.

+ * However, just subclassing <code>Plugin</code> is not

+ * sufficient. The name of the class must be explicitly configured

+ * in the plug-in's manifest (<code>plugin.xml</code>) file

+ * with the class attribute of the <code>&ltplugin&gt</code> element markup.

+ * </p>

+ * <p>

+ * Instances of plug-in runtime classes are automatically created 

+ * by the platform in the course of plug-in activation.

+ * <b>Clients must never explicitly instantiate a plug-in runtime class</b>.

+ * </p>

+ * <p>

+ * A typical implementation pattern for plug-in runtime classes is to

+ * provide a static convenience method to gain access to a plug-in's

+ * runtime object. This way, code in other parts of the plug-in

+ * implementation without direct access to the plug-in runtime object

+ * can easily obtain a reference to it, and thence to any plug-in-wide

+ * resources recorded on it. An example follows:

+ * <pre>

+ *     package myplugin;

+ *     public class MyPluginClass extends Plugin {

+ *         private static MyPluginClass instance;

+ *

+ *         public static MyPluginClass getInstance() { return instance; }

+ *

+ *         public void MyPluginClass(IPluginDescriptor descriptor) {

+ *             super(descriptor);

+ *             instance = this;

+ *             // ... other initialization

+ *         }

+ *         // ... other methods

+ *     }

+ * </pre>

+ * In the above example, a call to <code>MyPluginClass.getInstance()</code>

+ * will always return an initialized instance of <code>MyPluginClass</code>.

+ * </p>

+ * <p>

+ * The static method <code>Platform.getPlugin()</code>

+ * can be used to locate a plug-in's runtime object by name.

+ * The extension initialization would contain the following code:

+ * <pre>

+ *     Plugin myPlugin = Platform.getPlugin("com.example.myplugin");

+ * </pre>

+ * 

+ * Another typical implementation pattern for plug-in classes

+ * is handling of any initialization files required by the plug-in.

+ * Typically, each plug-in will ship one or more default files

+ * as part of the plug-in install. The executing plug-in will

+ * use the defaults on initial startup (or when explicitly requested

+ * by the user), but will subsequently rewrite any modifications

+ * to the default settings into one of the designated plug-in

+ * working directory locations. An example of such an implementation

+ * pattern is illustrated below:

+ * <pre>

+ * package myplugin;

+ * public class MyPlugin extends Plugin {

+ *

+ *     private static final String INI = "myplugin.ini"; 

+ *     private Properties myProperties = null;

+ *

+ *     public void startup() throws CoreException {

+ *         try {

+ *             InputStream input = null;

+ *             // look for working properties.  If none, use shipped defaults 

+ *             File file = getStateLocation().append(INI).toFile();

+ *             if (!file.exists()) {			

+ *                 URL base = getDescriptor().getInstallURL();

+ *                 input = (new URL(base,INI)).openStream();

+ *             } else 

+ *                 input = new FileInputStream(file);

+ * 

+ *             // load properties 

+ *             try {

+ *                 myProperties = new Properties();

+ *                 myProperties.load(input);

+ *             } finally {

+ *                 try {

+ *                     input.close();

+ *                 } catch (IOException e) {

+ *                     // ignore failure on close

+ *                 }

+ *             }

+ *         } catch (Exception e) {

+ *             throw new CoreException(

+ *                 new Status(IStatus.ERROR, getDescriptor().getUniqueIdentifier(),

+ *                     0, "Problems starting plug-in myplugin", e));

+ *         }

+ *     }

+ *

+ *     public void shutdown() throws CoreException { 

+ *         // save properties in plugin state location (r/w)

+ *         try {

+ *             FileOutputStream output = null; 

+ *             try {

+ *                 output = new FileOutputStream(getStateLocation().append(INI)); 

+ *                 myProperties.store(output, null);

+ *             } finally {

+ *                 try {

+ *                     output.close();

+ *                 } catch (IOException e) {

+ *                     // ignore failure on close

+ *                 }

+ *             }

+ *         } catch (Exception e) {

+ *             throw new CoreException(

+ *                 new Status(IStatus.ERROR, getDescriptor().getUniqueIdentifier(),

+ *                     0, "Problems shutting down plug-in myplugin", e));

+ *         }

+ *     }

+ *

+ *     public Properties getProperties() {	

+ *         return myProperties; 

+ *     }

+ * }

+ * </pre>

+ * </p>

+ */

+public abstract class Plugin  {

+

+	/**

+	 * The debug flag for this plug-in.  The flag is false by default.

+	 * It can be set to true either by the plug-in itself or in the platform 

+	 * debug options.

+	 */

+	private boolean debug = false;

+	

+	/** The plug-in descriptor.

+	 */

+	private IPluginDescriptor descriptor;

+/**

+ * Creates a new plug-in runtime object for the given plug-in descriptor.

+ * <p>

+ * Instances of plug-in runtime classes are automatically created 

+ * by the platform in the course of plug-in activation.

+ * <b>Clients must never explicitly instantiate a plug-in runtime class.</b>

+ * </p>

+ *

+ * @param descriptor the plug-in descriptor

+ * @see #getDescriptor

+ */

+public Plugin(IPluginDescriptor descriptor) {

+	Assert.isNotNull(descriptor);

+	Assert.isTrue(!descriptor.isPluginActivated(), Policy.bind("plugin.deactivatedLoad", this.getClass().getName(), descriptor.getUniqueIdentifier() + " is not activated"));

+	String className = ((PluginDescriptor) descriptor).getPluginClass();

+	if (this.getClass() == DefaultPlugin.class) 

+		Assert.isTrue(className == null || className.equals(""), Policy.bind("plugin.mismatchRuntime", descriptor.getUniqueIdentifier()));

+	else 

+		Assert.isTrue(this.getClass().getName().equals(className), Policy.bind("plugin.mismatchRuntime", descriptor.getUniqueIdentifier()));

+	this.descriptor = descriptor;

+	String key = descriptor.getUniqueIdentifier() + "/debug";

+	String value = Platform.getDebugOption(key);

+	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) {

+	URL install = getDescriptor().getInstallURL();

+	String first = path.segment(0);

+	if (first.charAt(0) != '$') {		

+		URL result = findInPlugin(install, path.toString());

+		if (result != null)

+			return result;	

+		return findInFragments(path.toString());

+	}

+	IPath rest = path.removeFirstSegments(1);

+	if (first.equalsIgnoreCase("$nl$"))

+		return findNL(install, rest);

+	if (first.equalsIgnoreCase("$os$"))

+		return findOS(install, rest);

+	if (first.equalsIgnoreCase("$ws$"))

+		return findWS(install, rest);

+	if (first.equalsIgnoreCase("$files$"))

+		return null;

+	return null;

+}

+

+private URL findOS(URL install, IPath path) {

+	String filePath = "os/" + BootLoader.getOS() + "/" + path.toString();	

+	URL result = findInPlugin(install, filePath);

+	if (result != null)

+		return result;	

+	return findInFragments(filePath);

+}

+

+private URL findWS(URL install, IPath path) {

+	String filePath = "ws/" + BootLoader.getWS() + "/" + path.toString();	

+	URL result = findInPlugin(install, filePath);

+	if (result != null)

+		return result;	

+	return findInFragments(filePath);

+}

+

+private URL findNL(URL install, IPath path) {

+	String nl = BootLoader.getNL();

+	URL result = null;

+	boolean done = false;

+	

+	while (!done) {		

+		String filePath = "nl/" + (nl.equals("") ? nl : nl + "/") + path.toString();

+		result = findInPlugin(install, filePath);

+		if (result != null)

+			return result;

+		result = findInFragments(filePath);

+		if (result != null)

+			return result;

+		if (nl.length() == 0)

+			done = true;

+		else {

+			int i = nl.lastIndexOf('_');

+			if (i < 0)

+				nl = "";

+			else

+				nl = nl.substring(0, i);

+		}

+	}

+	return null;

+}

+

+private URL findInPlugin(URL install, String filePath) {

+	try {

+		URL result = new URL(install, filePath);

+		URL location = Platform.resolve(result);

+		String file = getFileFromURL(location);

+		if (file != null && new File(file).exists())

+			return result;						

+	} catch (IOException e) {

+	}

+	return null;

+}

+

+private URL findInFragments(String path) {

+	PluginFragmentModel[] fragments = ((PluginDescriptor)getDescriptor()).getFragments();

+	if (fragments == null)

+		return null;

+		

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

+		try {

+			URL location = new URL(fragments[i].getLocation() + path);

+			String file = getFileFromURL(location);

+			if (file != null && new File(file).exists())

+				return location;

+		} catch (IOException e) {

+			// skip malformed url and urls that cannot be resolved

+		}

+	}

+	return null;

+}

+

+private String getFileFromURL(URL target) {

+	String protocol = target.getProtocol();

+	if (protocol.equals(PlatformURLHandler.FILE))

+		return target.getFile();

+	if (protocol.equals(PlatformURLHandler.VA))

+		return target.getFile();

+	if (protocol.equals(PlatformURLHandler.JAR)) {

+		// strip off the jar separator at the end of the url then do a recursive call

+		// to interpret the sub URL.

+		String file = target.getFile();

+		file = file.substring(0, file.length() - PlatformURLHandler.JAR_SEPARATOR.length());

+		try {

+			return getFileFromURL(new URL(file));

+		} catch (MalformedURLException e) {

+		}

+	}

+	return null;

+}

+/**

+ * Returns the plug-in descriptor for this plug-in runtime object.

+ *

+ * @return the plug-in descriptor for this plug-in runtime object

+ */

+public final IPluginDescriptor getDescriptor() {

+	return descriptor;

+}

+/**

+ * Returns the log for this plug-in.  If no such log exists, one is created.

+ *

+ * @return the log for this plug-in

+ */

+public final ILog getLog() {

+	return InternalPlatform.getLog(this);

+}

+/**

+ * Returns the location in the local file system of the 

+ * plug-in state area for this plug-in.

+ * If the plug-in state area did not exist prior to this call,

+ * it is created.

+ * <p>

+ * The plug-in state area is a file directory within the

+ * platform's metadata area where a plug-in is free to create files.

+ * The content and structure of this area is defined by the plug-in,

+ * and the particular plug-in is solely responsible for any files

+ * it puts there. It is recommended for plug-in preference settings and 

+ * other configuration parameters.

+ * </p>

+ *

+ * @return a local file system path

+ */

+public final IPath getStateLocation() {

+	return InternalPlatform.getPluginStateLocation(this);

+}

+/**

+ * Returns whether this plug-in is in debug mode.

+ * By default plug-ins are not in debug mode.  A plug-in can put itself

+ * into debug mode or the user can set an execution option to do so.

+ *

+ * @return whether this plug-in is in debug mode

+ */

+public boolean isDebugging() {

+	return debug;

+}

+/**

+ * Returns an input stream for the specified file. The file path

+ * must be specified relative this the plug-in's installation location.

+ *

+ * @param file path relative to plug-in installation location

+ * @return an input stream

+ * @see #openStream(IPath,boolean)

+ */

+public final InputStream openStream(IPath file) throws IOException {

+	return openStream(file, false);

+}

+/**

+ * Returns an input stream for the specified file. The file path

+ * must be specified relative to this plug-in's installation location.

+ * Optionally, the platform searches for the correct localized version

+ * of the specified file using the users current locale, and Java

+ * naming convention for localized resource files (locale suffix appended 

+ * to the specified file extension).

+ * <p>

+ * The caller must close the returned stream when done.

+ * </p>

+ *

+ * @param file path relative to plug-in installation location

+ * @param localized <code>true</code> for the localized version

+ *   of the file, and <code>false</code> for the file exactly

+ *   as specified

+ * @return an input stream

+ */

+public final InputStream openStream(IPath file, boolean localized) throws IOException {

+	URL target = new URL(getDescriptor().getInstallURL() + file.toString());

+	return target.openStream();

+}

+/**

+ * Sets whether this plug-in is in debug mode.

+ * By default plug-ins are not in debug mode.  A plug-in can put itself

+ * into debug mode or the user can set a debug option to do so.

+ *

+ * @param value whether or not this plugi-in is in debug mode

+ */

+public void setDebugging(boolean value) {

+	debug = value;

+}

+/**

+ * Shuts down this plug-in and discards all plug-in state.

+ * <p>

+ * This method should be re-implemented in subclasses that need to do something

+ * when the plug-in is shut down.  Implementors should call the inherited method

+ * to ensure that any system requirements can be met.

+ * </p>

+ * <p>

+ * Plug-in shutdown code should be robust. In particular, this method

+ * should always make an effort to shut down the plug-in. Furthermore,

+ * the code should not assume that the plug-in was started successfully,

+ * as this method will be invoked in the event of a failure during startup.

+ * </p>

+ * <p>

+ * Note 1: If a plug-in has been started, this method will be automatically

+ * invoked by the platform when the platform is shut down.

+ * </p>

+ * <p>

+ * Note 2: This method is intended to perform simple termination

+ * of the plug-in environment. The platform may terminate invocations

+ * that do not complete in a timely fashion.

+ * </p>

+ * <b>Cliens must never explicitly call this method.</b>

+ *

+ * @exception CoreException if this method fails to shut down

+ *   this plug-in 

+ */

+public void shutdown() throws CoreException {

+}

+/**

+ * Starts up this plug-in.

+ * <p>

+ * This method should be overridden in subclasses that need to do something

+ * when this plug-in is started.  Implementors should call the inherited method

+ * to ensure that any system requirements can be met.

+ * </p>

+ * <p>

+ * If this method throws an exception, it is taken as an indication that

+ * plug-in initialization has failed; as a result, the plug-in will not

+ * be activated; moreover, the plug-in will be marked as disabled and 

+ * ineligible for activation for the duration.

+ * </p>

+ * <p>

+ * Plug-in startup code should be robust. In the event of a startup failure,

+ * the plug-in's <code>shutdown</code> method will be invoked automatically,

+ * in an attempt to close open files, etc.

+ * </p>

+ * <p>

+ * Note 1: This method is automatically invoked by the platform 

+ * the first time any code in the plug-in is executed.

+ * </p>

+ * <p>

+ * Note 2: This method is intended to perform simple initialization 

+ * of the plug-in environment. The platform may terminate initializers 

+ * that do not complete in a timely fashion.

+ * </p>

+ * <b>Cliens must never explicitly call this method.</b>

+ *

+ * @exception CoreException if this plug-in did not start up properly

+ */

+public void startup() throws CoreException {

+}

+/**

+ * Returns a string representation of the plug-in, suitable 

+ * for debugging purposes only.

+ */

+public String toString() {

+	return descriptor.toString();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/PluginVersionIdentifier.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/PluginVersionIdentifier.java
new file mode 100644
index 0000000..401eef8
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/PluginVersionIdentifier.java
@@ -0,0 +1,249 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import java.util.Vector;

+import java.util.StringTokenizer;

+import org.eclipse.core.internal.runtime.Assert;

+

+/**

+ * <p>

+ * Version identifier for a plug-in. In its string representation, 

+ * it consists of up to 3 positive integer numbers separated by decimal point.

+ * For example, the following are valid version identifiers 

+ * (as strings):

+ * <ul>

+ *   <li><code>0.0.0</code></li>

+ *   <li><code>1.0.127564</code></li>

+ *   <li><code>3.7.2</code></li>

+ *   <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li>

+ *   <li><code>3</code> (interpreted as <code>3.0.0</code>)</li>

+ * </ul>

+ * </p>

+ * <p>

+ * The version identifier can be decomposed into a major, minor

+ * and service level component. A difference in the major 

+ * component is interpreted as an incompatible version change. 

+ * A difference in the minor (and not the major) component is 

+ * interpreted as a compatible version change. The service

+ * level component is interpreted as a cumulative 

+ * and compatible service update of the minor version component.

+ * </p>

+ * <p>

+ * Version identifiers can be matched for equality, equivalency,

+ * and compatibility.

+ * </p>

+ * <p>

+ * Clients may instantiate; not intended to be subclassed by clients.

+ * </p>

+ * @see IPluginDescriptor#getVersionIdentifier

+ */	

+public final class PluginVersionIdentifier {

+		

+	private	int major = 0;

+	private int minor = 0;

+	private int service = 0;

+	

+	private static final String	SEPARATOR = ".";

+/**

+ * Creates a plug-in version identifier from its components.

+ * 

+ * @param major major component of the version identifier

+ * @param minor minor component of the version identifier

+ * @param service service update component of the version identifier

+ */

+public PluginVersionIdentifier(int major, int minor, int service) {

+

+	Assert.isTrue(major>=0);

+	Assert.isTrue(minor>=0);

+	Assert.isTrue(service>=0);

+	

+	this.major = major;

+	this.minor = minor;

+	this.service = service;

+}

+/**

+ * Creates a plug-in version identifier from the given string.

+ * The string represenation consists of up to 3 integer 

+ * numbers separated by decimal point.

+ * For example, the following are valid version identifiers 

+ * (as strings):

+ * <ul>

+ *   <li><code>0.0.0</code></li>

+ *   <li><code>1.0.127564</code></li>

+ *   <li><code>3.7.2</code></li>

+ *   <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li>

+ *   <li><code>3</code> (interpreted as <code>3.0.0</code>)</li>

+ * </ul>

+ * </p>

+ * 

+ * @param versionId string representation of the version identifier

+ */

+public PluginVersionIdentifier(String versionId) {

+

+	Assert.isNotNull(versionId);

+	String s = versionId.trim();

+	Assert.isTrue(!s.equals(""));

+	Assert.isTrue(!s.startsWith(SEPARATOR));

+	Assert.isTrue(!s.endsWith(SEPARATOR));

+	Assert.isTrue(s.indexOf(SEPARATOR+SEPARATOR)==-1);

+	

+	StringTokenizer st = new StringTokenizer(s, SEPARATOR);

+	Integer token;

+	Vector elements = new Vector(3);

+

+	while(st.hasMoreTokens()) {

+		token = new Integer((String)st.nextToken());

+		Assert.isTrue(token.intValue() >= 0);

+		elements.addElement(token);

+	}

+

+	Assert.isTrue(elements.size()>0);

+	Assert.isTrue(elements.size()<=3);

+

+	if (elements.size()>=1) this.major = ((Integer)elements.elementAt(0)).intValue();

+	if (elements.size()>=2) this.minor = ((Integer)elements.elementAt(1)).intValue();

+	if (elements.size()>=3) this.service = ((Integer)elements.elementAt(2)).intValue();

+

+}

+/**

+ * Compare version identifiers for equality. Identifiers are

+ * equal if all of their components are equal.

+ *

+ * @param object an object to compare

+ * @return whehter or not the two objects are equal

+ */

+public boolean equals(Object object) {

+	if (!(object instanceof PluginVersionIdentifier))

+		return false;

+	PluginVersionIdentifier v = (PluginVersionIdentifier) object;

+	return v.getMajorComponent() == major && v.getMinorComponent() == minor && v.getServiceComponent() == service;

+}

+/**

+ * Returns a hash code value for the object. 

+ *

+ * @return an integer which is a hash code value for this object.

+ */

+public int hashCode() {

+	return major + minor + service;

+}

+/**

+ * Returns the major (incompatible) component of this 

+ * version identifier.

+ *

+ * @return the major version

+ */

+public int getMajorComponent() {

+	return major;

+}

+/**

+ * Returns the minor (compatible) component of this 

+ * version identifier.

+ *

+ * @return the minor version

+ */

+public int getMinorComponent() {

+	return minor;

+}

+/**

+ * Returns the service level component of this 

+ * version identifier.

+ *

+ * @return the service level

+ */

+public int getServiceComponent() {

+	return service;

+}

+/**

+ * Compares two version identifiers for compatibility.

+ * <p>

+ * A version identifier is considered to be compatible if its major 

+ * component equals to the argument major component, and its minor component

+ * is greater than or equal to the argument minor component.

+ * If the minor components are equal, than the service level of the

+ * version identifier must be greater than or equal to the service level

+ * of the argument identifier.

+ * </p>

+ *

+ * @param versionId the other version identifier

+ * @return <code>true</code> is this version identifier

+ *    is compatible with the given version identifier, and

+ *    <code>false</code> otherwise

+ */

+public boolean isCompatibleWith(PluginVersionIdentifier id) {

+	if (id == null)

+		return false;

+	if (major != id.getMajorComponent())

+		return false;

+	if (minor > id.getMinorComponent())

+		return true;

+	if (minor < id.getMinorComponent())

+		return false;

+	if (service >= id.getServiceComponent())

+		return true;

+	else

+		return false;

+}

+/**

+ * Compares two version identifiers for equivalency.

+ * <p>

+ * Two version identifiers are considered to be equivalent if their major 

+ * and minor component equal and are at least at the same service level 

+ * as the argument.

+ * </p>

+ *

+ * @param versionId the other version identifier

+ * @return <code>true</code> is this version identifier

+ *    is equivalent to the given version identifier, and

+ *    <code>false</code> otherwise

+ */

+public boolean isEquivalentTo(PluginVersionIdentifier id) {

+	if (id == null)

+		return false;

+	if (major != id.getMajorComponent())

+		return false;

+	if (minor != id.getMinorComponent())

+		return false;

+	if (service >= id.getServiceComponent())

+		return true;

+	else

+		return false;

+}

+/**

+ * Compares two version identifiers for order using multi-decimal

+ * comparison. 

+ *

+ * @param versionId the other version identifier

+ * @return <code>true</code> is this version identifier

+ *    is greater than the given version identifier, and

+ *    <code>false</code> otherwise

+ */

+public boolean isGreaterThan(PluginVersionIdentifier id) {

+

+	if (id == null) {

+		if (major==0 && minor==0 && service==0) return false;

+		else return true;

+	}

+

+	if (major > id.getMajorComponent()) return true;

+	if (major < id.getMajorComponent()) return false;

+	if (minor > id.getMinorComponent()) return true;

+	if (minor < id.getMinorComponent()) return false;	

+	if (service > id.getServiceComponent()) return true;

+	else return false;

+

+}

+/**

+ * Returns the string representation of this version identifier. 

+ * The result satisfies

+ * <code>vi.equals(new PluginVersionIdentifier(vi.toString()))</code>.

+ *

+ * @return the string representation of this plug-in version identifier

+ */

+public String toString() {

+	return major+SEPARATOR+minor+SEPARATOR+service;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ProgressMonitorWrapper.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ProgressMonitorWrapper.java
new file mode 100644
index 0000000..ff86d29
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/ProgressMonitorWrapper.java
@@ -0,0 +1,128 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.internal.runtime.Assert;

+

+/**

+ * An abstract wrapper around a progress monitor which,

+ * unless overridden, forwards <code>IProgressMonitor</code>

+ * methods to the wrapped progress monitor.

+ * <p>

+ * Clients may subclass.

+ * </p>

+ */

+public abstract class ProgressMonitorWrapper implements IProgressMonitor {

+

+	/** The wrapped progress monitor. */

+	private IProgressMonitor progressMonitor;

+

+/** 

+ * Creates a new wrapper around the given monitor.

+ *

+ * @param monitor the progress monitor to forward to

+ */

+protected ProgressMonitorWrapper(IProgressMonitor monitor) {

+	Assert.isNotNull(monitor);

+	progressMonitor = monitor;

+}

+/** 

+ * This implementation of a <code>IProgressMonitor</code>

+ * method forwards to the wrapped progress monitor.

+ * Clients may override this method to do additional

+ * processing.

+ *

+ * @see IProgressMonitor#beginTask

+ */

+public void beginTask(String name, int totalWork) {

+	progressMonitor.beginTask(name, totalWork);

+}

+/**

+ * This implementation of a <code>IProgressMonitor</code>

+ * method forwards to the wrapped progress monitor.

+ * Clients may override this method to do additional

+ * processing.

+ *

+ * @see IProgressMonitor#done

+ */

+public void done() {

+	progressMonitor.done();

+}

+/**

+ * Returns the wrapped progress monitor.

+ *

+ * @return the wrapped progress monitor

+ */

+public IProgressMonitor getWrappedProgressMonitor() {

+	return progressMonitor;

+}

+/**

+ * This implementation of a <code>IProgressMonitor</code>

+ * method forwards to the wrapped progress monitor.

+ * Clients may override this method to do additional

+ * processing.

+ *

+ * @see IProgressMonitor#internalWorked

+ */

+public void internalWorked(double work) {

+	progressMonitor.internalWorked(work);

+}

+/**

+ * This implementation of a <code>IProgressMonitor</code>

+ * method forwards to the wrapped progress monitor.

+ * Clients may override this method to do additional

+ * processing.

+ *

+ * @see IProgressMonitor#isCanceled

+ */

+public boolean isCanceled() {

+	return progressMonitor.isCanceled();

+}

+/**

+ * This implementation of a <code>IProgressMonitor</code>

+ * method forwards to the wrapped progress monitor.

+ * Clients may override this method to do additional

+ * processing.

+ *

+ * @see IProgressMonitor#setCanceled

+ */

+public void setCanceled(boolean b) {

+	progressMonitor.setCanceled(b);

+}

+/**

+ * This implementation of a <code>IProgressMonitor</code>

+ * method forwards to the wrapped progress monitor.

+ * Clients may override this method to do additional

+ * processing.

+ *

+ * @see IProgressMonitor#setTaskName

+ */

+public void setTaskName(String name) {

+	progressMonitor.setTaskName(name);

+}

+/**

+ * This implementation of a <code>IProgressMonitor</code>

+ * method forwards to the wrapped progress monitor.

+ * Clients may override this method to do additional

+ * processing.

+ *

+ * @see IProgressMonitor#subTask

+ */

+public void subTask(String name) {

+	progressMonitor.subTask(name);

+}

+/**

+ * This implementation of a <code>IProgressMonitor</code>

+ * method forwards to the wrapped progress monitor.

+ * Clients may override this method to do additional

+ * processing.

+ *

+ * @see IProgressMonitor#worked

+ */

+public void worked(int work) {

+	progressMonitor.worked(work);

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/QualifiedName.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/QualifiedName.java
new file mode 100644
index 0000000..17d8724
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/QualifiedName.java
@@ -0,0 +1,103 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.internal.runtime.Assert;

+ 

+/**

+ * Qualified names are two-part names: qualifier and local name.

+ * The qualifier must be in URI form (see RFC2396).  

+ * Note however that the qualifier may be <code>null</code> if

+ * the default name space is being used.  The empty string is not 

+ * a valid local name.

+ * <p>

+ * This class is not intended to be subclassed by clients.

+ * </p>

+ */

+public final class QualifiedName {

+

+	/** Qualifier part (potentially <code>null</code>). */

+	/*package*/ String qualifier = null;

+

+	/** Local name part. */

+	/*package*/ String localName = null;

+/**

+ * Creates and returns a new qualified name with the given qualifier

+ * and local name.  The local name must not be the empty string.

+ * The qualifier may be <code>null</code>.

+ * <p>

+ * Clients may instantiate.

+ * </p>

+ * @param qualifier the qualifier string, or <code>null</code>

+ * @param localName the local name string

+ */

+public QualifiedName(String qualifier, String localName) {

+	Assert.isLegal(localName != null && localName.length() != 0);

+	this.qualifier = qualifier;

+	this.localName = localName;

+}

+/**

+ * Returns whether this qualified name is equivalent to the given object.

+ * <p>

+ * Qualified names are equal if and only if they have the same

+ * qualified parts and local parts.

+ * Qualified names are not equal to objects other than qualified names.

+ * </p>

+ *

+ * @param obj the object to compare to

+ * @return <code>true</code> if these are equivalent qualified

+ *    names, and <code>false</code> otherwise

+ */

+public boolean equals(Object obj) {

+	if (obj == this) {

+		return true;

+	}

+	if (!(obj instanceof QualifiedName)) {

+		return false;

+	}

+	QualifiedName qName = (QualifiedName) obj;

+	/* There may or may not be a quailfier */

+	if (qualifier == null && qName.getQualifier() != null) {

+		return false;

+	}

+	if (qualifier != null && !qualifier.equals(qName.getQualifier())) {

+		return false;

+	}

+	return localName.equals(qName.getLocalName());

+}

+/**

+ * Returns the local part of this name.

+ *

+ * @return the local name string

+ */

+public String getLocalName() {

+	return localName;

+}

+/**

+ * Returns the qualifier part for this qualifed name, or <code>null</code>

+ * if none.

+ *

+ * @return the qualifier string, or <code>null</code>

+ */

+public String getQualifier() {

+	return qualifier;

+}

+/* (Intentionally omitted from javadoc)

+ * Implements the method <code>Object.hashCode</code>.

+ * 

+ * Returns the hash code for this qualified name.

+ */

+public int hashCode() {

+	return (qualifier == null ? 0 : qualifier.hashCode()) + localName.hashCode();

+}

+/**

+ * Converts this qualified name into a string, suitable for 

+ * debug purposes only.

+ */

+public String toString() {

+	return "QualifiedName(" + (getQualifier() == null ? "null" : getQualifier()) + "," + getLocalName() + ")";

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Status.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Status.java
new file mode 100644
index 0000000..b6d8f13
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Status.java
@@ -0,0 +1,192 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.internal.runtime.Assert;

+

+/**

+ * A concrete status implementation, suitable either for 

+ * instantiating or subclassing.

+ */

+public class Status implements IStatus {

+	/**

+	 * The severity. One of

+	 * <ul>

+	 * <li><code>ERROR</code></li>

+	 * <li><code>WARNING</code></li>

+	 * <li><code>INFO</code></li>

+	 * <li>or <code>OK</code> (0)</li>

+	 * </ul>

+	 */

+	private int severity = OK;

+	

+	/** Unique identifier of plug-in.

+	 */

+	private String pluginId;

+	

+	/** Plug-in-specific status code.

+	 */

+	private int code;

+

+	/** Message, localized to the current locale.

+	 */

+	private String message;

+

+	/** Wrapped exception, or <code>null</code> if none.

+	 */

+	private Throwable exception = null;

+

+	/** Constant to avoid generating garbage.

+	 */

+	private static final IStatus[] theEmptyStatusArray = new IStatus[0];

+/**

+ * Creates a new status object.  The created status has no children.

+ *

+ * @param severity the severity; one of <code>OK</code>,

+ *   <code>ERROR</code>, <code>INFO</code>, or <code>WARNING</code>

+ * @param pluginId the unique identifier of the relevant plug-in

+ * @param code the plug-in-specific status code, or <code>OK</code>

+ * @param message a human-readable message, localized to the

+ *    current locale

+ * @param exception a low-level exception, or <code>null</code> if not

+ *    applicable 

+ */

+public Status(int severity, String pluginId, int code, String message, Throwable exception) {

+	setSeverity(severity);

+	setPlugin(pluginId);

+	setCode(code);

+	setMessage(message);

+	setException(exception);

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public IStatus[] getChildren() {

+	return theEmptyStatusArray;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public int getCode() {

+	return code;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public Throwable getException() {

+	return exception;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public String getMessage() {

+	return message;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public String getPlugin() {

+	return pluginId;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public int getSeverity() {

+	return severity;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public boolean isMultiStatus() {

+	return false;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public boolean isOK() {

+	return severity == OK;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the corresponding method on <code>IStatus</code>.

+ */

+public boolean matches(int severityMask) {

+	return (severity & severityMask) != 0;

+}

+/**

+ * Sets the status code.

+ *

+ * @param code the plug-in-specific status code, or <code>OK</code>

+ */

+protected void setCode(int code) {

+	this.code = code;

+}

+/**

+ * Sets the exception.

+ *

+ * @param exception a low-level exception, or <code>null</code> if not

+ *    applicable 

+ */

+protected void setException(Throwable exception) {

+	this.exception = exception;

+}

+/**

+ * Sets the message.

+ *

+ * @param message a human-readable message, localized to the

+ *    current locale

+ */

+protected void setMessage(String message) {

+	Assert.isLegal(message != null);

+	this.message = message;

+}

+/**

+ * Sets the plug-in id.

+ *

+ * @param pluginId the unique identifier of the relevant plug-in

+ */

+protected void setPlugin(String pluginId) {

+	Assert.isLegal(pluginId != null && pluginId.length() > 0);

+	this.pluginId = pluginId;

+}

+/**

+ * Sets the severity.

+ *

+ * @param severity the severity; one of <code>OK</code>,

+ *   <code>ERROR</code>, <code>INFO</code>, or <code>WARNING</code>

+ */

+protected void setSeverity(int severity) {

+	Assert.isLegal(severity == OK || severity == ERROR || severity == WARNING || severity == INFO);

+	this.severity = severity;

+}

+/**

+ * Returns a string representation of the status, suitable 

+ * for debugging purposes only.

+ */

+public String toString() {

+	StringBuffer buf = new StringBuffer();

+	buf.append("Status ");

+	if (severity == OK) {

+		buf.append("OK");

+	} else if (severity == ERROR) {

+		buf.append("ERROR");

+	} else if (severity == WARNING) {

+		buf.append("WARNING");

+	} else if (severity == INFO) {

+		buf.append("INFO");

+	} else {

+		buf.append("severity=");

+		buf.append(severity);

+	}

+	buf.append(pluginId);

+	buf.append(" code=");

+	buf.append(code);

+	buf.append(" ");

+	buf.append(message);

+	buf.append(" ");

+	buf.append(exception);

+	return buf.toString();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/SubProgressMonitor.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/SubProgressMonitor.java
new file mode 100644
index 0000000..9692e97
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/SubProgressMonitor.java
@@ -0,0 +1,164 @@
+package org.eclipse.core.runtime;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * A progress monitor that uses the a given amount of work ticks

+ * form a parent monitor. It can be used as follows:

+ * <pre>

+ *     try {

+ *         pm.beginTask("Main Task", 100);

+ *         doSomeWork(pm, 30);

+ *         SubProgressMonitor subMonitor= new SubProgressMonitor(pm, 40);

+ *         try {

+ *             subMonitor.beginTask("", 300);

+ *             doSomeWork(subMonitor, 300);

+ *         } finally {

+ *             subMonitor.done();

+ *         }

+ *         doSomeWork(pm, 30);

+ *     } finally {

+ *         pm.done();

+ *     }

+ * </pre>

+ * <p>

+ * This class may be instantiated or subclassed by clients.

+  * </p>

+ */

+public class SubProgressMonitor extends ProgressMonitorWrapper {

+

+	/**

+	 * Style constant indicating that calls to <code>subTask</code>

+	 * should not have any effect.

+	 *

+	 * @see #SubProgressMonitor(IProgressMonitor,int,int)

+	 */

+	public static final int SUPPRESS_SUBTASK_LABEL= 1 << 1;

+	/**

+	 * Style constant indicating that the main task label 

+	 * should be prepended to the subtask label.

+	 *

+	 * @see #SubProgressMonitor(IProgressMonitor,int,int)

+	 */

+	public static final int PREPEND_MAIN_LABEL_TO_SUBTASK= 1 << 2;

+

+	private int parentTicks = 0;

+	private double sentToParent = 0.0;

+	private double scale = 0.0;

+	private int nestedBeginTasks = 0;

+	private boolean usedUp = false;

+	private int style;

+	private String mainTaskLabel;

+

+/**

+ * Creates a new sub-progress monitor for the given monitor. The sub 

+ * progress monitor uses the given number of work ticks from its 

+ * parent monitor.

+ *

+ * @param monitor the parent progress monitor

+ * @param ticks the number of work ticks allocated from the

+ *    parent monitor

+ */

+public SubProgressMonitor(IProgressMonitor monitor, int ticks) {

+	this(monitor, ticks, 0);

+}

+/**

+ * Creates a new sub-progress monitor for the given monitor. The sub 

+ * progress monitor uses the given number of work ticks from its 

+ * parent monitor.

+ *

+ * @param monitor the parent progress monitor

+ * @param ticks the number of work ticks allocated from the

+ *    parent monitor

+ * @param styles one of

+ *    <ul>

+ *    <li> <code>SUPPRESS_SUBTASK_LABEL</code> </li>

+ *    <li> <code>PREPEND_MAIN_LABEL_TO_SUBTASK</code> </li>

+ *    </ul>

+ * @see #SUPPRESS_SUBTASK_LABEL

+ * @see #PREPEND_MAIN_LABEL_TO_SUBTASK

+ */

+public SubProgressMonitor(IProgressMonitor monitor, int ticks, int style) {

+	super(monitor);

+	this.parentTicks = ticks;

+	this.style = style;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the method <code>IProgressMonitor.beginTask</code>.

+ *

+ * Starts a new main task. Since this progress monitor is a sub

+ * progress monitor, the given name will NOT be used to update

+ * the progress bar's main task label. That means the given 

+ * string will be ignored. If style <code>PREPEND_MAIN_LABEL_TO_SUBTASK

+ * <code> is specified, then the given string will be prepended to

+ * every string passed to <code>subTask(String)</code>.

+ */

+public void beginTask(String name, int totalWork) {

+	nestedBeginTasks++;

+	// Ignore nested begin task calls.

+	if (nestedBeginTasks > 1) {

+		return;

+	}

+	// be safe:  if the argument would cause math errors (zero or 

+	// negative), just use 0 as the scale.  This disables progress for

+	// this submonitor. 

+	scale = totalWork <= 0 ? 0 : (double) parentTicks / (double) totalWork;

+	if ((style & PREPEND_MAIN_LABEL_TO_SUBTASK) != 0) {

+		mainTaskLabel = name;

+	}

+}

+/* (Intentionally not javadoc'd)

+ * Implements the method <code>IProgressMonitor.done</code>.

+ */

+public void done() {

+	// Ignore if more done calls than beginTask calls or if we are still

+	// in some nested beginTasks

+	if (nestedBeginTasks == 0 || --nestedBeginTasks > 0)

+		return;

+	// Send any remaining ticks and clear out the subtask text

+	double remaining = (double) parentTicks - sentToParent;

+	if (remaining > 0) 

+		super.internalWorked(remaining);

+	subTask("");

+	sentToParent = 0;

+}

+/* (Intentionally not javadoc'd)

+ * Implements the internal method <code>IProgressMonitor.internalWorked</code>.

+ */

+public void internalWorked(double work) {

+	if (usedUp || nestedBeginTasks != 1) {

+		return;

+	}

+

+	double realWork = scale * work;

+	// System.out.println("Sub monitor: " + realWork);

+	super.internalWorked(realWork);

+	sentToParent += realWork;

+	if (sentToParent >= parentTicks) {

+		usedUp = true;

+	}

+}

+/* (Intentionally not javadoc'd)

+ * Implements the method <code>IProgressMonitor.subTask</code>.

+ */

+public void subTask(String name) {

+	if ((style & SUPPRESS_SUBTASK_LABEL) != 0) {

+		return;

+	}

+

+	String label = name;

+	if ((style & PREPEND_MAIN_LABEL_TO_SUBTASK) != 0 && mainTaskLabel != null && mainTaskLabel.length() > 0) {

+		label = mainTaskLabel + " " + label;

+	}

+	super.subTask(label);

+}

+/* (Intentionally not javadoc'd)

+ * Implements the method <code>IProgressMonitor.worked</code>.

+ */

+public void worked(int work) {

+	internalWorked(work);

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ComponentModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ComponentModel.java
new file mode 100644
index 0000000..754514f
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ComponentModel.java
@@ -0,0 +1,122 @@
+package org.eclipse.core.runtime.model;
+

+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.PluginVersionIdentifier;
+

+/**

+ * An object which represents the user-defined contents of a component model

+ * in a component manifest.

+ * <p>

+ * This class may be instantiated and further subclassed.

+ * </p>

+ */

+

+public class ComponentModel extends InstallModel {

+

+	// DTD properties (included in install manifest)

+	private boolean allowUpgrade = false;

+	private boolean optional = false;

+	private PluginDescriptorModel[] plugins = new PluginDescriptorModel[0];

+	private PluginFragmentModel[] fragments = new PluginFragmentModel[0];

+

+/**

+ * Returns whether this component can be upgraded within its configuration.

+ *

+ * @return whether this component is upgradeable

+ */

+public boolean getAllowUpgrade() {

+	return allowUpgrade;

+}

+

+/**

+ * Returns whether this component is optional within its configuration.

+ *

+ * @return whether this component is optional

+ */

+public boolean getOptional() {

+	return optional;

+}

+

+/**

+ * Returns the list of plug-ins managed by this component.

+ *

+ * @return the plug-ins in this component

+ */

+public PluginDescriptorModel[] getPlugins() {

+	return plugins;

+}

+

+/**

+ * Returns the list of fragments managed by this component.

+ *

+ * @return the fragments in this component

+ */

+public PluginFragmentModel[] getFragments() {

+	return fragments;

+}

+

+/**

+ * 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 (plugins != null)

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

+			plugins[i].markReadOnly();

+	if (fragments != null)

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

+			fragments[i].markReadOnly();

+}

+

+/**

+ * Sets whether this component can be upgraded within its configuration.

+ * This object must not be read-only.

+ *

+ * @param value whether this component is upgradeable

+ */

+public void setAllowUpgrade(boolean value) {

+	assertIsWriteable();

+	allowUpgrade = value;

+}

+

+/**

+ * Sets whether this component is optional within its configuration.

+ * This object must not be read-only.

+ *

+ * @param value whether this component is optional

+ */

+public void setOptional(boolean value) {

+	assertIsWriteable();

+	optional = value;

+}

+

+/**

+ * Sets the list of plug-ins managed by this component.

+ * This object must not be read-only.

+ *

+ * @param value the plug-ins managed by this component

+ */

+public void setPlugins(PluginDescriptorModel[] value) {

+	assertIsWriteable();

+	plugins = value;

+}

+

+/**

+ * Sets the list of fragments managed by this component.

+ * This object must not be read-only.

+ *

+ * @param value the fragments managed by this component

+ */

+public void setFragments(PluginFragmentModel[] value) {

+	assertIsWriteable();

+	fragments = value;

+}

+

+}
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationElementModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationElementModel.java
new file mode 100644
index 0000000..ee1841d
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationElementModel.java
@@ -0,0 +1,138 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An object which represents the user-defined contents of an extension

+ * in a plug-in manifest.

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+

+public class ConfigurationElementModel extends PluginModelObject {

+

+	// DTD properties (included in plug-in manifest)

+	private String value = null;

+	private ConfigurationPropertyModel[] properties = null;

+	private ConfigurationElementModel[] children = null;

+

+	// transient properties (not included in plug-in manifest)

+	private Object parent = null; // parent element or declaring extension

+/**

+ * Creates a new configuration element model in which all fields

+ * are <code>null</code>.

+ */

+public ConfigurationElementModel() {}

+/**

+ * Returns the element which contains this element.  If this element

+ * is an immediate child of an extension, the

+ * returned value can be downcast to <code>ExtensionModel</code>.

+ * Otherwise the returned value can be downcast to 

+ * <code>ConfigurationElementModel</code>.

+ *

+ * @return the parent of this configuration element

+ *  or <code>null</code>

+ */

+public Object getParent() {

+	return parent;

+}

+/**

+ * Returns the extension in which this configuration element is declared.

+ * If this element is a top-level child of an extension, the returned value

+ * is equivalent to <code>getParent</code>.

+ *

+ * @return the extension in which this configuration element is declared

+ *  or <code>null</code>

+ */

+public ExtensionModel getParentExtension() {

+	Object p = getParent();

+	while (p != null && p instanceof ConfigurationElementModel)

+		p = ((ConfigurationElementModel) p).getParent();

+	return (ExtensionModel) p;

+}

+/**

+ * Returns the properties associated with this element.

+ *

+ * @return the properties associated with this element

+ *  or <code>null</code>

+ */

+public ConfigurationPropertyModel[] getProperties() {

+	return properties;

+}

+/**

+ * Returns this element's sub-elements.

+ *

+ * @return the sub-elements of this element or <code>null</code>

+ */

+public ConfigurationElementModel[] getSubElements() {

+	return children;

+}

+/**

+ * Returns the value of this element.

+ * 

+ * @return the value of this element or <code>null</code>

+ */

+public String getValue() {

+	return value;

+}

+/**

+ * 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 (children != null)

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

+			children[i].markReadOnly();

+	if (properties != null)

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

+			properties[i].markReadOnly();

+}

+/**

+ * Sets the parent of this element.  The supplied parent is either

+ * an <code>ExtensionModel</code>, if this element is to be a 

+ * direct child of an extension, or another <code>ConfigurationElement</code>.

+ * This object must not be read-only.

+ *

+ * @param value the new parent of this element.  May be <code>null</code>.

+ */

+public void setParent(Object value) {

+	assertIsWriteable();

+	parent = value;

+}

+/**

+ * Sets the properties associated with this element.  This object must not be read-only.

+ *

+ * @param value the properties to associate with this element.  May be <code>null</code>.

+ */

+public void setProperties(ConfigurationPropertyModel[] value) {

+	assertIsWriteable();

+	properties = value;

+}

+/**

+ * Sets configuration elements contained by this element

+ * This object must not be read-only.

+ *

+ * @param value the configuration elements to be associated with this element.  

+ *		May be <code>null</code>.

+ */

+public void setSubElements(ConfigurationElementModel[] value) {

+	assertIsWriteable();

+	children = value;

+}

+/**

+ * Sets the value of this element.  This object must not be read-only.

+ * 

+ * @param value the new value of this element.  May be <code>null</code>.

+ */

+public void setValue(String value) {

+	assertIsWriteable();

+	this.value = value;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationModel.java
new file mode 100644
index 0000000..b7cc3ba
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationModel.java
@@ -0,0 +1,77 @@
+package org.eclipse.core.runtime.model;
+

+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.PluginVersionIdentifier;
+

+/**

+ * An object which represents the user-defined contents of a configuration model

+ * in a configuration manifest.

+ * <p>

+ * This class may be instantiated and further subclassed.

+ * </p>

+ */

+

+public class ConfigurationModel extends InstallModel {

+

+	// DTD properties (included in install manifest)

+	private String application = null;

+	private ComponentModel[] components = new ComponentModel[0];

+

+/**

+ * Returns the name of the application to be run for this configuration.

+ *

+ * @return the application to run for this configuration

+ */

+public String getApplication() {

+	return application;

+}

+

+/**

+ * Returns the list of components managed by this configuration.

+ *

+ * @return the components in this configuration

+ */

+public ComponentModel[] getComponents() {

+	return components;

+}

+

+/**

+ * 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 (components!= null)

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

+			components[i].markReadOnly();

+}

+

+/**

+ * Sets the application to run for this configuration.

+ * This object must not be read-only.

+ *

+ * @param value the application to run for this configuration

+ */

+public void setApplication(String value) {

+	assertIsWriteable();

+	application = value;

+}

+

+/**

+ * Sets the list of components managed by this configuration.

+ * This object must not be read-only.

+ *

+ * @param value the components managed by this configuration

+ */

+public void setComponents(ComponentModel[] value) {

+	assertIsWriteable();

+	components = value;

+}

+

+}
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationPropertyModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationPropertyModel.java
new file mode 100644
index 0000000..c780813
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ConfigurationPropertyModel.java
@@ -0,0 +1,45 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An object which represents the user-defined properties in a configuration

+ * element of a plug-in manifest.  Properties are <code>String</code>-based

+ * key/value pairs.

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+public class ConfigurationPropertyModel extends PluginModelObject {

+

+	// DTD properties (included in plug-in manifest)

+	private String value = null;

+/**

+ * Creates a new configuration property model in which all fields

+ * are <code>null</code>.

+ */

+public ConfigurationPropertyModel() {

+}

+/**

+ * Returns the value of this property.

+ * 

+ * @return the value of this property

+ *  or <code>null</code>

+ */

+public String getValue() {

+	return value;

+}

+/**

+ * Sets the value of this property.

+ * This object must not be read-only.

+ * 

+ * @param value the new value of this property.  May be <code>null</code>.

+ */

+public void setValue(String value) {

+	assertIsWriteable();

+	this.value = value;

+}

+}

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
new file mode 100644
index 0000000..b27ada2
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionModel.java
@@ -0,0 +1,149 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An object which represents the user-defined extension in a 

+ * plug-in manifest.  

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+public class ExtensionModel extends PluginModelObject {

+

+	// DTD properties (included in plug-in manifest)

+	private String extensionPoint = null;

+	private String id = null;

+	private ConfigurationElementModel[] elements = null;

+

+	// transient properties (not included in plug-in manifest)

+	private PluginModel plugin = null; // declaring plugin

+/**

+ * Creates a new extension model in which all fields

+ * are <code>null</code>.

+ */

+public ExtensionModel() {}

+/**

+ * Returns the extension point with which this extension is associated.

+ *

+ * @return the extension point with which this extension is associated

+ *  or <code>null</code>

+ */

+public String getExtensionPoint() {

+	return extensionPoint;

+}

+/**

+ * Returns the simple identifier of this extension, or <code>null</code>

+ * if this extension does not have an identifier.

+ * This identifier is specified in the plug-in manifest as a non-empty

+ * string containing no period characters (<code>'.'</code>) and 

+ * must be unique within the defining plug-in.

+ *

+ * @return the simple identifier of the extension (e.g. <code>"main"</code>)

+ *  or <code>null</code>

+ */

+public String getId() {

+	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 (PluginDescriptorModel) plugin;

+}

+/**

+ * Returns the configuration element children of this extension.

+ *

+ * @return the configuration elements in this extension

+ *  or <code>null</code>

+ */

+public ConfigurationElementModel[] getSubElements() {

+	return elements;

+}

+/**

+ * 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 (elements != null)

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

+			elements[i].markReadOnly();

+}

+/**

+ * Set the extension point with which this extension is associated.

+ * This object must not be read-only.

+ *

+ * @return the extension point with which this extension is associated.  

+ *		May be <code>null</code>.

+ */

+public void setExtensionPoint(String value) {

+	assertIsWriteable();

+	extensionPoint = value;

+}

+/**

+ * Sets the simple identifier of this extension, or <code>null</code>

+ * if this extension does not have an identifier.

+ * This identifier is specified in the plug-in manifest as a non-empty

+ * string containing no period characters (<code>'.'</code>) and 

+ * must be unique within the defining plug-in.

+ * This object must not be read-only.

+ *

+ * @param value the simple identifier of the extension (e.g. <code>"main"</code>).

+ *		May be <code>null</code>.

+ */

+public void setId(String value) {

+	assertIsWriteable();

+	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 value the plug-in descriptor in which this extension is declared.  

+ *		May be <code>null</code>.

+ */

+public void setParentPluginDescriptor(PluginDescriptorModel value) {

+	assertIsWriteable();

+	plugin = value;

+}

+/**

+ * Sets the configuration element children of this extension.

+ * This object must not be read-only.

+ *

+ * @param value the configuration elements in this extension.  

+ *		May be <code>null</code>.

+ */

+public void setSubElements(ConfigurationElementModel[] value) {

+	assertIsWriteable();

+	elements = 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
new file mode 100644
index 0000000..8c1752e
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/ExtensionPointModel.java
@@ -0,0 +1,135 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An object which represents the user-defined extension point in a 

+ * plug-in manifest. 

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+public class ExtensionPointModel extends PluginModelObject {

+

+	// DTD properties (included in plug-in manifest)

+	private String id = null;

+	private String schema = null;

+

+	// transient properties (not included in plug-in manifest)

+	private PluginModel plugin = null; // declaring plugin

+	private ExtensionModel[] extensions = null; // configured extensions

+/**

+ * Creates a new extension point model in which all fields

+ * are <code>null</code>.

+ */

+public ExtensionPointModel() {}

+/**

+ * Returns this extensions added to this extension point.

+ *

+ * @return the extensions in this extension point or <code>null</code>

+ */

+public ExtensionModel[] getDeclaredExtensions() {

+	return extensions;

+}

+/**

+ * Returns the simple identifier of this extension point, or <code>null</code>

+ * if this extension point does not have an identifier.

+ * This identifier is specified in the plug-in manifest as a non-empty

+ * string containing no period characters (<code>'.'</code>) and 

+ * must be unique within the defining plug-in.

+ *

+ * @return the simple identifier of the extension point (e.g. <code>"main"</code>)

+ *  or <code>null</code>

+ */

+public String getId() {

+	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 (PluginDescriptorModel) plugin;

+}

+/**

+ * Returns the schema specification for this extension point.

+ *

+ * @return the schema specification for this extension point or <code>null</code>

+ */

+public String getSchema() {

+	return schema;

+}

+/**

+ * Sets this extensions added to this extension point.

+ * This object must not be read-only.

+ *

+ * @param value the extensions in this extension point.

+ *		May be <code>null</code>.

+ */

+public void setDeclaredExtensions(ExtensionModel[] value) {

+	assertIsWriteable();

+	extensions = value;

+}

+/**

+ * Sets the simple identifier of this extension point, or <code>null</code>

+ * if this extension point does not have an identifier.

+ * This identifier is specified in the plug-in manifest as a non-empty

+ * string containing no period characters (<code>'.'</code>) and 

+ * must be unique within the defining plug-in.

+ * This object must not be read-only.

+ *

+ * @param value the simple identifier of the extension point (e.g. <code>"main"</code>).

+ *		May be <code>null</code>.

+ */

+public void setId(String value) {

+	assertIsWriteable();

+	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.

+ *

+ * @param the plug-in descriptor in which this extension point is declared.  

+ * 		May be <code>null</code>.

+ */

+public void setParentPluginDescriptor(PluginDescriptorModel value) {

+	assertIsWriteable();

+	plugin = value;

+}

+/**

+ * Sets the schema specification for this extension point.

+ * This object must not be read-only.

+ *

+ * @param value the schema specification for this extension point.

+ *		May be <code>null</code>.

+ */

+public void setSchema(String value) {

+	assertIsWriteable();

+	schema = value;

+}

+}

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
new file mode 100644
index 0000000..db5e7b4
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/Factory.java
@@ -0,0 +1,156 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.*;

+import org.eclipse.core.internal.runtime.InternalPlatform;

+import org.eclipse.core.runtime.model.*;

+import org.eclipse.core.internal.plugins.RegistryResolver;

+

+/**

+ * An object which can create plug-in related model objects (typically when

+ * parsing plug-in manifest files).

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+

+public class Factory {

+	private MultiStatus status;

+/**

+ * Creates a factory which can be used to create plug-in model objects.

+ * Errors and warnings during parsing etc. can be logged to the given 

+ * status via the <code>error</code> method.

+ *

+ * @param status the status to which errors should be logged

+ */

+public Factory(MultiStatus status) {

+	super();

+	this.status = status;

+}

+

+/**

+ * Returns a new component model which is not initialized.

+ *

+ * @return a new component model

+ */

+public ComponentModel createComponentModel() {

+	return new ComponentModel();

+}

+

+/**

+ * Returns a new configuration model which is not initialized.

+ *

+ * @return a new configuration model

+ */

+public ConfigurationModel createConfiguration() {

+	return new ConfigurationModel();

+}

+

+/**

+ * Returns a new configuration element model which is not initialized.

+ *

+ * @return a new configuration element model

+ */

+public ConfigurationElementModel createConfigurationElement() {

+	return new ConfigurationElementModel();

+}

+/**

+ * Returns a new configuration property model which is not initialized.

+ *

+ * @return a new configuration property model

+ */

+public ConfigurationPropertyModel createConfigurationProperty() {

+	return new ConfigurationPropertyModel();

+}

+/**

+ * Returns a new extension model which is not initialized.

+ *

+ * @return a new extension model

+ */

+public ExtensionModel createExtension() {

+	return new ExtensionModel();

+}

+/**

+ * Returns a new extension point model which is not initialized.

+ *

+ * @return a new extension point model

+ */

+public ExtensionPointModel createExtensionPoint() {

+	return new ExtensionPointModel();

+}

+/**

+ * Returns a new library model which is initialized to not export any

+ * of its code.

+ *

+ * @return a new library model

+ */

+public LibraryModel createLibrary() {

+	return new LibraryModel();

+}

+/**

+ * Returns a new plug-in descriptor model which is not initialized.

+ *

+ * @return a new plug-in descriptor model

+ */

+public PluginDescriptorModel createPluginDescriptor() {

+	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.

+ *

+ * @return a new plug-in prerequisite model

+ */

+public PluginPrerequisiteModel createPluginPrerequisite() {

+	return new PluginPrerequisiteModel();

+}

+/**

+ * Returns a new plug-in registry model with an empty plug-in table.

+ *

+ * @return a new plug-in registry model

+ */

+public PluginRegistryModel createPluginRegistry() {

+	return new PluginRegistryModel();

+}

+

+/**

+ * Returns a new URL model which is not initialized.

+ *

+ * @return a new URL model

+ */

+public URLModel createURL() {

+	return new URLModel();

+}

+

+/**

+ * Handles an error state specified by the status.  The collection of all logged status

+ * objects can be accessed using <code>getStatus()</code>.

+ *

+ * @param error a status detailing the error condition

+ */

+public void error(IStatus error) {

+	status.add(error);

+	if (InternalPlatform.DEBUG && InternalPlatform.DEBUG_PLUGINS)

+		System.out.println(error.toString());

+}

+/**

+ * Returns all of the status objects logged thus far by this factory.

+ *

+ * @return a multi-status containing all of the logged status objects

+ */

+public MultiStatus getStatus() {

+	return status;

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/InstallModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/InstallModel.java
new file mode 100644
index 0000000..2f3b913
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/InstallModel.java
@@ -0,0 +1,201 @@
+package org.eclipse.core.runtime.model;
+

+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import org.eclipse.core.runtime.PluginVersionIdentifier;
+

+/**

+ * An abstract class representing the common parts of the various install

+ * manifest structures.

+ * <p>

+ * This class may not be instantiated but may be further subclassed.

+ * </p>

+ */

+

+public abstract class InstallModel extends PluginModelObject {

+

+	// DTD properties (included in install manifest)

+	private String id = null;

+	private String version = null;

+	private String providerName = null;

+	private String description = null;

+	private String location = null;

+	private URLModel[] updates = new URLModel[0];

+	private URLModel[] discoveries = new URLModel[0];

+

+/**

+ * Returns the unique identifier of this component model

+ * or <code>null</code>.

+ * This identifier is a non-empty string and is unique 

+ * across all components.

+ *

+ * @return the unique identifier of this component model

+ *		(e.g. <code>"com.example"</code>) or <code>null</code>. 

+ */

+public String getId() {

+	return id;

+}

+

+/**

+ * Returns the location of this component.

+ *

+ * @return the location of this component or <code>null</code>

+ */

+public String getLocation() {

+	return location;

+}

+

+/**

+ * Returns the version name of this component.

+ *

+ * @return the version name of this component or <code>null</code>

+ */

+public String getVersion() {

+	return version;

+}

+

+/**

+ * Returns the name of the provider who authored this component.

+ *

+ * @return name of the provider who authored this component or <code>null</code>

+ */

+public String getProviderName() {

+	return providerName;

+}

+

+/**

+ * Returns the description of this component.

+ *

+ * @return description of this component or <code>null</code>

+ */

+public String getDescription() {

+	return description;

+}

+

+/**

+ * Returns the list of update URLs for this component.

+ *

+ * @return the update URLs for this component

+ */

+public URLModel[] getUpdates() {

+	return updates;

+}

+

+/**

+ * Returns the list of discovery URLs for this component.

+ *

+ * @return the discovery URLs for this component

+ */

+public URLModel[] getDiscoveries() {

+	return discoveries;

+}

+

+/**

+ * 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 (updates != null)

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

+			updates[i].markReadOnly();

+	if (discoveries != null)

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

+			discoveries[i].markReadOnly();

+}

+

+/**

+ * Sets the unique identifier of this component model.

+ * The identifier is a non-empty string and is unique 

+ * across all components.

+ * This object must not be read-only.

+ *

+ * @param value the unique identifier of this component model (e.g. <code>"com.example"</code>).

+ *		May be <code>null</code>.

+ */

+public void setId(String value) {

+	assertIsWriteable();

+	id = value;

+}

+

+/**

+ * Sets the version name of this component.  The version number

+ * is canonicalized.

+ * This object must not be read-only.

+ *

+ * @param value the version name of this component.

+ *		May be <code>null</code>.

+ */

+public void setVersion(String value) {

+	assertIsWriteable();

+	// XXX workaround because some people still do not use the correct 

+	// version format.

+	int i = value.indexOf(' ');

+	if (i > -1)

+		value = value.substring(0, i);

+	version = new PluginVersionIdentifier(value).toString();

+}

+

+/**

+ * Sets the name of the provider who authored this component.

+ * This object must not be read-only.

+ *

+ * @param value name of the provider who authored this component.

+ *		May be <code>null</code>.

+ */

+public void setProviderName(String value) {

+	assertIsWriteable();

+	providerName = value;

+}

+

+/**

+ * Sets the description of this component.

+ * This object must not be read-only.

+ *

+ * @param value the description of this component.

+ *		May be <code>null</code>.

+ */

+public void setDescription(String value) {

+	assertIsWriteable();

+	description = value;

+}

+

+/**

+ * Sets the location of this component.

+ * This object must not be read-only.

+ *

+ * @param value the location of this component

+ */

+public void setLocation(String value) {

+	assertIsWriteable();

+	location = value;

+}

+

+/**

+ * Sets the list of update URLs for this component.

+ * This object must not be read-only.

+ *

+ * @param value the update URLs for this component

+ */

+public void setUpdates(URLModel[] value) {

+	assertIsWriteable();

+	updates = value;

+}

+

+/**

+ * Sets the list of discovery URLs for this component.

+ * This object must not be read-only.

+ *

+ * @param value the discovery URLs for this component

+ */

+public void setDiscoveries(URLModel[] value) {

+	assertIsWriteable();

+	discoveries = value;

+}

+

+}
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
new file mode 100644
index 0000000..f061f67
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/LibraryModel.java
@@ -0,0 +1,114 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * 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> and

+ * <code>RESOURCE</code>.  

+ * </p>

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+public class LibraryModel extends PluginModelObject {

+

+	// DTD properties (included in plug-in manifest)

+	private String[] exports = null;

+	private String type = CODE;

+

+	// 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";

+	

+/**

+ * Creates a new library model in which all fields

+ * are <code>null</code>.

+ */

+public LibraryModel() {}

+/**

+ * Returns this library's export mask.

+ *

+ * @return this library's export mask or <code>null</code>

+ */

+public String[] getExports() {

+	return exports;

+}

+/**

+ * Returns this library's type.  

+ *

+ * @return the type of this library.  The valid types are: <code>CODE</code> and <code>RESOURCE</code>.

+ * @see #CODE

+ * @see #RESOURCE

+ */

+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

+ */

+public boolean isExported() {

+	return isExported;

+}

+/**

+ * Returns whether or not all of the code in this library is exported.

+ *

+ * @return whether or not all of the code in this library is exported

+ */

+public boolean isFullyExported() {

+	return isFullyExported;

+}

+/**

+ * Sets this library's export mask.

+ * This object must not be read-only.

+ *

+ * @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;

+		isFullyExported = false;

+	} else {

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

+			if (!value[i].equals(""))

+				isExported = true;

+			if (value[i].equals("*"))

+				isFullyExported = true;

+		}

+	}

+}

+/**

+ * Sets this library's type. The valid types are: <code>CODE</code> and <code>RESOURCE</code>.

+ * 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

+ */

+public void setType(String value) {

+	assertIsWriteable();

+	type = value.toLowerCase();

+}

+}

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
new file mode 100644
index 0000000..c9ee0d0
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginDescriptorModel.java
@@ -0,0 +1,106 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+/**

+ * An object which represents the user-defined contents of a plug-in

+ * in a plug-in manifest.

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+public class PluginDescriptorModel extends PluginModel {

+

+	// DTD properties (included in plug-in manifest)

+	private String pluginClass = null;

+

+	// transient properties (not included in plug-in manifest)

+	private boolean enabled = true; // whether or not the plugin definition loaded ok

+	private PluginFragmentModel[] fragments;

+

+/**

+ * Creates a new plug-in descriptor model in which all fields

+ * are <code>null</code>.

+ */

+public PluginDescriptorModel() {

+	super();

+}

+/*

+ * Returns true if this plugin has all of it's prerequisites and is,

+ * therefore enabled.

+ */

+public boolean getEnabled() {

+	return enabled;

+}

+

+/**

+ * Returns the fragments installed for this plug-in.

+ *

+ * @return this plug-in's fragments or <code>null</code>

+ */

+public PluginFragmentModel[] getFragments() {

+	return fragments;

+}

+

+/**

+ * Returns the fully qualified name of the Java class which implements

+ * the runtime support for this plug-in.

+ *

+ * @return the name of this plug-in's runtime class or <code>null</code>.

+ */

+public String getPluginClass() {

+	return pluginClass;

+}

+/**

+ * 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 getId();

+}

+

+/*

+ * Sets the value of the field 'enabled' to the parameter 'value'.

+ * If this plugin is enabled (default) it is assumed to have all

+ * of it's prerequisites.

+ *

+ * @param value set to false if this plugin should be disabled and

+ * true otherwise.

+ */

+public void setEnabled(boolean value) {

+	enabled = value;

+}

+

+/**

+ * Sets the list of fragments for this plug-in.

+ * This object must not be read-only.

+ *

+ * @param value the fragments for this plug-in.  May be <code>null</code>.

+ */

+public void setFragments(PluginFragmentModel[] value) {

+	assertIsWriteable();

+	fragments = 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.

+ *

+ * @param value the name of this plug-in's runtime class.

+ *		May be <code>null</code>.

+ */

+public void setPluginClass(String value) {

+	assertIsWriteable();

+	pluginClass = 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..df43ad1
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginFragmentModel.java
@@ -0,0 +1,85 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.PluginVersionIdentifier;

+

+/**

+ * 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.

+ * The given version number is canonicalized.

+ * 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();

+	// XXX workaround because some people still do not use the correct 

+	// version format.

+	int i = value.indexOf(' ');

+	if (i > -1)

+		value = value.substring(0, i);

+	pluginVersion = new PluginVersionIdentifier(value).toString();

+}

+}

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..1458e00
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginModel.java
@@ -0,0 +1,258 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.runtime.PluginVersionIdentifier;

+

+/**

+ * 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 LibraryModel[] runtime = null;

+	private ExtensionPointModel[] extensionPoints = null;

+	private ExtensionModel[] extensions = null;

+	private PluginPrerequisiteModel[] requires = 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 prerequisites of this plug-in.

+ *

+ * @return the prerequisites of this plug-in or <code>null</code>

+ */

+public PluginPrerequisiteModel[] getRequires() {

+	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.

+ *

+ * @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();

+	if (requires != null)

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

+			requires[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 prerequisites of this plug-in.

+ * This object must not be read-only.

+ *

+ * @param value the prerequisites of this plug-in.  May be <code>null</code>.

+ */

+public void setRequires(PluginPrerequisiteModel[] value) {

+	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.  The version number

+ * is canonicalized.

+ * 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();

+	// XXX workaround because some people still do not use the correct 

+	// version format.

+	int i = value.indexOf(' ');

+	if (i > -1)

+		value = value.substring(0, i);

+	version = new PluginVersionIdentifier(value).toString();

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginModelObject.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginModelObject.java
new file mode 100644
index 0000000..12478e6
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginModelObject.java
@@ -0,0 +1,68 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+import org.eclipse.core.internal.runtime.Assert;

+

+/**

+ * An object which has the general characteristics of all elements

+ * in a plug-in manifest.

+ * <p>

+ * This class may be subclassed.

+ * </p>

+ */

+

+public abstract class PluginModelObject {

+

+	// DTD properties (included in plug-in manifest)

+	private String name = null;

+

+	// transient properties (not included in plug-in manifest)

+	private boolean readOnly = false;

+/**

+ * Checks that this model object is writeable.  A runtime exception

+ * is thrown if it is not.

+ */

+protected final void assertIsWriteable() {

+	Assert.isTrue(!isReadOnly(), "Model is read-only");

+}

+/**

+ * Returns the name of this element.

+ * 

+ * @return the name of this element or <code>null</code>

+ */

+public String getName() {

+	return name;

+}

+/**

+ * Returns whether or not this model object is read-only.

+ * 

+ * @return <code>true</code> if this model object is read-only,

+ *		<code>false</code> otherwise

+ * @see #markReadOnly

+ */

+public boolean isReadOnly() {

+	return readOnly;

+}

+/**

+ * Sets this model object and all of its descendents to be read-only.

+ * Subclasses may extend this implementation.

+ *

+ * @see #isReadOnly

+ */

+public void markReadOnly() {

+	readOnly = true;

+}

+/**

+ * Sets the name of this element.

+ * 

+ * @param value the new name of this element.  May be <code>null</code>.

+ */

+public void setName(String value) {

+	assertIsWriteable();

+	name = 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
new file mode 100644
index 0000000..5bc65b8
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginPrerequisiteModel.java
@@ -0,0 +1,144 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

+ import org.eclipse.core.runtime.PluginVersionIdentifier;	// for javadoc

+/**

+ * An object which represents the relationship between a plug-in and a

+ * prerequisite plug-in in the dependent's plug-in manifest.

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+public class PluginPrerequisiteModel extends PluginModelObject {

+

+	// DTD properties (included in plug-in manifest)

+	private String plugin = null;

+	private String version = null;

+	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>.

+ */

+public PluginPrerequisiteModel() {

+	super();

+}

+/**

+ * Returns whether or not the code in this pre-requisite is exported.

+ *

+ * @return whether or not the code in this pre-requisite is exported

+ */

+public boolean getExport() {

+	return export;

+}

+/**

+ * Returns whether or not this pre-requisite requires an exact match.

+ *

+ * @return whether or not this pre-requisite requires an exact match

+ */

+public boolean getMatch() {

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

+ */

+public String getPlugin() {

+	return plugin;

+}

+/**

+ * Returns the resolved version of the prerequisite plug-in.  The

+ * returned value is in the format specified by <code>PluginVersionIdentifier</code>.

+ *

+ * @return the version of the prerequisite plug-in

+ * @see PluginVersionIdentifier

+ */

+public String getResolvedVersion() {

+	return resolvedVersion;

+}

+/**

+ * 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 whether or not the code in this pre-requisite is exported.

+ * This object must not be read-only.

+ *

+ * @param value whether or not the code in this pre-requisite is exported

+ */

+public void setExport(boolean value) {

+	assertIsWriteable();

+	export = value;

+}

+/**

+ * Sets whether or not this pre-requisite requires an exact match.

+ * This object must not be read-only.

+ *

+ * @param value whether or not this pre-requisite requires an exact match

+ */

+public void setMatch(boolean value) {

+	assertIsWriteable();

+	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.

+ * 

+ * @param value the prerequisite plug-in identifier.  May be <code>null</code>.

+ */

+public void setPlugin(String value) {

+	assertIsWriteable();

+	plugin = value;

+}

+/**

+ * Sets the resolved version of the prerequisite plug-in.  The

+ * given value is in the format specified by <code>PluginVersionIdentifier</code>.

+ *

+ * @param value the version of the prerequisite plug-in

+ * @see PluginVersionIdentifier

+ */

+public void setResolvedVersion(String value) {

+	assertIsWriteable();

+	resolvedVersion = value;

+}

+/**

+ * Sets the version name of this plug-in prerequisite.

+ * This object must not be read-only.

+ *

+ * @param value the version name of this plug-in prerequisite.

+ *		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/PluginRegistryModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginRegistryModel.java
new file mode 100644
index 0000000..667e34c
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/PluginRegistryModel.java
@@ -0,0 +1,359 @@
+package org.eclipse.core.runtime.model;

+

+/*

+ * (c) Copyright IBM Corp. 2000, 2001.

+ * All Rights Reserved.

+ */

+

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

+import org.eclipse.core.internal.runtime.Assert;

+import org.eclipse.core.internal.plugins.RegistryResolver;

+import java.util.*;

+

+/**

+ * A container for a collection of plug-in descriptors.

+ * <p>

+ * This class may be instantiated, or further subclassed.

+ * </p>

+ */

+public class PluginRegistryModel {

+

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

+/**

+ * Creates a new plug-in registry model which contains no plug-ins.

+ */

+public PluginRegistryModel() {

+	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.  

+ *

+ * @param plugin the plug-in descriptor to add

+ */

+public void addPlugin(PluginDescriptorModel plugin) {

+	assertIsWriteable();

+	String key = plugin.getId();

+	PluginDescriptorModel[] pluginList = getPlugins(key);

+	if (pluginList == null) {

+		pluginList = new PluginDescriptorModel[1];

+		pluginList[0] = plugin;

+		plugins.put(key, pluginList);

+	} else {

+		PluginDescriptorModel[] newPluginList = new PluginDescriptorModel[pluginList.length + 1];

+		System.arraycopy(pluginList, 0, newPluginList, 0, pluginList.length);

+		newPluginList[pluginList.length] = plugin;

+		plugins.put(key, newPluginList);

+	}

+}

+/**

+ * Checks that this model object is writeable.  A runtime exception

+ * is thrown if it is not.

+ */

+protected void assertIsWriteable() {

+	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,

+ * one will be non-deterministically choosen and returned.  

+ *

+ * @param pluginId the unique identifier of the plug-in 

+ *		(e.g. <code>"com.example.acme"</code>).

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

+ */

+public PluginDescriptorModel getPlugin(String pluginId) {

+	PluginDescriptorModel[] result = (PluginDescriptorModel[]) plugins.get(pluginId);

+	return result == null ? null : result[0];

+}

+/**

+ * Returns the identified plug-in or <code>null</code> if

+ * the plug-in does not exist.

+ *

+ * @return the matching plug-in in this registry

+ */

+public PluginDescriptorModel getPlugin(String pluginId, String version) {

+	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 list[0];

+

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

+		PluginDescriptorModel element = list[i];

+		if (element.getVersion().equals(version))

+			return element;

+	}

+	return null;

+}

+/**

+ * Returns the list of plug-ins managed by this registry.

+ *

+ * @return the plug-ins in this registry

+ */

+public PluginDescriptorModel[] getPlugins() {

+	List result = new ArrayList(plugins.size());

+	for (Iterator i = plugins.values().iterator(); i.hasNext();) {

+		PluginDescriptorModel[] entries = (PluginDescriptorModel[]) i.next();

+		for (int j = 0; j < entries.length; j++)

+			result.add(entries[j]);

+	}

+	return (PluginDescriptorModel[]) result.toArray(new PluginDescriptorModel[result.size()]);

+}

+/**

+ * Returns all versions of the identified plug-in descriptor

+ * known to this plug-in registry.

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

+ * with the specified identifier.

+ *

+ * @param pluginId the unique identifier of the plug-in 

+ *		(e.g. <code>"org.eclipse.core.resources"</code>).

+ * @return the plug-in descriptors known to this plug-in registry

+ */

+public PluginDescriptorModel[] getPlugins(String pluginId) {

+	return (PluginDescriptorModel[]) plugins.get(pluginId);

+}

+/**

+ * Returns whether or not this model object is read-only.

+ * 

+ * @return <code>true</code> if this model object is read-only,

+ *		<code>false</code> otherwise

+ * @see #markReadOnly

+ */

+public boolean isReadOnly() {

+	return readOnly;

+}

+/**

+ * Returns whether or not this model object has been resolved.

+ * 

+ * @return <code>true</code> if this model object has been resolved,

+ *		<code>false</code> otherwise

+ * @see #resolve

+ */

+public boolean isResolved() {

+	return resolved;

+}

+/**

+ * Sets this model object and all of its descendents to be read-only.

+ * Subclasses may extend this implementation.

+ *

+ * @see #isReadOnly

+ */

+public void markReadOnly() {

+	readOnly = true;

+	for (Iterator it = plugins.values().iterator(); it.hasNext();) {

+		PluginDescriptorModel[] list = (PluginDescriptorModel[]) it.next();

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

+			list[i].markReadOnly();

+	}

+}

+/**

+ * Sets this model object to be resolved.

+ */

+public void markResolved() {

+	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.

+ *

+ * @param pluginId the unique identifier of the plug-in to remove

+ * @param version the version of the plug-in to remove

+ */

+public void removePlugin(String pluginId, String version) {

+	assertIsWriteable();

+	PluginDescriptorModel[] plugins = getPlugins(pluginId);

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

+		return;

+	int removedCount = 0;

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

+		if (version.equals(plugins[i].getVersion())) {

+			plugins[i] = null;

+			removedCount++;

+		}

+	}

+	// If all were removed, toss the whole entry.  Otherwise, compact the array

+	if (removedCount == plugins.length)

+		removePlugins(pluginId);

+	else {

+		PluginDescriptorModel[] newList = new PluginDescriptorModel[plugins.length - removedCount];

+		int index = 0;

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

+			if (plugins[i] != null)

+				newList[index++] = plugins[i];

+		}

+		this.plugins.put(pluginId,newList);

+	}

+}

+/**

+ * Removes all versions of the given plug-in from this registry.

+ * This method has no effect if such a plug-in cannot be found.

+ *

+ * @param pluginId the unique identifier of the plug-ins to remove

+ */

+public void removePlugins(String pluginId) {

+	assertIsWriteable();

+	plugins.remove(pluginId);

+}

+/**

+ * Runs a resolve through the entire registry.  This resolve will

+ * mark any PluginDescriptorModels which do not have access to all

+ * of their prerequisites as disabled.  Prerequisites which cause

+ * cyclical dependencies will be marked as disabled.

+ *

+ * If the parameter trimDisabledPlugins is set to true, all PluginDescriptorModels

+ * which are labelled as disabled will be removed from the registry.

+ *

+ * If the paramter doCrossLinking is set to true, links will be

+ * created between ExtensionPointModels and their corresponding

+ * ExtensionModels.  Not that these links will include disabled

+ * plugins if trimDisabledPlugins was set to false.

+ *

+ * @param trimDisabledPlugins if true, remove all disabled plugins

+ * from the registry (recommended value = true)

+ *

+ * @param doCrossLinking if true, link all ExtensionModels in the registry

+ * to their corresponding ExtensionPointModel (recommended value = true).

+ */

+public IStatus resolve(boolean trimDisabledPlugins, boolean doCrossLinking) {

+	RegistryResolver resolver = new RegistryResolver();

+	resolver.setTrimPlugins(trimDisabledPlugins);

+	resolver.setCrossLink(doCrossLinking);

+	return resolver.resolve(this);

+}

+}

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/URLModel.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/URLModel.java
new file mode 100644
index 0000000..6ad5a64
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/URLModel.java
@@ -0,0 +1,41 @@
+package org.eclipse.core.runtime.model;
+

+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+/**

+ * An object which represents the a named URL in a component or configuration

+ * manifest.

+ * <p>

+ * This class may be instantiated and further subclassed.

+ * </p>

+ */

+

+public class URLModel extends PluginModelObject {
+	// DTD properties (included in install manifest)

+	private String url = null;

+

+/**

+ * Returns the URL specification.

+ *

+ * @return the URL specification or <code>null</code>.

+ */

+public String getURL() {

+	return url;

+}

+

+/**

+ * Sets the URL specification.

+ * This object must not be read-only.

+ *

+ * @param value the URL specification.

+ *		May be <code>null</code>.

+ */

+public void setURL(String value) {

+	assertIsWriteable();

+	url = value;

+}

+

+}
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/package.html b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/package.html
new file mode 100644
index 0000000..21671a0
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/model/package.html
@@ -0,0 +1,16 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">

+<html>

+<head>

+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

+   <title>Package-level Javadoc</title>

+</head>

+<body>

+Provides core support for the modeling plug-ins and the plug-in registry.

+<h2>Package Specification</h2>

+This package specifies the runtime API related to modeling plug-ins and the plug-in

+registry.  The types provided here are typically data containers and have very little 

+behaviour other than setters and getters.  They are primarily intended for clients writing

+tools which manipulate/change registry entries as part of their normal work.  

+

+</body>

+</html>

diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/package.html b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/package.html
new file mode 100644
index 0000000..44aae50
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/package.html
@@ -0,0 +1,20 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">

+<html>

+<head>

+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

+   <title>Package-level Javadoc</title>

+</head>

+<body>

+Provides core support for plug-ins and the plug-in registry.

+<h2>

+Package Specification</h2>

+This package specifies the API related to running the platform itself.  This includes 

+area such as the definition and management of plug-ins and the starting, stopping and maintaining the 

+platform itself.  In addition, this API supplies various utility types such as <tt>Path</tt>, 

+<tt>IPath</tt> and various flavours of progress monitors.

+<p>

+Clients writing plug-ins or accessing plug-in functionality will likely be interested in the types

+provided by this package.

+</p>

+</body>

+</html>