Bug 577574 - Speed-up and simplify FileLocator.getBundleFile()

Change-Id: I21497a934723b5dd2b0329937df3fac1ebaa955f
Signed-off-by: Hannes Wellmann <wellmann.hannes1@gmx.net>
Reviewed-on: https://git.eclipse.org/r/c/equinox/rt.equinox.bundles/+/188440
Tested-by: Equinox Bot <equinox-bot@eclipse.org>
Reviewed-by: Thomas Watson <tjwatson@us.ibm.com>
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/core/runtime/tests/FileLocatorTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/core/runtime/tests/FileLocatorTest.java
index c585836..d0f3830 100644
--- a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/core/runtime/tests/FileLocatorTest.java
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/core/runtime/tests/FileLocatorTest.java
@@ -16,6 +16,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
@@ -103,8 +104,9 @@
 		Bundle bundle = context.installBundle("reference:" + FileLocator.toFileURL(url).toExternalForm());
 		BundleTestingHelper.refreshPackages(context, new Bundle[] { bundle });
 
-		File file1 = FileLocator.getBundleFile(bundle);
+		File file1 = FileLocator.getBundleFileLocation(bundle).get();
 		assertNotNull(file1);
+		assertSame(file1, FileLocator.getBundleFile(bundle));
 
 		URL fileURL = FileLocator
 				.toFileURL(context.getBundle().getEntry("Plugin_Testing/fileLocator/testFileLocatorGetRootFile"));
@@ -123,8 +125,9 @@
 		Bundle bundle = context.installBundle("reference:" + FileLocator.toFileURL(url).toExternalForm());
 		BundleTestingHelper.refreshPackages(context, new Bundle[] { bundle });
 
-		File file1 = FileLocator.getBundleFile(bundle);
+		File file1 = FileLocator.getBundleFileLocation(bundle).get();
 		assertNotNull(file1);
+		assertSame(file1, FileLocator.getBundleFile(bundle));
 
 		URL fileURL = FileLocator
 				.toFileURL(context.getBundle().getEntry("Plugin_Testing/fileLocator/testFileLocatorGetRootFile.jar"));
diff --git a/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF
index 0f8c6f8..41003de 100644
--- a/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF
@@ -19,18 +19,7 @@
  org.eclipse.equinox.events;version="1.0.0"
 Bundle-Vendor: %providerName
 Bundle-Activator: org.eclipse.core.internal.runtime.Activator
-Import-Package: org.eclipse.equinox.log;version="[1.0,2.0)",
- org.eclipse.osgi.framework.log;version="[1.1, 2.0)",
- org.eclipse.osgi.service.datalocation,
- org.eclipse.osgi.service.debug,
- org.eclipse.osgi.service.localization,
- org.eclipse.osgi.service.urlconversion,
- org.eclipse.osgi.util,
- org.osgi.framework,
- org.osgi.service.log;version="[1.3.0, 2.0)",
- org.osgi.service.packageadmin,
- org.osgi.service.url,
- org.osgi.util.tracker
+Require-Bundle: org.eclipse.osgi;bundle-version="[3.17.200,4.0.0)"
 Bundle-RequiredExecutionEnvironment: JavaSE-11
 Bundle-ActivationPolicy: lazy
 Automatic-Module-Name: org.eclipse.equinox.common
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
index 9d7795e..bb2cacb 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2018 IBM Corporation and others.
+ * Copyright (c) 2006, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials 
  * are made available under the terms of the Eclipse Public License 2.0
@@ -12,12 +12,14 @@
  *     IBM Corporation - initial API and implementation
  *     Sergey Prigogin (Google) - use parameterized types (bug 442021)
  *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 483464
+ *     Hannes Wellmann - Bug 577574 - Speed-up and simplify getBundleFile() and add getBundleFileLocation
  *******************************************************************************/
 package org.eclipse.core.runtime;
 
 import java.io.*;
 import java.net.URL;
 import java.util.Map;
+import java.util.Optional;
 import org.eclipse.core.internal.runtime.Activator;
 import org.eclipse.core.internal.runtime.FindSupport;
 import org.eclipse.osgi.service.urlconversion.URLConverter;
@@ -284,9 +286,9 @@
 	}
 
 	/**
-	 * Returns a file for the contents of the specified bundle.  Depending 
-	 * on how the bundle is installed the returned file may be a directory or a jar file 
-	 * containing the bundle content.  
+	 * Returns a file for the contents of the specified bundle. Depending on how the
+	 * bundle is installed the returned file may be a directory or a jar file
+	 * containing the bundle content.
 	 * 
 	 * @param bundle the bundle
 	 * @return a file with the contents of the bundle
@@ -295,19 +297,26 @@
 	 * @since org.eclipse.equinox.common 3.4
 	 */
 	public static File getBundleFile(Bundle bundle) throws IOException {
-		URL rootEntry = bundle.getEntry("/"); //$NON-NLS-1$
-		rootEntry = resolve(rootEntry);
-		if ("file".equals(rootEntry.getProtocol())) //$NON-NLS-1$
-			return new File(rootEntry.getPath());
-		if ("jar".equals(rootEntry.getProtocol())) { //$NON-NLS-1$
-			String path = rootEntry.getPath();
-			if (path.startsWith("file:")) { //$NON-NLS-1$
-				// strip off the file: and the !/
-				path = path.substring(5, path.length() - 2);
-				return new File(path);
-			}
-		}
-		throw new IOException("Unknown protocol"); //$NON-NLS-1$
+		return getBundleFileLocation(bundle)
+				.orElseThrow(() -> new IOException("Unable to locate the bundle file: " + bundle)); //$NON-NLS-1$
+	}
+
+	/**
+	 * Returns an {@code Optional} {@link File}, that (if present) describes the
+	 * bundle's root location on the file system.
+	 * <p>
+	 * Depending on how the bundle is installed the returned file may be a directory
+	 * or a jar file containing the bundle content. In case the location cannot be
+	 * determined the returned {@code Optional} is empty, which is for example
+	 * usually the case for {@code CONNECT} bundles.
+	 * <p>
+	 * 
+	 * @param bundle the bundle
+	 * @return the optional file to the location of the bundle's root
+	 * @since 3.16
+	 */
+	public static Optional<File> getBundleFileLocation(Bundle bundle) {
+		return Optional.ofNullable(bundle.adapt(File.class));
 	}
 
 }
\ No newline at end of file