diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java')
-rw-r--r-- | bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java new file mode 100644 index 000000000..88b3cb0d5 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.engine/src/org/eclipse/equinox/internal/p2/engine/Phase.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright (c) 2007, 2009 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.internal.p2.engine; + +import java.util.*; +import java.util.Map.Entry; +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; +import org.eclipse.equinox.p2.engine.*; +import org.eclipse.equinox.p2.engine.spi.ProvisioningAction; +import org.eclipse.equinox.p2.engine.spi.Touchpoint; +import org.eclipse.osgi.util.NLS; + +public abstract class Phase { + protected static final String PARM_OPERAND = "operand"; //$NON-NLS-1$ + protected static final String PARM_PHASE_ID = "phaseId"; //$NON-NLS-1$ + protected static final String PARM_PROFILE = "profile"; //$NON-NLS-1$ + protected static final String PARM_PROFILE_DATA_DIRECTORY = "profileDataDirectory"; //$NON-NLS-1$ + protected static final String PARM_CONTEXT = "context"; //$NON-NLS-1$ + /** + * Internal property. + */ + protected static final String PARM_AGENT = "agent"; //$NON-NLS-1$ + protected static final String PARM_FORCED = "forced"; //$NON-NLS-1$ + protected static final String PARM_TOUCHPOINT = "touchpoint"; //$NON-NLS-1$ + + protected final String phaseId; + protected final int weight; + protected final boolean forced; + protected int prePerformWork = 1000; + protected int mainPerformWork = 10000; + protected int postPerformWork = 1000; + private Map<String, Object> operandParameters = null; + private Map<String, Object> phaseParameters = new HashMap<String, Object>(); + private Map<Touchpoint, Map<String, Object>> touchpointToTouchpointPhaseParameters = new HashMap<Touchpoint, Map<String, Object>>(); + private Map<Touchpoint, Map<String, Object>> touchpointToTouchpointOperandParameters = new HashMap<Touchpoint, Map<String, Object>>(); + ActionManager actionManager; // injected from phaseset + + protected Phase(String phaseId, int weight, boolean forced) { + if (phaseId == null || phaseId.length() == 0) + throw new IllegalArgumentException(Messages.phaseid_not_set); + if (weight <= 0) + throw new IllegalArgumentException(Messages.phaseid_not_positive); + this.weight = weight; + this.phaseId = phaseId; + this.forced = forced; + } + + protected Phase(String phaseId, int weight) { + this(phaseId, weight, false); + } + + final protected ActionManager getActionManager() { + return actionManager; + } + + public String toString() { + return getClass().getName() + " - " + this.weight; //$NON-NLS-1$ + } + + void perform(MultiStatus status, EngineSession session, Operand[] operands, IProgressMonitor monitor) { + SubMonitor subMonitor = SubMonitor.convert(monitor, prePerformWork + mainPerformWork + postPerformWork); + session.recordPhaseEnter(this); + prePerform(status, session, subMonitor.newChild(prePerformWork)); + if (status.matches(IStatus.ERROR | IStatus.CANCEL)) + return; + session.recordPhaseStart(this); + + subMonitor.setWorkRemaining(mainPerformWork + postPerformWork); + mainPerform(status, session, operands, subMonitor.newChild(mainPerformWork)); + if (status.matches(IStatus.ERROR | IStatus.CANCEL)) + return; + + session.recordPhaseEnd(this); + subMonitor.setWorkRemaining(postPerformWork); + postPerform(status, session, subMonitor.newChild(postPerformWork)); + phaseParameters.clear(); + if (status.matches(IStatus.ERROR | IStatus.CANCEL)) + return; + session.recordPhaseExit(this); + subMonitor.done(); + } + + void prePerform(MultiStatus status, EngineSession session, IProgressMonitor monitor) { + IProfile profile = session.getProfile(); + phaseParameters.put(PARM_PROFILE, profile); + phaseParameters.put(PARM_PROFILE_DATA_DIRECTORY, session.getProfileDataDirectory()); + phaseParameters.put(PARM_CONTEXT, session.getProvisioningContext()); + phaseParameters.put(PARM_PHASE_ID, phaseId); + phaseParameters.put(PARM_FORCED, Boolean.toString(forced)); + phaseParameters.put(PARM_AGENT, session.getAgent()); + mergeStatus(status, initializePhase(monitor, profile, phaseParameters)); + } + + private void mainPerform(MultiStatus status, EngineSession session, Operand[] operands, SubMonitor subMonitor) { + IProfile profile = session.getProfile(); + subMonitor.beginTask("", operands.length); //$NON-NLS-1$ + for (int i = 0; i < operands.length; i++) { + subMonitor.setWorkRemaining(operands.length - i); + if (subMonitor.isCanceled()) + throw new OperationCanceledException(); + Operand operand = operands[i]; + if (!isApplicable(operand)) + continue; + + session.recordOperandStart(operand); + List<ProvisioningAction> actions = getActions(operand); + operandParameters = new HashMap<String, Object>(phaseParameters); + operandParameters.put(PARM_OPERAND, operand); + mergeStatus(status, initializeOperand(profile, operand, operandParameters, subMonitor)); + if (status.matches(IStatus.ERROR | IStatus.CANCEL)) { + operandParameters = null; + return; + } + + Touchpoint operandTouchpoint = (Touchpoint) operandParameters.get(PARM_TOUCHPOINT); + if (operandTouchpoint != null) { + mergeStatus(status, initializeTouchpointParameters(profile, operand, operandTouchpoint, subMonitor)); + if (status.matches(IStatus.ERROR | IStatus.CANCEL)) + return; + + operandParameters = touchpointToTouchpointOperandParameters.get(operandTouchpoint); + } + + operandParameters = Collections.unmodifiableMap(operandParameters); + if (actions != null) { + for (int j = 0; j < actions.size(); j++) { + ProvisioningAction action = actions.get(j); + Map<String, Object> parameters = operandParameters; + Touchpoint touchpoint = action.getTouchpoint(); + if (touchpoint != null) { + mergeStatus(status, initializeTouchpointParameters(profile, operand, touchpoint, subMonitor)); + if (status.matches(IStatus.ERROR | IStatus.CANCEL)) + return; + + parameters = touchpointToTouchpointOperandParameters.get(touchpoint); + } + IStatus actionStatus = null; + try { + session.recordActionExecute(action, parameters); + actionStatus = action.execute(parameters); + } catch (RuntimeException e) { + if (!forced) + throw e; + // "action.execute" calls user code and might throw an unchecked exception + // we catch the error here to gather information on where the problem occurred. + actionStatus = new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.forced_action_execute_error, action.getClass().getName()), e); + } catch (LinkageError e) { + if (!forced) + throw e; + // Catch linkage errors as these are generally recoverable but let other Errors propagate (see bug 222001) + actionStatus = new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.forced_action_execute_error, action.getClass().getName()), e); + } + if (forced && actionStatus != null && actionStatus.matches(IStatus.ERROR)) { + MultiStatus result = new MultiStatus(EngineActivator.ID, IStatus.ERROR, getProblemMessage(), null); + result.add(new Status(IStatus.ERROR, EngineActivator.ID, session.getContextString(this, operand, action), null)); + LogHelper.log(result); + actionStatus = Status.OK_STATUS; + } + mergeStatus(status, actionStatus); + if (status.matches(IStatus.ERROR | IStatus.CANCEL)) + return; + } + } + mergeStatus(status, touchpointCompleteOperand(profile, operand, operandParameters, subMonitor)); + mergeStatus(status, completeOperand(profile, operand, operandParameters, subMonitor)); + if (status.matches(IStatus.ERROR | IStatus.CANCEL)) + return; + operandParameters = null; + session.recordOperandEnd(operand); + subMonitor.worked(1); + } + } + + private IStatus initializeTouchpointParameters(IProfile profile, Operand operand, Touchpoint touchpoint, IProgressMonitor monitor) { + if (touchpointToTouchpointOperandParameters.containsKey(touchpoint)) + return Status.OK_STATUS; + + Map<String, Object> touchpointPhaseParameters = touchpointToTouchpointPhaseParameters.get(touchpoint); + if (touchpointPhaseParameters == null) { + touchpointPhaseParameters = new HashMap<String, Object>(phaseParameters); + IStatus status = touchpoint.initializePhase(monitor, profile, phaseId, touchpointPhaseParameters); + if (status != null && status.matches(IStatus.ERROR | IStatus.CANCEL)) + return status; + touchpointToTouchpointPhaseParameters.put(touchpoint, touchpointPhaseParameters); + } + + Map<String, Object> touchpointOperandParameters = new HashMap<String, Object>(touchpointPhaseParameters); + touchpointOperandParameters.putAll(operandParameters); + IStatus status = touchpoint.initializeOperand(profile, operand, touchpointOperandParameters); + if (status != null && status.matches(IStatus.ERROR | IStatus.CANCEL)) + return status; + touchpointToTouchpointOperandParameters.put(touchpoint, touchpointOperandParameters); + return Status.OK_STATUS; + } + + /** + * Merges a given IStatus into a MultiStatus + */ + protected static void mergeStatus(MultiStatus multi, IStatus status) { + if (status != null && !status.isOK()) + multi.merge(status); + } + + void postPerform(MultiStatus status, EngineSession session, IProgressMonitor monitor) { + IProfile profile = session.getProfile(); + mergeStatus(status, touchpointCompletePhase(monitor, profile, phaseParameters)); + mergeStatus(status, completePhase(monitor, profile, phaseParameters)); + } + + void undo(MultiStatus status, EngineSession session, IProfile profile, Operand operand, ProvisioningAction[] actions, ProvisioningContext context) { + if (operandParameters == null) { + operandParameters = new HashMap<String, Object>(phaseParameters); + operandParameters.put(PARM_OPERAND, operand); + mergeStatus(status, initializeOperand(profile, operand, operandParameters, new NullProgressMonitor())); + Touchpoint operandTouchpoint = (Touchpoint) operandParameters.get(PARM_TOUCHPOINT); + if (operandTouchpoint != null) { + mergeStatus(status, initializeTouchpointParameters(profile, operand, operandTouchpoint, new NullProgressMonitor())); + if (status.matches(IStatus.ERROR | IStatus.CANCEL)) + return; + + operandParameters = touchpointToTouchpointOperandParameters.get(operandTouchpoint); + } + operandParameters = Collections.unmodifiableMap(operandParameters); + } + for (int j = 0; j < actions.length; j++) { + ProvisioningAction action = actions[j]; + Map<String, Object> parameters = operandParameters; + Touchpoint touchpoint = action.getTouchpoint(); + if (touchpoint != null) { + mergeStatus(status, initializeTouchpointParameters(profile, operand, touchpoint, new NullProgressMonitor())); + if (status.matches(IStatus.ERROR)) + return; + + parameters = touchpointToTouchpointOperandParameters.get(touchpoint); + } + IStatus actionStatus = null; + try { + session.recordActionUndo(action, parameters); + actionStatus = action.undo(parameters); + } catch (RuntimeException e) { + // "action.undo" calls user code and might throw an unchecked exception + // we catch the error here to gather information on where the problem occurred. + actionStatus = new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.action_undo_error, action.getClass().getName()), e); + } catch (LinkageError e) { + // Catch linkage errors as these are generally recoverable but let other Errors propagate (see bug 222001) + actionStatus = new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.action_undo_error, action.getClass().getName()), e); + } + if (actionStatus != null && actionStatus.matches(IStatus.ERROR)) { + MultiStatus result = new MultiStatus(EngineActivator.ID, IStatus.ERROR, getProblemMessage(), null); + result.add(new Status(IStatus.ERROR, EngineActivator.ID, session.getContextString(this, operand, action), null)); + result.merge(actionStatus); + } + } + mergeStatus(status, touchpointCompleteOperand(profile, operand, operandParameters, new NullProgressMonitor())); + mergeStatus(status, completeOperand(profile, operand, operandParameters, new NullProgressMonitor())); + operandParameters = null; + } + + public boolean isApplicable(Operand operand) { + return true; + } + + protected IStatus initializePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters) { + return Status.OK_STATUS; + } + + protected IStatus completePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters) { + return Status.OK_STATUS; + } + + IStatus touchpointCompletePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters) { + if (touchpointToTouchpointPhaseParameters.isEmpty()) + return Status.OK_STATUS; + + MultiStatus status = new MultiStatus(EngineActivator.ID, IStatus.OK, null, null); + for (Entry<Touchpoint, Map<String, Object>> entry : touchpointToTouchpointPhaseParameters.entrySet()) { + Touchpoint touchpoint = entry.getKey(); + Map<String, Object> touchpointParameters = entry.getValue(); + mergeStatus(status, touchpoint.completePhase(monitor, profile, phaseId, touchpointParameters)); + } + touchpointToTouchpointPhaseParameters.clear(); + return status; + } + + protected IStatus completeOperand(IProfile profile, Operand operand, Map<String, Object> parameters, IProgressMonitor monitor) { + return Status.OK_STATUS; + } + + IStatus touchpointCompleteOperand(IProfile profile, Operand operand, Map<String, Object> parameters, IProgressMonitor monitor) { + if (touchpointToTouchpointOperandParameters.isEmpty()) + return Status.OK_STATUS; + + MultiStatus status = new MultiStatus(EngineActivator.ID, IStatus.OK, null, null); + for (Entry<Touchpoint, Map<String, Object>> entry : touchpointToTouchpointOperandParameters.entrySet()) { + Touchpoint touchpoint = entry.getKey(); + Map<String, Object> touchpointParameters = entry.getValue(); + mergeStatus(status, touchpoint.completeOperand(profile, operand, touchpointParameters)); + } + touchpointToTouchpointOperandParameters.clear(); + return status; + } + + protected IStatus initializeOperand(IProfile profile, Operand operand, Map<String, Object> parameters, IProgressMonitor monitor) { + return Status.OK_STATUS; + } + + protected abstract List<ProvisioningAction> getActions(Operand operand); + + /** + * Returns a human-readable message to be displayed in case of an error performing + * this phase. Subclasses should override. + */ + protected String getProblemMessage() { + return NLS.bind(Messages.phase_error, getClass().getName()); + } +} |