Bug 576885 - Unify methods to parse bundle-sets from launch-configs

Change-Id: Ib6855a7a27ab09c748fe24b44539b82cb430f486
Signed-off-by: Hannes Wellmann <wellmann.hannes1@gmx.net>
Reviewed-on: https://git.eclipse.org/r/c/pde/eclipse.pde.ui/+/186942
Tested-by: PDE Bot <pde-bot@eclipse.org>
Reviewed-by: Julian Honnen <julian.honnen@vector.com>
diff --git a/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
index ea04064..d617cac 100644
--- a/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %name
 Bundle-SymbolicName: org.eclipse.pde.launching;singleton:=true
-Bundle-Version: 3.9.500.qualifier
+Bundle-Version: 3.9.600.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-11
 Bundle-Vendor: %provider-name
 Require-Bundle: org.eclipse.jdt.junit.core;bundle-version="[3.6.0,4.0.0)",
diff --git a/ui/org.eclipse.pde.launching/pom.xml b/ui/org.eclipse.pde.launching/pom.xml
index 0cdfdec..fdff78f 100644
--- a/ui/org.eclipse.pde.launching/pom.xml
+++ b/ui/org.eclipse.pde.launching/pom.xml
@@ -19,7 +19,7 @@
   </parent>
   <groupId>org.eclipse.pde</groupId>
   <artifactId>org.eclipse.pde.launching</artifactId>
-  <version>3.9.500-SNAPSHOT</version>
+  <version>3.9.600-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   <properties>
     <code.ignoredWarnings>-warn:-deprecation,unavoidableGenericProblems</code.ignoredWarnings>
diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/BundleLauncherHelper.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/BundleLauncherHelper.java
index 6c17de1..57e588d 100644
--- a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/BundleLauncherHelper.java
+++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/BundleLauncherHelper.java
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     EclipseSource Corporation - ongoing enhancements
+ *     Hannes Wellmann - Bug 576885: Unify methods to parse bundle-sets from launch-configs
  *******************************************************************************/
 package org.eclipse.pde.internal.launching.launcher;
 
@@ -18,6 +19,8 @@
 
 import java.util.*;
 import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.function.Predicate;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
@@ -307,59 +310,106 @@
 		return map.keySet().toArray(new IPluginModelBase[map.size()]);
 	}
 
-	public static Map<IPluginModelBase, String> getWorkspaceBundleMap(ILaunchConfiguration configuration, Set<String> set) throws CoreException {
-		Set<String> selected = configuration.getAttribute(IPDELauncherConstants.SELECTED_WORKSPACE_BUNDLES, Collections.emptySet());
-		Map<IPluginModelBase, String> map = new LinkedHashMap<>();
-		for (String token : selected) {
-			int index = token.indexOf('@');
-			if (index < 0) { // if no start levels, assume default
-				token = token.concat("@default:default"); //$NON-NLS-1$
-				index = token.indexOf('@');
-			}
-			String idVersion = token.substring(0, index);
-			int versionIndex = idVersion.indexOf(VERSION_SEPARATOR);
-			String id = (versionIndex > 0) ? idVersion.substring(0, versionIndex) : idVersion;
-			String version = (versionIndex > 0) ? idVersion.substring(versionIndex + 1) : null;
-			if (set != null)
-				set.add(id);
-			ModelEntry entry = PluginRegistry.findEntry(id);
-			if (entry != null) {
-				IPluginModelBase[] models = entry.getWorkspaceModels();
-				Set<String> versions = new HashSet<>();
-				for (IPluginModelBase model : models) {
-					IPluginBase base = model.getPluginBase();
-					String v = base.getVersion();
-					if (versions.add(v)) { // don't add exact same version more than once
+	public static Map<IPluginModelBase, String> getWorkspaceBundleMap(ILaunchConfiguration configuration, Set<String> pluginIds) throws CoreException {
+		Set<String> workspaceBundles = configuration.getAttribute(IPDELauncherConstants.SELECTED_WORKSPACE_BUNDLES, emptySet());
 
-						// match only if...
-						// a) if we have the same version
-						// b) no version
-						// c) all else fails, if there's just one bundle available, use it
-						if (base.getVersion().equals(version) || version == null || models.length == 1)
-							addBundleToMap(map, model, token.substring(index + 1));
+		Map<IPluginModelBase, String> map = getBundleMap(workspaceBundles, ModelEntry::getWorkspaceModels, pluginIds, id -> true);
+
+		if (configuration.getAttribute(IPDELauncherConstants.AUTOMATIC_ADD, true)) {
+			Set<String> deselectedWorkspaceBundles = configuration.getAttribute(IPDELauncherConstants.DESELECTED_WORKSPACE_BUNDLES, emptySet());
+			Set<IPluginModelBase> deselectedPlugins = getBundleMap(deselectedWorkspaceBundles, ModelEntry::getWorkspaceModels, null, id -> true).keySet();
+			IPluginModelBase[] models = PluginRegistry.getWorkspaceModels();
+			for (IPluginModelBase model : models) {
+				String id = model.getPluginBase().getId();
+				if (id != null && !deselectedPlugins.contains(model)) {
+					if (pluginIds != null) {
+						pluginIds.add(id);
+					}
+					if (!map.containsKey(model)) {
+						addBundleToMap(map, model, "default:default"); //$NON-NLS-1$
 					}
 				}
 			}
 		}
+		return map;
+	}
 
-		if (configuration.getAttribute(IPDELauncherConstants.AUTOMATIC_ADD, true)) {
-			Set<IPluginModelBase> deselectedPlugins = LaunchPluginValidator.parsePlugins(configuration, IPDELauncherConstants.DESELECTED_WORKSPACE_BUNDLES);
-			IPluginModelBase[] models = PluginRegistry.getWorkspaceModels();
-			for (int i = 0; i < models.length; i++) {
-				String id = models[i].getPluginBase().getId();
-				if (id == null)
-					continue;
-				if (!deselectedPlugins.contains(models[i])) {
-					if (set != null)
-						set.add(id);
-					if (!map.containsKey(models[i]))
-						addBundleToMap(map, models[i], "default:default"); //$NON-NLS-1$
+	public static Map<IPluginModelBase, String> getTargetBundleMap(ILaunchConfiguration configuration, Set<String> pluginIds) throws CoreException {
+		Set<String> targetBundles = configuration.getAttribute(IPDELauncherConstants.SELECTED_TARGET_BUNDLES, emptySet());
+		Predicate<String> idFilter = pluginIds != null ? id -> !pluginIds.contains(id) : id -> true;
+		return getBundleMap(targetBundles, ModelEntry::getExternalModels, null, idFilter);
+	}
+
+	private static Map<IPluginModelBase, String> getBundleMap(Set<String> entries, Function<ModelEntry, IPluginModelBase[]> getModels, Set<String> pluginIds, Predicate<String> idFilter) {
+		Map<IPluginModelBase, String> map = new LinkedHashMap<>();
+		for (String bundleEntry : entries) {
+			int index = bundleEntry.indexOf('@');
+			if (index < 0) { // if no start levels, assume default
+				index = bundleEntry.length();
+				bundleEntry += "@default:default"; //$NON-NLS-1$
+			}
+			String idVersion = bundleEntry.substring(0, index);
+			int versionIndex = idVersion.indexOf(VERSION_SEPARATOR);
+			String id = (versionIndex > 0) ? idVersion.substring(0, versionIndex) : idVersion;
+			String version = (versionIndex > 0) ? idVersion.substring(versionIndex + 1) : null;
+
+			if (idFilter.test(id)) {
+				if (pluginIds != null) {
+					pluginIds.add(id);
+				}
+				ModelEntry entry = PluginRegistry.findEntry(id);
+				if (entry != null) {
+					IPluginModelBase[] models = getModels.apply(entry);
+					String startData = bundleEntry.substring(index + 1);
+					addPluginModel(models, version, startData, map);
 				}
 			}
 		}
 		return map;
 	}
 
+	private static void addPluginModel(IPluginModelBase[] models, String version, String startData, Map<IPluginModelBase, String> map) {
+		Set<String> versions = new HashSet<>();
+		for (IPluginModelBase model : models) {
+			if (model.isEnabled()) { // always true for workspace models, external might be disabled
+				IPluginBase base = model.getPluginBase();
+				String v = base.getVersion();
+				if (versions.add(v)) { // don't add exact same version more than once
+					// match only if...
+					// a) if we have the same version
+					// b) no version
+					// c) all else fails, if there's just one bundle available, use it
+					if (base.getVersion().equals(version) || version == null || models.length == 1) {
+						addBundleToMap(map, model, startData);
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Adds the given bundle and start information to the map.  This will override anything set
+	 * for system bundles, and set their start level to the appropriate level
+	 * @param map The map to add the bundles too
+	 * @param bundle The bundle to add
+	 * @param substring the start information in the form level:autostart
+	 */
+	private static void addBundleToMap(Map<IPluginModelBase, String> map, IPluginModelBase bundle, String sl) {
+		BundleDescription desc = bundle.getBundleDescription();
+		boolean defaultsl = (sl == null || sl.equals("default:default")); //$NON-NLS-1$
+		if (desc != null && defaultsl) {
+			String runLevelText = resolveSystemRunLevelText(bundle);
+			String autoText = resolveSystemAutoText(bundle);
+			if (runLevelText != null && autoText != null) {
+				map.put(bundle, runLevelText + ":" + autoText); //$NON-NLS-1$
+			} else {
+				map.put(bundle, sl);
+			}
+		} else {
+			map.put(bundle, sl);
+		}
+	}
+
 	public static String resolveSystemRunLevelText(IPluginModelBase model) {
 		BundleDescription description = model.getBundleDescription();
 		String modelName = description.getSymbolicName();
@@ -408,64 +458,6 @@
 		}
 	}
 
-	/**
-	 * Adds the given bundle and start information to the map.  This will override anything set
-	 * for system bundles, and set their start level to the appropriate level
-	 * @param map The map to add the bundles too
-	 * @param bundle The bundle to add
-	 * @param substring the start information in the form level:autostart
-	 */
-	private static void addBundleToMap(Map<IPluginModelBase, String> map, IPluginModelBase bundle, String sl) {
-		BundleDescription desc = bundle.getBundleDescription();
-		boolean defaultsl = (sl == null || sl.equals("default:default")); //$NON-NLS-1$
-		if (desc != null && defaultsl) {
-			String runLevelText = resolveSystemRunLevelText(bundle);
-			String autoText = resolveSystemAutoText(bundle);
-			if (runLevelText != null && autoText != null) {
-				map.put(bundle, runLevelText + ":" + autoText); //$NON-NLS-1$
-			} else {
-				map.put(bundle, sl);
-			}
-		} else {
-			map.put(bundle, sl);
-		}
-
-	}
-
-	public static Map<IPluginModelBase, String> getTargetBundleMap(ILaunchConfiguration configuration, Set<String> set) throws CoreException {
-		Set<String> selected = configuration.getAttribute(IPDELauncherConstants.SELECTED_TARGET_BUNDLES, Collections.emptySet());
-		Map<IPluginModelBase, String> map = new LinkedHashMap<>();
-		for (String token : selected) {
-			int index = token.indexOf('@');
-			if (index < 0) { // if no start levels, assume default
-				token = token.concat("@default:default"); //$NON-NLS-1$
-				index = token.indexOf('@');
-			}
-			String idVersion = token.substring(0, index);
-			int versionIndex = idVersion.indexOf(VERSION_SEPARATOR);
-			String id = (versionIndex > 0) ? idVersion.substring(0, versionIndex) : idVersion;
-			String version = (versionIndex > 0) ? idVersion.substring(versionIndex + 1) : null;
-			if (set != null && set.contains(id))
-				continue;
-			ModelEntry entry = PluginRegistry.findEntry(id);
-			if (entry != null) {
-				IPluginModelBase[] models = entry.getExternalModels();
-				for (IPluginModelBase model : models) {
-					if (model.isEnabled()) {
-						IPluginBase base = model.getPluginBase();
-						// match only if...
-						// a) if we have the same version
-						// b) no version
-						// c) all else fails, if there's just one bundle available, use it
-						if (base.getVersion().equals(version) || version == null || models.length == 1)
-							addBundleToMap(map, model, token.substring(index + 1));
-					}
-				}
-			}
-		}
-		return map;
-	}
-
 	public static String writeBundleEntry(IPluginModelBase model, String startLevel, String autoStart) {
 		IPluginBase base = model.getPluginBase();
 		String id = base.getId();
diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchPluginValidator.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchPluginValidator.java
index c2c4d96..0df5b78 100644
--- a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchPluginValidator.java
+++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchPluginValidator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2016 IBM Corporation and others.
+ * Copyright (c) 2005, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -20,7 +20,8 @@
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.osgi.util.NLS;
-import org.eclipse.pde.core.plugin.*;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.plugin.PluginRegistry;
 import org.eclipse.pde.internal.core.*;
 import org.eclipse.pde.internal.launching.*;
 import org.eclipse.pde.launching.IPDELauncherConstants;
@@ -44,54 +45,6 @@
 	}
 
 	/**
-	 *
-	 * @param configuration launchConfiguration to get the attribute value
-	 * @param attribute launch configuration attribute to containing plug-in information
-	 * @return a TreeSet containing IPluginModelBase objects which are represented by the value of the attribute
-	 * @throws CoreException
-	 */
-	public static Set<IPluginModelBase> parsePlugins(ILaunchConfiguration configuration, String attribute) throws CoreException {
-		HashSet<IPluginModelBase> set = new HashSet<>();
-		Map<String, IPluginModelBase> unmatchedEntries = new HashMap<>();
-		Set<String> entries = configuration.getAttribute(attribute, Collections.emptySet());
-
-		for (String token : entries) {
-			int index = token.indexOf('@');
-			if (index < 0) { // if no start levels, assume default
-				token = token.concat("@default:default"); //$NON-NLS-1$
-				index = token.indexOf('@');
-			}
-			String idVersion = token.substring(0, index);
-			int versionIndex = token.indexOf(BundleLauncherHelper.VERSION_SEPARATOR);
-			String id = (versionIndex > 0) ? idVersion.substring(0, versionIndex) : idVersion;
-			String version = (versionIndex > 0) ? idVersion.substring(versionIndex + 1) : null;
-			ModelEntry entry = PluginRegistry.findEntry(id);
-			if (entry != null) {
-				IPluginModelBase matchingModels[] = attribute.equals(IPDELauncherConstants.SELECTED_TARGET_BUNDLES) ? entry.getExternalModels() : entry.getWorkspaceModels();
-				for (IPluginModelBase matchingModel : matchingModels) {
-					if (matchingModel.isEnabled()) {
-						// TODO Very similar logic to BundleLauncherHelper
-						// the logic here is this (see bug 225644)
-						// a) if we come across a bundle that has the right version, immediately add it
-						// b) if there's no version, add it
-						// c) if there's only one instance of that bundle in the list of ids... add it
-						if (version == null || matchingModel.getPluginBase().getVersion().equals(version)) {
-							set.add(matchingModel);
-						} else if (matchingModels.length == 1) {
-							if (unmatchedEntries.remove(id) == null) {
-								unmatchedEntries.put(id, matchingModel);
-							}
-						}
-					}
-				}
-			}
-		}
-
-		set.addAll(unmatchedEntries.values());
-		return set;
-	}
-
-	/**
 	 * @return all affected projects, independently of their nature
 	 */
 	public static IProject[] getAffectedProjects(ILaunchConfiguration config) throws CoreException {