blob: 1e5427a2c3e512049c07b23b9a2ad2b8f55c6483 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.update.internal.ui.wizards;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.*;
import org.eclipse.update.configuration.*;
import org.eclipse.update.core.*;
import org.eclipse.update.core.model.InstallAbortedException;
import org.eclipse.update.internal.ui.*;
import org.eclipse.update.internal.ui.model.*;
import org.eclipse.update.internal.ui.security.JarVerificationService;
public class MultiInstallWizard extends Wizard {
private static final String KEY_UNABLE = "MultiInstallWizard.error.unable";
private static final String KEY_OLD = "MultiInstallWizard.error.old";
private static final String KEY_SAVED_CONFIG =
"MultiInstallWizard.savedConfig";
private static final String KEY_INSTALLING =
"MultiInstallWizard.installing";
private MultiReviewPage reviewPage;
private LicensePage licensePage;
private MultiOptionalFeaturesPage optionalFeaturesPage;
private MultiTargetPage targetPage;
private PendingChange[] jobs;
private IInstallConfiguration config;
private boolean needLicensePage;
private int installCount = 0;
public MultiInstallWizard(PendingChange[] jobs) {
this(jobs, true);
}
public MultiInstallWizard(PendingChange[] jobs, boolean needLicensePage) {
setDialogSettings(UpdateUI.getDefault().getDialogSettings());
setDefaultPageImageDescriptor(UpdateUIImages.DESC_INSTALL_WIZ);
setForcePreviousAndNextButtons(true);
setNeedsProgressMonitor(true);
setWindowTitle(
UpdateUI.getString("MultiInstallWizard.wtitle"));
this.jobs = jobs;
this.needLicensePage = needLicensePage;
}
public boolean isSuccessfulInstall() {
return installCount > 0;
}
/**
* @see Wizard#performFinish()
*/
public boolean performFinish() {
final PendingChange[] selectedJobs = reviewPage.getSelectedJobs();
installCount = 0;
if (targetPage != null) {
// Check for duplication conflicts
ArrayList conflicts =
DuplicateConflictsDialog.computeDuplicateConflicts(
targetPage.getTargetSites(),
config);
if (conflicts != null) {
DuplicateConflictsDialog dialog =
new DuplicateConflictsDialog(getShell(), conflicts);
if (dialog.open() != 0)
return false;
}
}
// ok to continue
IRunnableWithProgress operation = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor)
throws InvocationTargetException {
try {
MultiInstallWizard.makeConfigurationCurrent(config, null);
execute(selectedJobs, monitor);
} catch (InstallAbortedException e) {
throw new InvocationTargetException(e);
} catch (CoreException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
}
}
};
try {
getContainer().run(true, true, operation);
} catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
if (targetException instanceof InstallAbortedException) {
return true;
} else {
UpdateUI.logException(e);
}
return false;
} catch (InterruptedException e) {
return false;
}
return true;
}
/*
* When we are uninstalling, there is not targetSite
*/
private void execute(
PendingChange[] selectedJobs,
IProgressMonitor monitor)
throws InstallAbortedException, CoreException {
monitor.beginTask(
UpdateUI.getString(KEY_INSTALLING),
selectedJobs.length);
for (int i = 0; i < selectedJobs.length; i++) {
PendingChange job = selectedJobs[i];
SubProgressMonitor subMonitor =
new SubProgressMonitor(
monitor,
1,
SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
executeOneJob(job, subMonitor);
//monitor.worked(1);
InstallWizard.saveLocalSite();
installCount++;
}
}
public void addPages() {
reviewPage = new MultiReviewPage(jobs);
addPage(reviewPage);
config = createInstallConfiguration();
boolean addLicensePage = false;
boolean addOptionalFeaturesPage = false;
boolean addTargetPage = false;
for (int i = 0; i < jobs.length; i++) {
PendingChange job = jobs[i];
if (job.getJobType() == PendingChange.INSTALL) {
if (needLicensePage && UpdateModel.hasLicense(job)) {
addLicensePage = true;
}
if (UpdateModel.hasOptionalFeatures(job.getFeature())) {
addOptionalFeaturesPage = true;
}
addTargetPage = true;
}
}
if (addLicensePage) {
licensePage = new LicensePage(true);
addPage(licensePage);
}
if (addOptionalFeaturesPage) {
optionalFeaturesPage = new MultiOptionalFeaturesPage(config);
addPage(optionalFeaturesPage);
}
if (addTargetPage) {
targetPage = new MultiTargetPage(config);
addPage(targetPage);
}
}
private boolean isPageRequired(IWizardPage page) {
if (page.equals(licensePage)) {
return reviewPage.hasSelectedJobsWithLicenses();
}
if (page.equals(optionalFeaturesPage)) {
return reviewPage.hasSelectedJobsWithOptionalFeatures();
}
if (page.equals(targetPage)) {
return reviewPage.hasSelectedInstallJobs();
}
return true;
}
public IWizardPage getNextPage(IWizardPage page) {
IWizardPage[] pages = getPages();
boolean start = false;
IWizardPage nextPage = null;
if (page.equals(reviewPage)) {
updateDynamicPages();
}
for (int i = 0; i < pages.length; i++) {
if (pages[i].equals(page)) {
start = true;
} else if (start) {
if (isPageRequired(pages[i])) {
nextPage = pages[i];
break;
}
}
}
return nextPage;
}
private void updateDynamicPages() {
if (licensePage != null) {
PendingChange[] licenseJobs =
reviewPage.getSelectedJobsWithLicenses();
licensePage.setJobs(licenseJobs);
}
if (optionalFeaturesPage != null) {
PendingChange[] optionalJobs =
reviewPage.getSelectedJobsWithOptionalFeatures();
optionalFeaturesPage.setJobs(optionalJobs);
}
if (targetPage != null) {
PendingChange[] installJobs = reviewPage.getSelectedInstallJobs();
targetPage.setJobs(installJobs);
}
}
public static IInstallConfiguration createInstallConfiguration() {
try {
ILocalSite localSite = SiteManager.getLocalSite();
IInstallConfiguration config =
localSite.cloneCurrentConfiguration();
config.setLabel(Utilities.format(config.getCreationDate()));
return config;
} catch (CoreException e) {
UpdateUI.logException(e);
return null;
}
}
public static void makeConfigurationCurrent(
IInstallConfiguration config,
PendingChange job)
throws CoreException {
ILocalSite localSite = SiteManager.getLocalSite();
if (job != null && job.getJobType() == PendingChange.INSTALL) {
if (job.getFeature().isPatch()) {
// Installing a patch - preserve the current configuration
IInstallConfiguration cconfig =
localSite.getCurrentConfiguration();
IInstallConfiguration savedConfig =
localSite.addToPreservedConfigurations(cconfig);
VersionedIdentifier vid =
job.getFeature().getVersionedIdentifier();
String key = "@" + vid.getIdentifier() + "_" + vid.getVersion();
String newLabel =
UpdateUI.getFormattedMessage(KEY_SAVED_CONFIG, key);
savedConfig.setLabel(newLabel);
UpdateModel model =
UpdateUI.getDefault().getUpdateModel();
model.fireObjectChanged(savedConfig, null);
}
}
localSite.addConfiguration(config);
}
public static void saveLocalSite() throws CoreException {
ILocalSite localSite = SiteManager.getLocalSite();
localSite.save();
}
public boolean canFinish() {
IWizardPage page = getContainer().getCurrentPage();
return page.getNextPage() == null && super.canFinish();
}
private void executeOneJob(PendingChange job, IProgressMonitor monitor)
throws CoreException {
IConfiguredSite targetSite = null;
Object[] optionalElements = null;
IFeatureReference[] optionalFeatures = null;
if (job.getJobType() == PendingChange.INSTALL) {
if (optionalFeaturesPage != null) {
optionalElements =
optionalFeaturesPage.getOptionalElements(job);
optionalFeatures =
optionalFeaturesPage.getCheckedOptionalFeatures(job);
}
if (targetPage != null) {
targetSite = targetPage.getTargetSite(job);
}
}
executeOneJob(
job,
targetSite,
optionalElements,
optionalFeatures,
monitor);
}
private void executeOneJob(
PendingChange job,
IConfiguredSite targetSite,
Object[] optionalElements,
IFeatureReference[] optionalFeatures,
IProgressMonitor monitor)
throws CoreException {
IFeature feature = job.getFeature();
if (job.getJobType() == PendingChange.UNINSTALL) {
//find the config site of this feature
IConfiguredSite site = findConfigSite(feature, config);
if (site != null) {
site.remove(feature, monitor);
} else {
// we should do something here
throwError(
UpdateUI.getFormattedMessage(
KEY_UNABLE,
feature.getLabel()));
}
} else if (job.getJobType() == PendingChange.INSTALL) {
if (optionalFeatures == null)
targetSite.install(feature, getVerificationListener(), monitor);
else
targetSite.install(
feature,
optionalFeatures,
getVerificationListener(),
monitor);
IFeature oldFeature = job.getOldFeature();
if (oldFeature != null && !job.isOptionalDelta()) {
if (optionalElements != null) {
boolean patch = UpdateUI.isPatch(feature);
preserveOptionalState(config, targetSite, patch, optionalElements);
}
boolean oldSuccess = unconfigure(config, oldFeature);
if (!oldSuccess) {
if (!isNestedChild(oldFeature))
// "eat" the error if nested child
throwError(
UpdateUI.getFormattedMessage(
KEY_OLD,
oldFeature.getLabel()));
}
}
if (oldFeature == null) {
ensureUnique(config, feature, targetSite);
if (optionalFeatures != null) {
preserveOriginatingURLs(feature, optionalFeatures);
}
}
} else if (job.getJobType() == PendingChange.CONFIGURE) {
configure(feature);
ensureUnique(config, feature, targetSite);
} else if (job.getJobType() == PendingChange.UNCONFIGURE) {
unconfigure(config, job.getFeature());
} else {
// should not be here
return;
}
UpdateModel model = UpdateUI.getDefault().getUpdateModel();
job.markProcessed();
model.fireObjectChanged(job, null);
}
static void ensureUnique(
IInstallConfiguration config,
IFeature feature,
IConfiguredSite targetSite)
throws CoreException {
boolean patch = false;
if (targetSite == null)
targetSite = feature.getSite().getCurrentConfiguredSite();
IImport[] imports = feature.getImports();
for (int i = 0; i < imports.length; i++) {
IImport iimport = imports[i];
if (iimport.isPatch()) {
patch = true;
break;
}
}
// Only need to check features that patch other features.
if (!patch)
return;
IFeature localFeature = findLocalFeature(targetSite, feature);
ArrayList oldFeatures = new ArrayList();
// First collect all older active features that
// have the same ID as new features marked as 'unique'.
collectOldFeatures(localFeature, targetSite, oldFeatures);
// Now unconfigure old features to enforce uniqueness
for (int i = 0; i < oldFeatures.size(); i++) {
IFeature oldFeature = (IFeature) oldFeatures.get(i);
unconfigure(config, oldFeature);
}
}
private void throwError(String message) throws CoreException {
IStatus status =
new Status(
IStatus.ERROR,
UpdateUI.getPluginId(),
IStatus.OK,
message,
null);
throw new CoreException(status);
}
static IConfiguredSite findConfigSite(
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;
}
private static boolean unconfigure(
IInstallConfiguration config,
IFeature feature)
throws CoreException {
IConfiguredSite site = findConfigSite(feature, config);
if (site != null) {
PatchCleaner cleaner = new PatchCleaner(site, feature);
boolean result = site.unconfigure(feature);
cleaner.dispose();
return result;
}
return false;
}
private void configure(IFeature feature) throws CoreException {
IConfiguredSite site = findConfigSite(feature, config);
if (site != null) {
site.configure(feature);
}
}
private IVerificationListener getVerificationListener() {
return new JarVerificationService(this.getShell());
}
private boolean isNestedChild(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;
}
static void preserveOptionalState(
IInstallConfiguration config,
IConfiguredSite targetSite,
boolean patch,
Object[] optionalElements) {
for (int i = 0; i < optionalElements.length; i++) {
FeatureHierarchyElement fe =
(FeatureHierarchyElement) optionalElements[i];
Object[] children = fe.getChildren(true, patch, config);
preserveOptionalState(config, targetSite, patch, children);
if (!fe.isEnabled(config)) {
IFeature newFeature = fe.getFeature();
try {
IFeature localFeature =
findLocalFeature(targetSite, newFeature);
if (localFeature != null)
targetSite.unconfigure(localFeature);
} catch (CoreException e) {
// Eat this - we will leave with it
}
}
}
}
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 =
UpdateUI.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);
}
}
private static IFeature findLocalFeature(
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;
}
private void preserveOriginatingURLs(
IFeature feature,
IFeatureReference[] optionalFeatures) {
// walk the hieararchy and preserve the originating URL
// for all the optional features that are not chosen to
// be installed.
URL url = feature.getSite().getURL();
try {
IIncludedFeatureReference[] irefs =
feature.getIncludedFeatureReferences();
for (int i = 0; i < irefs.length; i++) {
IIncludedFeatureReference iref = irefs[i];
boolean preserve = false;
if (iref.isOptional()) {
boolean onTheList = false;
for (int j = 0; j < optionalFeatures.length; j++) {
if (optionalFeatures[j].equals(iref)) {
//was on the list
onTheList = true;
break;
}
}
if (!onTheList)
preserve = true;
}
if (preserve) {
try {
String id =
iref.getVersionedIdentifier().getIdentifier();
UpdateUI.setOriginatingURL(id, url);
} catch (CoreException e) {
// Silently ignore
}
} else {
try {
IFeature ifeature = iref.getFeature(null);
preserveOriginatingURLs(ifeature, optionalFeatures);
} catch (CoreException e) {
// Silently ignore
}
}
}
} catch (CoreException e) {
// Silently ignore
}
}
}