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. 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>.
+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.
+This application is instantiated and run by the platform. Platform clients
+can also use the platform to lookup and run multiple applications.
+<p><b><i>Configuration Markup:</i></b>
+<p><tt> <!ELEMENT application run?></tt>
+<p>
+<tt> <!ELEMENT run parameter*></tt>
+<br><tt> <!ATTLIST run</tt>
+<br><tt> class
+CDATA #REQUIRED</tt>
+<br><tt> ></tt>
+<ul>
+<li>
+<b>class -</b> the fully-qualified name of a class which implements <tt>org.eclipse.core.boot.IPlatformRunnable</tt>.</li>
+</ul>
+<tt> <!ELEMENT parameter EMPTY></tt>
+<br><tt> <!ATTLIST parameter</tt>
+<br><tt> name
+CDATA #REQUIRED</tt>
+<br><tt> value
+CDATA #REQUIRED</tt>
+<br><tt> ></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> <extension id="coolApplication" point="org.eclipse.core.runtime.applications"></tt>
+<br><tt> <application></tt>
+<br><tt> <run class="com.xyz.applications.Cool"></tt>
+<br><tt>
+<parameter name="optimize" value="true"/></tt>
+<br><tt> </run></tt>
+<br><tt> </application></tt>
+<br><tt> </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> <!ELEMENT handler EMPTY></tt>
+<p><tt> <!ATTLIST handler</tt>
+<br><tt> protocol
+CDATA #REQUIRED</tt>
+<br><tt> class
+CDATA #REQUIRED</tt>
+<br><tt> ></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> <extension point="org.eclipse.core.runtime.urlHandlers"></tt>
+<br><tt> <handler protocol="foo" class="org.eclipse.handlers.FooHandler"/></tt>
+<br><tt> </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>
+ * <bg pattern="stripes"/>
+ * </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>
+ * <bg pattern="stripes"/>
+ * </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>
+ * <bg color="blue" pattern="stripes"/>
+ * </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>
+ * <view>
+ *     <verticalHint>top</verticalHint>
+ *     <horizontalHint>left</horizontalHint>
+ * </view>
+ * </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>
+ * <wizard name="Create Project"/>
+ * </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>
+ * <script lang="javascript">.\scripts\cp.js</script>
+ * </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>
+ * <script lang="javascript">.\scripts\cp.js</script>
+ * </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>
+ * <tooltip>#hattip</tooltip>
+ * </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>
+ * <action run="com.example.BaseAction"/>
+ * </pre>
+ * In the above example, this method would be called with a reference
+ * to the <code><action></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>
+ * <action run="com.example.ExternalAdapter:./cmds/util.exe -opt 3"/>
+ * </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>
+ * <action>
+ * <<it>run</it> class="com.xyz.ExternalAdapter">
+ * <parameter name="exec" value="./cmds/util.exe"/>
+ * <parameter name="opt" value="3"/>
+ * </<it>run</it>>
+ * </action>
+ * </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><plug-in id>/<option-path></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><plugin></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>