| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.update.internal.core; |
| import java.io.*; |
| import java.net.*; |
| import java.util.*; |
| |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.update.configuration.*; |
| import org.eclipse.update.core.*; |
| import org.eclipse.update.core.model.*; |
| import org.eclipse.update.internal.model.*; |
| import org.eclipse.update.configurator.*; |
| |
| /** |
| * This class manages the reconciliation. |
| */ |
| |
| public class SiteReconciler extends ModelObject implements IWritable { |
| |
| private SiteLocal siteLocal; |
| private List newFoundFeatures; |
| private Date date; |
| private static final String DEFAULT_INSTALL_CHANGE_NAME = "delta.xml"; |
| //$NON-NLS-1$ |
| |
| /** |
| * |
| */ |
| public SiteReconciler(SiteLocal siteLocal) { |
| this.siteLocal = siteLocal; |
| } |
| |
| |
| /** |
| * |
| */ |
| /*package */ |
| URL resolveSiteEntry(IPlatformConfiguration.ISiteEntry newSiteEntry) throws CoreException { |
| URL resolvedURL = null; |
| try { |
| resolvedURL = Platform.resolve(newSiteEntry.getURL()); |
| } catch (IOException e) { |
| throw Utilities.newCoreException(Policy.bind("SiteLocal.UnableToResolve", newSiteEntry.getURL().toExternalForm()), e); |
| //$NON-NLS-1$ |
| } |
| return resolvedURL; |
| } |
| |
| |
| /* |
| * Enable feature if: |
| * This is an optimistic reconciliation OR |
| * The feature is considered optional by ALL its parents AND at least one of them is enable |
| * Otherwise disable the feature. |
| * |
| * If all its parent consider the feature as optional but none are enable, |
| * do not add in the list of new found features. Just disable it. |
| */ |
| private void configureNewFoundFeature(boolean isOptimistic, ConfigurationPolicy newSitePolicy, ConfigurationPolicy oldSitePolicy, IFeatureReference foundFeature, IFeatureReference[] possibleParents) throws CoreException { |
| |
| // TRACE |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| String reconciliationType = isOptimistic ? "enable (optimistic)" : "disable (pessimistic)"; |
| UpdateCore.debug("This feature is new: " + foundFeature.getURL() + " reconciled as " + reconciliationType); |
| } |
| |
| if (isOptimistic) { |
| newSitePolicy.configure(foundFeature, true, false); |
| return; |
| } |
| |
| IFeatureReference[] allOptionalParents = UpdateManagerUtils.getParentFeatures(foundFeature, possibleParents, true); |
| IFeatureReference[] allParents = UpdateManagerUtils.getParentFeatures(foundFeature, possibleParents, false); |
| |
| // none of my parents consider me as optional OR I have no parents, |
| // consider as root feature |
| if (allOptionalParents.length == 0) { |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("There are no features who consider the feature as optional. Treat as root feature."); |
| } |
| newSitePolicy.unconfigure(foundFeature, true, false); |
| newFoundFeatures.add(foundFeature); |
| return; |
| |
| } |
| |
| //At least one of my parent considers me non optional |
| // consider root feature |
| if (allParents.length > allOptionalParents.length) { |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("At least one parent considers the feature as NON optional. Treat as root feature."); |
| } |
| newSitePolicy.unconfigure(foundFeature, true, false); |
| newFoundFeatures.add(foundFeature); |
| return; |
| } |
| |
| for (int i = 0; i < allOptionalParents.length; i++) { |
| // one parent that consider me optional is enable, enable feature |
| if (oldSitePolicy.isConfigured(allOptionalParents[i])) { |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("Found parent feature:" + allOptionalParents[i] + " as enable: Enable optional child feature:" + foundFeature); |
| } |
| newSitePolicy.configure(foundFeature, true, false); |
| return; |
| } |
| } |
| |
| // found parent that consider me optional but they are all disable |
| // unconfigure feature without adding it to the list fo new found features |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("No parents are enable. Disable feature."); |
| } |
| newSitePolicy.unconfigure(foundFeature, true, false); |
| |
| } |
| |
| /** |
| * Validate we have only one configured feature per site |
| * even if we found multiples |
| * |
| * If we find 2 features, the one with a higher version is configured |
| * If they have the same version, the first feature is configured |
| * |
| * DO NOT check across sites [17980] |
| * If Feature1 is installed natively on Site A |
| * If Feature1 is installed on Site B |
| * If Feature1 from SiteA is removed... |
| */ |
| private void checkConfiguredFeatures(IInstallConfiguration newDefaultConfiguration) throws CoreException { |
| |
| IConfiguredSite[] configuredSites = newDefaultConfiguration.getConfiguredSites(); |
| |
| // each configured site |
| for (int indexConfiguredSites = 0; indexConfiguredSites < configuredSites.length; indexConfiguredSites++) { |
| checkConfiguredFeatures(configuredSites[indexConfiguredSites]); |
| } |
| } |
| |
| /** |
| * Validate we have only one configured feature of a specific id |
| * per configured site |
| */ |
| public static void checkConfiguredFeaturesOld(IConfiguredSite configuredSite) throws CoreException { |
| |
| // NOT USED |
| |
| ConfiguredSite cSite = (ConfiguredSite) configuredSite; |
| IFeatureReference[] configuredFeatures = cSite.getConfiguredFeatures(); |
| ConfigurationPolicy cPolicy = cSite.getConfigurationPolicy(); |
| |
| // TRACE |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("Compare features within :" + configuredSite.getSite().getURL()); |
| } |
| |
| for (int indexConfiguredFeatures = 0; indexConfiguredFeatures < configuredFeatures.length - 1; indexConfiguredFeatures++) { |
| |
| IFeatureReference featureToCompare = configuredFeatures[indexConfiguredFeatures]; |
| |
| // within the configured site |
| // compare with the other configured features of this site |
| for (int restOfConfiguredFeatures = indexConfiguredFeatures + 1; restOfConfiguredFeatures < configuredFeatures.length; restOfConfiguredFeatures++) { |
| int result = compare(featureToCompare, configuredFeatures[restOfConfiguredFeatures]); |
| if (result != 0) { |
| if (result == 1) { |
| cPolicy.unconfigure(configuredFeatures[restOfConfiguredFeatures], true, false); |
| } |
| if (result == 2) { |
| cPolicy.unconfigure(featureToCompare, true, false); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * compare two feature references |
| * returns 0 if the feature are different |
| * returns 1 if the version of feature 1 is greater than the version of feature 2 |
| * returns 2 if opposite |
| */ |
| private static int compare(IFeatureReference featureRef1, IFeatureReference featureRef2) throws CoreException { |
| |
| // TRACE |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("Compare: " + featureRef1 + " && " + featureRef2); |
| } |
| |
| if (featureRef1 == null) |
| return 0; |
| |
| IFeature feature1 = null; |
| IFeature feature2 = null; |
| try { |
| feature1 = featureRef1.getFeature(null); |
| feature2 = featureRef2.getFeature(null); |
| } catch (CoreException e) { |
| UpdateCore.warn(null, e); |
| return 0; |
| } |
| |
| if (feature1 == null || feature2 == null) { |
| return 0; |
| } |
| |
| VersionedIdentifier id1 = feature1.getVersionedIdentifier(); |
| VersionedIdentifier id2 = feature2.getVersionedIdentifier(); |
| |
| if (id1 == null || id2 == null) { |
| return 0; |
| } |
| |
| if (id1.getIdentifier() != null && id1.getIdentifier().equals(id2.getIdentifier())) { |
| PluginVersionIdentifier version1 = id1.getVersion(); |
| PluginVersionIdentifier version2 = id2.getVersion(); |
| if (version1 != null) { |
| if (version1.isGreaterThan(version2)) { |
| return 1; |
| } else { |
| return 2; |
| } |
| } else { |
| return 2; |
| } |
| } |
| return 0; |
| } |
| |
| /* |
| * |
| */ |
| private ConfiguredSite createNewConfigSite(IConfiguredSite oldConfiguredSiteToReconcile) throws CoreException { |
| // create a copy of the ConfigSite based on old ConfigSite |
| // this is not a clone, do not copy any features |
| ConfiguredSite cSiteToReconcile = (ConfiguredSite) oldConfiguredSiteToReconcile; |
| SiteModel siteModel = cSiteToReconcile.getSiteModel(); |
| int policy = cSiteToReconcile.getConfigurationPolicy().getPolicy(); |
| |
| // copy values of the old ConfigSite that should be preserved except Features |
| ConfiguredSite newConfigurationSite = (ConfiguredSite) new BaseSiteLocalFactory().createConfigurationSiteModel(siteModel, policy); |
| newConfigurationSite.setUpdatable(cSiteToReconcile.isUpdatable()); |
| newConfigurationSite.setEnabled(cSiteToReconcile.isEnabled()); |
| newConfigurationSite.setPlatformURLString(cSiteToReconcile.getPlatformURLString()); |
| |
| return newConfigurationSite; |
| } |
| |
| /* |
| * |
| */ |
| private IFeatureReference[] getFeatureReferences() { |
| if (newFoundFeatures == null || newFoundFeatures.size() == 0) |
| return new IFeatureReference[0]; |
| |
| return (IFeatureReference[]) newFoundFeatures.toArray(arrayTypeFor(newFoundFeatures)); |
| } |
| |
| /* |
| * |
| */ |
| private boolean saveNewFeatures(IInstallConfiguration installConfig) throws CoreException { |
| |
| if (getFeatureReferences().length == 0) { |
| UpdateCore.warn("No new features found"); |
| return false; |
| } |
| |
| // recompute list of new features to only keep root features [16496] |
| IFeatureReference[] refs = getFeatureReferences(); |
| newFoundFeatures = new ArrayList(); |
| for (int i = 0; i < refs.length; i++) { |
| IFeatureReference[] parents = UpdateManagerUtils.getParentFeatures(refs[i], refs, false); |
| if (parents.length == 0) |
| newFoundFeatures.add(refs[i]); |
| } |
| |
| |
| if (getFeatureReferences().length == 0) { |
| UpdateCore.warn("No root feature found when saving new features"); |
| return false; |
| } |
| |
| // remove efixes from the delta that patch disabled feature from the installConfig |
| // bug 71730 |
| removeInvalidEfixes(installConfig); |
| |
| if (getFeatureReferences().length == 0) { |
| UpdateCore.warn("No new features found after removing invalid efixes"); |
| return false; |
| } |
| |
| |
| date = new Date(); |
| String fileName = UpdateManagerUtils.getLocalRandomIdentifier(DEFAULT_INSTALL_CHANGE_NAME, date); |
| IPath path = UpdateCore.getPlugin().getStateLocation(); |
| IPath filePath = path.append(fileName); |
| File file = filePath.toFile(); |
| // persist list of new features |
| try { |
| UpdateManagerUtils.Writer writer = UpdateManagerUtils.getWriter(file, "UTF-8"); |
| writer.write(this); |
| return true; |
| } catch (UnsupportedEncodingException e) { |
| throw Utilities.newCoreException(Policy.bind("SiteReconciler.UnableToEncodeConfiguration", file.getAbsolutePath()), e); |
| //$NON-NLS-1$ |
| } catch (FileNotFoundException e) { |
| throw Utilities.newCoreException(Policy.bind("SiteReconciler.UnableToSaveStateIn", file.getAbsolutePath()), e); |
| //$NON-NLS-1$ |
| } |
| } |
| |
| /* |
| * @see IWritable#write(int, PrintWriter) |
| */ |
| public void write(int indent, PrintWriter w) { |
| String gap = ""; //$NON-NLS-1$ |
| for (int i = 0; i < indent; i++) |
| gap += " "; //$NON-NLS-1$ |
| String increment = ""; //$NON-NLS-1$ |
| for (int i = 0; i < IWritable.INDENT; i++) |
| increment += " "; //$NON-NLS-1$ |
| |
| // CHANGE tag |
| w.print(gap + "<" + InstallChangeParser.CHANGE + " "); |
| //$NON-NLS-1$ //$NON-NLS-2$ |
| long time = (date != null) ? date.getTime() : 0L; |
| w.println("date=\"" + time + "\" >"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| // NEW FEATURE |
| w.println(gap + increment + "<" + InstallChangeParser.NEW_FEATURE + " >"); |
| |
| // FEATURE REF |
| IFeatureReference[] references = getFeatureReferences(); |
| String URLFeatureString = null; |
| if (references != null) { |
| for (int index = 0; index < references.length; index++) { |
| IFeatureReference ref = references[index]; |
| if (ref.getURL() != null) { |
| ISite featureSite = ref.getSite(); |
| URLFeatureString = UpdateManagerUtils.getURLAsString(featureSite.getURL(), ref.getURL()); |
| |
| w.print(gap + increment + increment + "<" + InstallChangeParser.REFERENCE + " "); |
| //$NON-NLS-1$ |
| w.println("siteURL = \"" + UpdateManagerUtils.Writer.xmlSafe(getURLSiteString(featureSite)) + "\" "); |
| //$NON-NLS-1$ //$NON-NLS-2$ |
| w.println(gap + increment + increment + increment + "featureURL=\"" + UpdateManagerUtils.Writer.xmlSafe(URLFeatureString) + "\" />"); |
| //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| w.println(""); //$NON-NLS-1$ |
| } |
| } |
| |
| // END NEW FEATURE |
| w.println(gap + increment + "</" + InstallChangeParser.NEW_FEATURE + " >"); |
| |
| // end |
| w.println(gap + "</" + InstallChangeParser.CHANGE + ">"); |
| //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /* |
| * Returns the Site URL, attempting to replace it by platform: URL if needed |
| */ |
| private String getURLSiteString(ISite site) { |
| // since 2.0.2 ISite.getConfiguredSite(); |
| ConfiguredSite cSite = (ConfiguredSite) site.getCurrentConfiguredSite(); |
| if (cSite != null) |
| return cSite.getPlatformURLString(); |
| return site.getURL().toExternalForm(); |
| } |
| |
| /* |
| * return true if the platformBase URL is not the same |
| * we thought it is. In this case we should reconcile in an optimistic way |
| */ |
| private boolean platformBaseChanged(IConfiguredSite[] oldConfiguredSites) { |
| |
| if (oldConfiguredSites == null) { |
| UpdateCore.warn("No previous configured sites. Optimistic reconciliation."); |
| return true; |
| } |
| |
| String platformString = "platform:/base/"; |
| URL platformURL = null; |
| try { |
| platformURL = new URL(platformString); |
| } catch (MalformedURLException e) { |
| UpdateCore.warn("Unable to resolve platform:/base/. Check you are running a Platform", e); |
| return true; |
| } |
| URL resolvedCurrentBaseURL = null; |
| try { |
| resolvedCurrentBaseURL = Platform.resolve(platformURL); |
| } catch (IOException e) { |
| UpdateCore.warn("Error while resolving platform:/base/. Check you are running a Platform", e); |
| return true; |
| } |
| |
| // find the 'platform:/base/' configuredSite |
| int index = 0; |
| boolean found = false; |
| ConfiguredSite cSite = null; |
| while (!found && index < oldConfiguredSites.length) { |
| if (oldConfiguredSites[index] instanceof ConfiguredSite) { |
| cSite = (ConfiguredSite) oldConfiguredSites[index]; |
| if (platformString.equalsIgnoreCase(cSite.getPlatformURLString())) { |
| found = true; |
| } |
| } |
| index++; |
| } |
| |
| if (!found) { |
| UpdateCore.warn("Unable to find an old configured site with platform:/base/ as a platform URL"); |
| return true; |
| } |
| |
| if (cSite == null) { |
| UpdateCore.warn("The configuredSite that contains the platform is null"); |
| return true; |
| } |
| |
| if (UpdateManagerUtils.sameURL(resolvedCurrentBaseURL, cSite.getSite().getURL())) { |
| UpdateCore.warn("Platform URL found are the same:" + resolvedCurrentBaseURL + " : " + cSite.getSite().getURL()); |
| return false; |
| } |
| |
| UpdateCore.warn("Platform URL found is different than the one previously saved. Reconcile optimistically:" + resolvedCurrentBaseURL + " : " + cSite.getSite().getURL()); |
| return true; |
| } |
| |
| /** |
| * Validate the list of configured features eliminating extra |
| * entries (if possible). Make sure we do not leave configured |
| * nested features with "holes" (ie. unconfigured children) |
| */ |
| public static void checkConfiguredFeatures(IConfiguredSite configuredSite) { |
| |
| // Note: if we hit errors in the various computation |
| // methods and throw a CoreException, we will not catch it |
| // in this method. Consequently we will not attempt to |
| // unconfigure any "extra" features because we would |
| // likely get it wrong. The platform will run with extra features |
| // configured. The runtime will eliminate extra plugins based |
| // on runtime binding rules. |
| |
| // determine "proposed" list of configured features |
| ConfiguredSite cSite = (ConfiguredSite) configuredSite; |
| // debug |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("Validate configuration of site " + cSite.getSite().getURL()); |
| } |
| IFeatureReference[] configuredRefs = cSite.getConfiguredFeatures(); |
| ArrayList allPossibleConfiguredFeatures = new ArrayList(); |
| for (int i = 0; i < configuredRefs.length; i++) { |
| try { |
| IFeature feature = configuredRefs[i].getFeature(null); |
| allPossibleConfiguredFeatures.add(feature); |
| // debug |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug(" configured feature " + feature.getVersionedIdentifier().toString()); |
| } |
| } catch (CoreException e) { |
| UpdateCore.warn("", e); |
| } |
| } |
| |
| // find top level features |
| ArrayList topFeatures = computeTopFeatures(allPossibleConfiguredFeatures); |
| |
| // find non efix top level features |
| ArrayList topNonEfixFeatures = getNonEfixFeatures(topFeatures); |
| |
| // expand non efix top level features (compute full nesting structures). |
| ArrayList configuredFeatures = expandFeatures(topNonEfixFeatures, configuredSite); |
| |
| // retrieve efixes that patch enable feature |
| // they must be kept enabled |
| if (topFeatures.size() != topNonEfixFeatures.size()) { |
| Map patches = getPatchesAsFeature(allPossibleConfiguredFeatures); |
| if (!patches.isEmpty()) { |
| // calculate efixes to enable |
| List efixesToEnable = getPatchesToEnable(patches, configuredFeatures); |
| // add efies to keep enable |
| //add them to the enable list |
| for (Iterator iter = efixesToEnable.iterator(); iter.hasNext();) { |
| IFeature element = (IFeature) iter.next(); |
| ArrayList expandedEfix = new ArrayList(); |
| expandEfixFeature(element, expandedEfix, configuredSite); |
| configuredFeatures.addAll(expandedEfix); |
| } |
| } |
| } |
| |
| // compute extra features |
| ArrayList extras = diff(allPossibleConfiguredFeatures, configuredFeatures); |
| |
| // unconfigure extra features |
| ConfigurationPolicy cPolicy = cSite.getConfigurationPolicy(); |
| for (int i = 0; i < extras.size(); i++) { |
| IFeature feature = (IFeature) extras.get(i); |
| IFeatureReference ref = cSite.getSite().getFeatureReference(feature); |
| try { |
| cPolicy.unconfigure(ref, true, false); |
| // debug |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("Unconfiguring \"extra\" feature " + feature.getVersionedIdentifier().toString()); |
| } |
| } catch (CoreException e) { |
| UpdateCore.warn("", e); |
| } |
| } |
| } |
| |
| /* |
| * |
| */ |
| private static ArrayList computeTopFeatures(ArrayList features) { |
| /* map of Feature by VersionedIdentifier */ |
| Map topFeatures = new HashMap(features.size()); |
| // start with the features passed in |
| for (Iterator it = features.iterator(); it.hasNext();) { |
| IFeature f = ((IFeature) it.next()); |
| topFeatures.put(f.getVersionedIdentifier(), f); |
| } |
| // remove all features that nest in some other feature |
| for (Iterator it = features.iterator(); it.hasNext();) { |
| try { |
| IIncludedFeatureReference[] children = ((IFeature) it.next()).getIncludedFeatureReferences(); |
| for (int j = 0; j < children.length; j++) { |
| try { |
| topFeatures.remove(children[j].getVersionedIdentifier()); |
| } catch (CoreException e1) { |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_WARNINGS) |
| UpdateCore.warn("", e1); |
| } |
| } |
| } catch (CoreException e) { |
| UpdateCore.warn("", e); |
| } |
| } |
| ArrayList list = new ArrayList(); |
| list.addAll(topFeatures.values()); |
| // debug |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("Computed top-level features"); |
| for (int i = 0; i < topFeatures.size(); i++) { |
| UpdateCore.debug(" " + ((IFeature) list.get(i)).getVersionedIdentifier().toString()); |
| } |
| } |
| return list; |
| } |
| |
| /* |
| * |
| */ |
| private static ArrayList expandFeatures(ArrayList features, IConfiguredSite configuredSite) { |
| ArrayList result = new ArrayList(); |
| |
| // expand all top level features |
| for (int i = 0; i < features.size(); i++) { |
| expandFeature((IFeature) features.get(i), result, configuredSite); |
| } |
| |
| return result; |
| } |
| |
| /* |
| * |
| */ |
| private static void expandFeature(IFeature feature, ArrayList features, IConfiguredSite configuredSite) { |
| |
| // add feature |
| if (!features.contains(feature)) { |
| features.add(feature); |
| // debug |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("Retaining configured feature " + feature.getVersionedIdentifier().toString()); |
| } |
| } |
| |
| // add nested children to the list |
| IIncludedFeatureReference[] children = null; |
| try { |
| children = feature.getIncludedFeatureReferences(); |
| } catch (CoreException e) { |
| UpdateCore.warn("", e); |
| return; |
| } |
| |
| for (int j = 0; j < children.length; j++) { |
| IFeature child = null; |
| try { |
| child = children[j].getFeature(null); |
| } catch (CoreException e) { |
| if (!UpdateManagerUtils.isOptional(children[j])) |
| UpdateCore.warn("", e); |
| // 25202 do not return right now, the peer children may be ok |
| } |
| if (child != null) |
| expandFeature(child, features, configuredSite); |
| } |
| } |
| |
| /* |
| * |
| */ |
| private static ArrayList diff(ArrayList left, ArrayList right) { |
| ArrayList result = new ArrayList(); |
| |
| // determine difference (left "minus" right) |
| for (int i = 0; i < left.size(); i++) { |
| IFeature feature = (IFeature) left.get(i); |
| if (!right.contains(feature)) |
| result.add(feature); |
| } |
| return result; |
| } |
| |
| /* |
| * get the list of enabled patches |
| */ |
| private static Map getPatchesAsFeature(ArrayList allConfiguredFeatures) { |
| // get all efixes and the associated patched features |
| Map patches = new HashMap(); |
| if (allConfiguredFeatures != null) { |
| Iterator iter = allConfiguredFeatures.iterator(); |
| while (iter.hasNext()) { |
| List patchedFeaturesID = new ArrayList(); |
| IFeature element = (IFeature) iter.next(); |
| // add the patched feature identifiers |
| for (int i = 0; i < element.getImports().length; i++) { |
| if (element.getImports()[i].isPatch()) { |
| VersionedIdentifier id = element.getImports()[i].getVersionedIdentifier(); |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) |
| UpdateCore.debug("Found patch " + element + " for feature identifier " + id); |
| patchedFeaturesID.add(id); |
| } |
| } |
| |
| if (!patchedFeaturesID.isEmpty()) { |
| patches.put(element, patchedFeaturesID); |
| } |
| } |
| } |
| |
| return patches; |
| } |
| |
| /* |
| * retruns the list of pathes-feature who patch enabled features |
| */ |
| private static List getPatchesToEnable(Map efixes, ArrayList configuredFeatures) { |
| |
| ArrayList enabledVersionedIdentifier = new ArrayList(); |
| Iterator iter = configuredFeatures.iterator(); |
| while (iter.hasNext()) { |
| IFeature element = (IFeature) iter.next(); |
| enabledVersionedIdentifier.add(element.getVersionedIdentifier()); |
| } |
| |
| // loop through the patches |
| List result = new ArrayList(); |
| iter = efixes.keySet().iterator(); |
| while (iter.hasNext()) { |
| boolean toEnable = false; |
| IFeature efixFeature = (IFeature) iter.next(); |
| List patchedFeatures = (List) efixes.get(efixFeature); |
| // loop through the 'patched features identifier' the for this patch |
| // see if it the patch patches at least one enable feature |
| Iterator patchedFeaturesIter = patchedFeatures.iterator(); |
| while (patchedFeaturesIter.hasNext() && !toEnable) { |
| VersionedIdentifier patchedFeatureID = (VersionedIdentifier) patchedFeaturesIter.next(); |
| if (enabledVersionedIdentifier.contains(patchedFeatureID)) { |
| toEnable = true; |
| } |
| } |
| |
| if (!toEnable) { |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) |
| UpdateCore.debug("The Patch " + efixFeature + " does not patch any enabled features: it will be disabled"); |
| } else { |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) |
| UpdateCore.debug("The patch " + efixFeature + " will be enabled."); |
| result.add(efixFeature); |
| } |
| } |
| return result; |
| } |
| |
| /* |
| * returns the feature that are not patches |
| */ |
| private static ArrayList getNonEfixFeatures(ArrayList topFeatures) { |
| Map efixFeatures = getPatchesAsFeature(topFeatures); |
| Set keySet = efixFeatures.keySet(); |
| if (keySet == null || keySet.isEmpty()) |
| return topFeatures; |
| |
| Iterator iter = topFeatures.iterator(); |
| ArrayList result = new ArrayList(); |
| while (iter.hasNext()) { |
| IFeature element = (IFeature) iter.next(); |
| if (!keySet.contains(element)) { |
| result.add(element); |
| } |
| } |
| return result; |
| } |
| |
| |
| /* |
| * get the map of enabled patches (as feature reference) or an empty map |
| */ |
| private Map getPatchesAsFeatureReference(List listOfFeatureReferences) { |
| // get all efixes and the associated patched features |
| Map patches = new HashMap(); |
| if (listOfFeatureReferences != null) { |
| Iterator iter = listOfFeatureReferences.iterator(); |
| while (iter.hasNext()) { |
| List patchedFeaturesID = new ArrayList(); |
| IFeatureReference element = (IFeatureReference) iter.next(); |
| // add the patched feature identifiers |
| try { |
| IFeature feature = element.getFeature(null); |
| if (feature != null) { |
| IImport[] imports = feature.getImports(); |
| for (int i = 0; i < imports.length; i++) { |
| if (imports[i].isPatch()) { |
| VersionedIdentifier id = imports[i].getVersionedIdentifier(); |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) |
| UpdateCore.debug("Found patch " + element + " for feature identifier " + id); |
| patchedFeaturesID.add(id); |
| } |
| } |
| } |
| |
| if (!patchedFeaturesID.isEmpty()) { |
| patches.put(element, patchedFeaturesID); |
| } |
| } catch (CoreException e) { |
| } |
| } |
| } |
| |
| return patches; |
| } |
| |
| |
| /* |
| * Removes efixes from new found features if they do not patch an enable feature |
| * either from the found delta or from the file system |
| */ |
| private void removeInvalidEfixes(IInstallConfiguration installConfig) { |
| |
| // disable new found efixes if the feature is not in the list nor enabled features |
| // on the file system |
| Map newFoundEfixesAsReference = getPatchesAsFeatureReference(newFoundFeatures); |
| |
| if (newFoundEfixesAsReference.size() > 0) { |
| // retrieve all enabled features on all the sites |
| ArrayList allEnabledFeatures = new ArrayList(); |
| IConfiguredSite[] configSites = installConfig.getConfiguredSites(); |
| for (int i = 0; i < configSites.length; i++) { |
| IFeatureReference[] references = configSites[i].getConfiguredFeatures(); |
| for (int j = 0; j < references.length; j++) { |
| try { |
| allEnabledFeatures.add(references[j].getFeature(null)); |
| } catch (CoreException e) { |
| } |
| } |
| } |
| |
| // create a List of eFixes Features |
| List arrayOfNewFoundFeatures = new ArrayList(); |
| for (Iterator iter = newFoundFeatures.iterator(); iter.hasNext();) { |
| IFeatureReference element = (IFeatureReference) iter.next(); |
| try { |
| arrayOfNewFoundFeatures.add(element.getFeature(null)); |
| } catch (CoreException e) { |
| } |
| } |
| |
| // retrieve the efixes that patch enable features in delta and enabled features on the |
| // file system |
| List patchesForNewFoundFeatures = getFeatureReferencePatchesToEnable(newFoundEfixesAsReference, allEnabledFeatures); |
| List patchesForEnabledFeatures = getFeatureReferencePatchesToEnable(newFoundEfixesAsReference, arrayOfNewFoundFeatures); |
| |
| // IMPORTANT: add efixes first so they will be processed first |
| newFoundFeatures.removeAll(newFoundEfixesAsReference.keySet()); |
| newFoundFeatures.addAll(0,patchesForEnabledFeatures); |
| newFoundFeatures.addAll(0,patchesForNewFoundFeatures); |
| } |
| } |
| |
| /* |
| * retruns the list of pathes-featureReference who patch enabled features |
| */ |
| private List getFeatureReferencePatchesToEnable(Map efixes, List configuredFeatures) { |
| |
| ArrayList enabledVersionedIdentifier = new ArrayList(); |
| Iterator iter = configuredFeatures.iterator(); |
| while (iter.hasNext()) { |
| IFeature element = (IFeature) iter.next(); |
| enabledVersionedIdentifier.add(element.getVersionedIdentifier()); |
| } |
| |
| // loop through the patches |
| List result = new ArrayList(); |
| iter = efixes.keySet().iterator(); |
| while (iter.hasNext()) { |
| boolean toEnable = false; |
| IFeatureReference efixFeatureReference = (IFeatureReference) iter.next(); |
| List patchedFeatures = (List) efixes.get(efixFeatureReference); |
| // loop through the 'patched features identifier' the for this patch |
| // see if it the patch patches at least one enable feature |
| Iterator patchedFeaturesIter = patchedFeatures.iterator(); |
| while (patchedFeaturesIter.hasNext() && !toEnable) { |
| VersionedIdentifier patchedFeatureID = (VersionedIdentifier) patchedFeaturesIter.next(); |
| if (enabledVersionedIdentifier.contains(patchedFeatureID)) { |
| toEnable = true; |
| } |
| } |
| |
| if (!toEnable) { |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) |
| UpdateCore.debug("The Patch " + efixFeatureReference + " does not patch any enabled features: it will be disabled"); |
| } else { |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) |
| UpdateCore.debug("The patch " + efixFeatureReference + " will be enabled."); |
| |
| result.add(efixFeatureReference); |
| } |
| } |
| return result; |
| } |
| |
| /* |
| * only enable non-efix children recursively |
| */ |
| private static void expandEfixFeature(IFeature feature, ArrayList features, IConfiguredSite configuredSite) { |
| |
| // add feature |
| if (!features.contains(feature)) { |
| features.add(feature); |
| // debug |
| if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { |
| UpdateCore.debug("Retaining configured feature " + feature.getVersionedIdentifier().toString()); |
| } |
| } |
| |
| // add nested children to the list |
| IIncludedFeatureReference[] children = null; |
| try { |
| children = feature.getIncludedFeatureReferences(); |
| } catch (CoreException e) { |
| UpdateCore.warn("", e); |
| return; |
| } |
| |
| for (int j = 0; j < children.length; j++) { |
| IFeature child = null; |
| try { |
| child = children[j].getFeature(null); |
| } catch (CoreException e) { |
| if (!children[j].isOptional()) |
| UpdateCore.warn("", e); |
| // 25202 do not return right now, the peer children may be ok |
| } |
| if (child != null){ |
| if (!UpdateCore.isPatch(child)) |
| expandEfixFeature(child, features, configuredSite); |
| } |
| } |
| } |
| |
| } |