Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.ui.discovery/src/org/eclipse/equinox/internal/p2/ui/discovery/operations/DiscoveryInstallOperation.java')
-rw-r--r--bundles/org.eclipse.equinox.p2.ui.discovery/src/org/eclipse/equinox/internal/p2/ui/discovery/operations/DiscoveryInstallOperation.java353
1 files changed, 353 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.ui.discovery/src/org/eclipse/equinox/internal/p2/ui/discovery/operations/DiscoveryInstallOperation.java b/bundles/org.eclipse.equinox.p2.ui.discovery/src/org/eclipse/equinox/internal/p2/ui/discovery/operations/DiscoveryInstallOperation.java
new file mode 100644
index 000000000..d4e89620d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.ui.discovery/src/org/eclipse/equinox/internal/p2/ui/discovery/operations/DiscoveryInstallOperation.java
@@ -0,0 +1,353 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.p2.ui.discovery.operations;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
+import org.eclipse.equinox.internal.p2.ui.discovery.DiscoveryUi;
+import org.eclipse.equinox.internal.p2.ui.discovery.util.WorkbenchUtil;
+import org.eclipse.equinox.internal.p2.ui.discovery.wizards.Messages;
+import org.eclipse.equinox.p2.core.ProvisionException;
+import org.eclipse.equinox.p2.metadata.IInstallableUnit;
+import org.eclipse.equinox.p2.metadata.IProvidedCapability;
+import org.eclipse.equinox.p2.metadata.Version;
+import org.eclipse.equinox.p2.operations.InstallOperation;
+import org.eclipse.equinox.p2.operations.ProvisioningSession;
+import org.eclipse.equinox.p2.operations.RepositoryTracker;
+import org.eclipse.equinox.p2.query.IQuery;
+import org.eclipse.equinox.p2.query.IQueryResult;
+import org.eclipse.equinox.p2.query.MatchQuery;
+import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
+import org.eclipse.equinox.p2.ui.ProvisioningUI;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * A job that configures a p2 {@link #getInstallAction() install action} for installing one or more {@link CatalogItem
+ * connectors}. The bulk of the installation work is done by p2; this class just sets up the p2 repository meta-data and
+ * selects the appropriate features to install. After running the job the {@link #getInstallAction() install action}
+ * must be run to perform the installation.
+ *
+ * @author David Green
+ * @author Steffen Pingel
+ */
+public class DiscoveryInstallOperation implements IRunnableWithProgress {
+
+ private static final String P2_FEATURE_GROUP_SUFFIX = ".feature.group"; //$NON-NLS-1$
+
+ private final List<CatalogItem> installableConnectors;
+
+ private final ProvisioningUI provisioningUI;
+
+ private Set<URI> repositoryLocations;
+
+ public DiscoveryInstallOperation(List<CatalogItem> installableConnectors) {
+ if (installableConnectors == null || installableConnectors.isEmpty()) {
+ throw new IllegalArgumentException();
+ }
+ this.installableConnectors = new ArrayList<CatalogItem>(installableConnectors);
+ this.provisioningUI = ProvisioningUI.getDefaultUI();
+ }
+
+ public void run(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException {
+ try {
+ SubMonitor monitor = SubMonitor.convert(progressMonitor, Messages.InstallConnectorsJob_task_configuring,
+ 100);
+ try {
+ final IInstallableUnit[] ius = computeInstallableUnits(monitor.newChild(50));
+
+ checkCancelled(monitor);
+
+ final InstallOperation installOperation = resolve(monitor.newChild(50), ius,
+ repositoryLocations.toArray(new URI[0]));
+
+ checkCancelled(monitor);
+
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ provisioningUI.openInstallWizard(WorkbenchUtil.getShell(), Arrays.asList(ius),
+ installOperation, null);
+ }
+ });
+ } finally {
+ monitor.done();
+ }
+ } catch (OperationCanceledException e) {
+ throw new InterruptedException();
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+
+ private void checkCancelled(IProgressMonitor monitor) {
+ if (monitor.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ }
+
+ private InstallOperation resolve(IProgressMonitor monitor, final IInstallableUnit[] ius, URI[] repositories)
+ throws CoreException {
+ final InstallOperation installOperation = provisioningUI.getInstallOperation(Arrays.asList(ius), repositories);
+ IStatus operationStatus = installOperation.resolveModal(new SubProgressMonitor(monitor,
+ installableConnectors.size()));
+ if (operationStatus.getSeverity() > IStatus.WARNING) {
+ throw new CoreException(operationStatus);
+ }
+ return installOperation;
+ }
+
+ public IInstallableUnit[] computeInstallableUnits(SubMonitor monitor) throws CoreException {
+ try {
+ monitor.setWorkRemaining(100);
+ // add repository urls and load meta data
+ List<IMetadataRepository> repositories = addRepositories(monitor.newChild(50));
+ final List<IInstallableUnit> installableUnits = queryInstallableUnits(monitor.newChild(50), repositories);
+ removeOldVersions(installableUnits);
+ checkForUnavailable(installableUnits);
+ return installableUnits.toArray(new IInstallableUnit[installableUnits.size()]);
+
+// MultiStatus status = new MultiStatus(DiscoveryUi.ID_PLUGIN, 0, Messages.PrepareInstallProfileJob_ok, null);
+// ius = installableUnits.toArray(new IInstallableUnit[installableUnits.size()]);
+// ProfileChangeRequest profileChangeRequest = InstallAction.computeProfileChangeRequest(ius, profileId,
+// status, new SubProgressMonitor(monitor, installableConnectors.size()));
+// if (status.getSeverity() > IStatus.WARNING) {
+// throw new CoreException(status);
+// }
+// if (profileChangeRequest == null) {
+// // failed but no indication as to why
+// throw new CoreException(new Status(IStatus.ERROR, DiscoveryUi.ID_PLUGIN,
+// Messages.PrepareInstallProfileJob_computeProfileChangeRequestFailed, null));
+// }
+// PlannerResolutionOperation operation = new PlannerResolutionOperation(
+// Messages.PrepareInstallProfileJob_calculatingRequirements, profileId, profileChangeRequest, null,
+// status, true);
+// IStatus operationStatus = operation.execute(new SubProgressMonitor(monitor, installableConnectors.size()));
+// if (operationStatus.getSeverity() > IStatus.WARNING) {
+// throw new CoreException(operationStatus);
+// }
+//
+// plannerResolutionOperation = operation;
+
+ } catch (URISyntaxException e) {
+ // should never happen, since we already validated URLs.
+ throw new CoreException(new Status(IStatus.ERROR, DiscoveryUi.ID_PLUGIN,
+ Messages.InstallConnectorsJob_unexpectedError_url, e));
+ } catch (MalformedURLException e) {
+ // should never happen, since we already validated URLs.
+ throw new CoreException(new Status(IStatus.ERROR, DiscoveryUi.ID_PLUGIN,
+ Messages.InstallConnectorsJob_unexpectedError_url, e));
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * Verifies that we found what we were looking for: it's possible that we have connector descriptors that are no
+ * longer available on their respective sites. In that case we must inform the user. Unfortunately this is the
+ * earliest point at which we can know.
+ */
+ private void checkForUnavailable(final List<IInstallableUnit> installableUnits) throws CoreException {
+ // at least one selected connector could not be found in a repository
+ Set<String> foundIds = new HashSet<String>();
+ for (IInstallableUnit unit : installableUnits) {
+ String id = unit.getId();
+ if (id.endsWith(P2_FEATURE_GROUP_SUFFIX)) {
+ id = id.substring(0, id.indexOf(P2_FEATURE_GROUP_SUFFIX));
+ }
+ foundIds.add(id);
+ }
+
+ String message = ""; //$NON-NLS-1$
+ String detailedMessage = ""; //$NON-NLS-1$
+ for (CatalogItem descriptor : installableConnectors) {
+ StringBuilder unavailableIds = null;
+ for (String id : descriptor.getInstallableUnits()) {
+ if (!foundIds.contains(id)) {
+ if (unavailableIds == null) {
+ unavailableIds = new StringBuilder();
+ } else {
+ unavailableIds.append(Messages.InstallConnectorsJob_commaSeparator);
+ }
+ unavailableIds.append(id);
+ }
+ }
+ if (unavailableIds != null) {
+ if (message.length() > 0) {
+ message += Messages.InstallConnectorsJob_commaSeparator;
+ }
+ message += descriptor.getName();
+
+ if (detailedMessage.length() > 0) {
+ detailedMessage += Messages.InstallConnectorsJob_commaSeparator;
+ }
+ detailedMessage += NLS.bind(Messages.PrepareInstallProfileJob_notFoundDescriptorDetail, new Object[] {
+ descriptor.getName(), unavailableIds.toString(), descriptor.getSiteUrl() });
+ }
+ }
+
+ if (message.length() > 0) {
+ // instead of aborting here we ask the user if they wish to proceed anyways
+ final boolean[] okayToProceed = new boolean[1];
+ final String finalMessage = message;
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ okayToProceed[0] = MessageDialog.openQuestion(WorkbenchUtil.getShell(),
+ Messages.InstallConnectorsJob_questionProceed, NLS.bind(
+ Messages.InstallConnectorsJob_questionProceed_long, new Object[] { finalMessage }));
+ }
+ });
+ if (!okayToProceed[0]) {
+ throw new CoreException(new Status(IStatus.ERROR, DiscoveryUi.ID_PLUGIN, NLS.bind(
+ Messages.InstallConnectorsJob_connectorsNotAvailable, detailedMessage), null));
+ }
+ }
+ }
+
+ /**
+ * Filters those installable units that have a duplicate in the list with a higher version number. it's possible
+ * that some repositories will host multiple versions of a particular feature. we assume that the user wants the
+ * highest version.
+ */
+ private void removeOldVersions(final List<IInstallableUnit> installableUnits) {
+ Map<String, Version> symbolicNameToVersion = new HashMap<String, Version>();
+ for (IInstallableUnit unit : installableUnits) {
+ Version version = symbolicNameToVersion.get(unit.getId());
+ if (version == null || version.compareTo(unit.getVersion()) == -1) {
+ symbolicNameToVersion.put(unit.getId(), unit.getVersion());
+ }
+ }
+ if (symbolicNameToVersion.size() != installableUnits.size()) {
+ for (IInstallableUnit unit : new ArrayList<IInstallableUnit>(installableUnits)) {
+ Version version = symbolicNameToVersion.get(unit.getId());
+ if (!version.equals(unit.getVersion())) {
+ installableUnits.remove(unit);
+ }
+ }
+ }
+ }
+
+ /**
+ * Perform a query to get the installable units. This causes p2 to determine what features are available in each
+ * repository. We select installable units by matching both the feature id and the repository; it is possible though
+ * unlikely that the same feature id is available from more than one of the selected repositories, and we must
+ * ensure that the user gets the one that they asked for.
+ */
+ private List<IInstallableUnit> queryInstallableUnits(SubMonitor monitor, List<IMetadataRepository> repositories)
+ throws URISyntaxException {
+ final List<IInstallableUnit> installableUnits = new ArrayList<IInstallableUnit>();
+
+ monitor.setWorkRemaining(repositories.size());
+ for (final IMetadataRepository repository : repositories) {
+ checkCancelled(monitor);
+ final Set<String> installableUnitIdsThisRepository = getDescriptorIds(repository);
+ IQuery<IInstallableUnit> query = new MatchQuery<IInstallableUnit>() {
+ @Override
+ public boolean isMatch(IInstallableUnit candidate) {
+ if ("true".equalsIgnoreCase(candidate.getProperty("org.eclipse.equinox.p2.type.group"))) { //$NON-NLS-1$ //$NON-NLS-2$
+ String id = candidate.getId();
+ if (isQualifyingFeature(installableUnitIdsThisRepository, id)) {
+ Collection<IProvidedCapability> providedCapabilities = candidate.getProvidedCapabilities();
+ if (providedCapabilities != null && providedCapabilities.size() > 0) {
+ for (IProvidedCapability capability : providedCapabilities) {
+ if ("org.eclipse.equinox.p2.iu".equals(capability.getNamespace())) { //$NON-NLS-1$
+ String name = capability.getName();
+ if (isQualifyingFeature(installableUnitIdsThisRepository, name)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isQualifyingFeature(final Set<String> installableUnitIdsThisRepository, String id) {
+ return id.endsWith(P2_FEATURE_GROUP_SUFFIX)
+ && installableUnitIdsThisRepository.contains(id.substring(0,
+ id.indexOf(P2_FEATURE_GROUP_SUFFIX)));
+ }
+ };
+ IQueryResult<IInstallableUnit> result = repository.query(query, monitor.newChild(1));
+ installableUnits.addAll(result.toSet());
+ }
+ return installableUnits;
+ }
+
+ private List<IMetadataRepository> addRepositories(SubMonitor monitor) throws MalformedURLException,
+ URISyntaxException, ProvisionException {
+ // tell p2 that it's okay to use these repositories
+ ProvisioningSession session = ProvisioningUI.getDefaultUI().getSession();
+ RepositoryTracker repositoryTracker = ProvisioningUI.getDefaultUI().getRepositoryTracker();
+ repositoryLocations = new HashSet<URI>();
+ monitor.setWorkRemaining(installableConnectors.size() * 5);
+ for (CatalogItem descriptor : installableConnectors) {
+ URI uri = new URL(descriptor.getSiteUrl()).toURI();
+ if (repositoryLocations.add(uri)) {
+ checkCancelled(monitor);
+ repositoryTracker.addRepository(uri, null, session);
+// ProvisioningUtil.addMetaDataRepository(url.toURI(), true);
+// ProvisioningUtil.addArtifactRepository(url.toURI(), true);
+// ProvisioningUtil.setColocatedRepositoryEnablement(url.toURI(), true);
+ }
+ monitor.worked(1);
+ }
+
+ // fetch meta-data for these repositories
+ ArrayList<IMetadataRepository> repositories = new ArrayList<IMetadataRepository>();
+ monitor.setWorkRemaining(repositories.size());
+ for (URI uri : repositoryLocations) {
+ checkCancelled(monitor);
+ IMetadataRepository repository = session.getMetadataRepositoryManager().loadRepository(uri,
+ monitor.newChild(1));
+ repositories.add(repository);
+ }
+ return repositories;
+ }
+
+ private Set<String> getDescriptorIds(final IMetadataRepository repository) throws URISyntaxException {
+ final Set<String> installableUnitIdsThisRepository = new HashSet<String>();
+ // determine all installable units for this repository
+ for (CatalogItem descriptor : installableConnectors) {
+ try {
+ if (repository.getLocation().equals(new URL(descriptor.getSiteUrl()).toURI())) {
+ installableUnitIdsThisRepository.addAll(descriptor.getInstallableUnits());
+ }
+ } catch (MalformedURLException e) {
+ // will never happen, ignore
+ }
+ }
+ return installableUnitIdsThisRepository;
+ }
+
+}

Back to the top