blob: 03af25be211eb2268f20ba383a976d2fb8fecb12 [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.operations;
//import java.io.*;
//import java.net.*;
//import java.nio.channels.*;
import org.eclipse.update.core.IUpdateConstants;
import org.eclipse.osgi.service.resolver.PlatformAdmin;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.service.resolver.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.update.configuration.*;
import org.eclipse.update.configurator.ConfiguratorUtils;
import org.eclipse.update.configurator.IPlatformConfiguration;
import org.eclipse.update.core.*;
import org.eclipse.update.internal.configurator.PlatformConfiguration;
import org.eclipse.update.internal.core.Messages;
import org.eclipse.update.internal.core.UpdateCore;
import org.eclipse.update.operations.IInstallFeatureOperation;
import org.eclipse.update.operations.IOperationValidator;
import org.osgi.framework.*;
/**
*
*/
public class OperationValidator implements IOperationValidator {
/**
* Checks if the platform configuration has been modified outside this program.
* @return the error status, or null if no errors
*/
public IStatus validatePlatformConfigValid() {
ArrayList status = new ArrayList(1);
checkPlatformWasModified(status);
// report status
if (status.size() > 0)
return createMultiStatus(Messages.ActivityConstraints_rootMessage, status, IStatus.ERROR);
return null;
}
/*
* Called by UI before performing operation. Returns null if no errors, a
* status with IStatus.WARNING code when the initial configuration is
* broken, or a status with IStatus.ERROR when there the operation
* introduces new errors
*/
public IStatus validatePendingInstall(
IFeature oldFeature,
IFeature newFeature) {
// check initial state
ArrayList beforeStatus = new ArrayList();
validateInitialState(beforeStatus);
// check proposed change
ArrayList status = new ArrayList();
checkPlatformWasModified(status);
validateInstall(oldFeature, newFeature, status);
// report status
return createCombinedReportStatus(beforeStatus, status);
}
/*
* Called by UI before performing operation
*/
public IStatus validatePendingUnconfig(IFeature feature) {
// check initial state
ArrayList beforeStatus = new ArrayList();
validateInitialState(beforeStatus);
// check proposed change
ArrayList status = new ArrayList();
checkPlatformWasModified(status);
validateUnconfigure(feature, status);
// report status
return createCombinedReportStatus(beforeStatus, status);
}
/*
* Called by UI before performing operation
*/
public IStatus validatePendingConfig(IFeature feature) {
// check initial state
ArrayList beforeStatus = new ArrayList();
validateInitialState(beforeStatus);
// check proposed change
ArrayList status = new ArrayList();
checkPlatformWasModified(status);
validateConfigure(feature, status);
// report status
return createCombinedReportStatus(beforeStatus, status);
}
/**
* Called before performing operation.
*/
public IStatus validatePendingReplaceVersion(
IFeature feature,
IFeature anotherFeature) {
// check initial state
ArrayList beforeStatus = new ArrayList();
validateInitialState(beforeStatus);
// check proposed change
ArrayList status = new ArrayList();
checkPlatformWasModified(status);
validateReplaceVersion(feature, anotherFeature, status);
// report status
return createCombinedReportStatus(beforeStatus, status);
}
/*
* Called by the UI before doing a revert/ restore operation
*/
public IStatus validatePendingRevert(IInstallConfiguration config) {
// check initial state
ArrayList beforeStatus = new ArrayList();
validateInitialState(beforeStatus);
// check proposed change
ArrayList status = new ArrayList();
checkPlatformWasModified(status);
validateRevert(config, status);
// report status
return createCombinedReportStatus(beforeStatus, status);
}
/*
* Called by the UI before doing a batched processing of several pending
* changes.
*/
public IStatus validatePendingChanges(IInstallFeatureOperation[] jobs) {
// check initial state
ArrayList beforeStatus = new ArrayList();
validateInitialState(beforeStatus);
checkPlatformWasModified(beforeStatus);
// check proposed change
ArrayList status = new ArrayList();
validatePendingChanges(jobs, status, beforeStatus);
// report status
return createCombinedReportStatus(beforeStatus, status);
}
/*
* Called by the UI before doing a batched processing of several pending
* changes.
*/
public RequiredFeaturesResult getRequiredFeatures(IInstallFeatureOperation[] jobs) {
RequiredFeaturesResult requiredFeaturesResult = new RequiredFeaturesResult();
// check initial state
ArrayList beforeStatus = new ArrayList();
validateInitialState(beforeStatus);
checkPlatformWasModified(beforeStatus);
// check proposed change
ArrayList status = new ArrayList();
Set requiredFeatures = validatePendingChanges(jobs, status, beforeStatus);
// report status
//return createCombinedReportStatus(beforeStatus, status);
requiredFeaturesResult.setRequiredFeatures(requiredFeatures);
requiredFeaturesResult.setStatus(createCombinedReportStatus(beforeStatus, status));
return requiredFeaturesResult;
}
/*
* Check the current state.
*/
public IStatus validateCurrentState() {
// check the state
ArrayList status = new ArrayList();
checkPlatformWasModified(status);
validateInitialState(status);
// report status
if (status.size() > 0)
return createMultiStatus(Messages.ActivityConstraints_rootMessage, status, IStatus.ERROR);
return null;
}
/*
* Check to see if we are not broken even before we start
*/
private static void validateInitialState(ArrayList status) {
try {
ArrayList features = computeFeatures();
// uncomment this when patch released in boot
//checkConfigurationLock(status);
checkConstraints(features, status);
} catch (CoreException e) {
status.add(e.getStatus());
}
}
/*
* handle unconfigure
*/
private static void validateUnconfigure(
IFeature feature,
ArrayList status) {
try {
checkSiteReadOnly(feature,status);
ArrayList features = computeFeatures();
features = computeFeaturesAfterOperation(features, null, feature);
checkConstraints(features, status);
} catch (CoreException e) {
status.add(e.getStatus());
}
}
/*
* handle configure
*/
private static void validateConfigure(IFeature feature, ArrayList status) {
try {
checkSiteReadOnly(feature,status);
ArrayList features = computeFeatures();
checkOptionalChildConfiguring(feature, status);
checkForCycles(feature, null, features);
features = computeFeaturesAfterOperation(features, feature, null);
checkConstraints(features, status);
} catch (CoreException e) {
status.add(e.getStatus());
}
}
/*
* handle replace version
*/
private static void validateReplaceVersion(
IFeature feature,
IFeature anotherFeature,
ArrayList status) {
try {
checkSiteReadOnly(feature,status);
ArrayList features = computeFeatures();
checkForCycles(feature, null, features);
features =
computeFeaturesAfterOperation(
features,
anotherFeature,
feature);
checkConstraints(features, status);
} catch (CoreException e) {
status.add(e.getStatus());
}
}
/*
* handle install and update
*/
private static void validateInstall(
IFeature oldFeature,
IFeature newFeature,
ArrayList status) {
try {
checkSiteReadOnly(oldFeature,status);
ArrayList features = computeFeatures();
checkForCycles(newFeature, null, features);
features =
computeFeaturesAfterOperation(features, newFeature, oldFeature);
checkConstraints(features, status);
checkLicense(newFeature, status);
} catch (CoreException e) {
status.add(e.getStatus());
}
}
/*
* handle revert and restore
*/
private static void validateRevert(
IInstallConfiguration config,
ArrayList status) {
try {
// // check the timeline and don't bother
// // to check anything else if negative
// if (!checkTimeline(config, status))
// return;
ArrayList features = computeFeaturesAfterRevert(config);
checkConstraints(features, status);
checkRevertConstraints(features, status);
} catch (CoreException e) {
status.add(e.getStatus());
}
}
/*
* Handle one-click changes as a batch
*/
private static Set validatePendingChanges(
IInstallFeatureOperation[] jobs,
ArrayList status,
ArrayList beforeStatus) {
try {
ArrayList features = computeFeatures();
ArrayList savedFeatures = features;
int nexclusives = 0;
// pass 1: see if we can process the entire "batch"
ArrayList tmpStatus = new ArrayList();
for (int i = 0; i < jobs.length; i++) {
IInstallFeatureOperation job = jobs[i];
IFeature newFeature = job.getFeature();
IFeature oldFeature = job.getOldFeature();
checkLicense(newFeature, status);
if (jobs.length > 1 && newFeature.isExclusive()) {
nexclusives++;
status.add(
createStatus(
newFeature,
FeatureStatus.CODE_EXCLUSIVE,
Messages.ActivityConstraints_exclusive));
continue;
}
checkForCycles(newFeature, null, features);
features =
computeFeaturesAfterOperation(
features,
newFeature,
oldFeature);
}
if (nexclusives > 0)
return Collections.EMPTY_SET;
checkConstraints(features, tmpStatus);
if (tmpStatus.size() == 0) // the whole "batch" is OK
return Collections.EMPTY_SET;
// pass 2: we have conflicts
features = savedFeatures;
for (int i = 0; i < jobs.length; i++) {
IInstallFeatureOperation job = jobs[i];
IFeature newFeature = job.getFeature();
IFeature oldFeature = job.getOldFeature();
features =
computeFeaturesAfterOperation(
features,
newFeature,
oldFeature);
Set result = checkConstraints(features, status);
if (status.size() > 0
&& !isBetterStatus(beforeStatus, status)) {
// bug 75613
// IStatus conflict =
// createStatus(
// newFeature,
// FeatureStatus.CODE_OTHER,
// Policy.bind(KEY_CONFLICT));
// status.add(0, conflict);
return result;
}
}
} catch (CoreException e) {
status.add(e.getStatus());
}
return Collections.EMPTY_SET;
}
private static void checkPlatformWasModified(ArrayList status) {
try {
// checks if the platform has been modified outside this eclipse instance
IPlatformConfiguration platformConfig = ConfiguratorUtils.getCurrentPlatformConfiguration();
long currentTimeStamp = platformConfig.getChangeStamp();
// get the last modified value for this config, from this process point of view
if (platformConfig instanceof PlatformConfiguration)
currentTimeStamp = ((PlatformConfiguration)platformConfig).getConfiguration().lastModified();
// get the real last modified value
URL platformXML = platformConfig.getConfigurationLocation();
long actualTimeStamp = currentTimeStamp;
if ("file".equals(platformXML.getProtocol())) //$NON-NLS-1$
actualTimeStamp = new File(platformXML.getFile()).lastModified();
else {
URLConnection connection = platformXML.openConnection();
actualTimeStamp = connection.getLastModified();
}
if (currentTimeStamp != actualTimeStamp)
status.add(createStatus(
null,
FeatureStatus.CODE_OTHER,
Messages.ActivityConstraints_platformModified));
} catch (IOException e) {
// ignore
}
}
private static void checkSiteReadOnly(IFeature feature, ArrayList status) {
if(feature == null){
return;
}
IConfiguredSite csite = feature.getSite().getCurrentConfiguredSite();
if (csite != null && !csite.isUpdatable())
status.add(createStatus(feature, FeatureStatus.CODE_OTHER,
NLS.bind(Messages.ActivityConstraints_readOnly, (new String[] { csite.getSite().getURL().toExternalForm() }))));
}
/*
* Compute a list of configured features
*/
private static ArrayList computeFeatures() throws CoreException {
return computeFeatures(true);
}
/*
* Compute a list of configured features
*/
private static ArrayList computeFeatures(boolean configuredOnly)
throws CoreException {
ArrayList features = new ArrayList();
ILocalSite localSite = SiteManager.getLocalSite();
IInstallConfiguration config = localSite.getCurrentConfiguration();
IConfiguredSite[] csites = config.getConfiguredSites();
for (int i = 0; i < csites.length; i++) {
IConfiguredSite csite = csites[i];
IFeatureReference[] crefs;
if (configuredOnly)
crefs = csite.getConfiguredFeatures();
else
crefs = csite.getSite().getFeatureReferences();
for (int j = 0; j < crefs.length; j++) {
IFeatureReference cref = crefs[j];
IFeature cfeature = cref.getFeature(null);
features.add(cfeature);
}
}
return features;
}
/*
* Compute the nested feature subtree starting at the specified base
* feature
*/
public static ArrayList computeFeatureSubtree(
IFeature top,
IFeature feature,
ArrayList features,
boolean tolerateMissingChildren,
ArrayList configuredFeatures,
ArrayList visitedFeatures)
throws CoreException {
// check arguments
if (top == null)
return features;
if (feature == null)
feature = top;
if (features == null)
features = new ArrayList();
if (visitedFeatures == null)
visitedFeatures = new ArrayList();
// check for <includes> cycle
if (visitedFeatures.contains(feature)) {
IStatus status =
createStatus(top, FeatureStatus.CODE_CYCLE, Messages.ActivityConstraints_cycle);
throw new CoreException(status);
} else {
// keep track of visited features so we can detect cycles
visitedFeatures.add(feature);
}
// return specified base feature and all its children
if (!features.contains(feature))
features.add(feature);
IIncludedFeatureReference[] children =
feature.getIncludedFeatureReferences();
for (int i = 0; i < children.length; i++) {
try {
IFeature child = UpdateUtils.getIncludedFeature(feature, children[i]);
features =
computeFeatureSubtree(
top,
child,
features,
tolerateMissingChildren,
null,
visitedFeatures);
} catch (CoreException e) {
if (!children[i].isOptional() && !tolerateMissingChildren)
throw e;
}
}
// no cycles for this feature during DFS
visitedFeatures.remove(feature);
return features;
}
private static void checkLicense(IFeature feature, ArrayList status) {
IURLEntry licenseEntry = feature.getLicense();
if (licenseEntry != null) {
String license = licenseEntry.getAnnotation();
if (license != null && license.trim().length() > 0)
return;
}
status.add(
createStatus(feature, FeatureStatus.CODE_OTHER, Messages.ActivityConstraints_noLicense));
}
/*
* Compute a list of features that will be configured after the operation
*/
private static ArrayList computeFeaturesAfterOperation(
ArrayList features,
IFeature add,
IFeature remove)
throws CoreException {
ArrayList addTree = computeFeatureSubtree(add, null, null, false,
/* do not tolerate missing children */
features, null);
ArrayList removeTree =
computeFeatureSubtree(
remove,
null,
null,
true /* tolerate missing children */,
null,
null
);
if (remove != null) {
// Patches to features are removed together with
// those features. Include them in the list.
contributePatchesFor(removeTree, features, removeTree);
}
if (remove != null)
features.removeAll(removeTree);
if (add != null)
features.addAll(addTree);
return features;
}
private static void contributePatchesFor(
ArrayList removeTree,
ArrayList features,
ArrayList result)
throws CoreException {
for (int i = 0; i < removeTree.size(); i++) {
IFeature feature = (IFeature) removeTree.get(i);
contributePatchesFor(feature, features, result);
}
}
private static void contributePatchesFor(
IFeature feature,
ArrayList features,
ArrayList result)
throws CoreException {
for (int i = 0; i < features.size(); i++) {
IFeature candidate = (IFeature) features.get(i);
if (UpdateUtils.isPatch(feature, candidate)) {
ArrayList removeTree =
computeFeatureSubtree(candidate, null, null, true,null,null);
result.addAll(removeTree);
}
}
}
/*
* Compute a list of features that will be configured after performing the
* revert
*/
private static ArrayList computeFeaturesAfterRevert(IInstallConfiguration config)
throws CoreException {
ArrayList list = new ArrayList();
IConfiguredSite[] csites = config.getConfiguredSites();
for (int i = 0; i < csites.length; i++) {
IConfiguredSite csite = csites[i];
IFeatureReference[] features = csite.getConfiguredFeatures();
for (int j = 0; j < features.length; j++) {
list.add(features[j].getFeature(null));
}
}
return list;
}
/*
* Compute a list of plugin entries for the specified features.
*/
private static ArrayList computePluginsForFeatures(ArrayList features)
throws CoreException {
if (features == null)
return new ArrayList();
HashMap plugins = new HashMap();
for (int i = 0; i < features.size(); i++) {
IFeature feature = (IFeature) features.get(i);
IPluginEntry[] entries = feature.getPluginEntries();
for (int j = 0; j < entries.length; j++) {
IPluginEntry entry = entries[j];
plugins.put(entry.getVersionedIdentifier(), entry);
}
}
ArrayList result = new ArrayList();
result.addAll(plugins.values());
return result;
}
/**
* Check for feature cycles:
* - visit feature
* - if feature is in the cycle candidates list, then cycle found, else add it to candidates list
* - DFS children
* - when return from DFS remove the feature from the candidates list
*/
private static void checkForCycles(
IFeature feature,
ArrayList candidates,
ArrayList configuredFeatures)
throws CoreException {
// check arguments
if (feature == null)
return;
if (configuredFeatures == null)
configuredFeatures = new ArrayList();
if (candidates == null)
candidates = new ArrayList();
// check for <includes> cycle
if (candidates.contains(feature)) {
String msg = NLS.bind(Messages.ActivityConstraints_cycle, (new String[] {feature.getLabel(),
feature.getVersionedIdentifier().toString()}));
IStatus status = createStatus(feature, FeatureStatus.CODE_CYCLE, msg);
throw new CoreException(status);
}
// potential candidate
candidates.add(feature);
// recursively, check cycles with children
IIncludedFeatureReference[] children =
feature.getIncludedFeatureReferences();
for (int i = 0; i < children.length; i++) {
try {
IFeature child = UpdateUtils.getIncludedFeature(feature, children[i]);
checkForCycles(child, candidates, configuredFeatures);
} catch (CoreException e) {
if (!children[i].isOptional())
throw e;
}
}
// no longer a candidate, because no cycles with children
candidates.remove(feature);
}
/*
* validate constraints
*/
private static Set checkConstraints(ArrayList features, ArrayList status)
throws CoreException {
if (features == null)
return Collections.EMPTY_SET;
ArrayList plugins = computePluginsForFeatures(features);
checkEnvironment(features, status);
checkPlatformFeature(features, plugins, status);
checkPrimaryFeature(features, plugins, status);
return checkPrereqs(features, plugins, status);
}
/*
* Verify all features are either portable, or match the current
* environment
*/
private static void checkEnvironment(
ArrayList features,
ArrayList status) {
String os = Platform.getOS();
String ws = Platform.getWS();
String arch = Platform.getOSArch();
for (int i = 0; i < features.size(); i++) {
IFeature feature = (IFeature) features.get(i);
ArrayList fos = createList(feature.getOS());
ArrayList fws = createList(feature.getWS());
ArrayList farch = createList(feature.getOSArch());
if (fos.size() > 0) {
if (!fos.contains(os)) {
IStatus s =
createStatus(feature, FeatureStatus.CODE_ENVIRONMENT, Messages.ActivityConstraints_os);
if (!status.contains(s))
status.add(s);
continue;
}
}
if (fws.size() > 0) {
if (!fws.contains(ws)) {
IStatus s =
createStatus(feature, FeatureStatus.CODE_ENVIRONMENT, Messages.ActivityConstraints_ws);
if (!status.contains(s))
status.add(s);
continue;
}
}
if (farch.size() > 0) {
if (!farch.contains(arch)) {
IStatus s =
createStatus(feature, FeatureStatus.CODE_ENVIRONMENT, Messages.ActivityConstraints_arch);
if (!status.contains(s))
status.add(s);
continue;
}
}
}
}
/*
* Verify we end up with a version of platform configured
*/
private static void checkPlatformFeature(
ArrayList features,
ArrayList plugins,
ArrayList status) {
// find the plugin that defines the product
IProduct product = Platform.getProduct();
if (product == null)
return; // normally this shouldn't happen
Bundle primaryBundle = product.getDefiningBundle();
// check if that plugin is among the resulting plugins
boolean found = false;
for (int j = 0; j < plugins.size(); j++) {
IPluginEntry plugin = (IPluginEntry) plugins.get(j);
if (primaryBundle.getSymbolicName().equals(plugin.getVersionedIdentifier().getIdentifier())) {
found = true;
break;
}
}
if (!found) {
IStatus s =
createStatus(null, FeatureStatus.CODE_OTHER, Messages.ActivityConstraints_platform);
if (!status.contains(s))
status.add(s);
}
}
/*
* Verify we end up with a version of primary feature configured
*/
private static void checkPrimaryFeature(
ArrayList features,
ArrayList plugins,
ArrayList status) {
String featureId =
ConfiguratorUtils
.getCurrentPlatformConfiguration()
.getPrimaryFeatureIdentifier();
if (featureId != null) {
// primary feature is defined
for (int i = 0; i < features.size(); i++) {
IFeature feature = (IFeature) features.get(i);
if (featureId
.equals(feature.getVersionedIdentifier().getIdentifier()))
return;
}
IStatus s = createStatus(null, FeatureStatus.CODE_OTHER, Messages.ActivityConstraints_primary);
if (!status.contains(s))
status.add(s);
} else {
// check if the product still ends up contributed
// find the plugin that defines the product
IProduct product = Platform.getProduct();
if (product == null)
return; // normally this shouldn't happen
Bundle primaryBundle = product.getDefiningBundle();
// check if that plugin is among the resulting plugins
for (int j = 0; j < plugins.size(); j++) {
IPluginEntry plugin = (IPluginEntry) plugins.get(j);
if (primaryBundle.getSymbolicName().equals(plugin.getVersionedIdentifier().getIdentifier())) {
return; // product found
}
}
IStatus s =
createStatus(null, FeatureStatus.CODE_OTHER, Messages.ActivityConstraints_primary);
if (!status.contains(s))
status.add(s);
}
}
/*
* Verify we do not break prereqs
*/
private static Set checkPrereqs(
ArrayList features,
ArrayList plugins,
ArrayList status) {
HashSet result = new HashSet();
for (int i = 0; i < features.size(); i++) {
IFeature feature = (IFeature) features.get(i);
IImport[] imports = feature.getImports();
for (int j = 0; j < imports.length; j++) {
IImport iimport = imports[j];
// for each import determine plugin or feature, version, match
// we need
VersionedIdentifier iid = iimport.getVersionedIdentifier();
String id = iid.getIdentifier();
PluginVersionIdentifier version = iid.getVersion();
boolean featurePrereq =
iimport.getKind() == IImport.KIND_FEATURE;
boolean ignoreVersion =
version.getMajorComponent() == 0
&& version.getMinorComponent() == 0
&& version.getServiceComponent() == 0;
int rule = iimport.getRule();
if (rule == IUpdateConstants.RULE_NONE)
rule = IUpdateConstants.RULE_COMPATIBLE;
boolean found = false;
ArrayList candidates;
if (featurePrereq)
candidates = features;
else
candidates = plugins;
for (int k = 0; k < candidates.size(); k++) {
VersionedIdentifier cid;
if (featurePrereq) {
// the candidate is a feature
IFeature candidate = (IFeature) candidates.get(k);
// skip self
if (feature.equals(candidate))
continue;
cid = candidate.getVersionedIdentifier();
} else {
// the candidate is a plug-in
IPluginEntry plugin = (IPluginEntry) candidates.get(k);
cid = plugin.getVersionedIdentifier();
}
PluginVersionIdentifier cversion = cid.getVersion();
if (id.equals(cid.getIdentifier())) {
// have a candidate
if (ignoreVersion)
found = true;
else if (
rule == IUpdateConstants.RULE_PERFECT
&& cversion.isPerfect(version))
found = true;
else if (
rule == IUpdateConstants.RULE_EQUIVALENT
&& cversion.isEquivalentTo(version))
found = true;
else if (
rule == IUpdateConstants.RULE_COMPATIBLE
&& cversion.isCompatibleWith(version))
found = true;
else if (
rule == IUpdateConstants.RULE_GREATER_OR_EQUAL
&& cversion.isGreaterOrEqualTo(version))
found = true;
}
if (found)
break;
}
// perhaps the bundle that we are looking for was installed
// but isn't a part of a feature
if (!found && !featurePrereq)
found = isInstalled(iid, rule, ignoreVersion);
if (!found) {
// report status
String target =
featurePrereq
? Messages.ActivityConstaints_prereq_feature
: Messages.ActivityConstaints_prereq_plugin;
int errorCode = featurePrereq
? FeatureStatus.CODE_PREREQ_FEATURE
: FeatureStatus.CODE_PREREQ_PLUGIN;
String msg =
NLS.bind(Messages.ActivityConstraints_prereq, (new String[] { target, id }));
if (!ignoreVersion) {
if (rule == IUpdateConstants.RULE_PERFECT)
msg =
NLS.bind(Messages.ActivityConstraints_prereqPerfect, (new String[] {
target,
id,
version.toString()}));
else if (rule == IUpdateConstants.RULE_EQUIVALENT)
msg =
NLS.bind(Messages.ActivityConstraints_prereqEquivalent, (new String[] {
target,
id,
version.toString()}));
else if (rule == IUpdateConstants.RULE_COMPATIBLE)
msg =
NLS.bind(Messages.ActivityConstraints_prereqCompatible, (new String[] {
target,
id,
version.toString()}));
else if (rule == IUpdateConstants.RULE_GREATER_OR_EQUAL)
msg =
NLS.bind(Messages.ActivityConstraints_prereqGreaterOrEqual, (new String[] {
target,
id,
version.toString()}));
}
IStatus s = createStatus(feature, errorCode, msg);
result.add(new InternalImport(iimport));
if (!status.contains(s))
status.add(s);
}
}
}
return result;
}
/*
* Return a boolean value indicating whether or not the bundle with the given id and version
* is installed in the system.
*/
private static boolean isInstalled(VersionedIdentifier vid, int rule, boolean ignoreVersion) {
BundleContext context = UpdateCore.getPlugin().getBundleContext();
if (context == null)
return false;
ServiceReference reference = context.getServiceReference(PlatformAdmin.class.getName());
if (reference == null)
return false;
PlatformAdmin admin = (PlatformAdmin) context.getService(reference);
try {
State state = admin.getState(false);
String id = vid.getIdentifier();
PluginVersionIdentifier version = vid.getVersion();
BundleDescription[] bundles = state.getBundles(id);
if (bundles == null || bundles.length == 0)
return false;
for (int i=0; i<bundles.length; i++) {
BundleDescription bundle = bundles[i];
PluginVersionIdentifier cversion = new PluginVersionIdentifier(bundle.getVersion().toString());
// have a candidate
if (ignoreVersion)
return true;
if (rule == IUpdateConstants.RULE_PERFECT && cversion.isPerfect(version))
return true;
else if (rule == IUpdateConstants.RULE_EQUIVALENT && cversion.isEquivalentTo(version))
return true;
else if (rule == IUpdateConstants.RULE_COMPATIBLE && cversion.isCompatibleWith(version))
return true;
else if (rule == IUpdateConstants.RULE_GREATER_OR_EQUAL && cversion.isGreaterOrEqualTo(version))
return true;
}
return false;
} finally {
context.ungetService(reference);
}
}
/*
* Verify we end up with valid nested features after revert
*/
private static void checkRevertConstraints(
ArrayList features,
ArrayList status) {
for (int i = 0; i < features.size(); i++) {
IFeature feature = (IFeature) features.get(i);
try {
computeFeatureSubtree(
feature,
null,
null,
false /* do not tolerate missing children */,
null,
null
);
} catch (CoreException e) {
status.add(e.getStatus());
}
}
}
/*
* Verify that a parent of an optional child is configured before we allow
* the child to be configured as well
*/
private static void checkOptionalChildConfiguring(
IFeature feature,
ArrayList status)
throws CoreException {
ILocalSite localSite = SiteManager.getLocalSite();
IInstallConfiguration config = localSite.getCurrentConfiguration();
IConfiguredSite[] csites = config.getConfiguredSites();
boolean included = false;
for (int i = 0; i < csites.length; i++) {
IConfiguredSite csite = csites[i];
ISiteFeatureReference[] crefs =
csite.getSite().getFeatureReferences();
for (int j = 0; j < crefs.length; j++) {
IFeatureReference cref = crefs[j];
IFeature cfeature = null;
try {
cfeature = cref.getFeature(null);
} catch (CoreException e) {
//FIXME: cannot ask 'isOptional' here
// Ignore missing optional feature.
/*
* if (cref.isOptional()) continue;
*/
throw e;
}
if (isParent(cfeature, feature, true)) {
// Included in at least one feature as optional
included = true;
if (csite.isConfigured(cfeature)) {
// At least one feature parent
// is enabled - it is OK to
// configure optional child.
return;
}
}
}
}
if (included) {
// feature is included as optional but
// no parent is currently configured.
String msg = Messages.ActivityConstraints_optionalChild;
status.add(createStatus(feature, FeatureStatus.CODE_OPTIONAL_CHILD, msg));
} else {
//feature is root - can be configured
}
}
//
// /**
// * Checks if the configuration is locked by other instances
// *
// * @param status
// */
// private static void checkConfigurationLock(ArrayList status) {
// IPlatformConfiguration config =
// BootLoader.getCurrentPlatformConfiguration();
// URL configURL = config.getConfigurationLocation();
// if (!"file".equals(configURL.getProtocol())) {
// status.add(
// createStatus(
// null,
// "Configuration location is not writable:" + configURL));
// return;
// }
// String locationString = configURL.getFile();
// File configDir = new File(locationString);
// if (!configDir.isDirectory())
// configDir = configDir.getParentFile();
// if (!configDir.exists()) {
// status.add(
// createStatus(null, "Configuration location does not exist"));
// return;
// }
// File locksDir = new File(configDir, "locks");
// // check all the possible lock files
// File[] lockFiles = locksDir.listFiles();
// File configLock = BootLoader.getCurrentPlatformConfiguration().getLockFile();
// for (int i = 0; i < lockFiles.length; i++) {
// if (lockFiles[i].equals(configLock))
// continue;
// try {
// RandomAccessFile raf = new RandomAccessFile(lockFiles[i], "rw");
// FileChannel channel = raf.getChannel();
// System.out.println(channel.isOpen());
// FileLock lock = channel.tryLock();
// if (lock == null){
// // there is another eclipse instance running
// raf.close();
// status.add(
// createStatus(
// null,
// "Another instance is running, please close it before performing any configuration operations"));
// return;
// }
//
// } catch (Exception e) {
// status.add(createStatus(null, "Failed to create lock:"+lockFiles[i]));
// return;
// }
// }
// }
private static boolean isParent(
IFeature candidate,
IFeature feature,
boolean optionalOnly)
throws CoreException {
IIncludedFeatureReference[] refs =
candidate.getIncludedFeatureReferences();
for (int i = 0; i < refs.length; i++) {
IIncludedFeatureReference child = refs[i];
VersionedIdentifier fvid = feature.getVersionedIdentifier();
VersionedIdentifier cvid = child.getVersionedIdentifier();
if (fvid.getIdentifier().equals(cvid.getIdentifier()) == false)
continue;
// same ID
PluginVersionIdentifier fversion = fvid.getVersion();
PluginVersionIdentifier cversion = cvid.getVersion();
if (fversion.equals(cversion)) {
// included and matched; return true if optionality is not
// important or it is and the inclusion is optional
return optionalOnly == false || child.isOptional();
}
}
return false;
}
// private static boolean checkTimeline(
// IInstallConfiguration config,
// ArrayList status) {
// try {
// ILocalSite lsite = SiteManager.getLocalSite();
// IInstallConfiguration cconfig = lsite.getCurrentConfiguration();
// if (cconfig.getTimeline() != config.getTimeline()) {
// // Not the same timeline - cannot revert
// String msg =
// UpdateUtils.getFormattedMessage(
// KEY_WRONG_TIMELINE,
// config.getLabel());
// status.add(createStatus(null, FeatureStatus.CODE_OTHER, msg));
// return false;
// }
// } catch (CoreException e) {
// status.add(e.getStatus());
// }
// return true;
// }
private static IStatus createMultiStatus(
String message,
ArrayList children,
int code) {
IStatus[] carray =
(IStatus[]) children.toArray(new IStatus[children.size()]);
return new MultiStatus(
UpdateCore.getPlugin().getBundle().getSymbolicName(),
code,
carray,
message,
null);
}
private static IStatus createStatus(IFeature feature, int errorCode, String message) {
String fullMessage;
if (feature == null)
fullMessage = message;
else {
PluginVersionIdentifier version =
feature.getVersionedIdentifier().getVersion();
fullMessage =
NLS.bind(Messages.ActivityConstraints_childMessage, (new String[] {
feature.getLabel(),
version.toString(),
message }));
}
return new FeatureStatus(
feature,
IStatus.ERROR,
UpdateCore.getPlugin().getBundle().getSymbolicName(),
errorCode,
fullMessage,
null);
}
// private static IStatus createReportStatus(ArrayList beforeStatus,
// ArrayList status) {
// // report status
// if (status.size() > 0) {
// if (beforeStatus.size() > 0)
// return createMultiStatus(KEY_ROOT_MESSAGE_INIT,
// beforeStatus,IStatus.ERROR);
// else
// return createMultiStatus(KEY_ROOT_MESSAGE, status,IStatus.ERROR);
// }
// return null;
// }
private static IStatus createCombinedReportStatus(
ArrayList beforeStatus,
ArrayList status) {
if (beforeStatus.size() == 0) { // good initial config
if (status.size() == 0) {
return null; // all fine
} else {
return createMultiStatus(Messages.ActivityConstraints_rootMessage,
status,
IStatus.ERROR);
// error after operation
}
} else { // beforeStatus.size() > 0 : initial config errors
if (status.size() == 0) {
return null; // errors will be fixed
} else {
if (isBetterStatus(beforeStatus, status)) {
return createMultiStatus(
Messages.ActivityConstraints_warning,
beforeStatus,
IStatus.WARNING);
// errors may be fixed
} else {
ArrayList combined = new ArrayList();
combined.add(
createMultiStatus(
Messages.ActivityConstraints_beforeMessage,
beforeStatus,
IStatus.ERROR));
combined.add(
createMultiStatus(
Messages.ActivityConstraints_afterMessage,
status,
IStatus.ERROR));
return createMultiStatus(
Messages.ActivityConstraints_rootMessageInitial,
combined,
IStatus.ERROR);
}
}
}
}
private static ArrayList createList(String commaSeparatedList) {
ArrayList list = new ArrayList();
if (commaSeparatedList != null) {
StringTokenizer t =
new StringTokenizer(commaSeparatedList.trim(), ","); //$NON-NLS-1$
while (t.hasMoreTokens()) {
String token = t.nextToken().trim();
if (!token.equals("")) //$NON-NLS-1$
list.add(token);
}
}
return list;
}
/**
* Returns true if status is a subset of beforeStatus
*
* @param beforeStatus
* @param status
* @return
*/
private static boolean isBetterStatus(
ArrayList beforeStatus,
ArrayList status) {
// if no status at all, then it's a subset
if (status == null || status.size() == 0)
return true;
// there is some status, so if there is no initial status, then it's
// not a subset
if (beforeStatus == null || beforeStatus.size() == 0)
return false;
// quick check
if (beforeStatus.size() < status.size())
return false;
// check if all the status elements appear in the original status
for (int i = 0; i < status.size(); i++) {
IStatus s = (IStatus) status.get(i);
// if this is not a feature status, something is wrong, so return
// false
if (!(s instanceof FeatureStatus))
return false;
FeatureStatus fs = (FeatureStatus) s;
// check against all status elements
boolean found = false;
for (int j = 0; !found && j < beforeStatus.size(); j++) {
if (fs.equals(beforeStatus.get(j)))
found = true;
}
if (!found)
return false;
}
return true;
}
public class RequiredFeaturesResult {
private IStatus status;
private Set requiredFeatures;
public Set getRequiredFeatures() {
return requiredFeatures;
}
public void setRequiredFeatures(Set requiredFeatures) {
this.requiredFeatures = requiredFeatures;
}
public void addRequiredFeatures(Set requiredFeatures) {
if (requiredFeatures == null) {
requiredFeatures = new HashSet();
}
this.requiredFeatures.addAll(requiredFeatures);
}
public IStatus getStatus() {
return status;
}
public void setStatus(IStatus status) {
this.status = status;
}
}
public static class InternalImport {
private IImport iimport;
public InternalImport(IImport iimport) {
this.iimport = iimport;
}
public IImport getImport() {
return iimport;
}
public void setImport(IImport iimport) {
this.iimport = iimport;
}
public boolean equals(Object object) {
if ( ( object == null) || !(object instanceof InternalImport))
return false;
if ( object == this)
return true;
return iimport.getVersionedIdentifier().equals( ((InternalImport)object).getImport().getVersionedIdentifier()) && (getImport().getRule() == ((InternalImport)object).getImport().getRule());
}
public int hashCode() {
return iimport.getVersionedIdentifier().hashCode() * iimport.getRule();
}
}
}