blob: 6914a0a91d4df282d0eb74f8b988072535ade0d4 [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
* James D Miles (IBM Corp.) - bug 191368, Policy URL doesn't support UTF-8 characters
*******************************************************************************/
package org.eclipse.update.internal.operations;
import java.lang.reflect.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Vector;
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.core.*;
import org.eclipse.update.internal.core.URLEncoder;
import org.eclipse.update.internal.search.*;
import org.eclipse.update.operations.*;
import org.eclipse.update.search.*;
/**
* Helper class for performing update related tasks, queries, etc.
* All the methods are static and this class should be a singleton.
*/
public class UpdateUtils {
public static final String P_UPDATE_POLICY_URL = "updatePolicyURL"; //$NON-NLS-1$
/**
* Private constructor
*/
private UpdateUtils() {
}
public static String getPluginId() {
return UpdateCore.getPlugin().getBundle().getSymbolicName();
}
public static void logException(Throwable e) {
if (e instanceof InvocationTargetException) {
e = ((InvocationTargetException) e).getTargetException();
}
IStatus status = null;
if (e instanceof CoreException) {
status = ((CoreException) e).getStatus();
} else {
String message = e.getMessage();
if (message == null)
message = e.toString();
status = new Status(IStatus.ERROR, getPluginId(), IStatus.OK, message, e);
}
log(status);
}
public static void log(IStatus status) {
if (status.getSeverity() != IStatus.INFO) {
UpdateCore.getPlugin().getLog().log(status);
}
}
public static IFeature[] searchSite(String featureId, IConfiguredSite site, boolean onlyConfigured) throws CoreException {
IFeatureReference[] references = null;
if (onlyConfigured)
references = site.getConfiguredFeatures();
else
references = site.getSite().getFeatureReferences();
Vector result = new Vector();
for (int i = 0; i < references.length; i++) {
IFeature feature = references[i].getFeature(null);
String id = feature.getVersionedIdentifier().getIdentifier();
if (featureId.equals(id)) {
result.add(feature);
}
}
return (IFeature[]) result.toArray(new IFeature[result.size()]);
}
public static IFeature[] getInstalledFeatures(IFeature feature) {
return getInstalledFeatures(feature, true);
}
/**
*
* @param feature
* @param onlyConfigured
* @return IFeature[] with features matching feature ID
*/
public static IFeature[] getInstalledFeatures(IFeature feature, boolean onlyConfigured) {
return getInstalledFeatures(feature.getVersionedIdentifier(), onlyConfigured);
}
/**
* @param vid
* @param onlyConfigured
* @return IFeature[] with features matching feature ID
*/
public static IFeature[] getInstalledFeatures(VersionedIdentifier vid, boolean onlyConfigured) {
Vector features = new Vector();
try {
ILocalSite localSite = SiteManager.getLocalSite();
IInstallConfiguration config = localSite.getCurrentConfiguration();
IConfiguredSite[] isites = config.getConfiguredSites();
String id = vid.getIdentifier();
for (int i = 0; i < isites.length; i++) {
IConfiguredSite isite = isites[i];
IFeature[] result = UpdateUtils.searchSite(id, isite, onlyConfigured);
for (int j = 0; j < result.length; j++) {
IFeature installedFeature = result[j];
features.add(installedFeature);
}
}
} catch (CoreException e) {
UpdateUtils.logException(e);
}
return (IFeature[]) features.toArray(new IFeature[features.size()]);
}
/**
* @param patch
* @return IFeature or null
*/
public static IFeature getPatchedFeature(IFeature patch) {
IImport[] imports = patch.getImports();
for (int i = 0; i < imports.length; i++) {
IImport iimport = imports[i];
if (iimport.isPatch()) {
VersionedIdentifier patchedVid = iimport
.getVersionedIdentifier();
// features with matching id
IFeature[] features = getInstalledFeatures(patchedVid, false);
for (int f = 0; f < features.length; f++) {
// check if version match
if (patchedVid.equals(features[f].getVersionedIdentifier())) {
return features[f];
}
}
}
}
return null;
}
public static boolean isPatch(IFeature candidate) {
IImport[] imports = candidate.getImports();
for (int i = 0; i < imports.length; i++) {
IImport iimport = imports[i];
if (iimport.isPatch()) return true;
}
return false;
}
public static boolean isPatch(IFeature target, IFeature candidate) {
VersionedIdentifier vid = target.getVersionedIdentifier();
IImport[] imports = candidate.getImports();
for (int i = 0; i < imports.length; i++) {
IImport iimport = imports[i];
if (iimport.isPatch()) {
VersionedIdentifier ivid = iimport.getVersionedIdentifier();
if (vid.equals(ivid)) {
// Bingo.
return true;
}
}
}
return false;
}
public static IInstallConfiguration getBackupConfigurationFor(IFeature feature) {
VersionedIdentifier vid = feature.getVersionedIdentifier();
String key = "@" + vid.getIdentifier() + "_" + vid.getVersion(); //$NON-NLS-1$ //$NON-NLS-2$
try {
ILocalSite lsite = SiteManager.getLocalSite();
IInstallConfiguration[] configs = lsite.getPreservedConfigurations();
for (int i = 0; i < configs.length; i++) {
IInstallConfiguration config = configs[i];
if (config.getLabel().startsWith(key))
return config;
}
} catch (CoreException e) {
}
return null;
}
public static boolean hasLicense(IFeature feature) {
IURLEntry info = feature.getLicense();
if (info == null)
return false;
String licenseTxt = info.getAnnotation();
if (licenseTxt == null)
return false;
return licenseTxt.trim().length() > 0;
}
public static boolean hasOptionalFeatures(IFeature feature) {
try {
IIncludedFeatureReference[] irefs = feature.getIncludedFeatureReferences();
for (int i = 0; i < irefs.length; i++) {
IIncludedFeatureReference iref = irefs[i];
if (iref.isOptional())
return true;
// see if it has optional children
IFeature child = getIncludedFeature( feature, iref);
if (hasOptionalFeatures(child))
return true;
}
} catch (CoreException e) {
}
return false;
}
public static IFeature getLocalFeature(
IConfiguredSite csite,
IFeature feature)
throws CoreException {
IFeatureReference[] refs = csite.getConfiguredFeatures();
for (int i = 0; i < refs.length; i++) {
IFeatureReference ref = refs[i];
VersionedIdentifier refVid = ref.getVersionedIdentifier();
if (feature.getVersionedIdentifier().equals(refVid))
return ref.getFeature(null);
}
return null;
}
public static IConfiguredSite getConfigSite(
IFeature feature,
IInstallConfiguration config)
throws CoreException {
IConfiguredSite[] configSites = config.getConfiguredSites();
for (int i = 0; i < configSites.length; i++) {
IConfiguredSite site = configSites[i];
if (site.getSite().equals(feature.getSite())) {
return site;
}
}
return null;
}
public static IConfiguredSite getDefaultTargetSite(
IInstallConfiguration config,
IInstallFeatureOperation pendingChange) {
return getDefaultTargetSite(config, pendingChange, true);
}
public static IConfiguredSite getDefaultTargetSite(
IInstallConfiguration config,
IInstallFeatureOperation pendingChange,
boolean checkAffinityFeature) {
IFeature oldFeature = pendingChange.getOldFeature();
IFeature newFeature = pendingChange.getFeature();
if (oldFeature != null) {
// We should install into the same site as
// the old feature
try {
return getConfigSite(oldFeature, config);
} catch (CoreException e) {
logException(e);
return null;
}
}
// This is a new install. Check if there is
// a disabled feature with the same ID
String newFeatureID =
newFeature.getVersionedIdentifier().getIdentifier();
IConfiguredSite sameSite = getSiteWithFeature(config, newFeatureID);
if (sameSite != null) {
return sameSite;
}
if (checkAffinityFeature) {
return getAffinitySite(config, newFeature);
}
return null;
}
public static IConfiguredSite getAffinitySite(
IInstallConfiguration config,
IFeature newFeature) {
// check if the affinity feature is installed
String affinityID = newFeature.getAffinityFeature();
if (affinityID != null) {
IConfiguredSite affinitySite =
getSiteWithFeature(config, affinityID);
if (affinitySite != null)
return affinitySite;
} else {
// if this is a patch, collocate with the feature
IFeature patchedFeature = getPatchedFeature(newFeature);
if (patchedFeature != null)
return getSiteWithFeature(config, patchedFeature.getVersionedIdentifier().getIdentifier());
}
return null;
}
public static IConfiguredSite getSiteWithFeature(
IInstallConfiguration config,
String featureID) {
if (featureID == null)
return null;
IConfiguredSite[] sites = config.getConfiguredSites();
for (int i = 0; i < sites.length; i++) {
IConfiguredSite site = sites[i];
IFeatureReference[] refs = site.getFeatureReferences();
for (int j = 0; j < refs.length; j++) {
IFeatureReference ref = refs[j];
try {
IFeature feature = ref.getFeature(null);
if (featureID
.equals(
feature
.getVersionedIdentifier()
.getIdentifier())) {
// found it
return site;
}
} catch (CoreException e) {
logException(e);
}
}
}
return null;
}
public static void collectOldFeatures(
IFeature feature,
IConfiguredSite targetSite,
ArrayList result)
throws CoreException {
IIncludedFeatureReference[] included =
feature.getIncludedFeatureReferences();
for (int i = 0; i < included.length; i++) {
IIncludedFeatureReference iref = included[i];
IFeature ifeature;
try {
ifeature = iref.getFeature(null);
} catch (CoreException e) {
if (iref.isOptional())
continue;
throw e;
}
// find other features and unconfigure
String id = iref.getVersionedIdentifier().getIdentifier();
IFeature[] sameIds = UpdateUtils.searchSite(id, targetSite, true);
for (int j = 0; j < sameIds.length; j++) {
IFeature sameId = sameIds[j];
// Ignore self.
if (sameId.equals(ifeature))
continue;
result.add(sameId);
}
collectOldFeatures(ifeature, targetSite, result);
}
}
//
// public static IInstallConfiguration createInstallConfiguration() throws CoreException{
// try {
// ILocalSite localSite = SiteManager.getLocalSite();
// IInstallConfiguration config =
// localSite.cloneCurrentConfiguration();
// config.setLabel(Utilities.format(config.getCreationDate()));
// return config;
// } catch (CoreException e) {
// // Let callers handle logging
// //logException(e);
// throw e;
// }
// }
public static UpdateSearchRequest createNewUpdatesRequest(IFeature [] features) {
return createNewUpdatesRequest(features, true);
}
public static UpdateSearchRequest createNewUpdatesRequest(IFeature [] features, boolean automatic) {
UpdateSearchScope scope = new UpdateSearchScope();
scope.setUpdateMapURL(UpdateUtils.getUpdateMapURL());
UpdatesSearchCategory category = new UpdatesSearchCategory(automatic);
if (features!=null)
category.setFeatures(features);
UpdateSearchRequest searchRequest = new UpdateSearchRequest(category, scope);
searchRequest.addFilter(new EnvironmentFilter());
searchRequest.addFilter(new BackLevelFilter());
return searchRequest;
}
public static boolean isNestedChild(IInstallConfiguration config, IFeature feature) {
IConfiguredSite[] csites = config.getConfiguredSites();
try {
for (int i = 0; csites != null && i < csites.length; i++) {
IFeatureReference[] refs = csites[i].getConfiguredFeatures();
for (int j = 0; refs != null && j < refs.length; j++) {
IFeature parent = refs[j].getFeature(null);
IFeatureReference[] children =
parent.getIncludedFeatureReferences();
for (int k = 0;
children != null && k < children.length;
k++) {
IFeature child = children[k].getFeature(null);
if (feature.equals(child))
return true;
}
}
}
} catch (CoreException e) {
// will return false
}
return false;
}
public static boolean hasObsoletePatches(IFeature feature) {
// Check all the included features that
// are unconfigured, and see if their patch
// references are better than the original.
try {
IFeatureReference[] irefs = feature.getIncludedFeatureReferences();
for (int i = 0; i < irefs.length; i++) {
IFeatureReference iref = irefs[i];
IFeature ifeature = iref.getFeature(null);
IConfiguredSite csite = ifeature.getSite().getCurrentConfiguredSite();
if (!csite.isConfigured(ifeature)) {
if (!isPatchHappy(ifeature))
return false;
}
}
} catch (CoreException e) {
return false;
}
// All checks went well
return true;
}
public static boolean isPatchHappy(IFeature feature) throws CoreException {
// If this is a patch and it includes
// another patch and the included patch
// is disabled but the feature it was declared
// to patch is now newer (and is presumed to
// contain the now disabled patch), and
// the newer patched feature is enabled,
// a 'leap of faith' assumption can be
// made:
// Although the included patch is disabled,
// the feature it was designed to patch
// is now newer and most likely contains
// the equivalent fix and more. Consequently,
// we can claim that the status and the error
// icon overlay are misleading because
// all the right plug-ins are configured.
IImport[] imports = feature.getImports();
IImport patchReference = null;
for (int i = 0; i < imports.length; i++) {
IImport iimport = imports[i];
if (iimport.isPatch()) {
patchReference = iimport;
break;
}
}
if (patchReference == null)
return false;
VersionedIdentifier refVid = patchReference.getVersionedIdentifier();
// Find the patched feature and
IConfiguredSite csite = feature.getSite().getCurrentConfiguredSite();
if (csite == null)
return false;
IFeatureReference[] crefs = csite.getConfiguredFeatures();
for (int i = 0; i < crefs.length; i++) {
IFeatureReference cref = crefs[i];
VersionedIdentifier cvid = cref.getVersionedIdentifier();
if (cvid.getIdentifier().equals(refVid.getIdentifier())) {
// This is the one.
if (cvid.getVersion().isGreaterThan(refVid.getVersion())) {
// Bingo: we found the referenced feature
// and its version is greater -
// we can assume that it contains better code
// than the patch that referenced the
// older version.
return true;
}
}
}
return false;
}
public static URL getUpdateMapURL() {
Preferences pref = UpdateCore.getPlugin().getPluginPreferences();
String mapFile = pref.getString(UpdateUtils.P_UPDATE_POLICY_URL);
if (mapFile!=null && mapFile.length()>0) {
try {
URL url = new URL(mapFile);
URL resolvedURL = URLEncoder.encode(url);
return resolvedURL;
}
catch (MalformedURLException e) {
UpdateUtils.logException(e);
}
}
return null;
}
/*
* Load the update map using the map URL found in the scope.
*/
public static IStatus loadUpdatePolicy(UpdatePolicy map, URL url, IProgressMonitor monitor) throws CoreException {
monitor.subTask(Messages.UpdateSearchRequest_loadingPolicy);
try {
map.load(url, monitor);
monitor.worked(1);
}
catch (CoreException e) {
IStatus status = e.getStatus();
if (status == null
|| status.getCode() != ISite.SITE_ACCESS_EXCEPTION)
throw e;
monitor.worked(1);
return status;
}
return null;
}
public static void downloadFeatureContent(
IConfiguredSite targetSite,
IFeature feature,
IFeatureReference[] optionalChildren, // null when feature has no optional features
IProgressMonitor progress)
throws InstallAbortedException, CoreException {
//DEBUG
if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL) {
UpdateCore.debug(
"Downloading...:" + feature.getURL().toExternalForm()); //$NON-NLS-1$
}
// Get source feature provider and verifier.
// Initialize target variables.
final IFeatureContentProvider provider =
feature.getFeatureContentProvider();
IPluginEntry[] targetSitePluginEntries = null;
// determine list of plugins to install
// find the intersection between the plugin entries already contained
// on the target site, and plugin entries packaged in source feature
IPluginEntry[] sourceFeaturePluginEntries = feature.getPluginEntries();
boolean featureAlreadyInstalled = false;
if (targetSite == null)
targetSite = getSiteWithFeature(SiteManager.getLocalSite()
.getCurrentConfiguration(), ((Feature) feature)
.getFeatureIdentifier());
if (targetSite == null) {
if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL) {
UpdateCore.debug("The site to install in is null"); //$NON-NLS-1$
}
targetSitePluginEntries = new IPluginEntry[0];
} else {
targetSitePluginEntries = targetSite.getSite().getPluginEntries();
featureAlreadyInstalled = UpdateUtils.getLocalFeature(targetSite,feature) != null;
}
IPluginEntry[] pluginsToInstall =
UpdateManagerUtils.diff(
sourceFeaturePluginEntries,
targetSitePluginEntries);
INonPluginEntry[] nonPluginsToInstall = feature.getNonPluginEntries();
IFeatureReference[] children = feature.getIncludedFeatureReferences();
if (optionalChildren != null) {
children =
UpdateManagerUtils.optionalChildrenToInstall(
children,
optionalChildren);
}
// make sure we have an InstallMonitor
InstallMonitor monitor;
if (progress == null)
monitor = new InstallMonitor(new NullProgressMonitor());
else if (progress instanceof InstallMonitor)
monitor = (InstallMonitor) progress;
else
monitor = new InstallMonitor(progress);
try {
// determine number of monitor tasks
// 1 task1 for the feature jar (download)
// + n tasks for plugin entries (download for each)
// + m tasks per non-plugin data entry (download for each)
// TODO custom install handler + 1 task for custom non-plugin entry handling (1 for all combined)
// + 3*x tasks for children features (3 subtasks per install)
int taskCount =
1
+ pluginsToInstall.length
+ nonPluginsToInstall.length
// + 1
+ 3 * children.length;
monitor.beginTask("", taskCount); //$NON-NLS-1$
// Download feature archive(s)
provider.getFeatureEntryArchiveReferences(monitor);
monitorWork(monitor,1);
// Download plugin archives
for (int i = 0; i < pluginsToInstall.length; i++) {
provider.getPluginEntryArchiveReferences(pluginsToInstall[i], monitor);
monitorWork(monitor,1);
}
// Download non-plugin archives. Verification handled by optional install handler
// Note: do not download non-plugin archives for installed features
if (nonPluginsToInstall.length > 0) {
// Setup optional install handler
InstallHandlerProxy handler = null;
if (feature.getInstallHandlerEntry()!=null)
handler = new InstallHandlerProxy(
IInstallHandler.HANDLER_ACTION_INSTALL,
feature,
feature.getInstallHandlerEntry(),
monitor);
if (!featureAlreadyInstalled)
for (int i = 0; i < nonPluginsToInstall.length; i++) {
if (handler==null || handler.acceptNonPluginData(nonPluginsToInstall[i]))
provider.getNonPluginEntryArchiveReferences(
nonPluginsToInstall[i], monitor);
monitorWork(monitor, 1);
}
else
monitorWork(monitor, nonPluginsToInstall.length);
}
// Download child features
for (int i = 0; i < children.length; i++) {
IFeature childFeature = null;
try {
childFeature = children[i].getFeature(null);
} catch (CoreException e) {
UpdateCore.warn(null, e);
}
if (childFeature != null) {
SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 3);
downloadFeatureContent(targetSite, childFeature, optionalChildren, subMonitor);
}
}
} finally {
if (monitor != null)
monitor.done();
}
}
private static void monitorWork(IProgressMonitor monitor, int tick)
throws CoreException {
if (monitor != null) {
monitor.worked(tick);
if (monitor.isCanceled()) {
String msg = "download cancelled";//Policy.bind("Feature.InstallationCancelled"); //$NON-NLS-1$
throw new InstallAbortedException(msg, null);
}
}
}
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;
}
}