Bug 125549 - Adding helpers for URL converter
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java
index 324f169..95908bd 100644
--- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java
+++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java
@@ -10,8 +10,11 @@
  *******************************************************************************/
 package org.eclipse.core.internal.runtime;
 
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.osgi.service.urlconversion.URLConverter;
+import org.osgi.framework.*;
+import org.osgi.util.tracker.ServiceTracker;
 
 /**
  * The Common runtime plugin class.
@@ -21,6 +24,11 @@
 public class Activator implements BundleActivator {
 
 	/**
+	 * Table to keep track of all the URL converter services.
+	 */
+	private static Map urlTrackers = new HashMap();
+
+	/**
 	 * The bundle context associated this plug-in
 	 */
 	private static BundleContext bundleContext;
@@ -37,10 +45,54 @@
 	 */
 	public void stop(BundleContext context) throws Exception {
 		CommonOSGiUtils.getDefault().closeServices();
+		closeURLTrackerServices();
 		bundleContext = null;
 	}
 
 	static BundleContext getContext() {
 		return bundleContext;
 	}
+
+	/*
+	 * Let go of all the services that we aquired and kept track of.
+	 */
+	private static void closeURLTrackerServices() {
+		synchronized (urlTrackers) {
+			if (!urlTrackers.isEmpty()) {
+				for (Iterator iter = urlTrackers.keySet().iterator(); iter.hasNext();) {
+					String key = (String) iter.next();
+					ServiceTracker tracker = (ServiceTracker) urlTrackers.get(key);
+					tracker.close();
+				}
+				urlTrackers = new HashMap();
+			}
+		}
+	}
+
+	/*
+	 * Return the URL Converter for the given URL. Return null if we can't
+	 * find one.
+	 */
+	public static URLConverter getURLConverter(URL url) {
+		String protocol = url.getProtocol();
+		synchronized (urlTrackers) {
+			ServiceTracker tracker = (ServiceTracker) urlTrackers.get(protocol);
+			if (tracker == null) {
+				// get the right service based on the protocol
+				String FILTER_PREFIX = "(&(objectClass=" + URLConverter.class.getName() + ")(protocol="; //$NON-NLS-1$ //$NON-NLS-2$
+				String FILTER_POSTFIX = "))"; //$NON-NLS-1$
+				Filter filter = null;
+				try {
+					filter = getContext().createFilter(FILTER_PREFIX + protocol + FILTER_POSTFIX);
+				} catch (InvalidSyntaxException e) {
+					return null;
+				}
+				tracker = new ServiceTracker(getContext(), filter, null);
+				tracker.open();
+				// cache it in the registry
+				urlTrackers.put(protocol, tracker);
+			}
+			return (URLConverter) tracker.getService();
+		}
+	}
 }
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/BundleFinder.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/BundleFinder.java
index e0652d0..5adf9c7 100644
--- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/BundleFinder.java
+++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/BundleFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2006 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
@@ -14,7 +14,6 @@
 import java.io.InputStream;
 import java.net.URL;
 import java.util.Map;
-import org.eclipse.core.internal.runtime.FindSupport;
 import org.osgi.framework.Bundle;
 
 /**
@@ -23,9 +22,8 @@
  * 
  * The class is not intended to be subclassed or instantiated by clients.
  * 
- * @since org.eclipse.equinox.common 1.0
- * XXX bundle finder renamed and it aggregates URLCOnverter.
- * This is not a service! just statics.
+ * @since 3.2
+ * @deprecated clients should use {@link FileLocator} instead
  */
 public final class BundleFinder {
 
@@ -38,9 +36,10 @@
 	 * @return a URL for the given path or <code>null</code>.  The actual form
 	 * of the returned URL is not specified.
 	 * @see #find(Bundle, IPath, Map)
+	 * @deprecated use {@link FileLocator#find(Bundle, IPath)}
 	 */
 	public static URL find(Bundle bundle, IPath path) {
-		return FindSupport.find(bundle, path, null);
+		return FileLocator.find(bundle, path, null);
 	}
 
 	/**
@@ -77,7 +76,8 @@
 	 * </pre>
 	 * </p><p>
 	 * The current environment variable values can be overridden using 
-	 * the override map argument.
+	 * the override map argument or <code>null</code> can be specified
+	 * if this is not desired.
 	 * </p>
 	 * 
 	 * @param bundle the bundle in which to search
@@ -90,9 +90,10 @@
 	 * is used.
 	 * @return a URL for the given path or <code>null</code>.  The actual form
 	 * of the returned URL is not specified.
+	 * @deprecated use {@link FileLocator#find(Bundle, IPath, Map)}
 	 */
 	public static URL find(Bundle bundle, IPath path, Map override) {
-		return FindSupport.find(bundle, path, override);
+		return FileLocator.find(bundle, path, override);
 	}
 
 	/**
@@ -113,9 +114,10 @@
 	 *   as specified
 	 * @return an input stream
 	 * @exception IOException if the given path cannot be found in this plug-in
+	 * @deprecated use {@link FileLocator#openStream(Bundle, IPath, boolean)}
 	 */
-	public static final InputStream openStream(Bundle bundle, IPath file, boolean localized) throws IOException {
-		return FindSupport.openStream(bundle, file, localized);
+	public static InputStream openStream(Bundle bundle, IPath file, boolean localized) throws IOException {
+		return FileLocator.openStream(bundle, file, localized);
 	}
 
 	/**
@@ -128,9 +130,10 @@
 	 * @exception IOException if the given path cannot be found in this plug-in
 	 * 
 	 * @see #openStream(Bundle,IPath,boolean)
+	 * @deprecated use {@link FileLocator#openStream(Bundle, IPath)}
 	 */
 	public static final InputStream openStream(Bundle bundle, IPath file) throws IOException {
-		return FindSupport.openStream(bundle, file, false);
+		return FileLocator.openStream(bundle, file, false);
 	}
 
 	/**
@@ -145,9 +148,10 @@
 	 * @return the converted file URL or the original URL passed in if it is 
 	 * 	not recognized by this converter
 	 * @throws IOException if an error occurs during the conversion
+	 * @deprecated use {@link FileLocator#toFileURL(URL)}
 	 */
 	public static URL toFileURL(URL url) throws IOException {
-		return null; //TODO get the code from internalplatform
+		return FileLocator.toFileURL(url);
 	}
 
 	/**
@@ -166,8 +170,9 @@
 	 * @return the resolved URL or the original if the protocol is unknown to this converter
 	 * @exception IOException if unable to resolve URL
 	 * @throws IOException if an error occurs during the resolution
+	 * @deprecated use {@link FileLocator#resolve(URL)}
 	 */
 	public static URL resolve(URL url) throws IOException {
-		return null; //TODO get the code from internalplatform
+		return FileLocator.resolve(url);
 	}
 }
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/FileLocator.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/FileLocator.java
new file mode 100644
index 0000000..de65840
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/FileLocator.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.runtime;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Map;
+import org.eclipse.core.internal.runtime.*;
+import org.eclipse.osgi.service.urlconversion.URLConverter;
+import org.osgi.framework.Bundle;
+
+/**
+ * This class contains collection of helper methods aimed at finding files in bundles.
+ * This class can only be used if OSGi plugin is available.
+ * <p>
+ * The class is not intended to be subclassed or instantiated by clients.
+ * </p>
+ * @since 3.2
+ */
+public final class FileLocator {
+
+	/**
+	 * Returns a URL for the given path in the given bundle.  Returns <code>null</code> if the URL
+	 * could not be computed or created. 
+	 * <p>
+	 * find looks for this path in given bundle and any attached fragments.  
+	 * <code>null</code> is returned if no such entry is found.  Note that
+	 * there is no specific order to the fragments.
+	 * </p><p>
+	 * The following arguments may also be used
+	 * <pre>
+	 *     $nl$ - for language specific information
+	 *     $os$ - for operating system specific information
+	 *     $ws$ - for windowing system specific information
+	 * </pre>
+	 * </p><p>
+	 * A path of $nl$/about.properties in an environment with a default 
+	 * locale of en_CA will return a URL corresponding to the first place
+	 * about.properties is found according to the following order:
+	 * <pre>
+	 *     plugin root/nl/en/CA/about.properties
+	 *     fragment1 root/nl/en/CA/about.properties
+	 *     fragment2 root/nl/en/CA/about.properties
+	 *     ...
+	 *     plugin root/nl/en/about.properties
+	 *     fragment1 root/nl/en/about.properties
+	 *     fragment2 root/nl/en/about.properties
+	 *     ...
+	 *     plugin root/about.properties
+	 *     fragment1 root/about.properties
+	 *     fragment2 root/about.properties
+	 *     ...
+	 * </pre>
+	 * </p><p>
+	 * The current environment variable values can be overridden using 
+	 * the override map argument or <code>null</code> can be specified
+	 * if this is not desired.
+	 * </p>
+	 * 
+	 * @param bundle the bundle in which to search
+	 * @param path file path relative to plug-in installation location
+	 * @param override map of override substitution arguments to be used for
+	 * any $arg$ path elements. The map keys correspond to the substitution
+	 * arguments (eg. "$nl$" or "$os$"). The resulting
+	 * values must be of type java.lang.String. If the map is <code>null</code>,
+	 * or does not contain the required substitution argument, the default
+	 * is used.
+	 * @return a URL for the given path or <code>null</code>.  The actual form
+	 * of the returned URL is not specified.
+	 */
+	public static URL find(Bundle bundle, IPath path, Map override) {
+		return FindSupport.find(bundle, path, override);
+	}
+
+	/**
+	 * 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 bundle the bundle in which to search
+	 * @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
+	 * @exception IOException if the given path cannot be found in this plug-in
+	 */
+	public static InputStream openStream(Bundle bundle, IPath file, boolean localized) throws IOException {
+		return FindSupport.openStream(bundle, file, localized);
+	}
+
+	/**
+	 * Converts a URL that uses a user-defined protocol into a URL that uses the file
+	 * protocol. The contents of the URL may be extracted into a cache on the file-system
+	 * in order to get a file URL. 
+	 * <p>
+	 * If the protocol for the given URL is not recognized by this converter, the original
+	 * URL is returned as-is.
+	 * </p>
+	 * @param url the original URL
+	 * @return the converted file URL or the original URL passed in if it is 
+	 * 	not recognized by this converter
+	 * @throws IOException if an error occurs during the conversion
+	 */
+	public static URL toFileURL(URL url) throws IOException {
+		URLConverter converter = Activator.getURLConverter(url);
+		return converter == null ? url : converter.toFileURL(url);
+	}
+
+	/**
+	 * Converts a URL that uses a client-defined protocol into a URL that uses a
+	 * protocol which is native to the Java class library (file, jar, http, etc).
+	 * <p>
+	 * Note however that users of this API should not assume too much about the
+	 * results of this method.  While it may consistently return a file: URL in certain
+	 * installation configurations, others may result in jar: or http: URLs.
+	 * </p>
+	 * <p>
+	 * If the protocol is not reconized by this converter, then the original URL is
+	 * returned as-is.
+	 * </p>
+	 * @param url the original URL
+	 * @return the resolved URL or the original if the protocol is unknown to this converter
+	 * @exception IOException if unable to resolve URL
+	 * @throws IOException if an error occurs during the resolution
+	 */
+	public static URL resolve(URL url) throws IOException {
+		URLConverter converter = Activator.getURLConverter(url);
+		return converter == null ? url : converter.resolve(url);
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/DefaultPreferences.java b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/DefaultPreferences.java
index bb7bffe..a2f2b44 100644
--- a/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/DefaultPreferences.java
+++ b/bundles/org.eclipse.equinox.preferences/src/org/eclipse/core/internal/preferences/DefaultPreferences.java
@@ -86,13 +86,13 @@
 		Bundle bundle = PreferencesOSGiUtils.getDefault().getBundle(name());
 		if (bundle == null)
 			return;
-		URL url = BundleFinder.find(bundle, new Path(IPreferencesConstants.PREFERENCES_DEFAULT_OVERRIDE_FILE_NAME));
+		URL url = FileLocator.find(bundle, new Path(IPreferencesConstants.PREFERENCES_DEFAULT_OVERRIDE_FILE_NAME), null);
 		if (url == null) {
 			if (EclipsePreferences.DEBUG_PREFERENCE_GENERAL)
 				PrefsMessages.message("Preference default override file not found for bundle: " + bundle.getSymbolicName()); //$NON-NLS-1$
 			return;
 		}
-		URL transURL = BundleFinder.find(bundle, NL_DIR.append(IPreferencesConstants.PREFERENCES_DEFAULT_OVERRIDE_BASE_NAME).addFileExtension(PROPERTIES_FILE_EXTENSION));
+		URL transURL = FileLocator.find(bundle, NL_DIR.append(IPreferencesConstants.PREFERENCES_DEFAULT_OVERRIDE_BASE_NAME).addFileExtension(PROPERTIES_FILE_EXTENSION), null);
 		if (transURL == null && EclipsePreferences.DEBUG_PREFERENCE_GENERAL)
 			PrefsMessages.message("Preference translation file not found for bundle: " + bundle.getSymbolicName()); //$NON-NLS-1$
 		applyDefaults(name(), loadProperties(url), loadProperties(transURL));