| /******************************************************************************* |
| * Copyright (c) 2008, 2010 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 |
| * Sonatype, Inc. - ongoing development |
| ******************************************************************************/ |
| |
| package org.eclipse.equinox.internal.p2.operations; |
| |
| import java.util.Collection; |
| import java.util.Map.Entry; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.equinox.internal.provisional.p2.director.*; |
| import org.eclipse.equinox.p2.engine.IProvisioningPlan; |
| import org.eclipse.equinox.p2.metadata.IInstallableUnit; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * This class analyzes a profile change request and the resultant provisioning plan, |
| * and reports problems in a way that can be communicated to a user. |
| * |
| * @since 3.5 |
| */ |
| public class PlanAnalyzer { |
| |
| public static IStatus getStatus(int statusCode, IInstallableUnit affectedIU) { |
| switch (statusCode) { |
| case IStatusCodes.NOTHING_TO_UPDATE : |
| return new Status(IStatus.INFO, Activator.ID, statusCode, Messages.PlanAnalyzer_NoUpdates, null); |
| case IStatusCodes.PROFILE_CHANGE_ALTERED : |
| return new MultiStatus(Activator.ID, statusCode, Messages.PlanAnalyzer_RequestAltered, null); |
| case IStatusCodes.ALTERED_IMPLIED_UPDATE : |
| return new Status(IStatus.INFO, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_ImpliedUpdate, getIUString(affectedIU)), null); |
| case IStatusCodes.ALTERED_IGNORED_IMPLIED_UPDATE : |
| return new Status(IStatus.WARNING, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_LockedImpliedUpdate0, getIUString(affectedIU)), null); |
| case IStatusCodes.ALTERED_IGNORED_IMPLIED_DOWNGRADE : |
| return new Status(IStatus.WARNING, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_IgnoringImpliedDowngrade, getIUString(affectedIU)), null); |
| case IStatusCodes.ALTERED_IGNORED_ALREADY_INSTALLED : |
| return new Status(IStatus.WARNING, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_AlreadyInstalled, getIUString(affectedIU)), null); |
| case IStatusCodes.ALTERED_PARTIAL_INSTALL : |
| return new Status(IStatus.INFO, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_PartialInstall, getIUString(affectedIU)), null); |
| case IStatusCodes.ALTERED_PARTIAL_UNINSTALL : |
| return new Status(IStatus.INFO, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_PartialUninstall, getIUString(affectedIU)), null); |
| case IStatusCodes.UNEXPECTED_NOTHING_TO_DO : |
| return new Status(IStatus.ERROR, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_NothingToDo, getIUString(affectedIU)), null); |
| case IStatusCodes.OPERATION_ALREADY_IN_PROGRESS : |
| return new Status(IStatus.ERROR, Activator.ID, statusCode, Messages.PlanAnalyzer_AnotherOperationInProgress, null); |
| default : |
| return new Status(IStatus.ERROR, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_UnexpectedError, new Integer(statusCode), getIUString(affectedIU)), null); |
| } |
| } |
| |
| public static MultiStatus getProfileChangeAlteredStatus() { |
| return (MultiStatus) getStatus(IStatusCodes.PROFILE_CHANGE_ALTERED, null); |
| } |
| |
| public static ResolutionResult computeResolutionResult(ProfileChangeRequest originalRequest, IProvisioningPlan plan, MultiStatus originalStatus) { |
| Assert.isNotNull(originalRequest); |
| Assert.isNotNull(plan); |
| Assert.isNotNull(originalStatus); |
| |
| ResolutionResult report = new ResolutionResult(); |
| |
| // If the plan was canceled, no further analysis is needed |
| if (plan.getStatus().getSeverity() == IStatus.CANCEL) { |
| report.addSummaryStatus(plan.getStatus()); |
| return report; |
| } |
| |
| if (nothingToDo(originalRequest)) { |
| report.addSummaryStatus(getStatus(IStatusCodes.UNEXPECTED_NOTHING_TO_DO, null)); |
| IStatus[] details = originalStatus.getChildren(); |
| for (int i = 0; i < details.length; i++) |
| report.addSummaryStatus(details[i]); |
| return report; |
| } |
| |
| // If there was already some status supplied before resolution, this should get included |
| // with the report. For example, this might contain information about the profile request |
| // being altered before resolution began. |
| if (originalStatus != null && originalStatus.getChildren().length > 0) { |
| report.addSummaryStatus(originalStatus); |
| } |
| |
| // If the overall plan had a non-OK status, capture that in the report. |
| if (!plan.getStatus().isOK()) |
| report.addSummaryStatus(plan.getStatus()); |
| |
| // Now we compare what was requested with what is going to happen. |
| // In the long run, when a RequestStatus can provide actual explanation/status |
| // about failures, we might want to add this information to the overall status. |
| // As it stands now, if the provisioning plan is in error, that info is more detailed |
| // than the request status. So we will only add request status info to the overall |
| // status when the overall status is not in error. |
| |
| PlannerStatus plannerStatus = plan.getStatus() instanceof PlannerStatus ? (PlannerStatus) plan.getStatus() : null; |
| // If there is no additional plannerStatus details just return the report |
| if (plannerStatus == null) |
| return report; |
| |
| if (plan.getStatus().getSeverity() != IStatus.ERROR) { |
| Collection<IInstallableUnit> iusAdded = originalRequest.getAdditions(); |
| for (IInstallableUnit added : iusAdded) { |
| RequestStatus rs = plannerStatus.getRequestChanges().get(added); |
| if (rs.getSeverity() == IStatus.ERROR) { |
| // This is a serious error so it must also appear in the overall status |
| IStatus fail = new Status(IStatus.ERROR, Activator.ID, IStatusCodes.ALTERED_IGNORED_INSTALL_REQUEST, NLS.bind(Messages.PlanAnalyzer_IgnoringInstall, getIUString(added)), null); |
| report.addStatus(added, fail); |
| report.addSummaryStatus(fail); |
| } |
| } |
| Collection<IInstallableUnit> iusRemoved = originalRequest.getRemovals(); |
| for (IInstallableUnit removed : iusRemoved) { |
| RequestStatus rs = plannerStatus.getRequestChanges().get(removed); |
| if (rs.getSeverity() == IStatus.ERROR) { |
| // TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=255984 |
| // We are making assumptions here about why the planner chose to ignore an uninstall. |
| // Assume it could not be uninstalled because of some other dependency, yet the planner did not view |
| // this as an error. So we inform the user that we can only uninstall parts of it. The root property will be |
| // removed per the original change request. |
| IStatus fail = new Status(IStatus.INFO, Activator.ID, IStatusCodes.ALTERED_PARTIAL_UNINSTALL, NLS.bind(Messages.PlanAnalyzer_PartialUninstall, getIUString(removed)), null); |
| report.addStatus(removed, fail); |
| report.addSummaryStatus(fail); |
| } |
| } |
| } |
| |
| // Now process the side effects |
| if (plannerStatus.getRequestSideEffects() != null) { |
| for (Entry<IInstallableUnit, RequestStatus> entry : plannerStatus.getRequestSideEffects().entrySet()) { |
| IInstallableUnit iu = entry.getKey(); |
| RequestStatus rs = entry.getValue(); |
| if (rs.getInitialRequestType() == RequestStatus.ADDED) { |
| report.addStatus(iu, new Status(rs.getSeverity(), Activator.ID, IStatusCodes.ALTERED_SIDE_EFFECT_INSTALL, NLS.bind(Messages.PlanAnalyzer_SideEffectInstall, getIUString(iu)), null)); |
| } else { |
| report.addStatus(iu, new Status(rs.getSeverity(), Activator.ID, IStatusCodes.ALTERED_SIDE_EFFECT_REMOVE, NLS.bind(Messages.PlanAnalyzer_SideEffectUninstall, getIUString(iu)), null)); |
| } |
| } |
| } |
| |
| return report; |
| |
| } |
| |
| private static String getIUString(IInstallableUnit iu) { |
| if (iu == null) |
| return Messages.PlanAnalyzer_Items; |
| // Get the iu name in the default locale |
| String name = iu.getProperty(IInstallableUnit.PROP_NAME, null); |
| if (name != null) |
| return name; |
| return iu.getId(); |
| } |
| |
| private static boolean nothingToDo(ProfileChangeRequest request) { |
| return request.getAdditions().size() == 0 && request.getRemovals().size() == 0 && request.getInstallableUnitProfilePropertiesToAdd().size() == 0 && request.getInstallableUnitProfilePropertiesToRemove().size() == 0; |
| } |
| } |