diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/prov/director/NewSimpleDirector.java')
-rw-r--r-- | bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/prov/director/NewSimpleDirector.java | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/prov/director/NewSimpleDirector.java b/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/prov/director/NewSimpleDirector.java new file mode 100644 index 000000000..665cca2ee --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/prov/director/NewSimpleDirector.java @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright (c) 2007 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.equinox.prov.director; + +import java.net.URL; +import java.util.*; +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.internal.prov.director.*; +import org.eclipse.equinox.internal.prov.rollback.FormerState; +import org.eclipse.equinox.prov.core.eventbus.ProvisioningEventBus; +import org.eclipse.equinox.prov.core.helpers.ServiceHelper; +import org.eclipse.equinox.prov.core.location.AgentLocation; +import org.eclipse.equinox.prov.core.repository.IRepositoryInfo; +import org.eclipse.equinox.prov.core.repository.IWritableRepositoryInfo; +import org.eclipse.equinox.prov.engine.*; +import org.eclipse.equinox.prov.metadata.*; +import org.eclipse.equinox.prov.metadata.repository.*; +import org.eclipse.equinox.prov.resolution.ResolutionHelper; +import org.eclipse.osgi.service.resolver.VersionRange; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.Version; + +public class NewSimpleDirector implements IDirector { + static final int ExpandWork = 10; + static final int OperationWork = 100; + private Engine engine; + + public static void tagAsImplementation(IWritableMetadataRepository repository) { + if (repository != null && repository.getProperties().getProperty(IRepositoryInfo.IMPLEMENTATION_ONLY_KEY) == null) { + IWritableRepositoryInfo writableInfo = (IWritableRepositoryInfo) repository.getAdapter(IWritableRepositoryInfo.class); + if (writableInfo != null) + writableInfo.getModifiableProperties().setProperty(IRepositoryInfo.IMPLEMENTATION_ONLY_KEY, Boolean.valueOf(true).toString()); + } + } + + public NewSimpleDirector() { + URL rollbackLocation = null; + AgentLocation agentLocation = (AgentLocation) ServiceHelper.getService(DirectorActivator.context, AgentLocation.class.getName()); + rollbackLocation = agentLocation.getTouchpointDataArea("director"); + ProvisioningEventBus eventBus = (ProvisioningEventBus) ServiceHelper.getService(DirectorActivator.context, ProvisioningEventBus.class.getName()); + IMetadataRepositoryManager manager = (IMetadataRepositoryManager) ServiceHelper.getService(DirectorActivator.context, IMetadataRepositoryManager.class.getName()); + IWritableMetadataRepository rollbackRepo = (IWritableMetadataRepository) manager.loadRepository(rollbackLocation, null); + if (rollbackRepo == null) + rollbackRepo = (IWritableMetadataRepository) manager.createRepository(rollbackLocation, "Agent rollback repo", "org.eclipse.equinox.prov.metadata.repository.simpleRepository"); //$NON-NLS-1$//$NON-NLS-2$ + if (rollbackRepo == null) + throw new IllegalStateException("Unable to open or create Agent's rollback repository"); + tagAsImplementation(rollbackRepo); + new FormerState(eventBus, rollbackRepo); + engine = (Engine) ServiceHelper.getService(DirectorActivator.context, Engine.class.getName()); + } + + //TODO This is really gross!!!!! We need to make things uniform + private IInstallableUnit[] toArray(Iterator it) { + ArrayList result = new ArrayList(); + while (it.hasNext()) { + result.add(it.next()); + } + return (IInstallableUnit[]) result.toArray(new IInstallableUnit[result.size()]); + } + + protected IInstallableUnit[] createEntryPointHelper(String entryPointName, IInstallableUnit[] content) { + if (entryPointName == null) + return content; + return new IInstallableUnit[] {createEntryPoint(entryPointName, content)}; + } + + protected InstallableUnit createEntryPoint(String entryPointName, IInstallableUnit[] content) { + InstallableUnit result = new InstallableUnit(); + result.setId("entry point " + entryPointId(content)); //$NON-NLS-1$ + result.setVersion(new Version(0, 0, 0, Long.toString(System.currentTimeMillis()))); + result.setRequiredCapabilities(IUTransformationHelper.toRequirements(content, false)); + result.setProperty(IInstallableUnitConstants.ENTRYPOINT_IU_KEY, Boolean.TRUE.toString()); + result.setProperty(IInstallableUnitConstants.NAME, entryPointName); + return result; + } + + private String entryPointId(IInstallableUnit[] ius) { + StringBuffer result = new StringBuffer(); + for (int i = 0; i < ius.length; i++) { + result.append(ius[i].getId()); + if (i < ius.length - 1) + result.append(", "); //$NON-NLS-1$ + } + return result.toString(); + } + + public IStatus install(IInstallableUnit[] installRoots, Profile profile, String entryPointName, IProgressMonitor monitor) { + SubMonitor sub = SubMonitor.convert(monitor, ExpandWork + OperationWork); + sub.setTaskName(Messages.Director_Task_Resolving_Dependencies); + try { + MultiStatus result = new MultiStatus(DirectorActivator.PI_DIRECTOR, 1, Messages.Director_Install_Problems, null); + // Get the list of ius installed in the profile we are installing into + IInstallableUnit[] alreadyInstalled = toArray(profile.getInstallableUnits()); + //Compute the complete closure of things to install to successfully install the installRoots. + NewDependencyExpander expander = new NewDependencyExpander(createEntryPointHelper(entryPointName, installRoots), alreadyInstalled, gatherAvailableInstallableUnits(installRoots), profile, true); + // NewDependencyExpander expander = new NewDependencyExpander(installRoots, alreadyInstalled, gatherAvailableInstallableUnits(), profile, true); + IStatus expanderResult = expander.expand(sub.newChild(ExpandWork)); + if (!expanderResult.isOK()) { + result.merge(expanderResult); + return result; + } + + ResolutionHelper oldStateHelper = new ResolutionHelper(profile.getSelectionContext(), null); + Collection oldState = oldStateHelper.attachCUs(Arrays.asList(alreadyInstalled)); + List oldStateOrder = oldStateHelper.getSorted(); + + ResolutionHelper newStateHelper = new ResolutionHelper(profile.getSelectionContext(), expander.getRecommendations()); + Collection newState = newStateHelper.attachCUs(expander.getAllInstallableUnits()); + List newStateOrder = newStateHelper.getSorted(); + + //TODO Here we need to sort the operations to ensure that the dependents will be treated first (see ensureDependencyOrder) + sub.setTaskName(NLS.bind(Messages.Director_Task_Installing, entryPointName, profile.getValue(Profile.PROP_INSTALL_FOLDER))); + IStatus engineResult = engine.perform(profile, new DefaultPhaseSet(), generateOperations(oldState, newState, oldStateOrder, newStateOrder), sub.newChild(OperationWork)); + if (!engineResult.isOK()) + result.merge(engineResult); + + return result.isOK() ? Status.OK_STATUS : result; + } finally { + sub.done(); + } + } + + private Operand[] generateOperations(Collection fromState, Collection toState, List fromStateOrder, List newStateOrder) { + return sortOperations(new OperationGenerator().generateOperation(fromState, toState), newStateOrder, fromStateOrder); + } + + private Operand[] sortOperations(Operand[] toSort, List installOrder, List uninstallOrder) { + List updateOp = new ArrayList(); + for (int i = 0; i < toSort.length; i++) { + Operand op = toSort[i]; + if (op.first() == null && op.second() != null) { + installOrder.set(installOrder.indexOf(op.second()), op); + continue; + } + if (op.first() != null && op.second() == null) { + uninstallOrder.set(uninstallOrder.indexOf(op.first()), op); + continue; + } + if (op.first() != null && op.second() != null) { + updateOp.add(op); + continue; + } + } + int i = 0; + for (Iterator iterator = installOrder.iterator(); iterator.hasNext();) { + Object elt = iterator.next(); + if (elt instanceof Operand) { + toSort[i++] = (Operand) elt; + } + } + for (Iterator iterator = uninstallOrder.iterator(); iterator.hasNext();) { + Object elt = iterator.next(); + if (elt instanceof Operand) { + toSort[i++] = (Operand) elt; + } + } + for (Iterator iterator = updateOp.iterator(); iterator.hasNext();) { + Object elt = iterator.next(); + if (elt instanceof Operand) { + toSort[i++] = (Operand) elt; + } + } + return toSort; + } + + public IStatus become(IInstallableUnit target, Profile profile, IProgressMonitor monitor) { + SubMonitor sub = SubMonitor.convert(monitor, OperationWork + ExpandWork); + sub.setTaskName(Messages.Director_Task_Resolving_Dependencies); + try { + MultiStatus result = new MultiStatus(DirectorActivator.PI_DIRECTOR, 1, Messages.Director_Become_Problems, null); + + if (!Boolean.valueOf(target.getProperty(IInstallableUnitConstants.PROFILE_IU_KEY)).booleanValue()) { + result.add(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, NLS.bind(Messages.Director_Unexpected_IU, target.getId()))); + return result; + } + + //TODO Here we need to deal with the change of properties between the two profiles + //Also if the profile changes (locations are being modified, etc), should not we do a full uninstall then an install? + //Maybe it depends on the kind of changes in a profile + //We need to get all the ius that were part of the profile and give that to be what to become + NewDependencyExpander toExpander = new NewDependencyExpander(new IInstallableUnit[] {target}, null, gatherAvailableInstallableUnits(new IInstallableUnit[] {target}), profile, true); + toExpander.expand(sub.newChild(ExpandWork)); + ResolutionHelper newStateHelper = new ResolutionHelper(profile.getSelectionContext(), toExpander.getRecommendations()); + Collection newState = newStateHelper.attachCUs(toExpander.getAllInstallableUnits()); + newState.remove(target); + + Iterator it = profile.getInstallableUnits(); + Collection oldIUs = new HashSet(); + for (; it.hasNext();) { + oldIUs.add(it.next()); + } + + ResolutionHelper oldStateHelper = new ResolutionHelper(profile.getSelectionContext(), null); + Collection oldState = oldStateHelper.attachCUs(oldIUs); + sub.setTaskName(Messages.Director_Task_Updating); + IStatus engineResult = engine.perform(profile, new DefaultPhaseSet(), generateOperations(oldState, newState, oldStateHelper.getSorted(), newStateHelper.getSorted()), sub.newChild(OperationWork)); + if (!engineResult.isOK()) + result.merge(engineResult); + + return result; + } finally { + sub.done(); + } + } + + private IInstallableUnit[] inProfile(IInstallableUnit[] toFind, Profile profile, boolean found, IProgressMonitor monitor) { + ArrayList result = new ArrayList(toFind.length); + for (int i = 0; i < toFind.length; i++) { + if (profile.query(toFind[i].getId(), new VersionRange(toFind[i].getVersion(), true, toFind[i].getVersion(), true), null, false, monitor).length > 0) { + if (found) + result.add(toFind[i]); + } else { + if (!found) + result.add(toFind[i]); + } + } + return (IInstallableUnit[]) result.toArray(new IInstallableUnit[result.size()]); + } + + public IStatus uninstall(IInstallableUnit[] uninstallRoots, Profile profile, IProgressMonitor monitor) { + SubMonitor sub = SubMonitor.convert(monitor, OperationWork + ExpandWork); + sub.setTaskName(Messages.Director_Task_Resolving_Dependencies); + try { + IInstallableUnit[] toReallyUninstall = inProfile(uninstallRoots, profile, true, sub.newChild(0)); + if (toReallyUninstall.length == 0) { + return new Status(IStatus.OK, DirectorActivator.PI_DIRECTOR, Messages.Director_Nothing_To_Uninstall); + } else if (toReallyUninstall.length != uninstallRoots.length) { + uninstallRoots = toReallyUninstall; + } + + MultiStatus result = new MultiStatus(DirectorActivator.PI_DIRECTOR, 1, Messages.Director_Uninstall_Problems, null); + + IInstallableUnit[] alreadyInstalled = toArray(profile.getInstallableUnits()); + ResolutionHelper oldStateHelper = new ResolutionHelper(profile.getSelectionContext(), null); + Collection oldState = oldStateHelper.attachCUs(Arrays.asList(alreadyInstalled)); + + NewDependencyExpander expander = new NewDependencyExpander(uninstallRoots, new IInstallableUnit[0], alreadyInstalled, profile, true); + expander.expand(sub.newChild(ExpandWork / 2)); + Collection toUninstallClosure = new ResolutionHelper(profile.getSelectionContext(), null).attachCUs(expander.getAllInstallableUnits()); + + Collection remainingIUs = new HashSet(oldState); + remainingIUs.removeAll(toUninstallClosure); + NewDependencyExpander finalExpander = new NewDependencyExpander(null, (IInstallableUnit[]) remainingIUs.toArray(new IInstallableUnit[remainingIUs.size()]), gatherAvailableInstallableUnits(uninstallRoots), profile, true); + finalExpander.expand(sub.newChild(ExpandWork / 2)); + ResolutionHelper newStateHelper = new ResolutionHelper(profile.getSelectionContext(), null); + Collection newState = newStateHelper.attachCUs(finalExpander.getAllInstallableUnits()); + + for (int i = 0; i < uninstallRoots.length; i++) { + if (newState.contains(uninstallRoots[i])) + result.add(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, NLS.bind(Messages.Director_Cannot_Uninstall, uninstallRoots[i]))); + } + if (!result.isOK()) + return result; + + sub.setTaskName(Messages.Director_Task_Uninstalling); + IStatus engineResult = engine.perform(profile, new DefaultPhaseSet(), generateOperations(oldState, newState, oldStateHelper.getSorted(), newStateHelper.getSorted()), sub.newChild(OperationWork)); + if (!engineResult.isOK()) + result.merge(engineResult); + + return result.isOK() ? Status.OK_STATUS : result; + } finally { + sub.done(); + } + } + + protected IInstallableUnit[] gatherAvailableInstallableUnits(IInstallableUnit[] additionalSource) { + IMetadataRepositoryManager repoMgr = (IMetadataRepositoryManager) ServiceHelper.getService(DirectorActivator.context, IMetadataRepositoryManager.class.getName()); + IMetadataRepository[] repos = repoMgr.getKnownRepositories(); + List results = new ArrayList(); + if (additionalSource != null) { + for (int i = 0; i < additionalSource.length; i++) { + results.add(additionalSource[i]); + } + } + + for (int i = 0; i < repos.length; i++) { + results.addAll(Arrays.asList(repos[i].getInstallableUnits(null))); + } + return (IInstallableUnit[]) results.toArray(new IInstallableUnit[results.size()]); + } + + public IStatus replace(IInstallableUnit[] toUninstall, IInstallableUnit[] toInstall, Profile profile, IProgressMonitor monitor) { + SubMonitor sub = SubMonitor.convert(monitor, OperationWork + ExpandWork); + sub.setTaskName(Messages.Director_Task_Resolving_Dependencies); + try { + MultiStatus result = new MultiStatus(DirectorActivator.PI_DIRECTOR, 1, Messages.Director_Replace_Problems, null); + + //TODO Need to worry about the entry points + + //find the things being updated in the profile + IInstallableUnit[] alreadyInstalled = toArray(profile.getInstallableUnits()); + IInstallableUnit[] uninstallRoots = toUninstall; + + //compute the transitive closure and remove them. + ResolutionHelper oldStateHelper = new ResolutionHelper(profile.getSelectionContext(), null); + Collection oldState = oldStateHelper.attachCUs(Arrays.asList(alreadyInstalled)); + + NewDependencyExpander expander = new NewDependencyExpander(uninstallRoots, new IInstallableUnit[0], alreadyInstalled, profile, true); + expander.expand(sub.newChild(ExpandWork / 2)); + Collection toUninstallClosure = new ResolutionHelper(profile.getSelectionContext(), null).attachCUs(expander.getAllInstallableUnits()); + + //add the new set. + Collection remainingIUs = new HashSet(oldState); + remainingIUs.removeAll(toUninstallClosure); + // for (int i = 0; i < updateRoots.length; i++) { + // remainingIUs.add(updateRoots[i]); + // } + NewDependencyExpander finalExpander = new NewDependencyExpander(toInstall, (IInstallableUnit[]) remainingIUs.toArray(new IInstallableUnit[remainingIUs.size()]), gatherAvailableInstallableUnits(null), profile, true); + finalExpander.expand(sub.newChild(ExpandWork / 2)); + ResolutionHelper newStateHelper = new ResolutionHelper(profile.getSelectionContext(), null); + Collection newState = newStateHelper.attachCUs(finalExpander.getAllInstallableUnits()); + + sub.setTaskName(Messages.Director_Task_Updating); + IStatus engineResult = engine.perform(profile, new DefaultPhaseSet(), generateOperations(oldState, newState, oldStateHelper.getSorted(), newStateHelper.getSorted()), sub.newChild(OperationWork)); + if (!engineResult.isOK()) + result.merge(engineResult); + + return result.isOK() ? Status.OK_STATUS : result; + } finally { + sub.done(); + } + } +} |