/******************************************************************************* * 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; } }