Bug 144876 Update is (getting) unusable as is
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/ContentReference.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/ContentReference.java
index 8ea21f8..72c2b6f 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/core/ContentReference.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/ContentReference.java
@@ -274,9 +274,9 @@
 	 */
 	public String toString() {
 		if (file != null)
-			return file.getAbsolutePath() + '(' + id + ')';
+			return file.getAbsolutePath();
 		else
-			return url.toExternalForm() + '(' + id + ')';
+			return url.toExternalForm();
 	}
 	/**
 	 * Returns the permission for this file.
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureContentProvider.java
index b8e7175..2b4a8b6 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureContentProvider.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/core/FeatureContentProvider.java
@@ -357,6 +357,9 @@
 		} // end lock
 		ContentReference reference =
 			ref.createContentReference(ref.getIdentifier(), localFile);
+		
+		UpdateCore.getPlugin().getUpdateSession().markVisited(ref.asURL());
+		
 		return reference;
 	}
 
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSite.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSite.java
index 0573c82..050ce5f 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSite.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/ExtendedSite.java
@@ -14,6 +14,7 @@
 import java.util.List;
 
 import org.eclipse.update.core.IURLEntry;
+import org.eclipse.update.core.VersionedIdentifier;
 import org.eclipse.update.internal.model.SiteWithTimestamp;
 
 public class ExtendedSite extends SiteWithTimestamp /*Site*/ {
@@ -22,6 +23,7 @@
 	private String[] availableLocals;
 	private String digestURL;
 	private LiteFeature[] liteFeatures;
+	private LiteFeature[] allLiteFeatures;
 	private IURLEntry[] associateSites;
 	private boolean pack200 = false;
 	
@@ -52,7 +54,31 @@
 			return getNonFilteredLiteFeatures();
 	}
 	public void setLiteFeatures(LiteFeature[] liteFeatures) {
-		this.liteFeatures = liteFeatures;
+		
+		if ((liteFeatures == null) || (liteFeatures.length == 0))
+			return;
+		this.allLiteFeatures = liteFeatures;
+		List temp = new ArrayList();
+		for(int i = 0; i < allLiteFeatures.length ; i++) {
+			if (getFeatureReference(allLiteFeatures[i]) != null) {
+				temp.add(allLiteFeatures[i]);
+			}
+		}
+		if (!temp.isEmpty()) {
+			this.liteFeatures = (LiteFeature[])temp.toArray( new LiteFeature[temp.size()]);
+		}
+	}
+	
+	public LiteFeature getLiteFeature(VersionedIdentifier vid) {
+		if (allLiteFeatures == null)
+			return null;
+		
+		for(int i = 0; i < allLiteFeatures.length ; i++) {
+			if (vid.equals(allLiteFeatures[i].getVersionedIdentifier())) {
+				return allLiteFeatures[i];
+			}
+		}
+		return null;
 	}
 	
 	public LiteFeature[] getNonFilteredLiteFeatures() {
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedContentProvider.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedContentProvider.java
index abf3e7e..ca6e06c 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedContentProvider.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/FeaturePackagedContentProvider.java
@@ -254,6 +254,7 @@
 	
 					tempFile.setLastModified(timeStamp);
 					Utilities.mapLocalFile(key, tempFile);
+					UpdateCore.getPlugin().getUpdateSession().markVisited(reference.asURL());
 				} finally {
 					LockManager.returnLock(packed);
 					LockManager.returnLock(key);
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalSiteManager.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalSiteManager.java
index 0014fb5..e754d32 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalSiteManager.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/InternalSiteManager.java
@@ -117,6 +117,7 @@
 		String siteURLString = siteURL.toExternalForm();
 		if ((useCache && globalUseCache) && isValidCachedSite(siteURL)) {
 			site = (ISite) sites.get(siteURLString);
+			UpdateCore.getPlugin().getUpdateSession().markVisited(site.getURL());
 			return site;
 		}
 		
@@ -180,6 +181,7 @@
 
 		if (site != null) {
 			sites.put(site.getURL().toExternalForm(), site);
+			UpdateCore.getPlugin().getUpdateSession().markVisited(site.getURL());
 			if (site instanceof ITimestamp) {
 				siteTimestamps.put(site.getURL(), new Long(((ITimestamp)site).getTimestamp().getTime()));
 			} else {
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java
index f3b4b4e..e7210c1 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/SiteFile.java
@@ -37,6 +37,7 @@
 import org.eclipse.update.core.model.FeatureModel;
 import org.eclipse.update.core.model.FeatureReferenceModel;
 import org.eclipse.update.core.model.InstallAbortedException;
+import org.eclipse.update.internal.operations.UpdateUtils;
 
 
 /**
@@ -278,7 +279,7 @@
 			IFeatureReference[] children = feature.getIncludedFeatureReferences();
 			IFeature currentFeature = null;
 			for (int i = 0; i < children.length; i++) {
-				currentFeature = children[i].getFeature(null);
+				currentFeature = UpdateUtils.getIncludedFeature(feature, children[i]);
 				if (currentFeature != null) {
 					result += getDownloadSizeFor(currentFeature);
 					if(result == ContentEntryModel.UNKNOWN_SIZE)
@@ -322,7 +323,7 @@
 			IFeatureReference[] children = feature.getIncludedFeatureReferences();
 			IFeature currentFeature = null;
 			for (int i = 0; i < children.length; i++) {
-				currentFeature = children[i].getFeature(null);
+				currentFeature = UpdateUtils.getIncludedFeature(feature, children[i]);
 				if (currentFeature != null) {
 					//[132029]
 					//pluginsToInstall.addAll(Arrays.asList(currentFeature.getPluginEntries()));
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateCore.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateCore.java
index 169e6ff..2f2520d 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateCore.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateCore.java
@@ -80,6 +80,9 @@
 	private ServiceTracker pkgAdminTracker;
 	private ServiceTracker verifierFactoryTracker;
 	
+	// Session
+	private UpdateSession updateSession = null;
+	
 	/**
 	 * The constructor.
 	 */
@@ -328,4 +331,13 @@
 		}
 		return (CertificateVerifierFactory)verifierFactoryTracker.getService();
 	}
+	
+	public UpdateSession getUpdateSession() {
+		synchronized(UpdateSession.class) {
+			if (updateSession == null) {
+				updateSession = new UpdateSession();
+			}
+		}		
+		return updateSession;
+	}
 }
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerUtils.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerUtils.java
index 6e5e002..1558263 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerUtils.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateManagerUtils.java
@@ -839,6 +839,9 @@
 	
 	public static boolean isSameTimestamp(URL url, long timestamp) {	
 		try {
+			if (UpdateCore.getPlugin().getUpdateSession().isVisited(url)) {
+				return true;
+			}
 			URL resolvedURL = URLEncoder.encode(url);
 			IResponse response = ConnectionFactory.get(resolvedURL);
 			long remoteLastModified = response.getLastModified();
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSession.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSession.java
new file mode 100644
index 0000000..6f8bedc
--- /dev/null
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/core/UpdateSession.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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 - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.update.internal.core;
+
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+
+public class UpdateSession {
+	
+	private Set visitedURLs = new HashSet();
+	
+	UpdateSession() {
+	}
+	
+	public boolean isVisited(URL url) {
+		return visitedURLs.contains(url.toExternalForm());
+	}
+
+	public void markVisited(URL url) {
+		visitedURLs.add(url.toExternalForm());
+	}
+	
+	public void reset() {
+		visitedURLs.clear();
+	}
+
+}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationValidator.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationValidator.java
index 98c1da4..5f3f39d 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationValidator.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/OperationValidator.java
@@ -519,7 +519,7 @@
 		feature.getIncludedFeatureReferences();
 		for (int i = 0; i < children.length; i++) {
 			try {
-				IFeature child = children[i].getFeature(null);
+				IFeature child = UpdateUtils.getIncludedFeature(feature, children[i]);
 				features =
 				computeFeatureSubtree(
 						top,
@@ -693,7 +693,7 @@
 		feature.getIncludedFeatureReferences();
 		for (int i = 0; i < children.length; i++) {
 			try {
-				IFeature child = children[i].getFeature(null);
+				IFeature child = UpdateUtils.getIncludedFeature(feature, children[i]);
 				checkForCycles(child, candidates, configuredFeatures);
 			} catch (CoreException e) {
 				if (!children[i].isOptional())
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UpdateUtils.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UpdateUtils.java
index 16fd34f..584bfc3 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UpdateUtils.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/operations/UpdateUtils.java
@@ -221,7 +221,7 @@
 				if (iref.isOptional())
 					return true;
 				// see if it has optional children
-				IFeature child = iref.getFeature(null);
+				IFeature child = getIncludedFeature( feature, iref);
 				if (hasOptionalFeatures(child))
 					return true;
 			}
@@ -669,4 +669,14 @@
 		}
 	}
 }
+	public static IFeature getIncludedFeature(IFeature feature, IFeatureReference iref) throws CoreException {
+		IFeature ifeature = null;
+		if (feature.getSite() instanceof ExtendedSite) {
+			ifeature = ((ExtendedSite)feature.getSite()).getLiteFeature(iref.getVersionedIdentifier());
+		}
+		if (ifeature == null) {
+			ifeature = iref.getFeature(new NullProgressMonitor());
+		}
+		return ifeature;
+	}
 }
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/provisional/SiteOptimizerApplication.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/provisional/SiteOptimizerApplication.java
index 1c55369..13d0197 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/provisional/SiteOptimizerApplication.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/provisional/SiteOptimizerApplication.java
@@ -31,7 +31,9 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPlatformRunnable;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.update.core.IIncludedFeatureReference;
 import org.eclipse.update.core.IncludedFeatureReference;
@@ -202,11 +204,9 @@
 			return false;
 		}
 
-		Iterator featureIterator = featureList.iterator();
-		// int i = 0;
-		while (featureIterator.hasNext()) {
-			String featureJarFileName = (String) featureIterator.next();
-			// System.out.println("i=" + i++);
+		for(int i = 0; i < featureList.size(); i++) {
+			
+			String featureJarFileName = (String) featureList.get(i);
 
 			if (featureJarFileName.endsWith("jar")) { //$NON-NLS-1$
 				System.out.println("Processing... " + featureJarFileName); //$NON-NLS-1$
@@ -233,6 +233,8 @@
 
 				FeatureModel featureModel = fmf.parseFeature(featureJar
 						.getInputStream(featureXMLEntry));
+				
+				featureList = addFeaturesToList( (String) params.get(SITE_XML), featureList, featureModel.getFeatureIncluded(), availableLocales, perFeatureLocales);
 
 				Iterator availableLocalesIterator = availableLocales.values()
 						.iterator();
@@ -277,6 +279,44 @@
 		return true;
 	}
 
+	private List addFeaturesToList( String siteXML, List featureList, IIncludedFeatureReference[] iIncludedFeatureReferences, Map availableLocales, Map perFeatureLocales ) throws CoreException {
+		
+		String directoryName = (new File(siteXML)).getParent();
+		if (!directoryName.endsWith(File.separator)) {
+			directoryName = directoryName + File.separator;
+		}
+		directoryName = directoryName + "features" + File.separator; //$NON-NLS-1$
+		
+		for (int i = 0; i < iIncludedFeatureReferences.length; i++) {
+			String featureURL = directoryName + iIncludedFeatureReferences[i].getVersionedIdentifier() + ".jar"; //$NON-NLS-1$
+			if (!(isFeatureAlreadyInList(featureList, featureURL))) {
+				try {
+					System.out.println("Extracting locales from inlcuded feature " + featureURL); //$NON-NLS-1$
+					processLocalesInJar(availableLocales, featureURL, perFeatureLocales, true);
+				} catch (IOException e) {
+					if (iIncludedFeatureReferences[i].isOptional()) 
+						continue;
+					System.out.println("Error while extracting locales from inlcuded feature " + featureURL);//$NON-NLS-1$	
+					e.printStackTrace();
+					throw new CoreException( new Status( IStatus.ERROR, "", IStatus.OK, "Error while extracting locales from inlcuded feature " + featureURL, e)); //$NON-NLS-1$ //$NON-NLS-2$
+				}
+				featureList.add(featureURL);
+			}
+		}
+		
+		return featureList;
+	}
+
+	private boolean isFeatureAlreadyInList(List featureList, String featureURL) {
+		for (int i = 0; i < featureList.size(); i++) {
+			String currentFeatureURL = (String)featureList.get(i);
+			if (currentFeatureURL.equals(featureURL)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	private Map loadProperties(JarFile featureJar, String featureJarFileName,
 			Map perFeatureLocales) {
 		// System.out.println(
@@ -325,7 +365,7 @@
 			String feature = (String) features.next();
 			try {
 				System.out.println("Extracting locales from " + feature); //$NON-NLS-1$
-				processLocalesInJar(locales, feature, perFeatureLocales);
+				processLocalesInJar(locales, feature, perFeatureLocales, false);
 			} catch (IOException e) {
 				System.out.println("Error while extracting locales from " //$NON-NLS-1$
 						+ feature);
@@ -337,7 +377,7 @@
 	}
 
 	private void processLocalesInJar(Map locales, String feature,
-			Map perFeatureLocales) throws IOException {
+			Map perFeatureLocales, boolean ignoreNewLocales) throws IOException {
 
 		JarFile jar = new JarFile(feature);
 		// System.out.println(feature);
@@ -361,14 +401,13 @@
 					localeString = name.substring(8, name.indexOf('.'));
 				}
 				// System.out.println(name +"::::\"" + localeString + "\"");
-				if (!locales.containsKey(localeString)) {
-					locales
-							.put(localeString,
-									new AvailableLocale(localeString));
+				if ( !ignoreNewLocales && !locales.containsKey(localeString)) {
+					locales.put(localeString, new AvailableLocale(localeString));
 				}
-				AvailableLocale currentLocale = (AvailableLocale) locales
-						.get(localeString);
-				currentLocale.addFeatures(feature);
+				if (locales.containsKey(localeString)) {
+					AvailableLocale currentLocale = (AvailableLocale) locales.get(localeString);
+					currentLocale.addFeatures(feature);
+				}
 			}
 		}
 
diff --git a/update/org.eclipse.update.ui/src/org/eclipse/update/internal/ui/wizards/InstallWizard.java b/update/org.eclipse.update.ui/src/org/eclipse/update/internal/ui/wizards/InstallWizard.java
index aace18b..4936be0 100644
--- a/update/org.eclipse.update.ui/src/org/eclipse/update/internal/ui/wizards/InstallWizard.java
+++ b/update/org.eclipse.update.ui/src/org/eclipse/update/internal/ui/wizards/InstallWizard.java
@@ -16,6 +16,7 @@
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.wizard.IWizardPage;
 import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.update.internal.core.UpdateCore;
 import org.eclipse.update.internal.search.SiteSearchCategory;
 import org.eclipse.update.internal.ui.UpdateUI;
 import org.eclipse.update.internal.ui.UpdateUIImages;
@@ -117,7 +118,7 @@
             if (!proceed)
                 return false; // cancel this job, and let the old one go on
         }
-        
+        UpdateCore.getPlugin().getUpdateSession().reset();
         launchInBackground();
         isRunning = false;
         return true;
diff --git a/update/org.eclipse.update.ui/src/org/eclipse/update/internal/ui/wizards/ReviewPage.java b/update/org.eclipse.update.ui/src/org/eclipse/update/internal/ui/wizards/ReviewPage.java
index d3f91e2..e9903ca 100644
--- a/update/org.eclipse.update.ui/src/org/eclipse/update/internal/ui/wizards/ReviewPage.java
+++ b/update/org.eclipse.update.ui/src/org/eclipse/update/internal/ui/wizards/ReviewPage.java
@@ -70,6 +70,7 @@
 import org.eclipse.update.core.IURLEntry;
 import org.eclipse.update.core.Utilities;
 import org.eclipse.update.core.VersionedIdentifier;
+import org.eclipse.update.internal.core.ExtendedSite;
 import org.eclipse.update.internal.core.UpdateCore;
 import org.eclipse.update.internal.core.UpdateManagerUtils;
 import org.eclipse.update.internal.operations.FeatureStatus;
@@ -370,7 +371,7 @@
 					feature.getIncludedFeatureReferences();
 				for (int i = 0; i < irefs.length; i++) {
 					IFeatureReference iref = irefs[i];
-					IFeature ifeature = iref.getFeature(null);
+					IFeature ifeature = UpdateUtils.getIncludedFeature(feature, iref);
 					VersionedIdentifier ivid =
 						ifeature.getVersionedIdentifier();
 					if (ivid.equals(vid))
@@ -1481,7 +1482,7 @@
 				for(int i = 0; i < iifr.length; i++) {
 					IFeature current;
 					try {
-						current = iifr[i].getFeature(new NullProgressMonitor());
+						current = UpdateUtils.getIncludedFeature(feature, iifr[i]);
 					} catch (CoreException e) {
 						// if we can not get feature then it can not satisfy requirement, so just ignore it
 						UpdateUI.logException(e);
@@ -1557,7 +1558,7 @@
 	private List getPluginEntriesFromIncludedFeatures(IFeature feature, List plugins, List visitedFeatures) throws CoreException {
 		IIncludedFeatureReference[] iifr = feature.getIncludedFeatureReferences();
 		for(int i = 0; i < iifr.length; i++) {
-			IFeature current = iifr[i].getFeature(new NullProgressMonitor());
+			IFeature current = UpdateUtils.getIncludedFeature( feature, iifr[i]);
 			if (!visitedFeatures.contains(current)) {
 				IPluginEntry[] pluginEntries = current.getPluginEntries();
 				plugins.addAll(Arrays.asList(pluginEntries));