Bug 117154 uniform API for obtaining the 'default' extension registry
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesOSGiUtils.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesOSGiUtils.java
index 9229064..37cc6a6 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesOSGiUtils.java
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesOSGiUtils.java
@@ -10,7 +10,6 @@
  *******************************************************************************/
 package org.eclipse.core.internal.preferences;
 
-import org.eclipse.equinox.registry.IExtensionRegistry;
 import org.eclipse.osgi.framework.log.FrameworkLog;
 import org.eclipse.osgi.service.datalocation.Location;
 import org.eclipse.osgi.service.debug.DebugOptions;
@@ -25,7 +24,6 @@
  * @since org.eclipse.equinox.preferences 1.0
  */
 public class PreferencesOSGiUtils {
-	private ServiceTracker registryTracker = null;
 	private ServiceTracker logTracker = null;
 	private ServiceTracker initTracker = null;
 	private ServiceTracker debugTracker = null;
@@ -58,9 +56,6 @@
 			return;
 		}
 
-		registryTracker = new ServiceTracker(context, IExtensionRegistry.class.getName(), null);
-		registryTracker.open();
-
 		initTracker = new ServiceTracker(context, ILegacyPreferences.class.getName(), null);
 		initTracker.open(true);
 
@@ -95,10 +90,6 @@
 	}
 
 	void closeServices() {
-		if (registryTracker != null) {
-			registryTracker.close();
-			registryTracker = null;
-		}
 		if (initTracker != null) {
 			initTracker.close();
 			initTracker = null;
@@ -125,13 +116,6 @@
 		}
 	}
 
-	public IExtensionRegistry getExtensionRegistry() {
-		if (registryTracker != null)
-			return (IExtensionRegistry) registryTracker.getService();
-		PrefsMessages.message("Registry tracker is not set"); //$NON-NLS-1$
-		return null;
-	}
-
 	public ILegacyPreferences getLegacyPreferences() {
 		if (initTracker != null)
 			return (ILegacyPreferences) initTracker.getService();
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java
index 67dbb25..7b25977 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/PreferencesService.java
@@ -95,8 +95,8 @@
 				if (ELEMENT_SCOPE.equalsIgnoreCase(elements[j].getName()))
 					scopeAdded(elements[j]);
 		}
-		PreferencesOSGiUtils.getDefault().getExtensionRegistry().addRegistryChangeListener(this, IPreferencesConstants.RUNTIME_NAME);
-		PreferencesOSGiUtils.getDefault().getExtensionRegistry().addRegistryChangeListener(this, IPreferencesConstants.PREFERS_NAME);
+		RegistryFactory.getRegistry().addRegistryChangeListener(this, IPreferencesConstants.RUNTIME_NAME);
+		RegistryFactory.getRegistry().addRegistryChangeListener(this, IPreferencesConstants.PREFERS_NAME);
 	}
 
 	private void initializeModifyListeners() {
@@ -108,8 +108,8 @@
 				if (ELEMENT_MODIFIER.equalsIgnoreCase(elements[j].getName()))
 					addModifyListener(elements[j]);
 		}
-		PreferencesOSGiUtils.getDefault().getExtensionRegistry().addRegistryChangeListener(this, IPreferencesConstants.RUNTIME_NAME);
-		PreferencesOSGiUtils.getDefault().getExtensionRegistry().addRegistryChangeListener(this, IPreferencesConstants.PREFERS_NAME);
+		RegistryFactory.getRegistry().addRegistryChangeListener(this, IPreferencesConstants.RUNTIME_NAME);
+		RegistryFactory.getRegistry().addRegistryChangeListener(this, IPreferencesConstants.PREFERS_NAME);
 	}
 
 	static void log(IStatus status) {
@@ -1127,7 +1127,7 @@
 	private final static IExtension[] emptyExtensionArray = new IExtension[0];
 
 	public static IExtension[] getPrefExtensions() {
-		IExtensionRegistry registry = PreferencesOSGiUtils.getDefault().getExtensionRegistry();
+		IExtensionRegistry registry = RegistryFactory.getRegistry();
 		IExtension[] extensionsOld = emptyExtensionArray;
 		IExtension[] extensionsNew = emptyExtensionArray;
 		// "old"
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java
index c81005f..4bc0cc1 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java
@@ -1098,4 +1098,8 @@
 		currentConfigurationElement.setParentType(parent instanceof ConfigurationElement ? RegistryObjectManager.CONFIGURATION_ELEMENT : RegistryObjectManager.EXTENSION);
 	}
 
+	public void setCompatibilityStrategy(ICompatibilityStrategy strategy) {
+		compatibilityStrategy = strategy;
+	}
+
 }
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/IRegistryConstants.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/IRegistryConstants.java
index ce605b0..130990d 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/IRegistryConstants.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/IRegistryConstants.java
@@ -26,6 +26,7 @@
 	public static final String PROP_NO_LAZY_CACHE_LOADING = "eclipse.noLazyRegistryCacheLoading"; //$NON-NLS-1$
 	public static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$
 	public static final String PROP_NO_REGISTRY_CACHE = "eclipse.noRegistryCache"; //$NON-NLS-1$
+	public static final String PROP_DEFAULT_REGISTRY = "eclipse.createRegistry"; //$NON-NLS-1$
 
 	// OSGI system properties
 	public static final String PROP_NL = "osgi.nl"; //$NON-NLS-1$
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryMessages.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryMessages.java
index 66e9f3e..e245e6f 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryMessages.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/RegistryMessages.java
@@ -28,6 +28,7 @@
 	public static String meta_unableToCreateCache;
 	public static String meta_unableToReadCache;
 	public static String registry_no_default;
+	public static String registry_default_exists;
 
 	// parsing/resolve
 	public static String parse_error;
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/messages.properties b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/messages.properties
index b0cf8bd..9acabd8 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/messages.properties
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/messages.properties
@@ -18,6 +18,7 @@
 meta_unableToCreateCache = Unable to create output stream for registry cache.
 meta_unableToReadCache = Unable to create input stream for registry cache.
 registry_no_default = Extension tracker was unable to obtain Eclipse extension registry.
+registry_default_exists = Extension registry provider is already set.
 
 ### parsing/resolve
 parse_error = Parsing error: \"{0}\".
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/Activator.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/Activator.java
index 7932ce3..eff2382 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/Activator.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/Activator.java
@@ -10,31 +10,57 @@
  *******************************************************************************/
 package org.eclipse.core.internal.registry.osgi;
 
+import java.io.File;
+import java.util.Hashtable;
 import org.eclipse.core.internal.registry.IRegistryConstants;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.equinox.registry.*;
+import org.eclipse.osgi.service.datalocation.Location;
 import org.eclipse.osgi.service.environment.EnvironmentInfo;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
+import org.osgi.framework.*;
 import org.osgi.util.tracker.ServiceTracker;
 
 /**
- * The extension registry bundle manager class.
+ * The extension registry bundle. This activator will create the default OSGi registry 
+ * unless told otherwise by setting the following system property to false:
+ * <code>eclipse.createRegistry=false</code>
+ * 
+ * The default registry will be stopped on the bundle shutdown.
+ * 
+ * @see IRegistryConstants#PROP_DEFAULT_REGISTRY
  */
 public class Activator implements BundleActivator {
 
 	private static BundleContext bundleContext;
 
 	/**
+	 * Location of the default registry relative to the configuration area
+	 */
+	private static final String STORAGE_DIR = "org.eclipse.core.runtime"; //$NON-NLS-1$
+
+	/**
+	 * Access key to the default registry
+	 */
+	private Object registryKey = new Object();
+
+	private IExtensionRegistry defaultRegistry = null;
+	private ServiceRegistration registryRegistration;
+	private RegistryProviderOSGI defaultProvider;
+
+	/**
 	 * This method is called upon plug-in activation
 	 */
 	public void start(BundleContext context) throws Exception {
 		bundleContext = context;
 		processCommandLine();
+		startRegistry();
 	}
 
 	/**
 	 * This method is called when the plug-in is stopped
 	 */
 	public void stop(BundleContext context) throws Exception {
+		stopRegistry();
 		bundleContext = null;
 	}
 
@@ -68,4 +94,29 @@
 		}
 	}
 
+	public void startRegistry() throws CoreException {
+		// see if the customer suppressed the creation of default registry
+		String property = bundleContext.getProperty(IRegistryConstants.PROP_DEFAULT_REGISTRY);
+		if (property != null && property.equalsIgnoreCase("false"))
+			return;
+
+		Location configuration = OSGIUtils.getDefault().getConfigurationLocation();
+		File theStorageDir = new File(configuration.getURL().getPath() + '/' + STORAGE_DIR);
+		EquinoxRegistryStrategy registryStrategy = new EquinoxRegistryStrategy(theStorageDir, configuration.isReadOnly(), registryKey);
+		defaultRegistry = RegistryFactory.createRegistry(registryStrategy, registryKey);
+
+		registryRegistration = Activator.getContext().registerService(IExtensionRegistry.class.getName(), defaultRegistry, new Hashtable());
+		defaultProvider = new RegistryProviderOSGI();
+		// Set the registry provider and specify this as a default registry:
+		RegistryFactory.setRegistryProvider(defaultProvider);
+	}
+
+	private void stopRegistry() {
+		if (defaultRegistry != null) {
+			defaultProvider.release();
+			registryRegistration.unregister();
+			defaultRegistry.stop(registryKey);
+		}
+	}
+
 }
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/OSGIUtils.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/OSGIUtils.java
index ea9e8d9..b967371 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/OSGIUtils.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/OSGIUtils.java
@@ -27,6 +27,7 @@
 public class OSGIUtils {
 	private ServiceTracker debugTracker = null;
 	private ServiceTracker bundleTracker = null;
+	// XXX platfromTracker is misspelt.
 	private ServiceTracker platfromTracker = null;
 	private ServiceTracker configurationLocationTracker = null;
 
@@ -52,6 +53,8 @@
 	 * Print a debug message to the console. 
 	 * Pre-pend the message with the current date and the name of the current thread.
 	 */
+	// XXX be careful using this method.  In general you should try to log first and then if 
+	//  debug is on print to system out.  
 	public static void message(String message) {
 		StringBuffer buffer = new StringBuffer();
 		buffer.append(new Date(System.currentTimeMillis()));
@@ -65,7 +68,7 @@
 	private void initServices() {
 		BundleContext context = Activator.getContext();
 		if (context == null) {
-			message("PreferencesUtils called before plugin started"); //$NON-NLS-1$
+			message("Registry OSGIUtils called before plugin started"); //$NON-NLS-1$
 			return;
 		}
 
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/RegistryProviderOSGI.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/RegistryProviderOSGI.java
new file mode 100644
index 0000000..08fd658
--- /dev/null
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/RegistryProviderOSGI.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.internal.registry.osgi;
+
+import org.eclipse.equinox.registry.IExtensionRegistry;
+import org.eclipse.equinox.registry.IRegistryProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+public final class RegistryProviderOSGI implements IRegistryProvider {
+
+	private ServiceTracker registryTracker = null;
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.equinox.registry.IRegistryProvider#getRegistry()
+	 */
+	public IExtensionRegistry getRegistry() {
+		if (registryTracker == null) {
+			BundleContext context = Activator.getContext();
+			if (context == null) {
+			// XXX should not print to system out.  Have to at least try and log.
+				OSGIUtils.message(this.getClass().getName() + ": plugin context is not set"); //$NON-NLS-1$
+				return null;
+			}
+			registryTracker = new ServiceTracker(context, IExtensionRegistry.class.getName(), null);
+			registryTracker.open();
+		}
+		return (IExtensionRegistry) registryTracker.getService();
+	}
+
+	/**
+	 * Release OSGi tracker
+	 */
+	public void release() {
+		if (registryTracker != null) {
+			registryTracker.close();
+			registryTracker = null;
+		}
+	}
+}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/RegistryStrategyOSGI.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/RegistryStrategyOSGI.java
index 5d2067d..580b9f0 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/RegistryStrategyOSGI.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/RegistryStrategyOSGI.java
@@ -22,6 +22,8 @@
 import org.eclipse.core.runtime.*;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.equinox.registry.IRegistryProvider;
+import org.eclipse.equinox.registry.RegistryFactory;
 import org.eclipse.equinox.registry.spi.RegistryStrategy;
 import org.eclipse.osgi.util.NLS;
 import org.osgi.framework.Bundle;
@@ -39,6 +41,10 @@
  *  - Performs registry validation based on the time stamps of the plugin.xml / fragment.xml files
  *  - XML parser is obtained via an OSGi service
  *  
+ * XXX really?!!
+ *  Only one registry with OSGI strategy can be instantied in the running application.
+ *  @see RegistryFactory#setRegistryProvider(IRegistryProvider)
+ *  
  * @since org.eclipse.equinox.registry 1.0
  * 
  */
@@ -123,6 +129,7 @@
 			return RegistryStrategy.processChangeEvent(listenerInfos, deltas, registry);
 		}
 	}
+
 	/* (non-Javadoc)
 
 	 * @see org.eclipse.equinox.registry.spi.RegistryStrategy#scheduleChangeEvent(java.lang.Object[], java.util.Map, java.lang.Object)
@@ -142,8 +149,11 @@
 		Bundle contributingBundle = getContributingBundle(contributingBundleId);
 		if (contributingBundle == null) // When restored from disk the underlying bundle may have been uninstalled
 			throw new IllegalStateException("Internal error in extension registry. The bundle corresponding to this contribution has been uninstalled."); //$NON-NLS-1$
-		if (OSGIUtils.getDefault().isFragment(contributingBundle))
-			return OSGIUtils.getDefault().getHosts(contributingBundle)[0];
+		if (OSGIUtils.getDefault().isFragment(contributingBundle)) {
+			Bundle[] hosts = OSGIUtils.getDefault().getHosts(contributingBundle);
+			if (hosts != null)
+				return hosts[0];
+		}
 		return contributingBundle;
 	}
 
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/IRegistryProvider.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/IRegistryProvider.java
new file mode 100644
index 0000000..2a7e791
--- /dev/null
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/IRegistryProvider.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.registry;
+
+/**
+ * Implement this interface to specify the default extension registry.
+ * 
+ * @see RegistryFactory#getRegistry()
+ * @see RegistryFactory#setRegistryProvider(IRegistryProvider)
+ * 
+ * <b>This is an experimental API. It might change in future.</b>
+ * 
+ * @since org.eclipse.equinox.registry 1.0
+ */
+public interface IRegistryProvider {
+
+	/**
+	 * Returns the "default" extension registry. 
+	 * @return an extension registry 
+	 */
+	public IExtensionRegistry getRegistry();
+}
diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/RegistryFactory.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/RegistryFactory.java
index 94ec1fd..ecc0f90 100644
--- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/RegistryFactory.java
+++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/equinox/registry/RegistryFactory.java
@@ -11,12 +11,13 @@
 package org.eclipse.equinox.registry;
 
 import java.io.File;
-import org.eclipse.core.internal.registry.ExtensionRegistry;
+import org.eclipse.core.internal.registry.*;
 import org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI;
+import org.eclipse.core.runtime.*;
 import org.eclipse.equinox.registry.spi.RegistryStrategy;
 
 /**
- * Use this class to create an extension registry.
+ * Use this class to create or obtain an extension registry.
  * 
  * This class is not intended to be subclassed or instantiated.
  * 
@@ -24,6 +25,8 @@
  */
 public final class RegistryFactory {
 
+	private static IRegistryProvider defaultRegistryProvider;
+
 	/**
 	 * Creates an extension registry.
 	 *  
@@ -31,11 +34,27 @@
 	 * @param token - control token for the registry. Keep it to access controlled methods of the
 	 * registry
 	 * @return - new extension registry
+	 * @throws CoreException in case if registry start conditions are not met. The exception's status 
+	 * message provides additional details.
 	 */
-	public static IExtensionRegistry createExtensionRegistry(RegistryStrategy strategy, Object token) {
+	public static IExtensionRegistry createRegistry(RegistryStrategy strategy, Object token) {
 		return new ExtensionRegistry(strategy, token);
 	}
-	
+
+	/**
+	 * Returns the existing extension registry specified by the registry provider.
+	 * May return null is the provider has not been set or registry was not created.
+	 * 
+	 * @return existing extension registry or null
+	 */
+	// XXX the team style is to put test filters first then do the work.  So here the if would
+	//   be == null then return null.  Then the return of getRegistry().
+	public static IExtensionRegistry getRegistry() {
+		if (defaultRegistryProvider != null)
+			return defaultRegistryProvider.getRegistry();
+		return null;
+	}
+
 	/**
 	 * Creates registry strategy that can be used in OSGi world. It provides the following functionality:
 	 *  - Event scheduling is done using Eclipse job scheduling mechanism
@@ -53,4 +72,25 @@
 	public static RegistryStrategy createOSGiStrategy(File storageDir, boolean cacheReadOnly, Object token) {
 		return new RegistryStrategyOSGI(storageDir, cacheReadOnly, token);
 	}
+
+	/**
+	 * Use this method to specify the default registry provider. The default registry provider
+	 * is immutable in the sense that it can be set only once during the application runtime.
+	 * Attempts to change the default registry provider will cause CoreException.
+	 * 
+	 * @see #getRegistry()
+	 * 
+	 * <b>This is an experimental API. It might change in future.</b>
+	 * 
+	 * @param provider - extension registry provider
+	 * @throws CoreException - default registry provider was already set for this application
+	 */
+	public static void setRegistryProvider(IRegistryProvider provider) throws CoreException {
+		if (defaultRegistryProvider != null) {
+			Status status = new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, IRegistryConstants.PLUGIN_ERROR, RegistryMessages.registry_default_exists, null);
+			throw new CoreException(status);
+		}
+		defaultRegistryProvider = provider;
+	}
+
 }