/******************************************************************************* * Copyright (c) 2011 Sonatype, Inc. 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: * Sonatype, Inc. - initial API and implementation * IBM Corporation - Ongoing development *******************************************************************************/ package org.eclipse.equinox.p2.operations; import java.net.URI; import java.util.*; import org.eclipse.core.runtime.*; import org.eclipse.equinox.internal.p2.operations.Activator; import org.eclipse.equinox.internal.p2.operations.Messages; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.engine.*; import org.eclipse.equinox.p2.engine.query.UserVisibleRootQuery; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IVersionedId; import org.eclipse.equinox.p2.query.*; import org.eclipse.osgi.util.NLS; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; /** * OperationFactory provides a set of helpers to simplify dealing with the running installation. * Among other things, it simplifies the installation, un-installation and update. * If the system you are trying to modify is not the running one, you need to directly use the various subclass of {@link ProfileChangeOperation}. * @since 2.1 */ public class OperationFactory { private IProvisioningAgent getAgent() { Collection<ServiceReference<IProvisioningAgent>> ref = null; try { ref = Activator.getContext().getServiceReferences(IProvisioningAgent.class, '(' + IProvisioningAgent.SERVICE_CURRENT + '=' + Boolean.TRUE.toString() + ')'); } catch (InvalidSyntaxException e) { //ignore can't happen since we write the filter ourselves } if (ref == null || ref.size() == 0) throw new IllegalStateException(Messages.OperationFactory_noAgent); IProvisioningAgent agent = Activator.getContext().getService(ref.iterator().next()); Activator.getContext().ungetService(ref.iterator().next()); return agent; } //Return a list of IUs from the list of versionedIDs originally provided private Collection<IInstallableUnit> gatherIUs(IQueryable<IInstallableUnit> searchContext, Collection<? extends IVersionedId> ius, boolean checkIUs, IProgressMonitor monitor) throws ProvisionException { Collection<IInstallableUnit> gatheredIUs = new ArrayList<IInstallableUnit>(ius.size()); for (IVersionedId versionedId : ius) { if (!checkIUs && versionedId instanceof IInstallableUnit) { gatheredIUs.add((IInstallableUnit) versionedId); continue; } IQuery<IInstallableUnit> installableUnits = QueryUtil.createIUQuery(versionedId.getId(), versionedId.getVersion()); IQueryResult<IInstallableUnit> matches = searchContext.query(installableUnits, monitor); if (matches.isEmpty()) throw new ProvisionException(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.OperationFactory_noIUFound, versionedId))); //Add the first IU Iterator<IInstallableUnit> iuIt = matches.iterator(); gatheredIUs.add(iuIt.next()); } return gatheredIUs; } private ProvisioningContext createProvisioningContext(Collection<URI> repos, IProvisioningAgent agent) { ProvisioningContext ctx = new ProvisioningContext(agent); if (repos != null) { ctx.setMetadataRepositories(repos.toArray(new URI[repos.size()])); ctx.setArtifactRepositories(repos.toArray(new URI[repos.size()])); } return ctx; } /** * This factory method creates an {@link InstallOperation} to install all the elements listed from the specified repositories. * @param toInstall the elements to install. This can not be null. * @param repos the repositories to install the elements from. If null is passed, it will use all previously registered repositories. * @param monitor the progress monitor * @return an operation to install */ public InstallOperation createInstallOperation(Collection<? extends IVersionedId> toInstall, Collection<URI> repos, IProgressMonitor monitor) throws ProvisionException { Assert.isNotNull(toInstall); IProvisioningAgent agent = getAgent(); //add the repos ProvisioningContext ctx = createProvisioningContext(repos, agent); //find the ius to install and create the operation InstallOperation resultingOperation = new InstallOperation(new ProvisioningSession(agent), gatherIUs(ctx.getMetadata(monitor), toInstall, false, monitor)); resultingOperation.setProvisioningContext(ctx); resultingOperation.setProfileId(IProfileRegistry.SELF); return resultingOperation; } /** * Create an {@link UninstallOperation} that will uninstall the listed elements from the running instance. * @param toUninstall the elements to uninstall. This can not be null. * @param repos the repositories to install the elements from. If null is passed, it will use all previously registered repositories. * @param monitor the progress monitor * @return an operation to uninstall */ public UninstallOperation createUninstallOperation(Collection<? extends IVersionedId> toUninstall, Collection<URI> repos, IProgressMonitor monitor) throws ProvisionException { Assert.isNotNull(toUninstall); IProvisioningAgent agent = getAgent(); ProvisioningContext ctx = createProvisioningContext(repos, agent); //find the ius to uninstall and create the operation UninstallOperation resultingOperation = new UninstallOperation(new ProvisioningSession(agent), gatherIUs(listInstalledElements(false, monitor), toUninstall, true, monitor)); resultingOperation.setProvisioningContext(ctx); resultingOperation.setProfileId(IProfileRegistry.SELF); return resultingOperation; } /** * Returns the {@link IInstallableUnit}s that are installed in the running instance of Eclipse. * * @param rootsOnly set to true to return only the elements that have been explicitly installed (aka roots). * @param monitor the progress monitor * @return the installable units installed, or an empty result if the installation profile of the running system * cannot be accessed */ public IQueryResult<IInstallableUnit> listInstalledElements(boolean rootsOnly, IProgressMonitor monitor) { IProfileRegistry registry = (IProfileRegistry) getAgent().getService(IProfileRegistry.SERVICE_NAME); IProfile profile = registry.getProfile(IProfileRegistry.SELF); if (profile == null) return new CollectionResult<IInstallableUnit>(null); if (rootsOnly) return profile.query(new UserVisibleRootQuery(), monitor); return profile.query(QueryUtil.ALL_UNITS, monitor); } /** * Create an {@link UpdateOperation} that will update the elements specified. * @param toUpdate The elements to update.Passing null will result in looking for an update to all the installed. Note that you can pass the results of {@link OperationFactory#listInstalledElements(boolean, IProgressMonitor)} to this * method if you wish to update all elements installed in the running instance of eclipse. * @param repos the repositories to update the elements from. If null is passed, it will use all previously registered repositories. * @param monitor the progress monitor * @return an instance of {@link UpdateOperation} */ public UpdateOperation createUpdateOperation(Collection<? extends IVersionedId> toUpdate, Collection<URI> repos, IProgressMonitor monitor) throws ProvisionException { IProvisioningAgent agent = getAgent(); ProvisioningContext ctx = createProvisioningContext(repos, agent); //find the ius to update and create the operation UpdateOperation resultingOperation = new UpdateOperation(new ProvisioningSession(agent), toUpdate == null ? null : gatherIUs(listInstalledElements(false, monitor), toUpdate, false, monitor)); resultingOperation.setProvisioningContext(ctx); resultingOperation.setProfileId(IProfileRegistry.SELF); return resultingOperation; } /** * This factory method creates an {@link SynchronizeOperation} that will cause the current installation to exclusively contain the elements listed once executed. * @param toInstall the elements to install. This can not be null. * @param repos the repositories to install the elements from. If null is passed, it will use all previously registered repositories. * @param monitor the progress monitor * @return an instance of {@link SynchronizeOperation}. */ public SynchronizeOperation createSynchronizeOperation(Collection<? extends IVersionedId> toInstall, Collection<URI> repos, IProgressMonitor monitor) throws ProvisionException { IProvisioningAgent agent = getAgent(); ProvisioningContext ctx = createProvisioningContext(repos, agent); Collection<IInstallableUnit> iusToInstall; if (toInstall == null) iusToInstall = ctx.getMetadata(monitor).query(QueryUtil.createIUGroupQuery(), monitor).toUnmodifiableSet(); else iusToInstall = gatherIUs(ctx.getMetadata(monitor), toInstall, false, monitor); SynchronizeOperation resultingOperation = new SynchronizeOperation(new ProvisioningSession(agent), iusToInstall); resultingOperation.setProvisioningContext(ctx); resultingOperation.setProfileId(IProfileRegistry.SELF); return resultingOperation; } }