blob: 7fdb7ffce11cf8c5c89d5097ed576df04792c7a2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 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 Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.update.internal.core;
import java.util.*;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.update.configuration.IConfiguredSite;
import org.eclipse.update.core.*;
import org.eclipse.update.core.model.ModelObject;
/**
* This class manages the reconciliation.
*/
public class SiteReconciler extends ModelObject {
private SiteReconciler(LocalSite siteLocal) {
//never instantiated
}
/**
* 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()); //$NON-NLS-1$
}
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()); //$NON-NLS-1$
}
} catch (CoreException e) {
UpdateCore.warn("", e); //$NON-NLS-1$
}
}
// 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()); //$NON-NLS-1$
}
} catch (CoreException e) {
UpdateCore.warn("", e); //$NON-NLS-1$
}
}
}
/*
*
*/
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); //$NON-NLS-1$
}
}
} catch (CoreException e) {
UpdateCore.warn("", e); //$NON-NLS-1$
}
}
ArrayList list = new ArrayList();
list.addAll(topFeatures.values());
// debug
if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) {
UpdateCore.debug("Computed top-level features"); //$NON-NLS-1$
for (int i = 0; i < topFeatures.size(); i++) {
UpdateCore.debug(" " + ((IFeature) list.get(i)).getVersionedIdentifier().toString()); //$NON-NLS-1$
}
}
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()); //$NON-NLS-1$
}
}
// add nested children to the list
IIncludedFeatureReference[] children = null;
try {
children = feature.getIncludedFeatureReferences();
} catch (CoreException e) {
UpdateCore.warn("", e); //$NON-NLS-1$
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); //$NON-NLS-1$
// 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); //$NON-NLS-1$ //$NON-NLS-2$
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"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER)
UpdateCore.debug("The patch " + efixFeature + " will be enabled."); //$NON-NLS-1$ //$NON-NLS-2$
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;
}
/*
* 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()); //$NON-NLS-1$
}
}
// add nested children to the list
IIncludedFeatureReference[] children = null;
try {
children = feature.getIncludedFeatureReferences();
} catch (CoreException e) {
UpdateCore.warn("", e); //$NON-NLS-1$
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); //$NON-NLS-1$
// 25202 do not return right now, the peer children may be ok
}
if (child != null) {
if (!UpdateCore.isPatch(child))
expandEfixFeature(child, features, configuredSite);
}
}
}
}