Bug 565066 - Force reresolve of all bundles on install/uninstall

In order to maximize the ability to select a good resolution after
incrementally installing or uninstalling bundles all existing bundles
are forced to re-resolve with the new set of available bundles.  This
forces the framework to forget its previous decisions for resolution
wiring so that it may make better choices in order to resolve the newly
installed set of bundles.

Change-Id: Ic28569f7dc35407261e7a39087817e572d7e8c8d
Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
diff --git a/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/ConfigApplier.java b/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/ConfigApplier.java
index 24eb1a3..9bed80f 100644
--- a/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/ConfigApplier.java
+++ b/bundles/org.eclipse.equinox.simpleconfigurator/src/org/eclipse/equinox/internal/simpleconfigurator/ConfigApplier.java
@@ -101,12 +101,24 @@
 			if (toUninstall != null)
 				toRefresh.addAll(uninstallBundles(toUninstall));
 		}
-		refreshPackages(toRefresh.toArray(new Bundle[toRefresh.size()]), manipulatingContext);
-		if (toRefresh.size() > 0) {
-			Bundle[] additionalRefresh = getAdditionalRefresh(prevouslyResolved, toRefresh);
-			if (additionalRefresh.length > 0)
-				refreshPackages(additionalRefresh, manipulatingContext);
+		if (!toRefresh.isEmpty()) {
+			if (manipulatingContext.getBundle().getState() == Bundle.STARTING) {
+				// This is the startup of simple configurator.
+				// Do the full refresh of all bundles to force re-resolve
+				refreshAllBundles();
+			} else {
+				// In this case the platform is up, we should try to do an incremental resolve
+				// TODO consider removing this case because it can cause inconsistent results.
+				refreshPackages(toRefresh.toArray(new Bundle[toRefresh.size()]), manipulatingContext);
+				if (toRefresh.size() > 0) {
+					Bundle[] additionalRefresh = getAdditionalRefresh(prevouslyResolved, toRefresh);
+					if (additionalRefresh.length > 0)
+						refreshPackages(additionalRefresh, manipulatingContext);
+				}
 		}
+
+		}
+
 		startBundles(toStart.toArray(new Bundle[toStart.size()]));
 	}
 
@@ -215,6 +227,47 @@
 		return resolved;
 	}
 
+	private void refreshAllBundles() {
+		Set<Bundle> toRefresh = new HashSet<>(frameworkWiring.getRemovalPendingBundles());
+		Set<Bundle> doNotRefresh = getDoNotRefresh();
+		for (Bundle bundle : manipulatingContext.getBundles()) {
+			if (!doNotRefresh.contains(bundle)) {
+				toRefresh.add(bundle);
+			}
+		}
+
+		CountDownLatch latch = new CountDownLatch(1);
+		FrameworkListener listener = event -> {
+			if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
+				latch.countDown();
+			}
+		};
+		frameworkWiring.refreshBundles(toRefresh, listener);
+		try {
+			latch.await();
+		} catch (InterruptedException e) {
+			// ignore
+		}
+	}
+
+	private Set<Bundle> getDoNotRefresh() {
+		Set<Bundle> doNotRefresh = new HashSet<>();
+		doNotRefresh.add(manipulatingContext.getBundle());
+		Bundle systemBundle = manipulatingContext.getBundle(Constants.SYSTEM_BUNDLE_LOCATION);
+		doNotRefresh.add(systemBundle);
+		BundleWiring systemWiring = systemBundle.adapt(BundleWiring.class);
+		if (systemWiring != null) {
+			for (BundleWire hostWire : systemWiring.getProvidedWires(HostNamespace.HOST_NAMESPACE)) {
+				Bundle systemFragment = hostWire.getRequirer().getBundle();
+				if (systemFragment.getState() != Bundle.UNINSTALLED
+						&& systemFragment.adapt(BundleWiring.class) != null) {
+					doNotRefresh.add(systemFragment);
+				}
+			}
+		}
+		return doNotRefresh;
+	}
+
 	private Collection<Bundle> uninstallBundles(HashSet<BundleInfo> toUninstall) {
 		Collection<Bundle> removedBundles = new ArrayList<>(toUninstall.size());
 		for (BundleInfo current : toUninstall) {