/******************************************************************************* * Copyright (c) 2000, 2006 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.io.*; import java.net.*; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.*; import org.eclipse.osgi.util.NLS; import org.eclipse.update.configuration.*; import org.eclipse.update.configurator.*; import org.eclipse.update.core.*; import org.eclipse.update.core.model.*; import org.eclipse.update.internal.model.*; /** * */ public class ConfigurationPolicy extends ConfigurationPolicyModel { /** * Constructor for ConfigurationPolicyModel. */ public ConfigurationPolicy() { } /** * Copy Constructor for ConfigurationPolicyModel. */ public ConfigurationPolicy(ConfigurationPolicy configPolicy) { super(); setPolicy(configPolicy.getPolicy()); setConfiguredFeatureReferences(configPolicy.getConfiguredFeatures()); setUnconfiguredFeatureReferences(configPolicy.getUnconfiguredFeatures()); setConfiguredSiteModel(configPolicy.getConfiguredSiteModel()); } /** * @since 2.0 */ private boolean isUnconfigured(IFeatureReference featureReference) { if (featureReference == null) return false; // returns true if the feature is part of the configured list IFeatureReference[] refs = getUnconfiguredFeatures(); for (int i = 0; i < refs.length; i++) { if (featureReference.equals(refs[i])) { return true; } } return false; } /** * @since 2.0 */ public boolean isConfigured(IFeatureReference featureReference) { if (featureReference == null) return false; // returns true if the feature is part of the configured list IFeatureReference[] refs = getConfiguredFeatures(); for (int i = 0; i < refs.length; i++) { if (featureReference.equals(refs[i])) { return true; } } return false; } /** * adds the feature to the list of features if the policy is USER_INCLUDE */ public void configure(IFeatureReference featureReference, boolean callInstallHandler, boolean createActivity) throws CoreException { if (isConfigured(featureReference)) // already configured return; if (featureReference == null) { UpdateCore.warn("The feature reference to configure is null"); //$NON-NLS-1$ return; } IFeature feature = null; try { feature = featureReference.getFeature(null); } catch (CoreException e) { if (!UpdateManagerUtils.isOptional(featureReference)) { URL url = featureReference.getURL(); String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$ UpdateCore.warn("Error retrieving feature:" + urlString, e); //$NON-NLS-1$ return; } } if (feature == null) { URL url = featureReference.getURL(); String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$ UpdateCore.warn("The feature to unconfigure is null: feature reference is:" + urlString); //$NON-NLS-1$ } // Setup optional install handler InstallHandlerProxy handler = null; if (callInstallHandler && feature.getInstallHandlerEntry() != null) handler = new InstallHandlerProxy(IInstallHandler.HANDLER_ACTION_CONFIGURE, feature, feature.getInstallHandlerEntry(), null); boolean success = false; Throwable originalException = null; // do the configure action try { if (handler != null) handler.configureInitiated(); ConfigurationActivity activity = null; if (createActivity) { activity = new ConfigurationActivity(IActivity.ACTION_CONFIGURE); activity.setLabel(feature.getVersionedIdentifier().toString()); activity.setDate(new Date()); } addConfiguredFeatureReference((FeatureReferenceModel) featureReference); // everything done ok if (activity != null) { InstallConfiguration installConfig = (InstallConfiguration) SiteManager.getLocalSite().getCurrentConfiguration(); activity.setStatus(IActivity.STATUS_OK); installConfig.addActivity(activity); } if (handler != null) handler.completeConfigure(); success = true; } catch (Throwable t) { originalException = t; } finally { Throwable newException = null; try { if (handler != null) handler.configureCompleted(success); } catch (Throwable t) { newException = t; } if (originalException != null) // original exception wins throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), originalException); if (newException != null) throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), newException); } } /** * check if the plugins to unconfigure are required by other configured feature and * adds the feature to the list of unconfigured features */ public boolean unconfigure(IFeatureReference featureReference, boolean callInstallHandler, boolean createActivity) throws CoreException { if (isUnconfigured(featureReference)) { UpdateCore.warn("Feature already unconfigured"); //$NON-NLS-1$ return true; } if (featureReference == null) { UpdateCore.warn("The feature reference to unconfigure is null"); //$NON-NLS-1$ return false; } IFeature feature = null; try { feature = featureReference.getFeature(null); } catch (CoreException e) { if (!UpdateManagerUtils.isOptional(featureReference)) { URL url = featureReference.getURL(); String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$ UpdateCore.warn("Error retrieving feature:" + urlString, e); //$NON-NLS-1$ return false; } } if (feature == null) { URL url = featureReference.getURL(); String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$ UpdateCore.warn("The feature to unconfigure is null: feature reference is:" + urlString); //$NON-NLS-1$ return false; } // Setup optional install handler InstallHandlerProxy handler = null; if (callInstallHandler && feature.getInstallHandlerEntry() != null) { handler = new InstallHandlerProxy(IInstallHandler.HANDLER_ACTION_UNCONFIGURE, feature, feature.getInstallHandlerEntry(), null); } boolean success = false; Throwable originalException = null; // do the unconfigure action try { ConfigurationActivity activity = null; if (createActivity) { activity = new ConfigurationActivity(IActivity.ACTION_UNCONFIGURE); activity.setLabel(feature.getVersionedIdentifier().toString()); activity.setDate(new Date()); } InstallConfiguration installConfig = null; // only ask for install config is activity created. // prevents loops during reconciliation if (activity != null) installConfig = ((InstallConfiguration) SiteManager.getLocalSite().getCurrentConfiguration()); // Allow unconfigure if the feature is optional from all the parents // or if the feature is mandatory and non of its parent are configured // removed, not a core issue (so deep down) //if (validateNoConfiguredParents(feature)) { if (handler != null) handler.unconfigureInitiated(); addUnconfiguredFeatureReference((FeatureReferenceModel) featureReference); if (handler != null) handler.completeUnconfigure(); // everything done ok if (activity != null) { activity.setStatus(IActivity.STATUS_OK); installConfig.addActivity(activity); } success = true; //} else { // if (activity != null) { // activity.setStatus(IActivity.STATUS_NOK); // installConfig.addActivityModel((ConfigurationActivityModel) activity); // } //} } catch (Throwable t) { originalException = t; } finally { Throwable newException = null; try { if (handler != null) handler.unconfigureCompleted(success); } catch (Throwable t) { newException = t; } if (originalException != null) // original exception wins throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), originalException); if (newException != null) throw Utilities.newCoreException(NLS.bind(Messages.InstallHandler_error, (new String[] { feature.getLabel() })), newException); } if (!success) { URL url = featureReference.getURL(); String urlString = (url != null) ? url.toExternalForm() : "<no feature reference url>"; //$NON-NLS-1$ UpdateCore.warn("Unable to unconfigure:" + urlString); //$NON-NLS-1$ } return success; } /** * Calculates the plugin list for the policy. For "INCLUDE" policy, this * corresponds to the plugins for configured features. For "EXCLUDE" * policy, this corresponds to the plugins for unconfigured features that * are not referenced by any configured features. */ public String[] getPluginPath(ISite site) throws CoreException { // TODO we may need to exclude patched plugins here, but this should be good enough for now if (getPolicy() == IPlatformConfiguration.ISitePolicy.MANAGED_ONLY) return new String[0]; String[] pluginPaths; // Note: Since 3.0M7 we leave patched features configured, // and take this into account when computing configured plugins // all unconfigured features. Note that patched features are still // configured IFeatureReference[] unconfiguredFeatures = getUnconfiguredFeatures(); // all configured features, including patches and patched features IFeatureReference[] configuredFeatures = getConfiguredFeatures(); if (!isEnabled()) { if (getPolicy() == IPlatformConfiguration.ISitePolicy.USER_INCLUDE) { // disabled site, INCLUDE policy pluginPaths = new String[0]; } else { // disabled site, EXCLUDE policy pluginPaths = getAllKnownPluginStrings(site, configuredFeatures, unconfiguredFeatures); } } else { // PatchedFeatures (may have no patches) with corresponding patches PatchedFeature[] patchedFeatures = buildPatchedFeatures(configuredFeatures); if (getPolicy() == IPlatformConfiguration.ISitePolicy.USER_INCLUDE) { // enabled site, INCLUDE policy pluginPaths = getConfiguredPluginStrings(site, patchedFeatures); } else { // enabled site, EXCLUDE policy - the usual scenario for local // site. // return all known MINUS configured plugins pluginPaths = subtract(getAllKnownPluginStrings(site, configuredFeatures, unconfiguredFeatures), getConfiguredPluginStrings(site, patchedFeatures)); } } //TRACE if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_RECONCILER) { UpdateCore .debug("GetPluginPath for: " //$NON-NLS-1$ + ((site == null) ? "<No site>" : site.getURL() //$NON-NLS-1$ .toString())); for (int i = 0; i < pluginPaths.length; i++) { UpdateCore.debug("To write:" + pluginPaths[i]); //$NON-NLS-1$ } } return pluginPaths; } /** * Obtains PatchedFeatures - non patch features with corresponding patches if any * * @param features * array of features to operate with * @return Patches */ private PatchedFeature[] buildPatchedFeatures(IFeatureReference[] features) { // PatchedFeatures by VersionedIdentifier Map map = new HashMap(); // Create a map of features (not patches) for (int f = 0; f < features.length; f++) { IFeatureReference featureRef = features[f]; try { if(featureRef.isPatch()){ continue; } VersionedIdentifier vi = featureRef.getVersionedIdentifier(); map.put(vi, new PatchedFeature(features[f])); } catch (CoreException e) { UpdateCore.warn(null, e); } } // attach patches to features for (int f = 0; f < features.length; f++) { IFeatureReference patchCandidate = features[f]; try { IFeature feature = patchCandidate.getFeature(null); IImport[] imports = feature.getImports(); for (int i = 0; i < imports.length; i++) { IImport oneImport = imports[i]; if (!oneImport.isPatch()) continue; // it is a patch for VersionedIdentifier patchedIdentifier = oneImport.getVersionedIdentifier(); PatchedFeature pf=(PatchedFeature) map.get(patchedIdentifier); if (pf!=null) { pf.addPatch(patchCandidate); } else { // patched feature not enabled } } } catch (CoreException e) { UpdateCore.warn(null, e); } } Collection patchedFeatures=map.values(); return (PatchedFeature[])patchedFeatures.toArray(new PatchedFeature[patchedFeatures.size()]); } /** * @since 2.0 */ public IFeatureReference[] getConfiguredFeatures() { FeatureReferenceModel[] result = getConfiguredFeaturesModel(); if (result.length == 0) return new IFeatureReference[0]; else return (IFeatureReference[]) result; } /** * @since 2.0 */ public IFeatureReference[] getUnconfiguredFeatures() { FeatureReferenceModel[] result = getUnconfiguredFeaturesModel(); if (result.length == 0) return new IFeatureReference[0]; else return (IFeatureReference[]) result; } /** * Gets the configuredSite. * @return Returns a IConfiguredSite */ public IConfiguredSite getConfiguredSite() { return (IConfiguredSite) getConfiguredSiteModel(); } /** * removes a feature reference */ public void removeFeatureReference(IFeatureReference featureRef) { if (featureRef instanceof FeatureReferenceModel) { removeFeatureReference((FeatureReferenceModel) featureRef); } } /** * @return an array of plugin path for the array of feature reference. For * features that have patches, plugin path will * point to plugin with the same ID provided by the patch if it * exists. Each plugin path only appears once [bug 21750] */ private String[] getConfiguredPluginStrings(ISite site, PatchedFeature[] features) throws CoreException { if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION){ UpdateCore.warn("CONFIGURED PLUGINS"); //$NON-NLS-1$ } // Use set to eliminate plugins with same ID and version. // Different versions of plugins with same ID are allowed if coming from different features Set featurePlugins = new HashSet(); for (int i = 0; i < features.length; i++) { FeaturePlugin[] plugins = features[i].getPlugins(); featurePlugins.addAll(Arrays.asList(plugins)); } Set pluginStrings = getPluginStrings(site, (FeaturePlugin[]) featurePlugins.toArray(new FeaturePlugin[featurePlugins.size()])); return (String[]) pluginStrings.toArray(new String[pluginStrings.size()]); } /** * @return an array of plugin path for every plugin in known features */ private String[] getAllKnownPluginStrings(ISite site, IFeatureReference[] configured,IFeatureReference[] unconfigured) throws CoreException { if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION){ UpdateCore.warn("ALL PLUGINS"); //$NON-NLS-1$ } // Add features, patched features, or patches IFeatureReference[] all=new IFeatureReference[configured.length+unconfigured.length]; System.arraycopy(configured, 0, all, 0, configured.length); System.arraycopy(unconfigured, 0, all, configured.length, unconfigured.length); // Set patchedPlugins = new HashSet(); for (int i=0; i< all.length; i++) { try { IFeature feature = all[i].getFeature(null); if (feature == null) { UpdateCore.warn("Null Feature", new Exception()); //$NON-NLS-1$ continue; } IPluginEntry[] entries = feature.getPluginEntries(); // add every plugin to the map for (int entr = 0; entr < entries.length; entr++) { patchedPlugins.add(new FeaturePlugin(entries[entr], feature)); } } catch (CoreException e) { UpdateCore.warn(null, e); } } Set pluginStrings = getPluginStrings(site, (FeaturePlugin[])patchedPlugins.toArray(new FeaturePlugin[patchedPlugins.size()])); return (String[]) pluginStrings.toArray(new String[pluginStrings.size()]); } /** * @param site * @param plugins[] * @return valid string pointing to plugins in given features * @throws CoreException */ private Set getPluginStrings(ISite site, FeaturePlugin[] plugins) throws CoreException { Set pluginStrings=new HashSet(); for (int i=0; i< plugins.length; i++) { IPluginEntry entry = plugins[i].getEntry(); IFeature feature=plugins[i].getFeature(); // obtain the path of the plugin directories on the site ContentReference[] featureContentReference = null; try { featureContentReference = feature.getFeatureContentProvider().getPluginEntryArchiveReferences(entry, null /*IProgressMonitor*/ ); } catch (CoreException e) { UpdateCore.warn(null, e); } // transform into a valid String if (featureContentReference != null) { for (int j = 0; j < featureContentReference.length; j++) { URL url = site.getSiteContentProvider().getArchiveReference(featureContentReference[j].getIdentifier()); if (url != null) { // make it relative to the site String path = UpdateManagerUtils.getURLAsString(site.getURL(), url); // add end "/" if(!path.endsWith(".jar")) //$NON-NLS-1$ path += (path.endsWith(File.separator) || path.endsWith("/")) ? "" : "/"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ pluginStrings.add(path); if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_CONFIGURATION) UpdateCore.warn("Add plugin: " + path + " to the list"); //$NON-NLS-1$ //$NON-NLS-2$ } } } } return pluginStrings; } /** * Obtains strings existing in the allStrings array, but not in the stringsToRemove */ private String[] subtract(String[] allStrings, String[] stringsToRemove) { HashSet resultList = new HashSet(Arrays.asList(allStrings)); resultList.removeAll(Arrays.asList(stringsToRemove)); return (String[])resultList.toArray(new String[resultList.size()]); } }