blob: 16472b18dba4edb52e13d8087814c49b28fe3f37 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 Sonatype, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Sonatype, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.m2e.internal.discovery.operation;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
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.MultiStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IVersionedId;
import org.eclipse.equinox.p2.metadata.VersionedId;
import org.eclipse.equinox.p2.operations.ProvisioningJob;
import org.eclipse.equinox.p2.operations.ProvisioningSession;
import org.eclipse.equinox.p2.operations.RepositoryTracker;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.equinox.p2.ui.ProvisioningUI;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.osgi.util.NLS;
import org.eclipse.m2e.internal.discovery.DiscoveryActivator;
import org.eclipse.m2e.internal.discovery.MavenDiscovery;
import org.eclipse.m2e.internal.discovery.Messages;
/*
* This class allows us to open MavenDiscoveryInstallWizard instead of the default p2 wizard
* to support changing the restart policy for the subsequent ProvisioningJob.
*/
@SuppressWarnings("restriction")
public class MavenDiscoveryInstallOperation implements IRunnableWithProgress {
private Collection<CatalogItem> installableConnectors;
private ProvisioningSession session;
private Set<URI> repositoryLocations;
private final boolean restart;
private List<IStatus> statuses = new ArrayList<IStatus>();
private RestartInstallOperation operation;
private final IRunnableWithProgress postInstallHook;
private Collection<String> projectsToConfigure;
private boolean shouldResolve;
public MavenDiscoveryInstallOperation(Collection<CatalogItem> installableConnectors,
IRunnableWithProgress postInstallHook, boolean restart) {
this(installableConnectors, postInstallHook, restart, true, null);
}
public MavenDiscoveryInstallOperation(Collection<CatalogItem> installableConnectors,
IRunnableWithProgress postInstallHook, boolean restart, boolean shouldResolve,
Collection<String> projectsToConfigure) {
this.installableConnectors = installableConnectors;
this.postInstallHook = postInstallHook;
this.restart = restart;
this.session = ProvisioningUI.getDefaultUI().getSession();
this.shouldResolve = shouldResolve;
this.projectsToConfigure = projectsToConfigure;
}
public void run(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException {
try {
SubMonitor monitor = SubMonitor
.convert(progressMonitor, Messages.MavenDiscoveryInstallOperation_Configuring, 100);
try {
final IInstallableUnit[] ius = computeInstallableUnits(monitor.newChild(50));
checkCancelled(monitor);
operation = createAndResolve(monitor.newChild(50), ius, new URI[0],
restart && MavenDiscovery.requireRestart(installableConnectors));
checkCancelled(monitor);
} finally {
monitor.done();
}
} catch(OperationCanceledException e) {
throw new InterruptedException();
} catch(Exception e) {
throw new InvocationTargetException(e);
}
}
/*
* Should only be called after a successful call to run
*/
public RestartInstallOperation getOperation() {
return operation;
}
/*
* Compute the InstallableUnits & IMetadataRepository
*/
public IInstallableUnit[] computeInstallableUnits(IProgressMonitor progressMonitor) throws CoreException {
SubMonitor monitor = SubMonitor.convert(progressMonitor);
try {
List<IMetadataRepository> repositories = addRepositories(monitor.newChild(50));
final Collection<IInstallableUnit> installableUnits = queryInstallableUnits(monitor.newChild(50), repositories);
if(!statuses.isEmpty()) {
throw new CoreException(new MultiStatus(DiscoveryActivator.PLUGIN_ID, 0, statuses.toArray(new IStatus[statuses
.size()]), Messages.MavenDiscoveryInstallOperation_ErrorMessage, null));
}
return installableUnits.toArray(new IInstallableUnit[installableUnits.size()]);
} finally {
monitor.done();
}
}
/*
* Get IUs to install from the specified repository
*/
private Collection<IInstallableUnit> queryInstallableUnits(IProgressMonitor progressMonitor,
List<IMetadataRepository> repositories) {
final Set<IInstallableUnit> installableUnits = new HashSet<IInstallableUnit>(installableConnectors.size());
SubMonitor monitor = SubMonitor.convert(progressMonitor, installableConnectors.size());
try {
for(CatalogItem item : installableConnectors) {
SubMonitor subMon = monitor.newChild(1);
checkCancelled(monitor);
URI address = URI.create(item.getSiteUrl());
// get repository
IMetadataRepository repository = null;
for(IMetadataRepository candidate : repositories) {
if(address.equals(candidate.getLocation())) {
repository = candidate;
break;
}
}
if(repository == null) {
statuses.add(new Status(IStatus.ERROR, DiscoveryActivator.PLUGIN_ID, NLS.bind(
Messages.MavenDiscoveryInstallOperation_missingRepository, item.getName(), item.getSiteUrl())));
// Continue so we gather all the problems before telling the user
continue;
}
// get IUs
checkCancelled(monitor);
Set<IVersionedId> ids = getDescriptorIds(repository);
for(IVersionedId versionedId : ids) {
IQueryResult<IInstallableUnit> result = repository.query(QueryUtil.createIUQuery(versionedId),
subMon.newChild(1));
Set<IInstallableUnit> matches = result.toSet();
if(matches.size() == 1) {
installableUnits.addAll(matches);
} else if(matches.size() == 0) {
statuses.add(new Status(IStatus.ERROR, DiscoveryActivator.PLUGIN_ID, NLS.bind(
Messages.MavenDiscoveryInstallOperation_missingIU, item.getName(), versionedId.toString())));
} else {
// Choose the highest available version
IInstallableUnit match = null;
for(IInstallableUnit iu : matches) {
if(match == null || iu.getVersion().compareTo(match.getVersion()) > 0) {
match = iu;
}
}
if(match != null) {
installableUnits.add(match);
}
}
}
}
return installableUnits;
} finally {
monitor.done();
}
}
/*
* Get the IVersionedId expected to be in the repository
*/
protected Set<IVersionedId> getDescriptorIds(IMetadataRepository repository) {
Set<IVersionedId> ids = new HashSet<IVersionedId>();
for(CatalogItem item : installableConnectors) {
if(repository.getLocation().equals(URI.create(item.getSiteUrl()))) {
for(String id : item.getInstallableUnits()) {
ids.add(VersionedId.parse(id));
}
}
}
return ids;
}
/*
* Add the necessary repositories
*/
protected List<IMetadataRepository> addRepositories(SubMonitor monitor) {
// TODO this isn't right
// tell p2 that it's okay to use these repositories
RepositoryTracker repositoryTracker = ProvisioningUI.getDefaultUI().getRepositoryTracker();
repositoryLocations = new HashSet<URI>();
monitor.setWorkRemaining(installableConnectors.size() * 5);
for(CatalogItem descriptor : installableConnectors) {
URI uri = URI.create(descriptor.getSiteUrl());
if(repositoryLocations.add(uri)) {
checkCancelled(monitor);
repositoryTracker.addRepository(uri, null, session);
}
monitor.worked(1);
}
// fetch meta-data for these repositories
ArrayList<IMetadataRepository> repositories = new ArrayList<IMetadataRepository>();
monitor.setWorkRemaining(repositories.size());
IMetadataRepositoryManager manager = (IMetadataRepositoryManager) session.getProvisioningAgent().getService(
IMetadataRepositoryManager.SERVICE_NAME);
for(URI uri : repositoryLocations) {
checkCancelled(monitor);
try {
IMetadataRepository repository = manager.loadRepository(uri, monitor.newChild(1));
repositories.add(repository);
} catch(ProvisionException e) {
statuses.add(e.getStatus());
}
}
return repositories;
}
/*
* Create a RestartInstallOperation and resolve
*/
private RestartInstallOperation createAndResolve(IProgressMonitor monitor, final IInstallableUnit[] ius,
URI[] repositories, boolean requireRestart) throws CoreException {
SubMonitor mon = SubMonitor.convert(monitor, ius.length);
try {
RestartInstallOperation op = new RestartInstallOperation(session, Arrays.asList(ius), postInstallHook,
projectsToConfigure, requireRestart ? ProvisioningJob.RESTART_ONLY : ProvisioningJob.RESTART_NONE);
if(shouldResolve) {
IStatus operationStatus = op.resolveModal(mon);
if(operationStatus.getSeverity() > IStatus.WARNING) {
throw new CoreException(operationStatus);
}
}
return op;
} finally {
mon.done();
}
}
private void checkCancelled(IProgressMonitor monitor) {
if(monitor.isCanceled()) {
throw new OperationCanceledException();
}
}
}