Bug 541444 - source.info contains old/duplicate bundles after platform upgrade

This change takes advantage of the fact that simpleconfigurator
has already done the checking to see if the shared installation
has been updated and set a system property accordingly. We then
use the presence of the system property to determine whether to
ignore the user configuration or not.

Ignoring the user configuration means the source.info will be re
-generated from scratch using the bundles in the updated shared
configuration, then the migration wizard will re-insert any third
-party bundles as appropriate.

This avoids the possibility that there will be out-of-date
entries in the source.info in the user configuration area.

Change-Id: Ia59ce22133c928fe23b72c65a6034c5267f38f1b
Signed-off-by: Mat Booth <mat.booth@redhat.com>
diff --git a/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/META-INF/MANIFEST.MF
index ffd97f8..d7bea43 100644
--- a/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.equinox.p2.touchpoint.eclipse;singleton:=true
-Bundle-Version: 2.2.100.qualifier
+Bundle-Version: 2.2.200.qualifier
 Bundle-Activator: org.eclipse.equinox.internal.p2.touchpoint.eclipse.Activator
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/pom.xml b/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/pom.xml
index e6de942..2b42ffb 100644
--- a/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/pom.xml
+++ b/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/pom.xml
@@ -9,6 +9,6 @@
   </parent>
   <groupId>org.eclipse.equinox</groupId>
   <artifactId>org.eclipse.equinox.p2.touchpoint.eclipse</artifactId>
-  <version>2.2.100-SNAPSHOT</version>
+  <version>2.2.200-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
diff --git a/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/src/org/eclipse/equinox/internal/p2/touchpoint/eclipse/SourceManipulator.java b/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/src/org/eclipse/equinox/internal/p2/touchpoint/eclipse/SourceManipulator.java
index df4d1e8..baf93e7 100644
--- a/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/src/org/eclipse/equinox/internal/p2/touchpoint/eclipse/SourceManipulator.java
+++ b/bundles/org.eclipse.equinox.p2.touchpoint.eclipse/src/org/eclipse/equinox/internal/p2/touchpoint/eclipse/SourceManipulator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2010 IBM Corporation and others.
+ * Copyright (c) 2008, 2018 IBM Corporation and others.
  *
  * This
  * program and the accompanying materials are made available under the terms of
@@ -13,7 +13,8 @@
  ******************************************************************************/
 package org.eclipse.equinox.internal.p2.touchpoint.eclipse;
 
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
 import java.net.MalformedURLException;
 import java.util.*;
 import org.eclipse.equinox.frameworkadmin.BundleInfo;
@@ -21,10 +22,12 @@
 import org.eclipse.equinox.p2.engine.IProfile;
 import org.eclipse.equinox.p2.metadata.Version;
 import org.eclipse.equinox.simpleconfigurator.manipulator.SimpleConfiguratorManipulator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
 
 //This class deals with source bundles and how their addition to the source.info
 public class SourceManipulator {
-	private List<BundleInfo> sourceBundles;
+	private Set<BundleInfo> sourceBundles;
 	private IProfile profile;
 	boolean changed = false;
 	private SimpleConfiguratorManipulatorImpl manipulator;
@@ -67,11 +70,8 @@
 	}
 
 	private void load() throws MalformedURLException, IOException {
-		if (getFileLocation().exists())
-			//input stream is bufferd and closed for us
-			sourceBundles = new ArrayList<BundleInfo>(Arrays.asList(manipulator.loadConfiguration(new FileInputStream(getFileLocation()), getLauncherLocation().toURI())));
-		else
-			sourceBundles = new ArrayList<BundleInfo>();
+		BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+		sourceBundles = new LinkedHashSet<>(Arrays.asList(manipulator.loadConfiguration(context, SimpleConfiguratorManipulator.SOURCE_INFO)));
 	}
 
 	private File getFileLocation() {
diff --git a/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/META-INF/MANIFEST.MF
index e2058fc..dd7cbfb 100644
--- a/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/META-INF/MANIFEST.MF
@@ -12,7 +12,6 @@
  org.eclipse.equinox.internal.provisional.frameworkadmin,
  org.eclipse.equinox.internal.simpleconfigurator,
  org.eclipse.equinox.internal.simpleconfigurator.utils,
- org.eclipse.osgi.service.datalocation,
  org.osgi.framework;version="1.3.0"
 Bundle-Vendor: %providerName
 Export-Package: org.eclipse.equinox.internal.simpleconfigurator.manipulator;x-friends:="org.eclipse.equinox.p2.touchpoint.eclipse",
diff --git a/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/src/org/eclipse/equinox/internal/simpleconfigurator/manipulator/SimpleConfiguratorManipulatorImpl.java b/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/src/org/eclipse/equinox/internal/simpleconfigurator/manipulator/SimpleConfiguratorManipulatorImpl.java
index 5432b00..14a45c2 100644
--- a/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/src/org/eclipse/equinox/internal/simpleconfigurator/manipulator/SimpleConfiguratorManipulatorImpl.java
+++ b/bundles/org.eclipse.equinox.simpleconfigurator.manipulator/src/org/eclipse/equinox/internal/simpleconfigurator/manipulator/SimpleConfiguratorManipulatorImpl.java
@@ -30,7 +30,6 @@
 import org.eclipse.equinox.internal.simpleconfigurator.utils.EquinoxUtils;
 import org.eclipse.equinox.internal.simpleconfigurator.utils.SimpleConfiguratorUtils;
 import org.eclipse.equinox.simpleconfigurator.manipulator.SimpleConfiguratorManipulator;
-import org.eclipse.osgi.service.datalocation.Location;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 
@@ -204,8 +203,6 @@
 
 		if (!state.isResolved())
 			state.resolve(false);
-		//		if (DEBUG)
-		//			System.out.println(state.toString());
 
 		if (!state.isResolved(bInfo)) {
 			printoutUnsatisfiedConstraints(bInfo, state);
@@ -301,12 +298,41 @@
 		}
 	}
 
+	/**
+	 * Like {@link SimpleConfiguratorImpl#chooseConfigurationURL(URL, URL[])} but it doesn't check
+	 * file timestamps because if the {@link SimpleConfiguratorImpl#PROP_IGNORE_USER_CONFIGURATION}
+	 * property is set then we already know that timestamps have been checked and we need to ignore
+	 * the user config.
+	 */
+	private URL chooseConfigurationURL(String relativePath, URL[] configURL) throws MalformedURLException {
+		if (configURL != null) {
+			File userConfig = new File(configURL[0].getFile(), relativePath);
+			if (configURL.length == 1) {
+				return userConfig.exists() ? userConfig.toURI().toURL() : null;
+			}
+
+			File sharedConfig = new File(configURL[1].getFile(), relativePath);
+			if (!userConfig.exists()) {
+				return sharedConfig.exists() ? sharedConfig.toURI().toURL() : null;
+			}
+
+			if (!sharedConfig.exists()) {
+				return userConfig.toURI().toURL();
+			}
+
+			if (Boolean.getBoolean(SimpleConfiguratorImpl.PROP_IGNORE_USER_CONFIGURATION)) {
+				return sharedConfig.toURI().toURL();
+			}
+			return userConfig.toURI().toURL();
+		}
+		return null;
+	}
+
 	@Override
 	public BundleInfo[] loadConfiguration(BundleContext context, String infoPath) throws IOException {
 		URI installArea = EquinoxUtils.getInstallLocationURI(context);
 
 		URL configURL = null;
-		InputStream stream = null;
 
 		if (infoPath == null) {
 			SimpleConfiguratorImpl simpleImpl = new SimpleConfiguratorImpl(context, null);
@@ -317,35 +343,23 @@
 			if (defaultSource)
 				infoPath = SOURCE_INFO_PATH;
 
-			Location configLocation = EquinoxUtils.getConfigLocation(context);
-			configURL = configLocation.getDataArea(infoPath);
-			try {
-				stream = configURL.openStream();
-			} catch (FileNotFoundException e) {
-				if (defaultSource && configLocation.getParentLocation() != null) {
-					configURL = configLocation.getParentLocation().getDataArea(infoPath);
-				} else {
-					return new BundleInfo[0];
-				}
-			}
+			URL[] configURLs = EquinoxUtils.getConfigAreaURL(context);
+			configURL = chooseConfigurationURL(infoPath, configURLs);
 		}
-		if (configURL == null)
-			return new BundleInfo[0];
-		else if (stream == null) {
-			try {
-				stream = configURL.openStream();
-			} catch (FileNotFoundException e) {
-				return new BundleInfo[0];
-			}
+
+		// At this point the file specified by configURL should definitely exist or be null
+		if (configURL == null) {
+			return NULL_BUNDLEINFOS;
 		}
 
 		List<BundleInfo> result = new ArrayList<>();
-		//stream will be closed
-		result.addAll(Arrays.asList(loadConfiguration(stream, installArea)));
+		// Stream will be closed by loadConfiguration
+		result.addAll(Arrays.asList(loadConfiguration(configURL.openStream(), installArea)));
 
 		try {
 			List<File> infoFiles = SimpleConfiguratorUtils.getInfoFiles();
 			for (File infoFile : infoFiles) {
+				// Stream will be closed by loadConfiguration
 				BundleInfo[] info = loadConfiguration(infoFile.toURL().openStream(), infoFile.getParentFile().toURI());
 				result.addAll(Arrays.asList(info));
 			}
@@ -353,7 +367,7 @@
 			// ignore the extended configurations
 		}
 
-		return result.toArray(new BundleInfo[0]);
+		return result.toArray(new BundleInfo[result.size()]);
 	}
 
 	/*